Index: src/IceTargetLoweringARM32.cpp |
diff --git a/src/IceTargetLoweringARM32.cpp b/src/IceTargetLoweringARM32.cpp |
index d61d93cf0430b57ff316dd2ab95ce07b48f33acf..f92160b47f0b7eb9ee3516f598bf24edb6b4b157 100644 |
--- a/src/IceTargetLoweringARM32.cpp |
+++ b/src/IceTargetLoweringARM32.cpp |
@@ -20,6 +20,7 @@ |
#include "IceDefs.h" |
#include "IceELFObjectWriter.h" |
#include "IceGlobalInits.h" |
+#include "IceInstARM32.def" |
#include "IceInstARM32.h" |
#include "IceLiveness.h" |
#include "IceOperand.h" |
@@ -30,6 +31,7 @@ |
#include "llvm/Support/MathExtras.h" |
#include <algorithm> |
+#include <utility> |
namespace Ice { |
@@ -380,8 +382,21 @@ IceString TargetARM32::getRegName(SizeT RegNum, Type Ty) const { |
} |
Variable *TargetARM32::getPhysicalRegister(SizeT RegNum, Type Ty) { |
- if (Ty == IceType_void) |
- Ty = IceType_i32; |
+ static const Type DefaultType[] = { |
+#define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt, \ |
+ isFP32, isFP64, isVec128, alias_init) \ |
+ (isFP32) \ |
+ ? IceType_f32 \ |
+ : ((isFP64) ? IceType_f64 : ((isVec128 ? IceType_v4i32 : IceType_i32))), |
+ REGARM32_TABLE |
+#undef X |
+ }; |
+ |
+ assert(RegNum < RegARM32::Reg_NUM); |
+ if (Ty == IceType_void) { |
+ assert(RegNum < llvm::array_lengthof(DefaultType)); |
+ Ty = DefaultType[RegNum]; |
+ } |
if (PhysicalRegisters[Ty].empty()) |
PhysicalRegisters[Ty].resize(RegARM32::Reg_NUM); |
assert(RegNum < PhysicalRegisters[Ty].size()); |
@@ -425,11 +440,17 @@ void TargetARM32::emitVariable(const Variable *Var) const { |
if (!hasFramePointer()) |
Offset += getStackAdjustment(); |
} |
- if (!isLegalVariableStackOffset(Offset)) { |
+ const Type VarTy = Var->getType(); |
+ // In general, no Variable64On32 should be emited in textual asm output. It |
+ // turns out that some lowering sequences Fake-Def/Fake-Use such a variables. |
+ // If they end up being assigned an illegal offset we get a runtime error. We |
+ // liberally allow Variable64On32 to have illegal offsets because offsets |
+ // don't matter in FakeDefs/FakeUses. |
+ if (!llvm::isa<Variable64On32>(Var) && |
+ !isLegalVariableStackOffset(VarTy, Offset)) { |
llvm::report_fatal_error("Illegal stack offset"); |
} |
- const Type FrameSPTy = stackSlotType(); |
- Str << "[" << getRegName(BaseRegNum, FrameSPTy); |
+ Str << "[" << getRegName(BaseRegNum, VarTy); |
if (Offset != 0) { |
Str << ", " << getConstantPrefix() << Offset; |
} |
@@ -592,17 +613,14 @@ void TargetARM32::finishArgumentLowering(Variable *Arg, Variable *FramePtr, |
// value from the stack slot. |
if (Arg->hasReg()) { |
assert(Ty != IceType_i64); |
- OperandARM32Mem *Mem = OperandARM32Mem::create( |
+ // This should be simple, just load the parameter off the stack using a nice |
+ // sp + imm addressing mode. Because ARM, we can't do that (e.g., VLDR, for |
+ // 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()))); |
- if (isVectorType(Arg->getType())) { |
- // Use vld1.$elem or something? |
- UnimplementedError(Func->getContext()->getFlags()); |
- } else if (isFloatingType(Arg->getType())) { |
- _vldr(Arg, Mem); |
- } else { |
- _ldr(Arg, Mem); |
- } |
+ 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. |
@@ -894,16 +912,15 @@ void TargetARM32::addEpilog(CfgNode *Node) { |
RI->setDeleted(); |
} |
-bool TargetARM32::isLegalVariableStackOffset(int32_t Offset) const { |
+bool TargetARM32::isLegalVariableStackOffset(Type Ty, int32_t Offset) const { |
constexpr bool SignExt = false; |
- // TODO(jvoung): vldr of FP stack slots has a different limit from the plain |
- // stackSlotType(). |
- return OperandARM32Mem::canHoldOffset(stackSlotType(), SignExt, Offset); |
+ return OperandARM32Mem::canHoldOffset(Ty, SignExt, Offset); |
} |
StackVariable *TargetARM32::legalizeVariableSlot(Variable *Var, |
+ int32_t StackAdjust, |
Variable *OrigBaseReg) { |
- int32_t Offset = Var->getStackOffset(); |
+ int32_t Offset = Var->getStackOffset() + StackAdjust; |
// Legalize will likely need a movw/movt combination, but if the top bits are |
// all 0 from negating the offset and subtracting, we could use that instead. |
bool ShouldSub = (-Offset & 0xFFFF0000) == 0; |
@@ -937,7 +954,9 @@ void TargetARM32::legalizeStackSlots() { |
Func->dump("Before legalizeStackSlots"); |
assert(hasComputedFrame()); |
// Early exit, if SpillAreaSizeBytes is really small. |
- if (isLegalVariableStackOffset(SpillAreaSizeBytes)) |
+ // TODO(jpp): this is not safe -- loads and stores of q registers can't have |
+ // offsets. |
+ if (isLegalVariableStackOffset(IceType_v4i32, SpillAreaSizeBytes)) |
return; |
Variable *OrigBaseReg = getPhysicalRegister(getFrameOrStackReg()); |
int32_t StackAdjust = 0; |
@@ -978,64 +997,77 @@ void TargetARM32::legalizeStackSlots() { |
continue; |
} |
} |
+ |
// For now, only Mov instructions can have stack variables. We need to |
// know the type of instruction because we currently create a fresh one |
// to replace Dest/Source, rather than mutate in place. |
- auto *MovInst = llvm::dyn_cast<InstARM32Mov>(CurInstr); |
- if (!MovInst) { |
+ bool MayNeedOffsetRewrite = false; |
+ if (auto *MovInstr = llvm::dyn_cast<InstARM32Mov>(CurInstr)) { |
+ MayNeedOffsetRewrite = |
+ !MovInstr->isMultiDest() && !MovInstr->isMultiSource(); |
+ } |
+ |
+ if (!MayNeedOffsetRewrite) { |
continue; |
} |
+ |
+ assert(Dest != nullptr); |
+ Type DestTy = Dest->getType(); |
+ assert(DestTy != IceType_i64); |
if (!Dest->hasReg()) { |
int32_t Offset = Dest->getStackOffset(); |
Offset += StackAdjust; |
- if (!isLegalVariableStackOffset(Offset)) { |
+ if (!isLegalVariableStackOffset(DestTy, Offset)) { |
if (NewBaseReg) { |
int32_t OffsetDiff = Offset - NewBaseOffset; |
- if (isLegalVariableStackOffset(OffsetDiff)) { |
+ if (isLegalVariableStackOffset(DestTy, OffsetDiff)) { |
StackVariable *NewDest = |
Func->makeVariable<StackVariable>(stackSlotType()); |
NewDest->setMustNotHaveReg(); |
NewDest->setBaseRegNum(NewBaseReg->getBaseRegNum()); |
NewDest->setStackOffset(OffsetDiff); |
Variable *NewDestVar = NewDest; |
- _mov(NewDestVar, MovInst->getSrc(0)); |
- MovInst->setDeleted(); |
+ _mov(NewDestVar, CurInstr->getSrc(0)); |
+ CurInstr->setDeleted(); |
continue; |
} |
} |
- StackVariable *LegalDest = legalizeVariableSlot(Dest, OrigBaseReg); |
+ StackVariable *LegalDest = |
+ legalizeVariableSlot(Dest, StackAdjust, OrigBaseReg); |
assert(LegalDest != Dest); |
Variable *LegalDestVar = LegalDest; |
- _mov(LegalDestVar, MovInst->getSrc(0)); |
- MovInst->setDeleted(); |
+ _mov(LegalDestVar, CurInstr->getSrc(0)); |
+ CurInstr->setDeleted(); |
NewBaseReg = LegalDest; |
NewBaseOffset = Offset; |
continue; |
} |
} |
- assert(MovInst->getSrcSize() == 1); |
- Variable *Var = llvm::dyn_cast<Variable>(MovInst->getSrc(0)); |
+ assert(CurInstr->getSrcSize() == 1); |
+ Variable *Var = llvm::dyn_cast<Variable>(CurInstr->getSrc(0)); |
if (Var && !Var->hasReg()) { |
+ Type VarTy = Var->getType(); |
int32_t Offset = Var->getStackOffset(); |
Offset += StackAdjust; |
- if (!isLegalVariableStackOffset(Offset)) { |
+ if (!isLegalVariableStackOffset(VarTy, Offset)) { |
if (NewBaseReg) { |
int32_t OffsetDiff = Offset - NewBaseOffset; |
- if (isLegalVariableStackOffset(OffsetDiff)) { |
+ if (isLegalVariableStackOffset(VarTy, OffsetDiff)) { |
StackVariable *NewVar = |
Func->makeVariable<StackVariable>(stackSlotType()); |
NewVar->setMustNotHaveReg(); |
NewVar->setBaseRegNum(NewBaseReg->getBaseRegNum()); |
NewVar->setStackOffset(OffsetDiff); |
_mov(Dest, NewVar); |
- MovInst->setDeleted(); |
+ CurInstr->setDeleted(); |
continue; |
} |
} |
- StackVariable *LegalVar = legalizeVariableSlot(Var, OrigBaseReg); |
+ StackVariable *LegalVar = |
+ legalizeVariableSlot(Var, StackAdjust, OrigBaseReg); |
assert(LegalVar != Var); |
_mov(Dest, LegalVar); |
- MovInst->setDeleted(); |
+ CurInstr->setDeleted(); |
NewBaseReg = LegalVar; |
NewBaseOffset = Offset; |
continue; |
@@ -1427,6 +1459,20 @@ void TargetARM32::lowerArithmetic(const InstArithmetic *Inst) { |
} |
case InstArithmetic::Shl: { |
// a=b<<c ==> |
+ // pnacl-llc does: |
+ // mov t_b.lo, b.lo |
+ // mov t_b.hi, b.hi |
+ // mov t_c.lo, c.lo |
+ // rsb T0, t_c.lo, #32 |
+ // lsr T1, t_b.lo, T0 |
+ // orr t_a.hi, T1, t_b.hi, lsl t_c.lo |
+ // sub T2, t_c.lo, #32 |
+ // cmp T2, #0 |
+ // lslge t_a.hi, t_b.lo, T2 |
+ // lsl t_a.lo, t_b.lo, t_c.lo |
+ // mov a.lo, t_a.lo |
+ // mov a.hi, t_a.hi |
+ // |
// GCC 4.8 does: |
// sub t_c1, c.lo, #32 |
// lsl t_hi, b.hi, c.lo |
@@ -1436,78 +1482,88 @@ void TargetARM32::lowerArithmetic(const InstArithmetic *Inst) { |
// lsl t_lo, b.lo, c.lo |
// a.lo = t_lo |
// a.hi = t_hi |
+ // |
+ // These are incompatible, therefore we mimic pnacl-llc. |
// Can be strength-reduced for constant-shifts, but we don't do that for |
// now. |
// Given the sub/rsb T_C, C.lo, #32, one of the T_C will be negative. On |
// ARM, shifts only take the lower 8 bits of the shift register, and |
// saturate to the range 0-32, so the negative value will saturate to 32. |
- Variable *T_Hi = makeReg(IceType_i32); |
+ Constant *_32 = Ctx->getConstantInt32(32); |
+ Constant *_0 = Ctx->getConstantZero(IceType_i32); |
Variable *Src1RLo = legalizeToReg(Src1Lo); |
- Constant *ThirtyTwo = Ctx->getConstantInt32(32); |
- Variable *T_C1 = makeReg(IceType_i32); |
- Variable *T_C2 = makeReg(IceType_i32); |
- _sub(T_C1, Src1RLo, ThirtyTwo); |
- _lsl(T_Hi, Src0RHi, Src1RLo); |
- _orr(T_Hi, T_Hi, OperandARM32FlexReg::create(Func, IceType_i32, Src0RLo, |
- OperandARM32::LSL, T_C1)); |
- _rsb(T_C2, Src1RLo, ThirtyTwo); |
- _orr(T_Hi, T_Hi, OperandARM32FlexReg::create(Func, IceType_i32, Src0RLo, |
- OperandARM32::LSR, T_C2)); |
- _mov(DestHi, T_Hi); |
- Variable *T_Lo = makeReg(IceType_i32); |
- // _mov seems to sometimes have better register preferencing than lsl. |
- // Otherwise mov w/ lsl shifted register is a pseudo-instruction that |
- // maps to lsl. |
- _mov(T_Lo, OperandARM32FlexReg::create(Func, IceType_i32, Src0RLo, |
- OperandARM32::LSL, Src1RLo)); |
- _mov(DestLo, T_Lo); |
+ Variable *T0 = makeReg(IceType_i32); |
+ Variable *T1 = makeReg(IceType_i32); |
+ Variable *T2 = makeReg(IceType_i32); |
+ Variable *TA_Hi = makeReg(IceType_i32); |
+ Variable *TA_Lo = makeReg(IceType_i32); |
+ _rsb(T0, Src1RLo, _32); |
+ _lsr(T1, Src0RLo, T0); |
+ _orr(TA_Hi, T1, OperandARM32FlexReg::create(Func, IceType_i32, Src0RHi, |
+ OperandARM32::LSL, Src1RLo)); |
+ _sub(T2, Src1RLo, _32); |
+ _cmp(T2, _0); |
+ _lsl(TA_Hi, Src0RLo, T2, CondARM32::GE); |
+ _set_dest_nonkillable(); |
+ _lsl(TA_Lo, Src0RLo, Src1RLo); |
+ _mov(DestLo, TA_Lo); |
+ _mov(DestHi, TA_Hi); |
return; |
} |
case InstArithmetic::Lshr: |
- // a=b>>c (unsigned) ==> |
- // GCC 4.8 does: |
- // rsb t_c1, c.lo, #32 |
- // lsr t_lo, b.lo, c.lo |
- // orr t_lo, t_lo, b.hi, lsl t_c1 |
- // sub t_c2, c.lo, #32 |
- // orr t_lo, t_lo, b.hi, lsr t_c2 |
- // lsr t_hi, b.hi, c.lo |
- // a.lo = t_lo |
- // a.hi = t_hi |
case InstArithmetic::Ashr: { |
- // a=b>>c (signed) ==> ... |
- // Ashr is similar, but the sub t_c2, c.lo, #32 should set flags, and the |
- // next orr should be conditioned on PLUS. The last two right shifts |
- // should also be arithmetic. |
- bool IsAshr = Inst->getOp() == InstArithmetic::Ashr; |
- Variable *T_Lo = makeReg(IceType_i32); |
+ // a=b>>c |
+ // pnacl-llc does: |
+ // mov t_b.lo, b.lo |
+ // mov t_b.hi, b.hi |
+ // mov t_c.lo, c.lo |
+ // lsr T0, t_b.lo, t_c.lo |
+ // rsb T1, t_c.lo, #32 |
+ // orr t_a.lo, T0, t_b.hi, lsl T1 |
+ // sub T2, t_c.lo, #32 |
+ // cmp T2, #0 |
+ // [al]srge t_a.lo, t_b.hi, T2 |
+ // [al]sr t_a.hi, t_b.hi, t_c.lo |
+ // mov a.lo, t_a.lo |
+ // mov a.hi, t_a.hi |
+ // |
+ // GCC 4.8 does (lsr): |
+ // rsb t_c1, c.lo, #32 |
+ // lsr t_lo, b.lo, c.lo |
+ // orr t_lo, t_lo, b.hi, lsl t_c1 |
+ // sub t_c2, c.lo, #32 |
+ // orr t_lo, t_lo, b.hi, lsr t_c2 |
+ // lsr t_hi, b.hi, c.lo |
+ // mov a.lo, t_lo |
+ // mov a.hi, t_hi |
+ // |
+ // These are incompatible, therefore we mimic pnacl-llc. |
+ const bool IsAshr = Inst->getOp() == InstArithmetic::Ashr; |
+ Constant *_32 = Ctx->getConstantInt32(32); |
+ Constant *_0 = Ctx->getConstantZero(IceType_i32); |
Variable *Src1RLo = legalizeToReg(Src1Lo); |
- Constant *ThirtyTwo = Ctx->getConstantInt32(32); |
- Variable *T_C1 = makeReg(IceType_i32); |
- Variable *T_C2 = makeReg(IceType_i32); |
- _rsb(T_C1, Src1RLo, ThirtyTwo); |
- _lsr(T_Lo, Src0RLo, Src1RLo); |
- _orr(T_Lo, T_Lo, OperandARM32FlexReg::create(Func, IceType_i32, Src0RHi, |
- OperandARM32::LSL, T_C1)); |
- OperandARM32::ShiftKind RShiftKind; |
- CondARM32::Cond Pred; |
+ Variable *T0 = makeReg(IceType_i32); |
+ Variable *T1 = makeReg(IceType_i32); |
+ Variable *T2 = makeReg(IceType_i32); |
+ Variable *TA_Lo = makeReg(IceType_i32); |
+ Variable *TA_Hi = makeReg(IceType_i32); |
+ _lsr(T0, Src0RLo, Src1RLo); |
+ _rsb(T1, Src1RLo, _32); |
+ _orr(TA_Lo, T0, OperandARM32FlexReg::create(Func, IceType_i32, Src0RHi, |
+ OperandARM32::LSL, T1)); |
+ _sub(T2, Src1RLo, _32); |
+ _cmp(T2, _0); |
if (IsAshr) { |
- _subs(T_C2, Src1RLo, ThirtyTwo); |
- RShiftKind = OperandARM32::ASR; |
- Pred = CondARM32::PL; |
+ _asr(TA_Lo, Src0RHi, T2, CondARM32::GE); |
+ _set_dest_nonkillable(); |
+ _asr(TA_Hi, Src0RHi, Src1RLo); |
} else { |
- _sub(T_C2, Src1RLo, ThirtyTwo); |
- RShiftKind = OperandARM32::LSR; |
- Pred = CondARM32::AL; |
+ _lsr(TA_Lo, Src0RHi, T2, CondARM32::GE); |
+ _set_dest_nonkillable(); |
+ _lsr(TA_Hi, Src0RHi, Src1RLo); |
} |
- _orr(T_Lo, T_Lo, OperandARM32FlexReg::create(Func, IceType_i32, Src0RHi, |
- RShiftKind, T_C2), |
- Pred); |
- _mov(DestLo, T_Lo); |
- Variable *T_Hi = makeReg(IceType_i32); |
- _mov(T_Hi, OperandARM32FlexReg::create(Func, IceType_i32, Src0RHi, |
- RShiftKind, Src1RLo)); |
- _mov(DestHi, T_Hi); |
+ _mov(DestLo, TA_Lo); |
+ _mov(DestHi, TA_Hi); |
return; |
} |
case InstArithmetic::Fadd: |
@@ -1527,9 +1583,11 @@ void TargetARM32::lowerArithmetic(const InstArithmetic *Inst) { |
} |
return; |
} else if (isVectorType(Dest->getType())) { |
- UnimplementedError(Func->getContext()->getFlags()); |
// Add a fake def to keep liveness consistent in the meantime. |
- Context.insert(InstFakeDef::create(Func, Dest)); |
+ Variable *T = makeReg(Dest->getType()); |
+ Context.insert(InstFakeDef::create(Func, T)); |
+ _mov(Dest, T); |
+ UnimplementedError(Func->getContext()->getFlags()); |
return; |
} |
// Dest->getType() is a non-i64 scalar. |
@@ -1585,25 +1643,25 @@ void TargetARM32::lowerArithmetic(const InstArithmetic *Inst) { |
case InstArithmetic::Fadd: { |
Variable *Src1R = legalizeToReg(Src1); |
_vadd(T, Src0R, Src1R); |
- _vmov(Dest, T); |
+ _mov(Dest, T); |
return; |
} |
case InstArithmetic::Fsub: { |
Variable *Src1R = legalizeToReg(Src1); |
_vsub(T, Src0R, Src1R); |
- _vmov(Dest, T); |
+ _mov(Dest, T); |
return; |
} |
case InstArithmetic::Fmul: { |
Variable *Src1R = legalizeToReg(Src1); |
_vmul(T, Src0R, Src1R); |
- _vmov(Dest, T); |
+ _mov(Dest, T); |
return; |
} |
case InstArithmetic::Fdiv: { |
Variable *Src1R = legalizeToReg(Src1); |
_vdiv(T, Src0R, Src1R); |
- _vmov(Dest, T); |
+ _mov(Dest, T); |
return; |
} |
} |
@@ -1677,7 +1735,8 @@ void TargetARM32::lowerAssign(const InstAssign *Inst) { |
Operand *Src0Hi = legalize(hiOperand(Src0), Legal_Reg | Legal_Flex); |
Variable *DestLo = llvm::cast<Variable>(loOperand(Dest)); |
Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest)); |
- Variable *T_Lo = nullptr, *T_Hi = nullptr; |
+ Variable *T_Lo = makeReg(IceType_i32); |
+ Variable *T_Hi = makeReg(IceType_i32); |
_mov(T_Lo, Src0Lo); |
_mov(DestLo, T_Lo); |
_mov(T_Hi, Src0Hi); |
@@ -1696,10 +1755,11 @@ void TargetARM32::lowerAssign(const InstAssign *Inst) { |
NewSrc = legalize(Src0, Legal_Reg); |
} |
if (isVectorType(Dest->getType())) { |
- UnimplementedError(Func->getContext()->getFlags()); |
+ Variable *SrcR = legalizeToReg(NewSrc); |
+ _mov(Dest, SrcR); |
} else if (isFloatingType(Dest->getType())) { |
Variable *SrcR = legalizeToReg(NewSrc); |
- _vmov(Dest, SrcR); |
+ _mov(Dest, SrcR); |
} else { |
_mov(Dest, NewSrc); |
} |
@@ -1769,7 +1829,7 @@ void TargetARM32::lowerCall(const InstCall *Instr) { |
ParameterAreaSizeBytes = |
applyStackAlignmentTy(ParameterAreaSizeBytes, Ty); |
StackArgs.push_back(std::make_pair(Arg, ParameterAreaSizeBytes)); |
- ParameterAreaSizeBytes += typeWidthInBytesOnStack(Arg->getType()); |
+ ParameterAreaSizeBytes += typeWidthInBytesOnStack(Ty); |
} |
} |
@@ -1809,19 +1869,6 @@ void TargetARM32::lowerCall(const InstCall *Instr) { |
lowerStore(InstStore::create(Func, StackArg.first, Addr)); |
} |
- // Copy arguments to be passed in registers to the appropriate registers. |
- for (auto &GPRArg : GPRArgs) { |
- Variable *Reg = legalizeToReg(GPRArg.first, GPRArg.second); |
- // Generate a FakeUse of register arguments so that they do not get dead |
- // code eliminated as a result of the FakeKill of scratch registers after |
- // the call. |
- Context.insert(InstFakeUse::create(Func, Reg)); |
- } |
- for (auto &FPArg : FPArgs) { |
- Variable *Reg = legalizeToReg(FPArg.first, FPArg.second); |
- Context.insert(InstFakeUse::create(Func, Reg)); |
- } |
- |
// Generate the call instruction. Assign its result to a temporary with high |
// register allocation weight. |
Variable *Dest = Instr->getDest(); |
@@ -1872,6 +1919,19 @@ void TargetARM32::lowerCall(const InstCall *Instr) { |
if (!llvm::isa<ConstantRelocatable>(CallTarget)) { |
CallTarget = legalize(CallTarget, Legal_Reg); |
} |
+ |
+ // Copy arguments to be passed in registers to the appropriate registers. |
+ for (auto &FPArg : FPArgs) { |
+ Variable *Reg = legalizeToReg(FPArg.first, FPArg.second); |
+ Context.insert(InstFakeUse::create(Func, Reg)); |
+ } |
+ for (auto &GPRArg : GPRArgs) { |
+ Variable *Reg = legalizeToReg(GPRArg.first, GPRArg.second); |
+ // Generate a FakeUse of register arguments so that they do not get dead |
+ // code eliminated as a result of the FakeKill of scratch registers after |
+ // the call. |
+ Context.insert(InstFakeUse::create(Func, Reg)); |
+ } |
Inst *NewCall = InstARM32Call::create(Func, ReturnReg, CallTarget); |
Context.insert(NewCall); |
if (ReturnRegHi) |
@@ -1908,7 +1968,7 @@ void TargetARM32::lowerCall(const InstCall *Instr) { |
_mov(DestHi, ReturnRegHi); |
} else { |
if (isFloatingType(Dest->getType()) || isVectorType(Dest->getType())) { |
- _vmov(Dest, ReturnReg); |
+ _mov(Dest, ReturnReg); |
} else { |
assert(isIntegerType(Dest->getType()) && |
typeWidthInBytes(Dest->getType()) <= 4); |
@@ -1918,6 +1978,13 @@ void TargetARM32::lowerCall(const InstCall *Instr) { |
} |
} |
+namespace { |
+void forceHiLoInReg(Variable64On32 *Var) { |
+ Var->getHi()->setMustHaveReg(); |
+ Var->getLo()->setMustHaveReg(); |
+} |
+} // end of anonymous namespace |
+ |
void TargetARM32::lowerCast(const InstCast *Inst) { |
InstCast::OpKind CastKind = Inst->getCastKind(); |
Variable *Dest = Inst->getDest(); |
@@ -1928,6 +1995,9 @@ void TargetARM32::lowerCast(const InstCast *Inst) { |
return; |
case InstCast::Sext: { |
if (isVectorType(Dest->getType())) { |
+ Variable *T = makeReg(Dest->getType()); |
+ Context.insert(InstFakeDef::create(Func, T, legalizeToReg(Src0))); |
+ _mov(Dest, T); |
UnimplementedError(Func->getContext()->getFlags()); |
} else if (Dest->getType() == IceType_i64) { |
// t1=sxtb src; t2= mov t1 asr #31; dst.lo=t1; dst.hi=t2 |
@@ -1978,6 +2048,9 @@ void TargetARM32::lowerCast(const InstCast *Inst) { |
} |
case InstCast::Zext: { |
if (isVectorType(Dest->getType())) { |
+ Variable *T = makeReg(Dest->getType()); |
+ Context.insert(InstFakeDef::create(Func, T, legalizeToReg(Src0))); |
+ _mov(Dest, T); |
UnimplementedError(Func->getContext()->getFlags()); |
} else if (Dest->getType() == IceType_i64) { |
// t1=uxtb src; dst.lo=t1; dst.hi=0 |
@@ -2024,6 +2097,9 @@ void TargetARM32::lowerCast(const InstCast *Inst) { |
} |
case InstCast::Trunc: { |
if (isVectorType(Dest->getType())) { |
+ Variable *T = makeReg(Dest->getType()); |
+ Context.insert(InstFakeDef::create(Func, T, legalizeToReg(Src0))); |
+ _mov(Dest, T); |
UnimplementedError(Func->getContext()->getFlags()); |
} else { |
if (Src0->getType() == IceType_i64) |
@@ -2044,6 +2120,9 @@ void TargetARM32::lowerCast(const InstCast *Inst) { |
// fpext: dest.f64 = fptrunc src0.fp32 |
const bool IsTrunc = CastKind == InstCast::Fptrunc; |
if (isVectorType(Dest->getType())) { |
+ Variable *T = makeReg(Dest->getType()); |
+ Context.insert(InstFakeDef::create(Func, T, legalizeToReg(Src0))); |
+ _mov(Dest, T); |
UnimplementedError(Func->getContext()->getFlags()); |
break; |
} |
@@ -2057,6 +2136,26 @@ void TargetARM32::lowerCast(const InstCast *Inst) { |
} |
case InstCast::Fptosi: |
case InstCast::Fptoui: { |
+ if (isVectorType(Dest->getType())) { |
+ Variable *T = makeReg(Dest->getType()); |
+ Context.insert(InstFakeDef::create(Func, T, legalizeToReg(Src0))); |
+ _mov(Dest, T); |
+ UnimplementedError(Func->getContext()->getFlags()); |
+ break; |
+ } |
+ |
+ const bool DestIsSigned = CastKind == InstCast::Fptosi; |
+ const bool Src0IsF32 = isFloat32Asserting32Or64(Src0->getType()); |
+ if (llvm::isa<Variable64On32>(Dest)) { |
+ const char *HelperName = |
+ Src0IsF32 ? (DestIsSigned ? H_fptosi_f32_i64 : H_fptoui_f32_i64) |
+ : (DestIsSigned ? H_fptosi_f64_i64 : H_fptoui_f64_i64); |
+ static constexpr SizeT MaxSrcs = 1; |
+ InstCall *Call = makeHelperCall(HelperName, Dest, MaxSrcs); |
+ Call->addArg(Src0); |
+ lowerCall(Call); |
+ break; |
+ } |
// fptosi: |
// t1.fp = vcvt src0.fp |
// t2.i32 = vmov t1.fp |
@@ -2065,28 +2164,14 @@ void TargetARM32::lowerCast(const InstCast *Inst) { |
// t1.fp = vcvt src0.fp |
// t2.u32 = vmov t1.fp |
// dest.uint = conv t2.u32 @ Truncates the result if needed. |
- if (isVectorType(Dest->getType())) { |
- UnimplementedError(Func->getContext()->getFlags()); |
- break; |
- } |
- if (auto *Dest64On32 = llvm::dyn_cast<Variable64On32>(Dest)) { |
- Context.insert(InstFakeDef::create(Func, Dest64On32->getLo())); |
- Context.insert(InstFakeDef::create(Func, Dest64On32->getHi())); |
- UnimplementedError(Func->getContext()->getFlags()); |
- break; |
- } |
- const bool DestIsSigned = CastKind == InstCast::Fptosi; |
Variable *Src0R = legalizeToReg(Src0); |
Variable *T_fp = makeReg(IceType_f32); |
- if (isFloat32Asserting32Or64(Src0->getType())) { |
- _vcvt(T_fp, Src0R, |
- DestIsSigned ? InstARM32Vcvt::S2si : InstARM32Vcvt::S2ui); |
- } else { |
- _vcvt(T_fp, Src0R, |
- DestIsSigned ? InstARM32Vcvt::D2si : InstARM32Vcvt::D2ui); |
- } |
+ const InstARM32Vcvt::VcvtVariant Conversion = |
+ Src0IsF32 ? (DestIsSigned ? InstARM32Vcvt::S2si : InstARM32Vcvt::S2ui) |
+ : (DestIsSigned ? InstARM32Vcvt::D2si : InstARM32Vcvt::D2ui); |
+ _vcvt(T_fp, Src0R, Conversion); |
Variable *T = makeReg(IceType_i32); |
- _vmov(T, T_fp); |
+ _mov(T, T_fp); |
if (Dest->getType() != IceType_i32) { |
Variable *T_1 = makeReg(Dest->getType()); |
lowerCast(InstCast::create(Func, InstCast::Trunc, T_1, T)); |
@@ -2097,6 +2182,25 @@ void TargetARM32::lowerCast(const InstCast *Inst) { |
} |
case InstCast::Sitofp: |
case InstCast::Uitofp: { |
+ if (isVectorType(Dest->getType())) { |
+ Variable *T = makeReg(Dest->getType()); |
+ Context.insert(InstFakeDef::create(Func, T, legalizeToReg(Src0))); |
+ _mov(Dest, T); |
+ UnimplementedError(Func->getContext()->getFlags()); |
+ break; |
+ } |
+ const bool SourceIsSigned = CastKind == InstCast::Sitofp; |
+ const bool DestIsF32 = isFloat32Asserting32Or64(Dest->getType()); |
+ if (Src0->getType() == IceType_i64) { |
+ const char *HelperName = |
+ DestIsF32 ? (SourceIsSigned ? H_sitofp_i64_f32 : H_uitofp_i64_f32) |
+ : (SourceIsSigned ? H_sitofp_i64_f64 : H_uitofp_i64_f64); |
+ static constexpr SizeT MaxSrcs = 1; |
+ InstCall *Call = makeHelperCall(HelperName, Dest, MaxSrcs); |
+ Call->addArg(Src0); |
+ lowerCall(Call); |
+ break; |
+ } |
// sitofp: |
// t1.i32 = sext src.int @ sign-extends src0 if needed. |
// t2.fp32 = vmov t1.i32 |
@@ -2105,17 +2209,6 @@ void TargetARM32::lowerCast(const InstCast *Inst) { |
// t1.i32 = zext src.int @ zero-extends src0 if needed. |
// t2.fp32 = vmov t1.i32 |
// t3.fp = vcvt.{fp}.s32 @ fp is either f32 or f64 |
- if (isVectorType(Dest->getType())) { |
- UnimplementedError(Func->getContext()->getFlags()); |
- break; |
- } |
- if (Src0->getType() == IceType_i64) { |
- // avoid cryptic liveness errors |
- Context.insert(InstFakeDef::create(Func, Dest)); |
- UnimplementedError(Func->getContext()->getFlags()); |
- break; |
- } |
- const bool SourceIsSigned = CastKind == InstCast::Sitofp; |
if (Src0->getType() != IceType_i32) { |
Variable *Src0R_32 = makeReg(IceType_i32); |
lowerCast(InstCast::create(Func, SourceIsSigned ? InstCast::Sext |
@@ -2125,16 +2218,14 @@ void TargetARM32::lowerCast(const InstCast *Inst) { |
} |
Variable *Src0R = legalizeToReg(Src0); |
Variable *Src0R_f32 = makeReg(IceType_f32); |
- _vmov(Src0R_f32, Src0R); |
+ _mov(Src0R_f32, Src0R); |
Src0R = Src0R_f32; |
Variable *T = makeReg(Dest->getType()); |
- if (isFloat32Asserting32Or64(Dest->getType())) { |
- _vcvt(T, Src0R, |
- SourceIsSigned ? InstARM32Vcvt::Si2s : InstARM32Vcvt::Ui2s); |
- } else { |
- _vcvt(T, Src0R, |
- SourceIsSigned ? InstARM32Vcvt::Si2d : InstARM32Vcvt::Ui2d); |
- } |
+ const InstARM32Vcvt::VcvtVariant Conversion = |
+ DestIsF32 |
+ ? (SourceIsSigned ? InstARM32Vcvt::Si2s : InstARM32Vcvt::Ui2s) |
+ : (SourceIsSigned ? InstARM32Vcvt::Si2d : InstARM32Vcvt::Ui2d); |
+ _vcvt(T, Src0R, Conversion); |
_mov(Dest, T); |
break; |
} |
@@ -2153,9 +2244,6 @@ void TargetARM32::lowerCast(const InstCast *Inst) { |
case IceType_i1: |
UnimplementedError(Func->getContext()->getFlags()); |
break; |
- case IceType_v4i1: |
- UnimplementedError(Func->getContext()->getFlags()); |
- break; |
case IceType_i8: |
UnimplementedError(Func->getContext()->getFlags()); |
break; |
@@ -2166,7 +2254,7 @@ void TargetARM32::lowerCast(const InstCast *Inst) { |
case IceType_f32: { |
Variable *Src0R = legalizeToReg(Src0); |
Variable *T = makeReg(DestType); |
- _vmov(T, Src0R); |
+ _mov(T, Src0R); |
lowerAssign(InstAssign::create(Func, Dest, T)); |
break; |
} |
@@ -2175,13 +2263,17 @@ void TargetARM32::lowerCast(const InstCast *Inst) { |
// dest[31..0] = t0 |
// dest[63..32] = t1 |
assert(Src0->getType() == IceType_f64); |
- Variable *T0 = makeReg(IceType_i32); |
- Variable *T1 = makeReg(IceType_i32); |
+ auto *T = llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64)); |
+ T->initHiLo(Func); |
+ forceHiLoInReg(T); |
Variable *Src0R = legalizeToReg(Src0); |
- _vmov(InstARM32Vmov::RegisterPair(T0, T1), Src0R); |
+ _mov(T, Src0R); |
+ Context.insert(InstFakeDef::create(Func, T->getLo())); |
+ Context.insert(InstFakeDef::create(Func, T->getHi())); |
auto *Dest64On32 = llvm::cast<Variable64On32>(Dest); |
- lowerAssign(InstAssign::create(Func, Dest64On32->getLo(), T0)); |
- lowerAssign(InstAssign::create(Func, Dest64On32->getHi(), T1)); |
+ lowerAssign(InstAssign::create(Func, Dest64On32->getLo(), T->getLo())); |
+ lowerAssign(InstAssign::create(Func, Dest64On32->getHi(), T->getHi())); |
+ Context.insert(InstFakeUse::create(Func, T)); |
break; |
} |
case IceType_f64: { |
@@ -2190,41 +2282,47 @@ void TargetARM32::lowerCast(const InstCast *Inst) { |
// vmov T2, T0, T1 |
// Dest <- T2 |
assert(Src0->getType() == IceType_i64); |
- Variable *SrcLo = legalizeToReg(loOperand(Src0)); |
- Variable *SrcHi = legalizeToReg(hiOperand(Src0)); |
- Variable *T = makeReg(IceType_f64); |
- _vmov(T, InstARM32Vmov::RegisterPair(SrcLo, SrcHi)); |
+ auto *Src64 = llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64)); |
+ Src64->initHiLo(Func); |
+ forceHiLoInReg(Src64); |
+ Variable *T = Src64->getLo(); |
+ _mov(T, legalizeToReg(loOperand(Src0))); |
+ T = Src64->getHi(); |
+ _mov(T, legalizeToReg(hiOperand(Src0))); |
+ T = makeReg(IceType_f64); |
+ Context.insert(InstFakeDef::create(Func, Src64)); |
+ _mov(T, Src64); |
+ Context.insert(InstFakeUse::create(Func, Src64->getLo())); |
+ Context.insert(InstFakeUse::create(Func, Src64->getHi())); |
lowerAssign(InstAssign::create(Func, Dest, T)); |
break; |
} |
+ case IceType_v4i1: |
case IceType_v8i1: |
- UnimplementedError(Func->getContext()->getFlags()); |
- break; |
case IceType_v16i1: |
- UnimplementedError(Func->getContext()->getFlags()); |
- break; |
case IceType_v8i16: |
- UnimplementedError(Func->getContext()->getFlags()); |
- break; |
case IceType_v16i8: |
- UnimplementedError(Func->getContext()->getFlags()); |
- break; |
- case IceType_v4i32: |
- // avoid cryptic liveness errors |
- Context.insert(InstFakeDef::create(Func, Dest)); |
- UnimplementedError(Func->getContext()->getFlags()); |
- break; |
case IceType_v4f32: |
+ case IceType_v4i32: { |
+ // avoid cryptic liveness errors |
+ Variable *T = makeReg(DestType); |
+ Context.insert(InstFakeDef::create(Func, T, legalizeToReg(Src0))); |
+ _mov(Dest, T); |
UnimplementedError(Func->getContext()->getFlags()); |
break; |
} |
+ } |
break; |
} |
} |
} |
void TargetARM32::lowerExtractElement(const InstExtractElement *Inst) { |
- (void)Inst; |
+ Variable *Dest = Inst->getDest(); |
+ Type DestType = Dest->getType(); |
+ Variable *T = makeReg(DestType); |
+ Context.insert(InstFakeDef::create(Func, T)); |
+ _mov(Dest, T); |
UnimplementedError(Func->getContext()->getFlags()); |
} |
@@ -2269,6 +2367,9 @@ struct { |
void TargetARM32::lowerFcmp(const InstFcmp *Inst) { |
Variable *Dest = Inst->getDest(); |
if (isVectorType(Dest->getType())) { |
+ Variable *T = makeReg(Dest->getType()); |
+ Context.insert(InstFakeDef::create(Func, T)); |
+ _mov(Dest, T); |
UnimplementedError(Func->getContext()->getFlags()); |
return; |
} |
@@ -2306,6 +2407,9 @@ void TargetARM32::lowerIcmp(const InstIcmp *Inst) { |
Operand *Src1 = legalizeUndef(Inst->getSrc(1)); |
if (isVectorType(Dest->getType())) { |
+ Variable *T = makeReg(Dest->getType()); |
+ Context.insert(InstFakeDef::create(Func, T)); |
+ _mov(Dest, T); |
UnimplementedError(Func->getContext()->getFlags()); |
return; |
} |
@@ -2514,7 +2618,7 @@ void TargetARM32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) { |
if (Val->getType() == IceType_i64) { |
Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest)); |
Constant *Zero = Ctx->getConstantZero(IceType_i32); |
- Variable *T = nullptr; |
+ Variable *T = makeReg(Zero->getType()); |
_mov(T, Zero); |
_mov(DestHi, T); |
} |
@@ -2561,9 +2665,18 @@ void TargetARM32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) { |
return; |
} |
case Intrinsics::Fabs: { |
- // Add a fake def to keep liveness consistent in the meantime. |
- Context.insert(InstFakeDef::create(Func, Instr->getDest())); |
- UnimplementedError(Func->getContext()->getFlags()); |
+ Variable *Dest = Instr->getDest(); |
+ Type DestTy = Dest->getType(); |
+ Variable *T = makeReg(DestTy); |
+ if (isVectorType(DestTy)) { |
+ // Add a fake def to keep liveness consistent in the meantime. |
+ Context.insert(InstFakeDef::create(Func, T)); |
+ _mov(Instr->getDest(), T); |
+ UnimplementedError(Func->getContext()->getFlags()); |
+ return; |
+ } |
+ _vabs(T, legalizeToReg(Instr->getArg(0))); |
+ _mov(Dest, T); |
return; |
} |
case Intrinsics::Longjmp: { |
@@ -2628,7 +2741,7 @@ void TargetARM32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) { |
Variable *Dest = Instr->getDest(); |
Variable *T = makeReg(Dest->getType()); |
_vsqrt(T, Src); |
- _vmov(Dest, T); |
+ _mov(Dest, T); |
return; |
} |
case Intrinsics::Stacksave: { |
@@ -2674,7 +2787,7 @@ void TargetARM32::lowerCLZ(Variable *Dest, Variable *ValLoR, Variable *ValHiR) { |
// of T2 as if it was used as a source. |
_set_dest_nonkillable(); |
_mov(DestLo, T2); |
- Variable *T3 = nullptr; |
+ Variable *T3 = makeReg(Zero->getType()); |
_mov(T3, Zero); |
_mov(DestHi, T3); |
return; |
@@ -2734,7 +2847,8 @@ void TargetARM32::lowerRet(const InstRet *Inst) { |
Reg = Q0; |
} else { |
Operand *Src0F = legalize(Src0, Legal_Reg | Legal_Flex); |
- _mov(Reg, Src0F, CondARM32::AL, RegARM32::Reg_r0); |
+ Reg = makeReg(Src0F->getType(), RegARM32::Reg_r0); |
+ _mov(Reg, Src0F, CondARM32::AL); |
} |
} |
// Add a ret instruction even if sandboxing is enabled, because addEpilog |
@@ -2758,6 +2872,9 @@ void TargetARM32::lowerSelect(const InstSelect *Inst) { |
Operand *Condition = Inst->getCondition(); |
if (isVectorType(DestTy)) { |
+ Variable *T = makeReg(DestTy); |
+ Context.insert(InstFakeDef::create(Func, T)); |
+ _mov(Dest, T); |
UnimplementedError(Func->getContext()->getFlags()); |
return; |
} |
@@ -2772,16 +2889,16 @@ void TargetARM32::lowerSelect(const InstSelect *Inst) { |
SrcF = legalizeUndef(SrcF); |
// Set the low portion. |
Variable *DestLo = llvm::cast<Variable>(loOperand(Dest)); |
- Variable *TLo = nullptr; |
Operand *SrcFLo = legalize(loOperand(SrcF), Legal_Reg | Legal_Flex); |
+ Variable *TLo = makeReg(SrcFLo->getType()); |
_mov(TLo, SrcFLo); |
Operand *SrcTLo = legalize(loOperand(SrcT), Legal_Reg | Legal_Flex); |
_mov_nonkillable(TLo, SrcTLo, Cond); |
_mov(DestLo, TLo); |
// Set the high portion. |
Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest)); |
- Variable *THi = nullptr; |
Operand *SrcFHi = legalize(hiOperand(SrcF), Legal_Reg | Legal_Flex); |
+ Variable *THi = makeReg(SrcFHi->getType()); |
_mov(THi, SrcFHi); |
Operand *SrcTHi = legalize(hiOperand(SrcT), Legal_Reg | Legal_Flex); |
_mov_nonkillable(THi, SrcTHi, Cond); |
@@ -2793,17 +2910,17 @@ void TargetARM32::lowerSelect(const InstSelect *Inst) { |
Variable *T = makeReg(DestTy); |
SrcF = legalizeToReg(SrcF); |
assert(DestTy == SrcF->getType()); |
- _vmov(T, SrcF); |
+ _mov(T, SrcF); |
SrcT = legalizeToReg(SrcT); |
assert(DestTy == SrcT->getType()); |
- _vmov(T, SrcT, Cond); |
+ _mov(T, SrcT, Cond); |
_set_dest_nonkillable(); |
- _vmov(Dest, T); |
+ _mov(Dest, T); |
return; |
} |
- Variable *T = nullptr; |
SrcF = legalize(SrcF, Legal_Reg | Legal_Flex); |
+ Variable *T = makeReg(SrcF->getType()); |
_mov(T, SrcF); |
SrcT = legalize(SrcT, Legal_Reg | Legal_Flex); |
_mov_nonkillable(T, SrcT, Cond); |
@@ -2823,9 +2940,6 @@ void TargetARM32::lowerStore(const InstStore *Inst) { |
_str(ValueHi, llvm::cast<OperandARM32Mem>(hiOperand(NewAddr))); |
_str(ValueLo, llvm::cast<OperandARM32Mem>(loOperand(NewAddr))); |
} else { |
- if (isVectorType(Ty)) { |
- UnimplementedError(Func->getContext()->getFlags()); |
- } |
Variable *ValueR = legalizeToReg(Value); |
_str(ValueR, NewAddr); |
} |
@@ -2878,6 +2992,7 @@ void TargetARM32::prelowerPhis() { |
Variable *TargetARM32::makeVectorOfZeros(Type Ty, int32_t RegNum) { |
Variable *Reg = makeReg(Ty, RegNum); |
+ Context.insert(InstFakeDef::create(Func, Reg)); |
UnimplementedError(Func->getContext()->getFlags()); |
return Reg; |
} |
@@ -2887,16 +3002,7 @@ Variable *TargetARM32::makeVectorOfZeros(Type Ty, int32_t RegNum) { |
Variable *TargetARM32::copyToReg(Operand *Src, int32_t RegNum) { |
Type Ty = Src->getType(); |
Variable *Reg = makeReg(Ty, RegNum); |
- if (isVectorType(Ty)) { |
- // TODO(jpp): Src must be a register, or an address with base register. |
- _vmov(Reg, Src); |
- } else if (isFloatingType(Ty)) { |
- _vmov(Reg, Src); |
- } else { |
- // Mov's Src operand can really only be the flexible second operand type or |
- // a register. Users should guarantee that. |
- _mov(Reg, Src); |
- } |
+ _mov(Reg, Src); |
return Reg; |
} |
@@ -2912,10 +3018,22 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed, |
// type of operand is not legal (e.g., OperandARM32Mem and !Legal_Mem), we |
// can always copy to a register. |
if (auto Mem = llvm::dyn_cast<OperandARM32Mem>(From)) { |
+ static const struct { |
+ bool CanHaveOffset; |
+ bool CanHaveIndex; |
+ } MemTraits[] = { |
+#define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr) \ |
+ { (ubits) > 0, rraddr } \ |
+ , |
+ ICETYPEARM32_TABLE |
+#undef X |
+ }; |
// Before doing anything with a Mem operand, we need to ensure that the |
// Base and Index components are in physical registers. |
Variable *Base = Mem->getBase(); |
Variable *Index = Mem->getIndex(); |
+ ConstantInteger32 *Offset = Mem->getOffset(); |
+ assert(Index == nullptr || Offset == nullptr); |
Variable *RegBase = nullptr; |
Variable *RegIndex = nullptr; |
if (Base) { |
@@ -2923,32 +3041,43 @@ Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed, |
} |
if (Index) { |
RegIndex = legalizeToReg(Index); |
+ if (!MemTraits[Ty].CanHaveIndex) { |
+ Variable *T = makeReg(IceType_i32, getReservedTmpReg()); |
+ _add(T, RegBase, RegIndex); |
+ RegBase = T; |
+ RegIndex = nullptr; |
+ } |
+ } |
+ if (Offset && Offset->getValue() != 0) { |
+ static constexpr bool SignExt = false; |
+ if (!MemTraits[Ty].CanHaveOffset || |
+ !OperandARM32Mem::canHoldOffset(Ty, SignExt, Offset->getValue())) { |
+ Variable *T = legalizeToReg(Offset, getReservedTmpReg()); |
+ _add(T, T, RegBase); |
+ RegBase = T; |
+ Offset = llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(0)); |
+ } |
} |
+ |
// Create a new operand if there was a change. |
if (Base != RegBase || Index != RegIndex) { |
// There is only a reg +/- reg or reg + imm form. |
// Figure out which to re-create. |
- if (Mem->isRegReg()) { |
+ if (RegBase && RegIndex) { |
Mem = OperandARM32Mem::create(Func, Ty, RegBase, RegIndex, |
Mem->getShiftOp(), Mem->getShiftAmt(), |
Mem->getAddrMode()); |
} else { |
- Mem = OperandARM32Mem::create(Func, Ty, RegBase, Mem->getOffset(), |
+ Mem = OperandARM32Mem::create(Func, Ty, RegBase, Offset, |
Mem->getAddrMode()); |
} |
} |
- if (!(Allowed & Legal_Mem)) { |
+ if (Allowed & Legal_Mem) { |
+ From = Mem; |
+ } else { |
Variable *Reg = makeReg(Ty, RegNum); |
- if (isVectorType(Ty)) { |
- UnimplementedError(Func->getContext()->getFlags()); |
- } else if (isFloatingType(Ty)) { |
- _vldr(Reg, Mem); |
- } else { |
- _ldr(Reg, Mem); |
- } |
+ _ldr(Reg, Mem); |
From = Reg; |
- } else { |
- From = Mem; |
} |
return From; |
} |