Index: include/llvm/IR/InlineAsm.h =================================================================== --- include/llvm/IR/InlineAsm.h +++ include/llvm/IR/InlineAsm.h @@ -257,6 +257,7 @@ Constraint_Uv, Constraint_Uy, Constraint_Z, + Constraint_ZC, Constraint_Zy, Constraints_Max = Constraint_Zy, Constraints_ShiftAmount = 16, Index: lib/Target/Mips/MipsAsmPrinter.cpp =================================================================== --- lib/Target/Mips/MipsAsmPrinter.cpp +++ lib/Target/Mips/MipsAsmPrinter.cpp @@ -438,7 +438,7 @@ // Print out an operand for an inline asm expression. bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, - unsigned AsmVariant,const char *ExtraCode, + unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) { // Does this asm operand have a single letter operand modifier? if (ExtraCode && ExtraCode[0]) { @@ -540,18 +540,23 @@ unsigned OpNum, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) { - int Offset = 0; + const MachineOperand &BaseMO = MI->getOperand(OpNum); + const MachineOperand &OffsetMO = MI->getOperand(OpNum + 1); + assert(BaseMO.isReg() && "Unexpected base pointer for inline asm memory operand."); + assert(OffsetMO.isImm() && "Unexpected offset for inline asm memory operand."); + int Offset = OffsetMO.getImm(); + // Currently we are expecting either no ExtraCode or 'D' if (ExtraCode) { if (ExtraCode[0] == 'D') - Offset = 4; + Offset += 4; else return true; // Unknown modifier. + // FIXME: M = high order bits + // FIXME: L = low order bits } - const MachineOperand &MO = MI->getOperand(OpNum); - assert(MO.isReg() && "unexpected inline asm memory operand"); - O << Offset << "($" << MipsInstPrinter::getRegisterName(MO.getReg()) << ")"; + O << Offset << "($" << MipsInstPrinter::getRegisterName(BaseMO.getReg()) << ")"; return false; } Index: lib/Target/Mips/MipsISelDAGToDAG.cpp =================================================================== --- lib/Target/Mips/MipsISelDAGToDAG.cpp +++ lib/Target/Mips/MipsISelDAGToDAG.cpp @@ -232,8 +232,16 @@ bool MipsDAGToDAGISel:: SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) { - assert(ConstraintID == InlineAsm::Constraint_m && - "unexpected asm memory constraint"); - OutOps.push_back(Op); - return false; + // All memory constraints can at least accept raw pointers. + switch(ConstraintID) { + default: + llvm_unreachable("Unexpected asm memory constraint"); + case InlineAsm::Constraint_i: + case InlineAsm::Constraint_m: + case InlineAsm::Constraint_R: + case InlineAsm::Constraint_ZC: + OutOps.push_back(Op); + return false; + } + return true; } Index: lib/Target/Mips/MipsISelLowering.h =================================================================== --- lib/Target/Mips/MipsISelLowering.h +++ lib/Target/Mips/MipsISelLowering.h @@ -505,8 +505,11 @@ unsigned getInlineAsmMemConstraint( const std::string &ConstraintCode) const override { - // FIXME: Map different constraints differently. - return InlineAsm::Constraint_m; + if (ConstraintCode == "R") + return InlineAsm::Constraint_R; + else if (ConstraintCode == "ZC") + return InlineAsm::Constraint_ZC; + return TargetLowering::getInlineAsmMemConstraint(ConstraintCode); } bool isLegalAddressingMode(const AddrMode &AM, Type *Ty) const override; Index: lib/Target/Mips/MipsISelLowering.cpp =================================================================== --- lib/Target/Mips/MipsISelLowering.cpp +++ lib/Target/Mips/MipsISelLowering.cpp @@ -3164,6 +3164,10 @@ return C_Memory; } } + + if (Constraint == "ZC") + return C_Memory; + return TargetLowering::getConstraintType(Constraint); } Index: lib/Target/Mips/MipsSEISelDAGToDAG.h =================================================================== --- lib/Target/Mips/MipsSEISelDAGToDAG.h +++ lib/Target/Mips/MipsSEISelDAGToDAG.h @@ -56,12 +56,18 @@ bool selectIntAddr(SDValue Addr, SDValue &Base, SDValue &Offset) const override; + bool selectAddrRegImm9(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + bool selectAddrRegImm10(SDValue Addr, SDValue &Base, SDValue &Offset) const; bool selectAddrRegImm12(SDValue Addr, SDValue &Base, SDValue &Offset) const; + bool selectAddrRegImm16(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + bool selectIntAddrMM(SDValue Addr, SDValue &Base, SDValue &Offset) const override; @@ -111,6 +117,10 @@ // Insert instructions to initialize the global base register in the // first MBB of the function. void initGlobalBaseReg(MachineFunction &MF); + + bool SelectInlineAsmMemoryOperand(const SDValue &Op, + unsigned ConstraintID, + std::vector &OutOps) override; }; FunctionPass *createMipsSEISelDag(MipsTargetMachine &TM); Index: lib/Target/Mips/MipsSEISelDAGToDAG.cpp =================================================================== --- lib/Target/Mips/MipsSEISelDAGToDAG.cpp +++ lib/Target/Mips/MipsSEISelDAGToDAG.cpp @@ -382,6 +382,17 @@ selectAddrDefault(Addr, Base, Offset); } +bool MipsSEDAGToDAGISel::selectAddrRegImm9(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if (selectAddrFrameIndex(Addr, Base, Offset)) + return true; + + if (selectAddrFrameIndexOffset(Addr, Base, Offset, 9)) + return true; + + return false; +} + bool MipsSEDAGToDAGISel::selectAddrRegImm10(SDValue Addr, SDValue &Base, SDValue &Offset) const { if (selectAddrFrameIndex(Addr, Base, Offset)) @@ -405,6 +416,17 @@ return false; } +bool MipsSEDAGToDAGISel::selectAddrRegImm16(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if (selectAddrFrameIndex(Addr, Base, Offset)) + return true; + + if (selectAddrFrameIndexOffset(Addr, Base, Offset, 16)) + return true; + + return false; +} + bool MipsSEDAGToDAGISel::selectIntAddrMM(SDValue Addr, SDValue &Base, SDValue &Offset) const { return selectAddrRegImm12(Addr, Base, Offset) || @@ -916,6 +938,52 @@ return std::make_pair(false, nullptr); } +bool MipsSEDAGToDAGISel:: +SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, + std::vector &OutOps) { + SDValue Base, Offset; + + switch(ConstraintID) { + default: + llvm_unreachable("Unexpected asm memory constraint"); + // All memory constraints can at least accept raw pointers. + case InlineAsm::Constraint_i: + case InlineAsm::Constraint_m: + case InlineAsm::Constraint_R: + OutOps.push_back(Op); + OutOps.push_back(CurDAG->getTargetConstant(0, MVT::i32)); + return false; + case InlineAsm::Constraint_ZC: + // ZC matches whatever the pref, ll, and sc instructions can handle for the + // given subtarget. + if (Subtarget->inMicroMipsMode()) { + // On microMIPS, they can handle 12-bit offsets. + if (selectAddrRegImm12(Op, Base, Offset)) { + OutOps.push_back(Base); + OutOps.push_back(Offset); + return false; + } + } else if (Subtarget->hasMips32r6()) { + // On MIPS32r6/MIPS64r6, they can only handle 9-bit offsets. + if (selectAddrRegImm9(Op, Base, Offset)) { + OutOps.push_back(Base); + OutOps.push_back(Offset); + return false; + } + } else if (selectAddrRegImm16(Op, Base, Offset)) { + // Prior to MIPS32r6/MIPS64r6, they can handle 16-bit offsets. + OutOps.push_back(Base); + OutOps.push_back(Offset); + return false; + } + // In all cases, 0-bit offsets are acceptable. + OutOps.push_back(Op); + OutOps.push_back(CurDAG->getTargetConstant(0, MVT::i32)); + return false; + } + return true; +} + FunctionPass *llvm::createMipsSEISelDag(MipsTargetMachine &TM) { return new MipsSEDAGToDAGISel(TM); } Index: test/CodeGen/Mips/inlineasm_constraint_ZC.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/inlineasm_constraint_ZC.ll @@ -0,0 +1,153 @@ +; RUN: llc -march=mipsel -mcpu=mips32r6 < %s | FileCheck %s -check-prefix=ALL -check-prefix=09BIT +; RUN: llc -march=mipsel -mattr=+micromips < %s | FileCheck %s -check-prefix=ALL -check-prefix=12BIT +; RUN: llc -march=mipsel < %s | FileCheck %s -check-prefix=ALL -check-prefix=16BIT + +@data = global [8193 x i32] zeroinitializer + +define void @ZC(i32 *%p) nounwind { +entry: + ; ALL-LABEL: ZC: + + call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 0)) + + ; ALL: lw $[[BASEPTR:[0-9]+]], %got(data)( + ; ALL: #APP + ; ALL: lw $1, 0($[[BASEPTR]]) + ; ALL: #NO_APP + + ret void +} + +define void @ZC_offset_4(i32 *%p) nounwind { +entry: + ; ALL-LABEL: ZC_offset_4: + + call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 1)) + + ; ALL: lw $[[BASEPTR:[0-9]+]], %got(data)( + ; ALL: #APP + ; ALL: lw $1, 4($[[BASEPTR]]) + ; ALL: #NO_APP + + ret void +} + +define void @ZC_offset_252(i32 *%p) nounwind { +entry: + ; ALL-LABEL: ZC_offset_252: + + call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 63)) + + ; ALL: lw $[[BASEPTR:[0-9]+]], %got(data)( + ; ALL: #APP + ; ALL: lw $1, 252($[[BASEPTR]]) + ; ALL: #NO_APP + + ret void +} + +define void @ZC_offset_256(i32 *%p) nounwind { +entry: + ; ALL-LABEL: ZC_offset_256: + + call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 64)) + + ; ALL: lw $[[BASEPTR:[0-9]+]], %got(data)( + + ; 09BIT: addiu $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], 256 + + ; ALL: #APP + + ; 09BIT: lw $1, 0($[[BASEPTR2]]) + ; 12BIT: lw $1, 256($[[BASEPTR]]) + ; 16BIT: lw $1, 256($[[BASEPTR]]) + + ; ALL: #NO_APP + + ret void +} + +define void @ZC_offset_2044(i32 *%p) nounwind { +entry: + ; ALL-LABEL: ZC_offset_2044: + + call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 511)) + + ; ALL: lw $[[BASEPTR:[0-9]+]], %got(data)( + + ; 09BIT: addiu $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], 2044 + + ; ALL: #APP + + ; 09BIT: lw $1, 0($[[BASEPTR2]]) + ; 12BIT: lw $1, 2044($[[BASEPTR]]) + ; 16BIT: lw $1, 2044($[[BASEPTR]]) + + ; ALL: #NO_APP + + ret void +} + +define void @ZC_offset_2048(i32 *%p) nounwind { +entry: + ; ALL-LABEL: ZC_offset_2048: + + call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 512)) + + ; ALL: lw $[[BASEPTR:[0-9]+]], %got(data)( + + ; 09BIT: addiu $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], 2048 + ; 12BIT: addiu $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], 2048 + + ; ALL: #APP + + ; 09BIT: lw $1, 0($[[BASEPTR2]]) + ; 12BIT: lw $1, 0($[[BASEPTR2]]) + ; 16BIT: lw $1, 2048($[[BASEPTR]]) + + ; ALL: #NO_APP + + ret void +} + +define void @ZC_offset_32764(i32 *%p) nounwind { +entry: + ; ALL-LABEL: ZC_offset_32764: + + call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 8191)) + + ; ALL-DAG: lw $[[BASEPTR:[0-9]+]], %got(data)( + + ; 09BIT: addiu $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], 32764 + ; 12BIT: addiu $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], 32764 + + ; ALL: #APP + + ; 09BIT: lw $1, 0($[[BASEPTR2]]) + ; 12BIT: lw $1, 0($[[BASEPTR2]]) + ; 16BIT: lw $1, 32764($[[BASEPTR]]) + + ; ALL: #NO_APP + + ret void +} + +define void @ZC_offset_32768(i32 *%p) nounwind { +entry: + ; ALL-LABEL: ZC_offset_32768: + + call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 8192)) + + ; ALL-DAG: lw $[[BASEPTR:[0-9]+]], %got(data)( + ; ALL-DAG: ori $[[T0:[0-9]+]], $zero, 32768 + + ; 09BIT: addu $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], $[[T0]] + ; 12BIT: addu16 $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], $[[T0]] + ; 16BIT: addu $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], $[[T0]] + + ; ALL: #APP + ; ALL: lw $1, 0($[[BASEPTR2]]) + ; ALL: #NO_APP + + ret void +}