Commit 3f6b47d5 by John Porto

Subzero. ARM32. Removes memory legalization warts.

This CL removes two warts from the ARM32 backend: 1) during argument lowering, if a stack parameter is assigned a register, the backend creates a new Variable that references the stack location with the incoming argument, and _mov() it to the parameter. 2) During stack slot legalization, all _mov(Mem(), Reg) are converted to stores; and all _mov(Reg, Mem()) are converted to loads. BUG= https://code.google.com/p/nativeclient/issues/detail?id=4076 R=kschimpf@google.com Review URL: https://codereview.chromium.org/1457683004 .
parent 174531ec
...@@ -765,7 +765,7 @@ void InstARM32Mov::emitSingleDestMultiSource(const Cfg *Func) const { ...@@ -765,7 +765,7 @@ void InstARM32Mov::emitSingleDestMultiSource(const Cfg *Func) const {
namespace { namespace {
bool isVariableWithoutRegister(const Operand *Op) { bool isVariableWithoutRegister(const Operand *Op) {
if (const auto *OpV = llvm::dyn_cast<const Variable>(Op)) { if (const auto *OpV = llvm::dyn_cast<Variable>(Op)) {
return !OpV->hasReg(); return !OpV->hasReg();
} }
return false; return false;
...@@ -789,84 +789,57 @@ void InstARM32Mov::emitSingleDestSingleSource(const Cfg *Func) const { ...@@ -789,84 +789,57 @@ void InstARM32Mov::emitSingleDestSingleSource(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
Variable *Dest = getDest(); Variable *Dest = getDest();
if (Dest->hasReg()) { if (!Dest->hasReg()) {
Type Ty = Dest->getType(); llvm::report_fatal_error("mov can't store.");
Operand *Src0 = getSrc(0); }
const bool IsVector = isVectorType(Ty);
const bool IsScalarFP = isScalarFloatingType(Ty); Operand *Src0 = getSrc(0);
const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0); if (isMemoryAccess(Src0)) {
const char *LoadOpcode = IsVector ? "vld1" : (IsScalarFP ? "vldr" : "ldr"); llvm::report_fatal_error("mov can't load.");
const bool IsVMove = (IsVector || IsScalarFP || CoreVFPMove); }
const char *RegMovOpcode = IsVMove ? "vmov" : "mov";
const char *ActualOpcode = isMemoryAccess(Src0) ? LoadOpcode : RegMovOpcode; Type Ty = Dest->getType();
// when vmov{c}'ing, we need to emit a width string. Otherwise, the const bool IsVector = isVectorType(Ty);
// assembler might be tempted to assume we want a vector vmov{c}, and that const bool IsScalarFP = isScalarFloatingType(Ty);
// is disallowed because ARM. const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0);
const char *NoWidthString = ""; const bool IsVMove = (IsVector || IsScalarFP || CoreVFPMove);
const char *WidthString = const char *Opcode = IsVMove ? "vmov" : "mov";
isMemoryAccess(Src0) // when vmov{c}'ing, we need to emit a width string. Otherwise, the
? (IsVector ? ".64" : getWidthString(Ty)) // assembler might be tempted to assume we want a vector vmov{c}, and that
: (!CoreVFPMove ? getVecWidthString(Ty) : NoWidthString); // is disallowed because ARM.
Str << "\t" << ActualOpcode; const char *WidthString = !CoreVFPMove ? getVecWidthString(Ty) : "";
const bool IsVInst = IsVMove || IsVector || IsScalarFP; Str << "\t" << Opcode;
if (IsVInst) { if (IsVMove) {
Str << getPredicate() << WidthString; Str << getPredicate() << WidthString;
} else {
Str << WidthString << getPredicate();
}
Str << "\t";
Dest->emit(Func);
Str << ", ";
Src0->emit(Func);
} else { } else {
Variable *Src0 = llvm::cast<Variable>(getSrc(0)); Str << WidthString << getPredicate();
assert(Src0->hasReg());
Type Ty = Src0->getType();
const bool IsVector = isVectorType(Ty);
const bool IsScalarFP = isScalarFloatingType(Ty);
const char *ActualOpcode =
IsVector ? "vst1" : (IsScalarFP ? "vstr" : "str");
const char *WidthString = IsVector ? ".64" : getWidthString(Ty);
Str << "\t" << ActualOpcode;
const bool IsVInst = IsVector || IsScalarFP;
if (IsVInst) {
Str << getPredicate() << WidthString;
} else {
Str << WidthString << getPredicate();
}
Str << "\t";
Src0->emit(Func);
Str << ", ";
Dest->emit(Func);
} }
Str << "\t";
Dest->emit(Func);
Str << ", ";
Src0->emit(Func);
} }
void InstARM32Mov::emitIASSingleDestSingleSource(const Cfg *Func) const { void InstARM32Mov::emitIASSingleDestSingleSource(const Cfg *Func) const {
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Variable *Dest = getDest(); Variable *Dest = getDest();
Operand *Src0 = getSrc(0); Operand *Src0 = getSrc(0);
if (Dest->hasReg()) {
const Type DestTy = Dest->getType(); if (!Dest->hasReg()) {
const bool DestIsVector = isVectorType(DestTy); llvm::report_fatal_error("mov can't store.");
const bool DestIsScalarFP = isScalarFloatingType(DestTy); }
const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0);
if (DestIsVector || DestIsScalarFP || CoreVFPMove) if (isMemoryAccess(Src0)) {
return Asm->setNeedsTextFixup(); llvm::report_fatal_error("mov can't load.");
if (isMemoryAccess(Src0)) {
// TODO(kschimpf) Figure out how to do ldr on CoreVPFMove? (see
// emitSingleDestSingleSource, local variable LoadOpcode).
return Asm->ldr(Dest, Src0, getPredicate(), Func->getTarget());
}
return Asm->mov(Dest, Src0, getPredicate());
} else {
const Type Src0Type = Src0->getType();
const bool Src0IsVector = isVectorType(Src0Type);
const bool Src0IsScalarFP = isScalarFloatingType(Src0Type);
const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0);
if (Src0IsVector || Src0IsScalarFP || CoreVFPMove)
return Asm->setNeedsTextFixup();
return Asm->str(Src0, Dest, getPredicate(), Func->getTarget());
} }
const Type DestTy = Dest->getType();
const bool DestIsVector = isVectorType(DestTy);
const bool DestIsScalarFP = isScalarFloatingType(DestTy);
const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0);
if (DestIsVector || DestIsScalarFP || CoreVFPMove)
return Asm->setNeedsTextFixup();
return Asm->mov(Dest, Src0, getPredicate());
} }
void InstARM32Mov::emit(const Cfg *Func) const { void InstARM32Mov::emit(const Cfg *Func) const {
......
...@@ -475,9 +475,6 @@ void TargetARM32::emitVariable(const Variable *Var) const { ...@@ -475,9 +475,6 @@ void TargetARM32::emitVariable(const Variable *Var) const {
Offset += getStackAdjustment(); Offset += getStackAdjustment();
} }
const Type VarTy = Var->getType(); const Type VarTy = Var->getType();
if (!isLegalMemOffset(VarTy, Offset)) {
llvm::report_fatal_error("Illegal stack offset");
}
Str << "[" << getRegName(BaseRegNum, VarTy); Str << "[" << getRegName(BaseRegNum, VarTy);
if (Offset != 0) { if (Offset != 0) {
Str << ", " << getConstantPrefix() << Offset; Str << ", " << getConstantPrefix() << Offset;
...@@ -625,7 +622,7 @@ void TargetARM32::lowerArguments() { ...@@ -625,7 +622,7 @@ void TargetARM32::lowerArguments() {
// to copy Arg into its assigned register if applicable. // to copy Arg into its assigned register if applicable.
void TargetARM32::finishArgumentLowering(Variable *Arg, Variable *FramePtr, void TargetARM32::finishArgumentLowering(Variable *Arg, Variable *FramePtr,
size_t BasicFrameOffset, size_t BasicFrameOffset,
size_t &InArgsSizeBytes) { size_t *InArgsSizeBytes) {
if (auto *Arg64On32 = llvm::dyn_cast<Variable64On32>(Arg)) { if (auto *Arg64On32 = llvm::dyn_cast<Variable64On32>(Arg)) {
Variable *Lo = Arg64On32->getLo(); Variable *Lo = Arg64On32->getLo();
Variable *Hi = Arg64On32->getHi(); Variable *Hi = Arg64On32->getHi();
...@@ -634,26 +631,23 @@ void TargetARM32::finishArgumentLowering(Variable *Arg, Variable *FramePtr, ...@@ -634,26 +631,23 @@ void TargetARM32::finishArgumentLowering(Variable *Arg, Variable *FramePtr,
return; return;
} }
Type Ty = Arg->getType(); Type Ty = Arg->getType();
InArgsSizeBytes = applyStackAlignmentTy(InArgsSizeBytes, Ty); assert(Ty != IceType_i64);
Arg->setStackOffset(BasicFrameOffset + InArgsSizeBytes);
InArgsSizeBytes += typeWidthInBytesOnStack(Ty); *InArgsSizeBytes = applyStackAlignmentTy(*InArgsSizeBytes, Ty);
// If the argument variable has been assigned a register, we need to load the const int32_t ArgStackOffset = BasicFrameOffset + *InArgsSizeBytes;
// value from the stack slot. *InArgsSizeBytes += typeWidthInBytesOnStack(Ty);
if (Arg->hasReg()) {
assert(Ty != IceType_i64); if (!Arg->hasReg()) {
// This should be simple, just load the parameter off the stack using a nice Arg->setStackOffset(ArgStackOffset);
// sp + imm addressing mode. Because ARM, we can't do that (e.g., VLDR, for return;
// fp types, cannot have an index register), so we legalize the memory
// operand instead.
auto *Mem = OperandARM32Mem::create(
Func, Ty, FramePtr, llvm::cast<ConstantInteger32>(
Ctx->getConstantInt32(Arg->getStackOffset())));
_mov(Arg, legalizeToReg(Mem, Arg->getRegNum()));
// This argument-copying instruction uses an explicit OperandARM32Mem
// operand instead of a Variable, so its fill-from-stack operation has to
// be tracked separately for statistics.
Ctx->statsUpdateFills();
} }
// If the argument variable has been assigned a register, we need to copy the
// value from the stack slot.
Variable *Parameter = Func->makeVariable(Ty);
Parameter->setMustNotHaveReg();
Parameter->setStackOffset(ArgStackOffset);
_mov(Arg, Parameter);
} }
Type TargetARM32::stackSlotType() { return IceType_i32; } Type TargetARM32::stackSlotType() { return IceType_i32; }
...@@ -754,8 +748,6 @@ void TargetARM32::addProlog(CfgNode *Node) { ...@@ -754,8 +748,6 @@ void TargetARM32::addProlog(CfgNode *Node) {
continue; continue;
} }
if (CalleeSaves[i] && RegsUsed[i]) { if (CalleeSaves[i] && RegsUsed[i]) {
// TODO(jvoung): do separate vpush for each floating point register
// segment and += 4, or 8 depending on type.
++NumCallee; ++NumCallee;
Variable *PhysicalRegister = getPhysicalRegister(i); Variable *PhysicalRegister = getPhysicalRegister(i);
PreservedRegsSizeBytes += PreservedRegsSizeBytes +=
...@@ -837,7 +829,7 @@ void TargetARM32::addProlog(CfgNode *Node) { ...@@ -837,7 +829,7 @@ void TargetARM32::addProlog(CfgNode *Node) {
InRegs = CC.I32InReg(&DummyReg); InRegs = CC.I32InReg(&DummyReg);
} }
if (!InRegs) if (!InRegs)
finishArgumentLowering(Arg, FramePtr, BasicFrameOffset, InArgsSizeBytes); finishArgumentLowering(Arg, FramePtr, BasicFrameOffset, &InArgsSizeBytes);
} }
// Fill in stack offsets for locals. // Fill in stack offsets for locals.
...@@ -981,11 +973,18 @@ Variable *TargetARM32::newBaseRegister(int32_t OriginalOffset, ...@@ -981,11 +973,18 @@ Variable *TargetARM32::newBaseRegister(int32_t OriginalOffset,
return ScratchReg; return ScratchReg;
} }
StackVariable *TargetARM32::legalizeStackSlot(Type Ty, int32_t Offset, OperandARM32Mem *TargetARM32::createMemOperand(Type Ty, int32_t Offset,
int32_t StackAdjust, int32_t StackAdjust,
Variable *OrigBaseReg, Variable *OrigBaseReg,
Variable **NewBaseReg, Variable **NewBaseReg,
int32_t *NewBaseOffset) { int32_t *NewBaseOffset) {
if (isLegalMemOffset(Ty, Offset + StackAdjust)) {
return OperandARM32Mem::create(
Func, Ty, OrigBaseReg, llvm::cast<ConstantInteger32>(
Ctx->getConstantInt32(Offset + StackAdjust)),
OperandARM32Mem::Offset);
}
if (*NewBaseReg == nullptr) { if (*NewBaseReg == nullptr) {
*NewBaseReg = newBaseRegister(Offset, StackAdjust, OrigBaseReg); *NewBaseReg = newBaseRegister(Offset, StackAdjust, OrigBaseReg);
*NewBaseOffset = Offset + StackAdjust; *NewBaseOffset = Offset + StackAdjust;
...@@ -998,18 +997,15 @@ StackVariable *TargetARM32::legalizeStackSlot(Type Ty, int32_t Offset, ...@@ -998,18 +997,15 @@ StackVariable *TargetARM32::legalizeStackSlot(Type Ty, int32_t Offset,
OffsetDiff = 0; OffsetDiff = 0;
} }
StackVariable *NewDest = Func->makeVariable<StackVariable>(Ty); return OperandARM32Mem::create(
NewDest->setMustNotHaveReg(); Func, Ty, *NewBaseReg,
NewDest->setBaseRegNum((*NewBaseReg)->getRegNum()); llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(OffsetDiff)),
NewDest->setStackOffset(OffsetDiff); OperandARM32Mem::Offset);
return NewDest;
} }
void TargetARM32::legalizeMovStackAddrImm(InstARM32Mov *MovInstr, void TargetARM32::legalizeMov(InstARM32Mov *MovInstr, int32_t StackAdjust,
int32_t StackAdjust, Variable *OrigBaseReg, Variable **NewBaseReg,
Variable *OrigBaseReg, int32_t *NewBaseOffset) {
Variable **NewBaseReg,
int32_t *NewBaseOffset) {
Variable *Dest = MovInstr->getDest(); Variable *Dest = MovInstr->getDest();
assert(Dest != nullptr); assert(Dest != nullptr);
Type DestTy = Dest->getType(); Type DestTy = Dest->getType();
...@@ -1017,6 +1013,7 @@ void TargetARM32::legalizeMovStackAddrImm(InstARM32Mov *MovInstr, ...@@ -1017,6 +1013,7 @@ void TargetARM32::legalizeMovStackAddrImm(InstARM32Mov *MovInstr,
Operand *Src = MovInstr->getSrc(0); Operand *Src = MovInstr->getSrc(0);
Type SrcTy = Src->getType(); Type SrcTy = Src->getType();
(void)SrcTy;
assert(SrcTy != IceType_i64); assert(SrcTy != IceType_i64);
if (MovInstr->isMultiDest() || MovInstr->isMultiSource()) if (MovInstr->isMultiDest() || MovInstr->isMultiSource())
...@@ -1024,40 +1021,29 @@ void TargetARM32::legalizeMovStackAddrImm(InstARM32Mov *MovInstr, ...@@ -1024,40 +1021,29 @@ void TargetARM32::legalizeMovStackAddrImm(InstARM32Mov *MovInstr,
bool Legalized = false; bool Legalized = false;
if (!Dest->hasReg()) { if (!Dest->hasReg()) {
assert(llvm::cast<Variable>(Src)->hasReg()); auto *const SrcR = llvm::cast<Variable>(Src);
assert(SrcR->hasReg());
const int32_t Offset = Dest->getStackOffset(); const int32_t Offset = Dest->getStackOffset();
if (!isLegalMemOffset(DestTy, Offset + StackAdjust)) { // This is a _mov(Mem(), Variable), i.e., a store.
Legalized = true; _str(SrcR, createMemOperand(DestTy, Offset, StackAdjust, OrigBaseReg,
Dest = legalizeStackSlot(DestTy, Offset, StackAdjust, OrigBaseReg, NewBaseReg, NewBaseOffset),
NewBaseReg, NewBaseOffset); MovInstr->getPredicate());
} // _str() does not have a Dest, so we add a fake-def(Dest).
Context.insert(InstFakeDef::create(Func, Dest));
Legalized = true;
} else if (auto *Var = llvm::dyn_cast<Variable>(Src)) { } else if (auto *Var = llvm::dyn_cast<Variable>(Src)) {
if (!Var->hasReg()) { if (!Var->hasReg()) {
const int32_t Offset = Var->getStackOffset(); const int32_t Offset = Var->getStackOffset();
if (!isLegalMemOffset(SrcTy, Offset + StackAdjust)) { _ldr(Dest, createMemOperand(DestTy, Offset, StackAdjust, OrigBaseReg,
Legalized = true; NewBaseReg, NewBaseOffset),
Src = legalizeStackSlot(SrcTy, Offset, StackAdjust, OrigBaseReg, MovInstr->getPredicate());
NewBaseReg, NewBaseOffset); Legalized = true;
}
}
} else if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Src)) {
if (ConstantInteger32 *OffsetOp = Mem->getOffset()) {
const int32_t Offset = OffsetOp->getValue();
if (!isLegalMemOffset(SrcTy, Offset + StackAdjust)) {
assert(Mem->getBase()->hasReg());
assert(Mem->getBase()->getRegNum() == (int32_t)getFrameOrStackReg());
Legalized = true;
Src = legalizeStackSlot(SrcTy, Offset, StackAdjust, OrigBaseReg,
NewBaseReg, NewBaseOffset);
}
} }
} }
if (Legalized) { if (Legalized) {
if (MovInstr->isDestRedefined()) { if (MovInstr->isDestRedefined()) {
_mov_redefined(Dest, Src, MovInstr->getPredicate()); _set_dest_redefined();
} else {
_mov(Dest, Src, MovInstr->getPredicate());
} }
MovInstr->setDeleted(); MovInstr->setDeleted();
} }
...@@ -1075,11 +1061,6 @@ void TargetARM32::legalizeStackSlots() { ...@@ -1075,11 +1061,6 @@ void TargetARM32::legalizeStackSlots() {
// clobber the flags register. // clobber the flags register.
Func->dump("Before legalizeStackSlots"); Func->dump("Before legalizeStackSlots");
assert(hasComputedFrame()); assert(hasComputedFrame());
// Early exit, if SpillAreaSizeBytes is really small.
// TODO(jpp): this is not safe -- loads and stores of q registers can't have
// offsets.
if (isLegalMemOffset(IceType_v4i32, SpillAreaSizeBytes))
return;
Variable *OrigBaseReg = getPhysicalRegister(getFrameOrStackReg()); Variable *OrigBaseReg = getPhysicalRegister(getFrameOrStackReg());
int32_t StackAdjust = 0; int32_t StackAdjust = 0;
// Do a fairly naive greedy clustering for now. Pick the first stack slot // Do a fairly naive greedy clustering for now. Pick the first stack slot
...@@ -1122,11 +1103,9 @@ void TargetARM32::legalizeStackSlots() { ...@@ -1122,11 +1103,9 @@ void TargetARM32::legalizeStackSlots() {
} }
} }
// The Lowering ensures that ldr and str always have legal Mem operands.
// The only other instruction that may access memory is mov.
if (auto *MovInstr = llvm::dyn_cast<InstARM32Mov>(CurInstr)) { if (auto *MovInstr = llvm::dyn_cast<InstARM32Mov>(CurInstr)) {
legalizeMovStackAddrImm(MovInstr, StackAdjust, OrigBaseReg, &NewBaseReg, legalizeMov(MovInstr, StackAdjust, OrigBaseReg, &NewBaseReg,
&NewBaseOffset); &NewBaseOffset);
} }
} }
} }
...@@ -4600,7 +4579,11 @@ Variable *TargetARM32::makeVectorOfZeros(Type Ty, int32_t RegNum) { ...@@ -4600,7 +4579,11 @@ Variable *TargetARM32::makeVectorOfZeros(Type Ty, int32_t RegNum) {
Variable *TargetARM32::copyToReg(Operand *Src, int32_t RegNum) { Variable *TargetARM32::copyToReg(Operand *Src, int32_t RegNum) {
Type Ty = Src->getType(); Type Ty = Src->getType();
Variable *Reg = makeReg(Ty, RegNum); Variable *Reg = makeReg(Ty, RegNum);
_mov(Reg, Src); if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Src)) {
_ldr(Reg, Mem);
} else {
_mov(Reg, Src);
}
return Reg; return Reg;
} }
...@@ -4641,7 +4624,6 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed, ...@@ -4641,7 +4624,6 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed,
Variable *RegIndex = nullptr; Variable *RegIndex = nullptr;
assert(Base); assert(Base);
RegBase = legalizeToReg(Base); RegBase = legalizeToReg(Base);
bool InvalidImm = false;
assert(Ty < MemTraitsSize); assert(Ty < MemTraitsSize);
if (Index) { if (Index) {
assert(Offset == nullptr); assert(Offset == nullptr);
...@@ -4653,12 +4635,7 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed, ...@@ -4653,12 +4635,7 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed,
static constexpr bool ZeroExt = false; static constexpr bool ZeroExt = false;
assert(MemTraits[Ty].CanHaveImm); assert(MemTraits[Ty].CanHaveImm);
if (!OperandARM32Mem::canHoldOffset(Ty, ZeroExt, Offset->getValue())) { if (!OperandARM32Mem::canHoldOffset(Ty, ZeroExt, Offset->getValue())) {
assert(RegBase->hasReg()); llvm::report_fatal_error("Invalid memory offset.");
assert(RegBase->getRegNum() == (int32_t)getFrameOrStackReg());
// We are a bit more lenient with invalid immediate when accessing the
// stack here, and then rely on legalizeStackSlots() to fix things as
// appropriate.
InvalidImm = true;
} }
} }
...@@ -4679,15 +4656,7 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed, ...@@ -4679,15 +4656,7 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed,
From = Mem; From = Mem;
} else { } else {
Variable *Reg = makeReg(Ty, RegNum); Variable *Reg = makeReg(Ty, RegNum);
if (InvalidImm) { _ldr(Reg, Mem);
// If Mem has an invalid immediate, we legalize it to a Reg using mov
// instead of ldr because legalizeStackSlots() will later kick in and
// fix the immediate for us.
_mov(Reg, Mem);
} else {
_ldr(Reg, Mem);
}
From = Reg; From = Reg;
} }
return From; return From;
......
...@@ -135,7 +135,7 @@ public: ...@@ -135,7 +135,7 @@ public:
Operand *loOperand(Operand *Operand); Operand *loOperand(Operand *Operand);
Operand *hiOperand(Operand *Operand); Operand *hiOperand(Operand *Operand);
void finishArgumentLowering(Variable *Arg, Variable *FramePtr, void finishArgumentLowering(Variable *Arg, Variable *FramePtr,
size_t BasicFrameOffset, size_t &InArgsSizeBytes); size_t BasicFrameOffset, size_t *InArgsSizeBytes);
bool hasCPUFeature(TargetARM32Features::ARM32InstructionSet I) const { bool hasCPUFeature(TargetARM32Features::ARM32InstructionSet I) const {
return CPUFeatures.hasFeature(I); return CPUFeatures.hasFeature(I);
...@@ -384,6 +384,7 @@ protected: ...@@ -384,6 +384,7 @@ protected:
// an assert around just in case there is some untested code path where Dest // an assert around just in case there is some untested code path where Dest
// is nullptr. // is nullptr.
assert(Dest != nullptr); assert(Dest != nullptr);
assert(!llvm::isa<OperandARM32Mem>(Src0));
auto *Instr = InstARM32Mov::create(Func, Dest, Src0, Pred); auto *Instr = InstARM32Mov::create(Func, Dest, Src0, Pred);
Context.insert(Instr); Context.insert(Instr);
...@@ -794,15 +795,15 @@ protected: ...@@ -794,15 +795,15 @@ protected:
CondARM32::Cond Pred = CondARM32::AL) { CondARM32::Cond Pred = CondARM32::AL) {
Context.insert(InstARM32Vcmp::create(Func, Src0, FpZero, Pred)); Context.insert(InstARM32Vcmp::create(Func, Src0, FpZero, Pred));
} }
void _veor(Variable *Dest, Variable *Src0, Variable *Src1) {
Context.insert(InstARM32Veor::create(Func, Dest, Src0, Src1));
}
void _vmrs(CondARM32::Cond Pred = CondARM32::AL) { void _vmrs(CondARM32::Cond Pred = CondARM32::AL) {
Context.insert(InstARM32Vmrs::create(Func, Pred)); Context.insert(InstARM32Vmrs::create(Func, Pred));
} }
void _vmul(Variable *Dest, Variable *Src0, Variable *Src1) { void _vmul(Variable *Dest, Variable *Src0, Variable *Src1) {
Context.insert(InstARM32Vmul::create(Func, Dest, Src0, Src1)); Context.insert(InstARM32Vmul::create(Func, Dest, Src0, Src1));
} }
void _veor(Variable *Dest, Variable *Src0, Variable *Src1) {
Context.insert(InstARM32Veor::create(Func, Dest, Src0, Src1));
}
void _vsqrt(Variable *Dest, Variable *Src, void _vsqrt(Variable *Dest, Variable *Src,
CondARM32::Cond Pred = CondARM32::AL) { CondARM32::Cond Pred = CondARM32::AL) {
Context.insert(InstARM32Vsqrt::create(Func, Dest, Src, Pred)); Context.insert(InstARM32Vsqrt::create(Func, Dest, Src, Pred));
...@@ -821,17 +822,27 @@ protected: ...@@ -821,17 +822,27 @@ protected:
// [OrigBaseReg, +/- Offset+StackAdjust]. // [OrigBaseReg, +/- Offset+StackAdjust].
Variable *newBaseRegister(int32_t Offset, int32_t StackAdjust, Variable *newBaseRegister(int32_t Offset, int32_t StackAdjust,
Variable *OrigBaseReg); Variable *OrigBaseReg);
/// Creates a new, legal StackVariable w.r.t. ARM's Immediate requirements. /// Creates a new, legal OperandARM32Mem for accessing OrigBase + Offset +
/// This method is not very smart: it will always create and return a new /// StackAdjust. The returned mem operand is a legal operand for accessing
/// StackVariable, even if Offset + StackAdjust is encodable. /// memory that is of type Ty.
StackVariable *legalizeStackSlot(Type Ty, int32_t Offset, int32_t StackAdjust, ///
Variable *OrigBaseReg, Variable **NewBaseReg, /// If [OrigBaseReg, #Offset+StackAdjust] is encodable, then the method
int32_t *NewBaseOffset); /// returns a Mem operand expressing it. Otherwise,
/// Legalizes Mov if its Source (or Destination) contains an invalid ///
/// immediate. /// if [*NewBaseReg, #Offset+StackAdjust-*NewBaseOffset] is encodable, the
void legalizeMovStackAddrImm(InstARM32Mov *Mov, int32_t StackAdjust, /// method will return that. Otherwise,
Variable *OrigBaseReg, Variable **NewBaseReg, ///
int32_t *NewBaseOffset); /// a new base register ip=OrigBaseReg+Offset+StackAdjust is created, and the
/// method returns [ip, #0].
OperandARM32Mem *createMemOperand(Type Ty, int32_t Offset,
int32_t StackAdjust, Variable *OrigBaseReg,
Variable **NewBaseReg,
int32_t *NewBaseOffset);
/// Legalizes Mov if its Source (or Destination) is a spilled Variable. Moves
/// to memory become store instructions, and moves from memory, loads.
void legalizeMov(InstARM32Mov *Mov, int32_t StackAdjust,
Variable *OrigBaseReg, Variable **NewBaseReg,
int32_t *NewBaseOffset);
TargetARM32Features CPUFeatures; TargetARM32Features CPUFeatures;
bool UsesFramePointer = false; bool UsesFramePointer = false;
......
...@@ -24,7 +24,9 @@ define internal void @mult_fwd_branches(i32 %a, i32 %b) { ...@@ -24,7 +24,9 @@ define internal void @mult_fwd_branches(i32 %a, i32 %b) {
; ASM-NEXT: sub sp, sp, #12 ; ASM-NEXT: sub sp, sp, #12
; ASM-NEXT: str r0, [sp, #8] ; ASM-NEXT: str r0, [sp, #8]
; ASM-NEXT: # [sp, #8] = def.pseudo
; ASM-NEXT: str r1, [sp, #4] ; ASM-NEXT: str r1, [sp, #4]
; ASM-NEXT: # [sp, #4] = def.pseudo
; DIS-LABEL:00000000 <mult_fwd_branches>: ; DIS-LABEL:00000000 <mult_fwd_branches>:
...@@ -58,6 +60,7 @@ define internal void @mult_fwd_branches(i32 %a, i32 %b) { ...@@ -58,6 +60,7 @@ define internal void @mult_fwd_branches(i32 %a, i32 %b) {
; ASM-NEXT: cmp r1, r2 ; ASM-NEXT: cmp r1, r2
; ASM-NEXT: movlt r0, #1 ; ASM-NEXT: movlt r0, #1
; ASM-NEXT: strb r0, [sp] ; ASM-NEXT: strb r0, [sp]
; ASM-NEXT: # [sp] = def.pseudo
; DIS-NEXT: c: e3a00000 ; DIS-NEXT: c: e3a00000
; DIS-NEXT: 10: e59d1008 ; DIS-NEXT: 10: e59d1008
...@@ -172,5 +175,4 @@ end: ...@@ -172,5 +175,4 @@ end:
; IASM-NEXT: .byte 0xff ; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x2f ; IASM-NEXT: .byte 0x2f
; IASM-NEXT: .byte 0xe1 ; IASM-NEXT: .byte 0xe1
} }
...@@ -35,6 +35,7 @@ define internal i32 @add1ToR0(i32 %p) { ...@@ -35,6 +35,7 @@ define internal i32 @add1ToR0(i32 %p) {
; IASM-NEXT: .byte 0xe2 ; IASM-NEXT: .byte 0xe2
; ASM-NEXT: str r0, [sp, #4] ; ASM-NEXT: str r0, [sp, #4]
; ASM-NEXT: # [sp, #4] = def.pseudo
; DIS-NEXT: 4: e58d0004 ; DIS-NEXT: 4: e58d0004
; IASM-NEXT: .byte 0x4 ; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
...@@ -56,6 +57,7 @@ define internal i32 @add1ToR0(i32 %p) { ...@@ -56,6 +57,7 @@ define internal i32 @add1ToR0(i32 %p) {
; IASM-NEXT: .byte 0xe2 ; IASM-NEXT: .byte 0xe2
; ASM-NEXT: str r0, [sp] ; ASM-NEXT: str r0, [sp]
; ASM-NEXT: # [sp] = def.pseudo
; DIS-NEXT: 10: e58d0000 ; DIS-NEXT: 10: e58d0000
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
......
...@@ -29,7 +29,7 @@ entry: ...@@ -29,7 +29,7 @@ entry:
; ASM-NEXT: movw ip, #4092 ; ASM-NEXT: movw ip, #4092
; ASM-NEXT: sub sp, sp, ip ; ASM-NEXT: sub sp, sp, ip
; ASM-NEXT: str r0, [sp, #4088] ; ASM-NEXT: str r0, [sp, #4088]
; ASM-NEXT: # [sp, #4088] = def.pseudo
; DIS-LABEL: 00000000 <foo>: ; DIS-LABEL: 00000000 <foo>:
; DIS-NEXT: 0: e300cffc ; DIS-NEXT: 0: e300cffc
; DIS-NEXT: 4: e04dd00c ; DIS-NEXT: 4: e04dd00c
...@@ -59,6 +59,7 @@ entry: ...@@ -59,6 +59,7 @@ entry:
; ASM-NEXT: ldr r1, [sp, #4088] ; ASM-NEXT: ldr r1, [sp, #4088]
; ASM-NEXT: mul r0, r0, r1 ; ASM-NEXT: mul r0, r0, r1
; ASM-NEXT: str r0, [sp, #4084] ; ASM-NEXT: str r0, [sp, #4084]
; ASM-NEXT: # [sp, #4084] = def.pseudo
; DIS-NEXT: c: e59d0ff8 ; DIS-NEXT: c: e59d0ff8
; DIS-NEXT: 10: e59d1ff8 ; DIS-NEXT: 10: e59d1ff8
......
...@@ -57,7 +57,7 @@ entry: ...@@ -57,7 +57,7 @@ entry:
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xb ; IASM-NEXT: .byte 0xb
; IASM-NEXT: .byte 0xe5 ; IASM-NEXT: .byte 0xe5
; ASM-NEXT: # [fp, #-4] = def.pseudo
br label %next br label %next
; ASM-NEXT: b .Ltest_vla_in_loop$next ; ASM-NEXT: b .Ltest_vla_in_loop$next
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment