diff --git a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp index 15cda9b9432d5..fbe6fb7521a1f 100644 --- a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp @@ -478,7 +478,22 @@ bool ARMAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, const MachineOperand &MO = MI->getOperand(OpNum); assert(MO.isReg() && "unexpected inline asm memory operand"); - O << "[" << ARMInstPrinter::getRegisterName(MO.getReg()) << "]"; + O << "[" << ARMInstPrinter::getRegisterName(MO.getReg()); + if (MI->isInlineAsm()) { + assert(OpNum > 0 && "unexpected offset"); + const MachineOperand &MD = MI->getOperand(OpNum - 1); + assert(MD.isImm() && "unexpected meta operand"); + const InlineAsm::Flag F(MD.getImm()); + const unsigned NumOps = F.getNumOperandRegisters(); + if (NumOps == 2) { + assert(OpNum + 1 < MI->getNumOperands() && "missing offset operand"); + const MachineOperand &OffsetOp = MI->getOperand(OpNum + 1); + assert(OffsetOp.isImm() && "unexpected inline asm memory operand"); + if (uint64_t Offset = OffsetOp.getImm()) + O << ", #" << Offset; + } + } + O << "]"; return false; } diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp index 1ffdde0360cf6..65318bd921067 100644 --- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp +++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp @@ -2649,9 +2649,16 @@ bool llvm::rewriteARMFrameIndex(MachineInstr &MI, unsigned FrameRegIdx, unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask); bool isSub = false; - // Memory operands in inline assembly always use AddrMode2. - if (Opcode == ARM::INLINEASM || Opcode == ARM::INLINEASM_BR) - AddrMode = ARMII::AddrMode2; + // Memory operands in inline assembly use AddrMode_i12 for frame indices + // otherwise AddrMode2 is used. + if (MI.isInlineAsm()) { + assert(FrameRegIdx && "FrameRegIdx should not be first operand"); + const MachineOperand &MD = MI.getOperand(FrameRegIdx - 1); + assert(MD.isImm() && "unexpected operand"); + InlineAsm::Flag F(MD.getImm()); + AddrMode = F.getNumOperandRegisters() == 2 ? ARMII::AddrMode_i12 + : ARMII::AddrMode2; + } if (Opcode == ARM::ADDri) { Offset += MI.getOperand(FrameRegIdx+1).getImm(); diff --git a/llvm/lib/Target/ARM/ARMFrameLowering.cpp b/llvm/lib/Target/ARM/ARMFrameLowering.cpp index a3a71a8ec09a4..3d919179e5c64 100644 --- a/llvm/lib/Target/ARM/ARMFrameLowering.cpp +++ b/llvm/lib/Target/ARM/ARMFrameLowering.cpp @@ -2097,7 +2097,7 @@ static unsigned estimateRSStackSizeLimit(MachineFunction &MF, unsigned Limit = (1 << 12) - 1; for (auto &MBB : MF) { for (auto &MI : MBB) { - if (MI.isDebugInstr()) + if (MI.isDebugInstr() || MI.isInlineAsm()) continue; for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { if (!MI.getOperand(i).isFI()) diff --git a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp index 984d8d3e0b08c..baba295624a41 100644 --- a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -5880,13 +5880,21 @@ bool ARMDAGToDAGISel::SelectInlineAsmMemoryOperand( case InlineAsm::ConstraintCode::Us: case InlineAsm::ConstraintCode::Ut: case InlineAsm::ConstraintCode::Uv: - case InlineAsm::ConstraintCode::Uy: + case InlineAsm::ConstraintCode::Uy: { + SDValue Base, OffImm; + if (Op.getOpcode() == ISD::FrameIndex && + SelectAddrModeImm12(Op, Base, OffImm)) { + OutOps.push_back(Base); + OutOps.push_back(OffImm); + return false; + } // Require the address to be in a register. That is safe for all ARM // variants and it is hard to do anything much smarter without knowing // how the operand is used. OutOps.push_back(Op); return false; } + } return true; } diff --git a/llvm/test/CodeGen/ARM/inlineasm-m-constraint.ll b/llvm/test/CodeGen/ARM/inlineasm-m-constraint.ll new file mode 100644 index 0000000000000..1e680fb4c03ee --- /dev/null +++ b/llvm/test/CodeGen/ARM/inlineasm-m-constraint.ll @@ -0,0 +1,42 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 3 +; RUN: llc -mtriple=arm-linux-gnueabihf -o - %s 2>&1 | FileCheck %s + +; The intent of this test is 3 fold: +; 1. The first asm demonstrates a change in behavior of using sp. +; 2. The second asm is a case the previously would cause register exhaustion +; due to not using sp. +; 3. The third asm demonstrates ARMAsmPrinter::PrintAsmMemoryOperand not +; needing to print an offset when the offset is zero, and that we get the other +; alloca's offset correct. +define void @fail() { +; CHECK-LABEL: fail: +; CHECK: @ %bb.0: +; CHECK-NEXT: .save {r4, r5, r6, r7, r8, r9, r10, r11, lr} +; CHECK-NEXT: push {r4, r5, r6, r7, r8, r9, r10, r11, lr} +; CHECK-NEXT: .pad #8 +; CHECK-NEXT: sub sp, sp, #8 +; CHECK-NEXT: mov r0, #42 +; CHECK-NEXT: str r0, [sp, #4] +; CHECK-NEXT: @APP +; CHECK-NEXT: @ [sp, #4] +; CHECK-NEXT: @NO_APP +; CHECK-NEXT: @APP +; CHECK-NEXT: @ [sp, #4] +; CHECK-NEXT: @NO_APP +; CHECK-NEXT: mov r0, #99 +; CHECK-NEXT: str r0, [sp] +; CHECK-NEXT: @APP +; CHECK-NEXT: @ [sp] +; CHECK-NEXT: @NO_APP +; CHECK-NEXT: add sp, sp, #8 +; CHECK-NEXT: pop {r4, r5, r6, r7, r8, r9, r10, r11, lr} +; CHECK-NEXT: mov pc, lr + %x = alloca i32, align 4 + %y = alloca i32, align 4 + store i32 42, ptr %x + call void asm sideeffect "# $0", "*m,~{r1},~{r2},~{r3},~{r12},~{lr},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11}"(ptr elementtype(i32) %x) + call void asm sideeffect "# $0", "*m,~{r0},~{r1},~{r2},~{r3},~{r12},~{lr},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11}"(ptr elementtype(i32) %x) + store i32 99, ptr %y + call void asm sideeffect "# $0", "*m,~{r1},~{r2},~{r3},~{r12},~{lr},~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11}"(ptr elementtype(i32) %y) + ret void +} diff --git a/llvm/test/CodeGen/ARM/inlineasm3.ll b/llvm/test/CodeGen/ARM/inlineasm3.ll index 5589885bd1745..fd9bbe64a85a8 100644 --- a/llvm/test/CodeGen/ARM/inlineasm3.ll +++ b/llvm/test/CodeGen/ARM/inlineasm3.ll @@ -105,7 +105,7 @@ entry: define void @t10(ptr %f, i32 %g) nounwind { entry: ; CHECK: t10 -; CHECK: str r1, [r0] +; CHECK: str r1, [sp] %f.addr = alloca ptr, align 4 store ptr %f, ptr %f.addr, align 4 call void asm "str $1, $0", "=*Q,r"(ptr elementtype(ptr) %f.addr, i32 %g) nounwind