From 123ed8f099b116449b8d9c284046863488390a47 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Sat, 7 Nov 2009 17:13:35 +0000 Subject: [PATCH] Initial support for addrmode handling. Tests by Brian Lucas! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@86382 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../MSP430/AsmPrinter/MSP430AsmPrinter.cpp | 31 +-- .../MSP430/AsmPrinter/MSP430InstPrinter.cpp | 31 +-- lib/Target/MSP430/MSP430ISelDAGToDAG.cpp | 245 +++++++++++++++--- .../CodeGen/MSP430/2009-09-18-AbsoluteAddr.ll | 2 +- test/CodeGen/MSP430/AddrMode-bis-rx.ll | 74 ++++++ test/CodeGen/MSP430/AddrMode-bis-xr.ll | 81 ++++++ test/CodeGen/MSP430/AddrMode-mov-rx.ll | 67 +++++ test/CodeGen/MSP430/AddrMode-mov-xr.ll | 67 +++++ test/CodeGen/MSP430/inline-asm.ll | 3 +- 9 files changed, 531 insertions(+), 70 deletions(-) create mode 100644 test/CodeGen/MSP430/AddrMode-bis-rx.ll create mode 100644 test/CodeGen/MSP430/AddrMode-bis-xr.ll create mode 100644 test/CodeGen/MSP430/AddrMode-mov-rx.ll create mode 100644 test/CodeGen/MSP430/AddrMode-mov-xr.ll diff --git a/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp b/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp index d53389a0371..22d80d4fba2 100644 --- a/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp +++ b/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp @@ -295,22 +295,23 @@ void MSP430AsmPrinter::printSrcMemOperand(const MachineInstr *MI, int OpNum, const MachineOperand &Base = MI->getOperand(OpNum); const MachineOperand &Disp = MI->getOperand(OpNum+1); - if (Base.isGlobal()) - printOperand(MI, OpNum, "mem"); - else if (Disp.isImm() && !Base.getReg()) + // Print displacement first + if (!Disp.isImm()) { + printOperand(MI, OpNum+1, "mem"); + } else { + if (!Base.getReg()) + O << '&'; + + printOperand(MI, OpNum+1, "nohash"); + } + + + // Print register base field + if (Base.getReg()) { + O << '('; printOperand(MI, OpNum); - else if (Base.getReg()) { - if (Disp.getImm()) { - printOperand(MI, OpNum + 1, "nohash"); - O << '('; - printOperand(MI, OpNum); - O << ')'; - } else { - O << '@'; - printOperand(MI, OpNum); - } - } else - llvm_unreachable("Unsupported memory operand"); + O << ')'; + } } void MSP430AsmPrinter::printCCOperand(const MachineInstr *MI, int OpNum) { diff --git a/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp b/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp index 6ea930bc394..0a403c4d29e 100644 --- a/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp +++ b/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp @@ -63,25 +63,22 @@ void MSP430InstPrinter::printSrcMemOperand(const MCInst *MI, unsigned OpNo, const MCOperand &Base = MI->getOperand(OpNo); const MCOperand &Disp = MI->getOperand(OpNo+1); - // FIXME: move global to displacement field! - if (Base.isExpr()) { + // Print displacement first + if (Disp.isExpr()) { O << '&'; - Base.getExpr()->print(O, &MAI); - } else if (Disp.isImm() && !Base.isReg()) - printOperand(MI, OpNo); - else if (Base.isReg()) { - if (Disp.getImm()) { - O << Disp.getImm() << '('; - printOperand(MI, OpNo); - O << ')'; - } else { - O << '@'; - printOperand(MI, OpNo); - } + Disp.getExpr()->print(O, &MAI); } else { - Base.dump(); - Disp.dump(); - llvm_unreachable("Unsupported memory operand"); + assert(Disp.isImm() && "Expected immediate in displacement field"); + if (!Base.getReg()) + O << '&'; + + O << Disp.getImm(); + } + + + // Print register base field + if (Base.getReg()) { + O << '(' << getRegisterName(Base.getReg()) << ')'; } } diff --git a/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp b/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp index 9cebb5f5627..37a6107c25c 100644 --- a/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp +++ b/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp @@ -45,6 +45,70 @@ static const bool ViewRMWDAGs = false; STATISTIC(NumLoadMoved, "Number of loads moved below TokenFactor"); + +namespace { + struct MSP430ISelAddressMode { + enum { + RegBase, + FrameIndexBase + } BaseType; + + struct { // This is really a union, discriminated by BaseType! + SDValue Reg; + int FrameIndex; + } Base; + + int16_t Disp; + GlobalValue *GV; + Constant *CP; + BlockAddress *BlockAddr; + const char *ES; + int JT; + unsigned Align; // CP alignment. + + MSP430ISelAddressMode() + : BaseType(RegBase), Disp(0), GV(0), CP(0), BlockAddr(0), + ES(0), JT(-1), Align(0) { + } + + bool hasSymbolicDisplacement() const { + return GV != 0 || CP != 0 || ES != 0 || JT != -1; + } + + bool hasBaseReg() const { + return Base.Reg.getNode() != 0; + } + + void setBaseReg(SDValue Reg) { + BaseType = RegBase; + Base.Reg = Reg; + } + + void dump() { + errs() << "MSP430ISelAddressMode " << this << '\n'; + if (Base.Reg.getNode() != 0) { + errs() << "Base.Reg "; + Base.Reg.getNode()->dump(); + } else { + errs() << " Base.FrameIndex " << Base.FrameIndex << '\n'; + } + errs() << " Disp " << Disp << '\n'; + if (GV) { + errs() << "GV "; + GV->dump(); + } else if (CP) { + errs() << " CP "; + CP->dump(); + errs() << " Align" << Align << '\n'; + } else if (ES) { + errs() << "ES "; + errs() << ES << '\n'; + } else if (JT != -1) + errs() << " JT" << JT << " Align" << Align << '\n'; + } + }; +} + /// MSP430DAGToDAGISel - MSP430 specific code to select MSP430 machine /// instructions for SelectionDAG operations. /// @@ -65,6 +129,10 @@ namespace { return "MSP430 DAG->DAG Pattern Instruction Selection"; } + bool MatchAddress(SDValue N, MSP430ISelAddressMode &AM); + bool MatchWrapper(SDValue N, MSP430ISelAddressMode &AM); + bool MatchAddressBase(SDValue N, MSP430ISelAddressMode &AM); + bool IsLegalAndProfitableToFold(SDNode *N, SDNode *U, SDNode *Root) const; @@ -95,50 +163,155 @@ FunctionPass *llvm::createMSP430ISelDag(MSP430TargetMachine &TM, return new MSP430DAGToDAGISel(TM, OptLevel); } -// FIXME: This is pretty dummy routine and needs to be rewritten in the future. -bool MSP430DAGToDAGISel::SelectAddr(SDValue Op, SDValue Addr, - SDValue &Base, SDValue &Disp) { - // Try to match frame address first. - if (FrameIndexSDNode *FIN = dyn_cast(Addr)) { - Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i16); - Disp = CurDAG->getTargetConstant(0, MVT::i16); + +/// MatchWrapper - Try to match MSP430ISD::Wrapper node into an addressing mode. +/// These wrap things that will resolve down into a symbol reference. If no +/// match is possible, this returns true, otherwise it returns false. +bool MSP430DAGToDAGISel::MatchWrapper(SDValue N, MSP430ISelAddressMode &AM) { + // If the addressing mode already has a symbol as the displacement, we can + // never match another symbol. + if (AM.hasSymbolicDisplacement()) + return true; + + SDValue N0 = N.getOperand(0); + + if (GlobalAddressSDNode *G = dyn_cast(N0)) { + AM.GV = G->getGlobal(); + AM.Disp += G->getOffset(); + //AM.SymbolFlags = G->getTargetFlags(); + } else if (ConstantPoolSDNode *CP = dyn_cast(N0)) { + AM.CP = CP->getConstVal(); + AM.Align = CP->getAlignment(); + AM.Disp += CP->getOffset(); + //AM.SymbolFlags = CP->getTargetFlags(); + } else if (ExternalSymbolSDNode *S = dyn_cast(N0)) { + AM.ES = S->getSymbol(); + //AM.SymbolFlags = S->getTargetFlags(); + } else if (JumpTableSDNode *J = dyn_cast(N0)) { + AM.JT = J->getIndex(); + //AM.SymbolFlags = J->getTargetFlags(); + } else { + AM.BlockAddr = cast(N0)->getBlockAddress(); + //AM.SymbolFlags = cast(N0)->getTargetFlags(); + } + return false; +} + +/// MatchAddressBase - Helper for MatchAddress. Add the specified node to the +/// specified addressing mode without any further recursion. +bool MSP430DAGToDAGISel::MatchAddressBase(SDValue N, MSP430ISelAddressMode &AM) { + // Is the base register already occupied? + if (AM.BaseType != MSP430ISelAddressMode::RegBase || AM.Base.Reg.getNode()) { + // If so, we cannot select it. return true; } - switch (Addr.getOpcode()) { - case ISD::ADD: - // Operand is a result from ADD with constant operand which fits into i16. - if (ConstantSDNode *CN = dyn_cast(Addr.getOperand(1))) { - uint64_t CVal = CN->getZExtValue(); - // Offset should fit into 16 bits. - if (((CVal << 48) >> 48) == CVal) { - SDValue N0 = Addr.getOperand(0); - if (FrameIndexSDNode *FIN = dyn_cast(N0)) - Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i16); - else - Base = N0; - - Disp = CurDAG->getTargetConstant(CVal, MVT::i16); - return true; - } + // Default, generate it as a register. + AM.BaseType = MSP430ISelAddressMode::RegBase; + AM.Base.Reg = N; + return false; +} + +bool MSP430DAGToDAGISel::MatchAddress(SDValue N, MSP430ISelAddressMode &AM) { + DebugLoc dl = N.getDebugLoc(); + DEBUG({ + errs() << "MatchAddress: "; + AM.dump(); + }); + + switch (N.getOpcode()) { + default: break; + case ISD::Constant: { + uint64_t Val = cast(N)->getSExtValue(); + AM.Disp += Val; + return false; + } + + case MSP430ISD::Wrapper: + if (!MatchWrapper(N, AM)) + return false; + break; + + case ISD::FrameIndex: + if (AM.BaseType == MSP430ISelAddressMode::RegBase + && AM.Base.Reg.getNode() == 0) { + AM.BaseType = MSP430ISelAddressMode::FrameIndexBase; + AM.Base.FrameIndex = cast(N)->getIndex(); + return false; } break; - case MSP430ISD::Wrapper: - SDValue N0 = Addr.getOperand(0); - if (GlobalAddressSDNode *G = dyn_cast(N0)) { - Base = CurDAG->getTargetGlobalAddress(G->getGlobal(), - MVT::i16, G->getOffset()); - Disp = CurDAG->getTargetConstant(0, MVT::i16); - return true; - } else if (ExternalSymbolSDNode *E = dyn_cast(N0)) { - Base = CurDAG->getTargetExternalSymbol(E->getSymbol(), MVT::i16); - Disp = CurDAG->getTargetConstant(0, MVT::i16); + + case ISD::ADD: { + MSP430ISelAddressMode Backup = AM; + if (!MatchAddress(N.getNode()->getOperand(0), AM) && + !MatchAddress(N.getNode()->getOperand(1), AM)) + return false; + AM = Backup; + if (!MatchAddress(N.getNode()->getOperand(1), AM) && + !MatchAddress(N.getNode()->getOperand(0), AM)) + return false; + AM = Backup; + + break; + } + + case ISD::OR: + // Handle "X | C" as "X + C" iff X is known to have C bits clear. + if (ConstantSDNode *CN = dyn_cast(N.getOperand(1))) { + MSP430ISelAddressMode Backup = AM; + uint64_t Offset = CN->getSExtValue(); + // Start with the LHS as an addr mode. + if (!MatchAddress(N.getOperand(0), AM) && + // Address could not have picked a GV address for the displacement. + AM.GV == NULL && + // Check to see if the LHS & C is zero. + CurDAG->MaskedValueIsZero(N.getOperand(0), CN->getAPIntValue())) { + AM.Disp += Offset; + return false; + } + AM = Backup; } break; - }; + } - Base = Addr; - Disp = CurDAG->getTargetConstant(0, MVT::i16); + return MatchAddressBase(N, AM); +} + +/// SelectAddr - returns true if it is able pattern match an addressing mode. +/// It returns the operands which make up the maximal addressing mode it can +/// match by reference. +bool MSP430DAGToDAGISel::SelectAddr(SDValue Op, SDValue N, + SDValue &Base, SDValue &Disp) { + MSP430ISelAddressMode AM; + + if (MatchAddress(N, AM)) + return false; + + EVT VT = N.getValueType(); + if (AM.BaseType == MSP430ISelAddressMode::RegBase) { + if (!AM.Base.Reg.getNode()) + AM.Base.Reg = CurDAG->getRegister(0, VT); + } + + Base = (AM.BaseType == MSP430ISelAddressMode::FrameIndexBase) ? + CurDAG->getTargetFrameIndex(AM.Base.FrameIndex, TLI.getPointerTy()) : + AM.Base.Reg; + + if (AM.GV) + Disp = CurDAG->getTargetGlobalAddress(AM.GV, MVT::i16, AM.Disp, + 0/*AM.SymbolFlags*/); + else if (AM.CP) + Disp = CurDAG->getTargetConstantPool(AM.CP, MVT::i16, + AM.Align, AM.Disp, 0/*AM.SymbolFlags*/); + else if (AM.ES) + Disp = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i16, 0/*AM.SymbolFlags*/); + else if (AM.JT != -1) + Disp = CurDAG->getTargetJumpTable(AM.JT, MVT::i16, 0/*AM.SymbolFlags*/); + else if (AM.BlockAddr) + Disp = CurDAG->getBlockAddress(AM.BlockAddr, DebugLoc()/*MVT::i32*/, + true /*AM.SymbolFlags*/); + else + Disp = CurDAG->getTargetConstant(AM.Disp, MVT::i16); return true; } diff --git a/test/CodeGen/MSP430/2009-09-18-AbsoluteAddr.ll b/test/CodeGen/MSP430/2009-09-18-AbsoluteAddr.ll index cc574c7290a..4d7d9b96c7d 100644 --- a/test/CodeGen/MSP430/2009-09-18-AbsoluteAddr.ll +++ b/test/CodeGen/MSP430/2009-09-18-AbsoluteAddr.ll @@ -3,7 +3,7 @@ target datalayout = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8" target triple = "msp430-unknown-unknown" -@"\010x0021" = common global i8 0, align 1 ; [#uses=2] +@"\010x0021" = external global i8, align 1 ; [#uses=2] define zeroext i8 @foo(i8 zeroext %x) nounwind { entry: diff --git a/test/CodeGen/MSP430/AddrMode-bis-rx.ll b/test/CodeGen/MSP430/AddrMode-bis-rx.ll new file mode 100644 index 00000000000..3340494f6bb --- /dev/null +++ b/test/CodeGen/MSP430/AddrMode-bis-rx.ll @@ -0,0 +1,74 @@ +; RUN: llvm-as < %s | llc -march=msp430 | FileCheck %s +target datalayout = "e-p:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:16:16" +target triple = "msp430-generic-generic" + +define i16 @am1(i16 %x, i16* %a) nounwind { + %1 = load i16* %a + %2 = or i16 %1,%x + ret i16 %2 +} +; CHECK: am1: +; CHECK: bis.w 0(r14), r15 + +@foo = external global i16 + +define i16 @am2(i16 %x) nounwind { + %1 = load i16* @foo + %2 = or i16 %1,%x + ret i16 %2 +} +; CHECK: am2: +; CHECK: bis.w &foo, r15 + +@bar = internal constant [2 x i8] [ i8 32, i8 64 ] + +define i8 @am3(i8 %x, i16 %n) nounwind { + %1 = getelementptr [2 x i8]* @bar, i16 0, i16 %n + %2 = load i8* %1 + %3 = or i8 %2,%x + ret i8 %3 +} +; CHECK: am3: +; CHECK: bis.b &bar(r14), r15 + +define i16 @am4(i16 %x) nounwind { + %1 = volatile load i16* inttoptr(i16 32 to i16*) + %2 = or i16 %1,%x + ret i16 %2 +} +; CHECK: am4: +; CHECK: bis.w &32, r15 + +define i16 @am5(i16 %x, i16* %a) nounwind { + %1 = getelementptr i16* %a, i16 2 + %2 = load i16* %1 + %3 = or i16 %2,%x + ret i16 %3 +} +; CHECK: am5: +; CHECK: bis.w 4(r14), r15 + +%S = type { i16, i16 } +@baz = common global %S zeroinitializer, align 1 + +define i16 @am6(i16 %x) nounwind { + %1 = load i16* getelementptr (%S* @baz, i32 0, i32 1) + %2 = or i16 %1,%x + ret i16 %2 +} +; CHECK: am6: +; CHECK: bis.w &baz+2, r15 + +%T = type { i16, [2 x i8] } +@duh = internal constant %T { i16 16, [2 x i8][i8 32, i8 64 ] } + +define i8 @am7(i8 %x, i16 %n) nounwind { + %1 = getelementptr %T* @duh, i32 0, i32 1 + %2 = getelementptr [2 x i8]* %1, i16 0, i16 %n + %3= load i8* %2 + %4 = or i8 %3,%x + ret i8 %4 +} +; CHECK: am7: +; CHECK: bis.b &duh+2(r14), r15 + diff --git a/test/CodeGen/MSP430/AddrMode-bis-xr.ll b/test/CodeGen/MSP430/AddrMode-bis-xr.ll new file mode 100644 index 00000000000..ca79fb6d33f --- /dev/null +++ b/test/CodeGen/MSP430/AddrMode-bis-xr.ll @@ -0,0 +1,81 @@ +; RUN: llvm-as < %s | llc -march=msp430 | FileCheck %s +target datalayout = "e-p:16:16:16-i8:8:8-i16:16:16-i32:16:16" +target triple = "msp430-generic-generic" + +define void @am1(i16* %a, i16 %x) nounwind { + %1 = load i16* %a + %2 = or i16 %x, %1 + store i16 %2, i16* %a + ret void +} +; CHECK: am1: +; CHECK: bis.w r14, 0(r15) + +@foo = external global i16 + +define void @am2(i16 %x) nounwind { + %1 = load i16* @foo + %2 = or i16 %x, %1 + store i16 %2, i16* @foo + ret void +} +; CHECK: am2: +; CHECK: bis.w r15, &foo + +@bar = external global [2 x i8] + +define void @am3(i16 %i, i8 %x) nounwind { + %1 = getelementptr [2 x i8]* @bar, i16 0, i16 %i + %2 = load i8* %1 + %3 = or i8 %x, %2 + store i8 %3, i8* %1 + ret void +} +; CHECK: am3: +; CHECK: bis.b r14, &bar(r15) + +define void @am4(i16 %x) nounwind { + %1 = volatile load i16* inttoptr(i16 32 to i16*) + %2 = or i16 %x, %1 + volatile store i16 %2, i16* inttoptr(i16 32 to i16*) + ret void +} +; CHECK: am4: +; CHECK: bis.w r15, &32 + +define void @am5(i16* %a, i16 %x) readonly { + %1 = getelementptr inbounds i16* %a, i16 2 + %2 = load i16* %1 + %3 = or i16 %x, %2 + store i16 %3, i16* %1 + ret void +} +; CHECK: am5: +; CHECK: bis.w r14, 4(r15) + +%S = type { i16, i16 } +@baz = common global %S zeroinitializer + +define void @am6(i16 %x) nounwind { + %1 = load i16* getelementptr (%S* @baz, i32 0, i32 1) + %2 = or i16 %x, %1 + store i16 %2, i16* getelementptr (%S* @baz, i32 0, i32 1) + ret void +} +; CHECK: am6: +; CHECK: bis.w r15, &baz+2 + +%T = type { i16, [2 x i8] } +@duh = external global %T + +define void @am7(i16 %n, i8 %x) nounwind { + %1 = getelementptr %T* @duh, i32 0, i32 1 + %2 = getelementptr [2 x i8]* %1, i16 0, i16 %n + %3 = load i8* %2 + %4 = or i8 %x, %3 + store i8 %4, i8* %2 + ret void +} +; CHECK: am7: +; CHECK: bis.b r14, &duh+2(r15) + diff --git a/test/CodeGen/MSP430/AddrMode-mov-rx.ll b/test/CodeGen/MSP430/AddrMode-mov-rx.ll new file mode 100644 index 00000000000..67cbb021c80 --- /dev/null +++ b/test/CodeGen/MSP430/AddrMode-mov-rx.ll @@ -0,0 +1,67 @@ +; RUN: llvm-as < %s | llc -march=msp430 | FileCheck %s +target datalayout = "e-p:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:16:16" +target triple = "msp430-generic-generic" + +define i16 @am1(i16* %a) nounwind { + %1 = load i16* %a + ret i16 %1 +} +; CHECK: am1: +; CHECK: mov.w 0(r15), r15 + +@foo = external global i16 + +define i16 @am2() nounwind { + %1 = load i16* @foo + ret i16 %1 +} +; CHECK: am2: +; CHECK: mov.w &foo, r15 + +@bar = internal constant [2 x i8] [ i8 32, i8 64 ] + +define i8 @am3(i16 %n) nounwind { + %1 = getelementptr [2 x i8]* @bar, i16 0, i16 %n + %2 = load i8* %1 + ret i8 %2 +} +; CHECK: am3: +; CHECK: mov.b &bar(r15), r15 + +define i16 @am4() nounwind { + %1 = volatile load i16* inttoptr(i16 32 to i16*) + ret i16 %1 +} +; CHECK: am4: +; CHECK: mov.w &32, r15 + +define i16 @am5(i16* %a) nounwind { + %1 = getelementptr i16* %a, i16 2 + %2 = load i16* %1 + ret i16 %2 +} +; CHECK: am5: +; CHECK: mov.w 4(r15), r15 + +%S = type { i16, i16 } +@baz = common global %S zeroinitializer, align 1 + +define i16 @am6() nounwind { + %1 = load i16* getelementptr (%S* @baz, i32 0, i32 1) + ret i16 %1 +} +; CHECK: am6: +; CHECK: mov.w &baz+2, r15 + +%T = type { i16, [2 x i8] } +@duh = internal constant %T { i16 16, [2 x i8][i8 32, i8 64 ] } + +define i8 @am7(i16 %n) nounwind { + %1 = getelementptr %T* @duh, i32 0, i32 1 + %2 = getelementptr [2 x i8]* %1, i16 0, i16 %n + %3= load i8* %2 + ret i8 %3 +} +; CHECK: am7: +; CHECK: mov.b &duh+2(r15), r15 + diff --git a/test/CodeGen/MSP430/AddrMode-mov-xr.ll b/test/CodeGen/MSP430/AddrMode-mov-xr.ll new file mode 100644 index 00000000000..b8155d3a551 --- /dev/null +++ b/test/CodeGen/MSP430/AddrMode-mov-xr.ll @@ -0,0 +1,67 @@ +; RUN: llvm-as < %s | llc -march=msp430 | FileCheck %s +target datalayout = "e-p:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:16:16" +target triple = "msp430-generic-generic" + +define void @am1(i16* %a, i16 %b) nounwind { + store i16 %b, i16* %a + ret void +} +; CHECK: am1: +; CHECK: mov.w r14, 0(r15) + +@foo = external global i16 + +define void @am2(i16 %a) nounwind { + store i16 %a, i16* @foo + ret void +} +; CHECK: am2: +; CHECK: mov.w r15, &foo + +@bar = external global [2 x i8] + +define void @am3(i16 %i, i8 %a) nounwind { + %1 = getelementptr [2 x i8]* @bar, i16 0, i16 %i + store i8 %a, i8* %1 + ret void +} +; CHECK: am3: +; CHECK: mov.b r14, &bar(r15) + +define void @am4(i16 %a) nounwind { + volatile store i16 %a, i16* inttoptr(i16 32 to i16*) + ret void +} +; CHECK: am4: +; CHECK: mov.w r15, &32 + +define void @am5(i16* nocapture %p, i16 %a) nounwind readonly { + %1 = getelementptr inbounds i16* %p, i16 2 + store i16 %a, i16* %1 + ret void +} +; CHECK: am5: +; CHECK: mov.w r14, 4(r15) + +%S = type { i16, i16 } +@baz = common global %S zeroinitializer, align 1 + +define void @am6(i16 %a) nounwind { + store i16 %a, i16* getelementptr (%S* @baz, i32 0, i32 1) + ret void +} +; CHECK: am6: +; CHECK: mov.w r15, &baz+2 + +%T = type { i16, [2 x i8] } +@duh = external global %T + +define void @am7(i16 %n, i8 %a) nounwind { + %1 = getelementptr %T* @duh, i32 0, i32 1 + %2 = getelementptr [2 x i8]* %1, i16 0, i16 %n + store i8 %a, i8* %2 + ret void +} +; CHECK: am7: +; CHECK: mov.b r14, &duh+2(r15) + diff --git a/test/CodeGen/MSP430/inline-asm.ll b/test/CodeGen/MSP430/inline-asm.ll index 2cc25a4835d..0e7886a4721 100644 --- a/test/CodeGen/MSP430/inline-asm.ll +++ b/test/CodeGen/MSP430/inline-asm.ll @@ -20,6 +20,7 @@ define void @immmem() nounwind { } define void @mem() nounwind { - call void asm sideeffect "bic\09$0,r2", "m"(i16* @foo) nounwind + %fooval = load i16* @foo + call void asm sideeffect "bic\09$0,r2", "m"(i16 %fooval) nounwind ret void } -- 2.34.1