| Index: src/IceTargetLoweringARM32.cpp
|
| diff --git a/src/IceTargetLoweringARM32.cpp b/src/IceTargetLoweringARM32.cpp
|
| index 26f01f9492c2cbdcbdd2273cb0745d8f335692a7..2305a1b0c50107f439f6a7e3e616269bf6d44742 100644
|
| --- a/src/IceTargetLoweringARM32.cpp
|
| +++ b/src/IceTargetLoweringARM32.cpp
|
| @@ -123,6 +123,9 @@ ICEINSTICMP_TABLE
|
| // The maximum number of arguments to pass in GPR registers.
|
| const uint32_t ARM32_MAX_GPR_ARG = 4;
|
|
|
| +// Stack alignment
|
| +const uint32_t ARM32_STACK_ALIGNMENT_BYTES = 16;
|
| +
|
| } // end of anonymous namespace
|
|
|
| TargetARM32::TargetARM32(Cfg *Func)
|
| @@ -607,8 +610,42 @@ void TargetARM32::lowerAlloca(const InstAlloca *Inst) {
|
| // stack alignment is preserved after the alloca. The stack alignment
|
| // restriction can be relaxed in some cases.
|
| NeedsStackAlignment = true;
|
| - (void)Inst;
|
| - UnimplementedError(Func->getContext()->getFlags());
|
| +
|
| + // TODO(stichnot): minimize the number of adjustments of SP, etc.
|
| + Variable *SP = getPhysicalRegister(RegARM32::Reg_sp);
|
| + Variable *Dest = Inst->getDest();
|
| + uint32_t AlignmentParam = Inst->getAlignInBytes();
|
| + // For default align=0, set it to the real value 1, to avoid any
|
| + // bit-manipulation problems below.
|
| + AlignmentParam = std::max(AlignmentParam, 1u);
|
| +
|
| + // LLVM enforces power of 2 alignment.
|
| + assert(llvm::isPowerOf2_32(AlignmentParam));
|
| + assert(llvm::isPowerOf2_32(ARM32_STACK_ALIGNMENT_BYTES));
|
| +
|
| + uint32_t Alignment = std::max(AlignmentParam, ARM32_STACK_ALIGNMENT_BYTES);
|
| + if (Alignment > ARM32_STACK_ALIGNMENT_BYTES) {
|
| + alignRegisterPow2(SP, Alignment);
|
| + }
|
| + Operand *TotalSize = Inst->getSizeInBytes();
|
| + if (const auto *ConstantTotalSize =
|
| + llvm::dyn_cast<ConstantInteger32>(TotalSize)) {
|
| + uint32_t Value = ConstantTotalSize->getValue();
|
| + Value = Utils::applyAlignment(Value, Alignment);
|
| + Operand *SubAmount = legalize(Ctx->getConstantInt32(Value));
|
| + _sub(SP, SP, SubAmount);
|
| + } else {
|
| + // Non-constant sizes need to be adjusted to the next highest
|
| + // multiple of the required alignment at runtime.
|
| + TotalSize = legalize(TotalSize);
|
| + Variable *T = makeReg(IceType_i32);
|
| + _mov(T, TotalSize);
|
| + Operand *AddAmount = legalize(Ctx->getConstantInt32(Alignment - 1));
|
| + _add(T, T, AddAmount);
|
| + alignRegisterPow2(T, Alignment);
|
| + _sub(SP, SP, T);
|
| + }
|
| + _mov(Dest, SP);
|
| }
|
|
|
| void TargetARM32::lowerArithmetic(const InstArithmetic *Inst) {
|
| @@ -1528,6 +1565,23 @@ Variable *TargetARM32::makeReg(Type Type, int32_t RegNum) {
|
| return Reg;
|
| }
|
|
|
| +void TargetARM32::alignRegisterPow2(Variable *Reg, uint32_t Align) {
|
| + assert(llvm::isPowerOf2_32(Align));
|
| + uint32_t RotateAmt = 0;
|
| + uint32_t Immed_8;
|
| + Operand *Mask;
|
| + // Use AND or BIC to mask off the bits, depending on which immediate fits
|
| + // (if it fits at all). Assume Align is usually small, in which case BIC
|
| + // works better.
|
| + if (OperandARM32FlexImm::canHoldImm(Align - 1, &RotateAmt, &Immed_8)) {
|
| + Mask = legalize(Ctx->getConstantInt32(Align - 1), Legal_Reg | Legal_Flex);
|
| + _bic(Reg, Reg, Mask);
|
| + } else {
|
| + Mask = legalize(Ctx->getConstantInt32(-Align), Legal_Reg | Legal_Flex);
|
| + _and(Reg, Reg, Mask);
|
| + }
|
| +}
|
| +
|
| void TargetARM32::postLower() {
|
| if (Ctx->getFlags().getOptLevel() == Opt_m1)
|
| return;
|
|
|