Index: include/llvm/CodeGen/SelectionDAGISel.h =================================================================== --- include/llvm/CodeGen/SelectionDAGISel.h +++ include/llvm/CodeGen/SelectionDAGISel.h @@ -80,12 +80,12 @@ virtual SDNode *Select(SDNode *N) = 0; /// SelectInlineAsmMemoryOperand - Select the specified address as a target - /// addressing mode, according to the specified constraint code. If this does + /// addressing mode, according to the specified constraint. If this does /// not match or is not implemented, return true. The resultant operands /// (which will appear in the machine instruction) should be added to the /// OutOps vector. virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, - char ConstraintCode, + unsigned ConstraintID, std::vector &OutOps) { return true; } Index: include/llvm/IR/InlineAsm.h =================================================================== --- include/llvm/IR/InlineAsm.h +++ include/llvm/IR/InlineAsm.h @@ -189,6 +189,19 @@ // These are helper methods for dealing with flags in the INLINEASM SDNode // in the backend. + // + // The encoding of the flag word is currently: + // Bits 2-0 - A Kind_* value indicating the kind of the operand. + // Bits 15-3 - The number of SDNode operands associated with this inline + // assembly operand. + // If bits 2-0 are Kind_Mem: + // Bit 31 - 0 + // Bit 30-16 - A Constraint_* value indicating the original constraint + // code. + // Else if bit 31 is set: + // Bit 30-16 - The operand number that this operand must match. + // Else if bit 31 is clear: + // Bit 30-16 - The register class ID to use for the operand. enum : uint32_t { // Fixed operands on an INLINEASM SDNode. @@ -220,6 +233,17 @@ Kind_Imm = 5, // Immediate. Kind_Mem = 6, // Memory operand, "m". + // Memory constraint codes. + // These could be tablegenerated but there's little need to do that since + // there's plenty of space in the encoding to support the union of all + // constraint codes for all targets. + Constraint_Unknown = 0, + Constraint_m, + Constraint_o, // Unused at the moment since Constraint_m is always used. + Constraint_v, // Unused at the moment since Constraint_m is always used. + Constraints_Max = Constraint_v, + Constraints_ShiftAmount = 16, + Flag_MatchingOperand = 0x80000000 }; @@ -252,6 +276,15 @@ return InputFlag | (RC << 16); } + /// Augment an existing flag word returned by getFlagWord with the constraint + /// code for a memory constraint. + static unsigned getFlagWordForMem(unsigned InputFlag, unsigned Constraint) { + assert(Constraint <= 0x7fff && "Too large a memory constraint ID"); + assert(Constraint <= Constraints_Max && "Unknown constraint ID"); + assert((InputFlag & ~0xffff) == 0 && "High bits already contain data"); + return InputFlag | (Constraint << Constraints_ShiftAmount); + } + static unsigned getKind(unsigned Flags) { return Flags & 7; } @@ -266,6 +299,11 @@ return getKind(Flag) == Kind_Clobber; } + static unsigned getMemoryConstraintID(unsigned Flag) { + assert(isMemKind(Flag)); + return (Flag >> Constraints_ShiftAmount) & 0x7fff; + } + /// getNumOperandRegisters - Extract the number of registers field from the /// inline asm operand flag. static unsigned getNumOperandRegisters(unsigned Flag) { Index: include/llvm/Target/TargetLowering.h =================================================================== --- include/llvm/Target/TargetLowering.h +++ include/llvm/Target/TargetLowering.h @@ -2594,6 +2594,13 @@ getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, const std::string &Constraint, MVT VT) const; + virtual unsigned + getInlineAsmMemConstraint(const std::string &ConstraintCode) const { + // FIXME: This currently maps all constraints to the the same code. + // This will be corrected once all targets are updated. + return InlineAsm::Constraint_m; + } + /// Try to replace an X constraint, which matches anything, with another that /// has more specific requirements based on the type of the corresponding /// operand. This returns null if there is no replacement to make. Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -6592,8 +6592,14 @@ // Memory output, or 'other' output (e.g. 'X' constraint). assert(OpInfo.isIndirect && "Memory output must be indirect operand"); + unsigned ConstraintID = + TLI.getInlineAsmMemConstraint(OpInfo.ConstraintCode); + assert(ConstraintID != InlineAsm::Constraint_Unknown && + "Failed to convert memory constraint code to constraint id."); + // Add information to the INLINEASM node to know about this output. unsigned OpFlags = InlineAsm::getFlagWord(InlineAsm::Kind_Mem, 1); + OpFlags = InlineAsm::getFlagWordForMem(OpFlags, ConstraintID); AsmNodeOperands.push_back(DAG.getTargetConstant(OpFlags, MVT::i32)); AsmNodeOperands.push_back(OpInfo.CallOperand); break; @@ -6737,8 +6743,14 @@ assert(InOperandVal.getValueType() == TLI.getPointerTy() && "Memory operands expect pointer values"); + unsigned ConstraintID = + TLI.getInlineAsmMemConstraint(OpInfo.ConstraintCode); + assert(ConstraintID != InlineAsm::Constraint_Unknown && + "Failed to convert memory constraint code to constraint id."); + // Add information to the INLINEASM node to know about this input. unsigned ResOpType = InlineAsm::getFlagWord(InlineAsm::Kind_Mem, 1); + ResOpType = InlineAsm::getFlagWordForMem(ResOpType, ConstraintID); AsmNodeOperands.push_back(DAG.getTargetConstant(ResOpType, MVT::i32)); AsmNodeOperands.push_back(InOperandVal); break; Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -1780,7 +1780,9 @@ "Memory operand with multiple values?"); // Otherwise, this is a memory operand. Ask the target to select it. std::vector SelOps; - if (SelectInlineAsmMemoryOperand(InOps[i+1], 'm', SelOps)) + if (SelectInlineAsmMemoryOperand(InOps[i+1], + InlineAsm::getMemoryConstraintID(Flags), + SelOps)) report_fatal_error("Could not match memory address. Inline asm" " failure!"); Index: lib/Target/AArch64/AArch64ISelDAGToDAG.cpp =================================================================== --- lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -65,7 +65,7 @@ /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for /// inline asm expressions. bool SelectInlineAsmMemoryOperand(const SDValue &Op, - char ConstraintCode, + unsigned ConstraintID, std::vector &OutOps) override; SDNode *SelectMLAV64LaneV128(SDNode *N); @@ -211,8 +211,9 @@ } bool AArch64DAGToDAGISel::SelectInlineAsmMemoryOperand( - const SDValue &Op, char ConstraintCode, std::vector &OutOps) { - assert(ConstraintCode == 'm' && "unexpected asm memory constraint"); + const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) { + assert(ConstraintID == InlineAsm::Constraint_m && + "unexpected asm memory constraint"); // Require the address to be in a register. That is safe for all AArch64 // variants and it is hard to do anything much smarter without knowing // how the operand is used. Index: lib/Target/ARM/ARMISelDAGToDAG.cpp =================================================================== --- lib/Target/ARM/ARMISelDAGToDAG.cpp +++ lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -257,7 +257,7 @@ /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for /// inline asm expressions. - bool SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, + bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) override; // Form pairs of consecutive R, S, D, or Q registers. @@ -3472,9 +3472,10 @@ bool ARMDAGToDAGISel:: -SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, +SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) { - assert(ConstraintCode == 'm' && "unexpected asm memory constraint"); + assert(ConstraintID == InlineAsm::Constraint_m && + "unexpected asm memory constraint"); // 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. Index: lib/Target/Hexagon/HexagonISelDAGToDAG.cpp =================================================================== --- lib/Target/Hexagon/HexagonISelDAGToDAG.cpp +++ lib/Target/Hexagon/HexagonISelDAGToDAG.cpp @@ -95,7 +95,7 @@ /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for /// inline asm expressions. bool SelectInlineAsmMemoryOperand(const SDValue &Op, - char ConstraintCode, + unsigned ConstraintID, std::vector &OutOps) override; bool SelectAddr(SDNode *Op, SDValue Addr, SDValue &Base, SDValue &Offset); @@ -1529,15 +1529,15 @@ bool HexagonDAGToDAGISel:: -SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, +SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) { SDValue Op0, Op1; - switch (ConstraintCode) { - case 'o': // Offsetable. - case 'v': // Not offsetable. + switch (ConstraintID) { + case InlineAsm::Constraint_o: // Offsetable. + case InlineAsm::Constraint_v: // Not offsetable. default: return true; - case 'm': // Memory. + case InlineAsm::Constraint_m: // Memory. if (!SelectAddr(Op.getNode(), Op, Op0, Op1)) return true; break; Index: lib/Target/MSP430/MSP430ISelDAGToDAG.cpp =================================================================== --- lib/Target/MSP430/MSP430ISelDAGToDAG.cpp +++ lib/Target/MSP430/MSP430ISelDAGToDAG.cpp @@ -104,7 +104,7 @@ bool MatchWrapper(SDValue N, MSP430ISelAddressMode &AM); bool MatchAddressBase(SDValue N, MSP430ISelAddressMode &AM); - bool SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, + bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) override; // Include the pieces autogenerated from the target description. @@ -280,12 +280,12 @@ } bool MSP430DAGToDAGISel:: -SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, +SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) { SDValue Op0, Op1; - switch (ConstraintCode) { + switch (ConstraintID) { default: return true; - case 'm': // memory + case InlineAsm::Constraint_m: // memory if (!SelectAddr(Op, Op0, Op1)) return true; break; Index: lib/Target/Mips/MipsISelDAGToDAG.h =================================================================== --- lib/Target/Mips/MipsISelDAGToDAG.h +++ lib/Target/Mips/MipsISelDAGToDAG.h @@ -125,7 +125,7 @@ virtual void processFunctionAfterISel(MachineFunction &MF) = 0; bool SelectInlineAsmMemoryOperand(const SDValue &Op, - char ConstraintCode, + unsigned ConstraintID, std::vector &OutOps) override; }; } Index: lib/Target/Mips/MipsISelDAGToDAG.cpp =================================================================== --- lib/Target/Mips/MipsISelDAGToDAG.cpp +++ lib/Target/Mips/MipsISelDAGToDAG.cpp @@ -230,9 +230,10 @@ } bool MipsDAGToDAGISel:: -SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, +SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) { - assert(ConstraintCode == 'm' && "unexpected asm memory constraint"); + assert(ConstraintID == InlineAsm::Constraint_m && + "unexpected asm memory constraint"); OutOps.push_back(Op); return false; } Index: lib/Target/NVPTX/NVPTXISelDAGToDAG.h =================================================================== --- lib/Target/NVPTX/NVPTXISelDAGToDAG.h +++ lib/Target/NVPTX/NVPTXISelDAGToDAG.h @@ -48,7 +48,7 @@ const NVPTXSubtarget *Subtarget; bool SelectInlineAsmMemoryOperand(const SDValue &Op, - char ConstraintCode, + unsigned ConstraintID, std::vector &OutOps) override; private: // Include the pieces autogenerated from the target description. Index: lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp =================================================================== --- lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp +++ lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp @@ -5044,12 +5044,12 @@ /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for /// inline asm expressions. bool NVPTXDAGToDAGISel::SelectInlineAsmMemoryOperand( - const SDValue &Op, char ConstraintCode, std::vector &OutOps) { + const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) { SDValue Op0, Op1; - switch (ConstraintCode) { + switch (ConstraintID) { default: return true; - case 'm': // memory + case InlineAsm::Constraint_m: // memory if (SelectDirectAddr(Op, Op0)) { OutOps.push_back(Op0); OutOps.push_back(CurDAG->getTargetConstant(0, MVT::i32)); Index: lib/Target/PowerPC/PPCISelDAGToDAG.cpp =================================================================== --- lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -186,7 +186,7 @@ /// register can be improved, but it is wrong to substitute Reg+Reg for /// Reg in an asm, because the load or store opcode would have to change. bool SelectInlineAsmMemoryOperand(const SDValue &Op, - char ConstraintCode, + unsigned ConstraintID, std::vector &OutOps) override { // We need to make sure that this one operand does not end up in r0 // (because we might end up lowering this as 0(%op)). Index: lib/Target/Sparc/SparcISelDAGToDAG.cpp =================================================================== --- lib/Target/Sparc/SparcISelDAGToDAG.cpp +++ lib/Target/Sparc/SparcISelDAGToDAG.cpp @@ -50,7 +50,7 @@ /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for /// inline asm expressions. bool SelectInlineAsmMemoryOperand(const SDValue &Op, - char ConstraintCode, + unsigned ConstraintID, std::vector &OutOps) override; const char *getPassName() const override { @@ -195,12 +195,12 @@ /// inline asm expressions. bool SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op, - char ConstraintCode, + unsigned ConstraintID, std::vector &OutOps) { SDValue Op0, Op1; - switch (ConstraintCode) { + switch (ConstraintID) { default: return true; - case 'm': // memory + case InlineAsm::Constraint_m: // memory if (!SelectADDRrr(Op, Op0, Op1)) SelectADDRri(Op, Op0, Op1); break; Index: lib/Target/SystemZ/SystemZISelDAGToDAG.cpp =================================================================== --- lib/Target/SystemZ/SystemZISelDAGToDAG.cpp +++ lib/Target/SystemZ/SystemZISelDAGToDAG.cpp @@ -328,7 +328,7 @@ // Override SelectionDAGISel. SDNode *Select(SDNode *Node) override; - bool SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, + bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) override; // Include the pieces autogenerated from the target description. @@ -1129,9 +1129,10 @@ bool SystemZDAGToDAGISel:: SelectInlineAsmMemoryOperand(const SDValue &Op, - char ConstraintCode, + unsigned ConstraintID, std::vector &OutOps) { - assert(ConstraintCode == 'm' && "Unexpected constraint code"); + assert(ConstraintID == InlineAsm::Constraint_m && + "Unexpected constraint code"); // Accept addresses with short displacements, which are compatible // with Q, R, S and T. But keep the index operand for future expansion. SDValue Base, Disp, Index; Index: lib/Target/X86/X86ISelDAGToDAG.cpp =================================================================== --- lib/Target/X86/X86ISelDAGToDAG.cpp +++ lib/Target/X86/X86ISelDAGToDAG.cpp @@ -228,7 +228,7 @@ /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for /// inline asm expressions. bool SelectInlineAsmMemoryOperand(const SDValue &Op, - char ConstraintCode, + unsigned ConstraintID, std::vector &OutOps) override; void EmitSpecialCodeForMain(); @@ -2814,14 +2814,14 @@ } bool X86DAGToDAGISel:: -SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, +SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) { SDValue Op0, Op1, Op2, Op3, Op4; - switch (ConstraintCode) { - case 'o': // offsetable ?? - case 'v': // not offsetable ?? + switch (ConstraintID) { + case InlineAsm::Constraint_o: // offsetable ?? + case InlineAsm::Constraint_v: // not offsetable ?? default: return true; - case 'm': // memory + case InlineAsm::Constraint_m: // memory if (!SelectAddr(nullptr, Op, Op0, Op1, Op2, Op3, Op4)) return true; break; Index: lib/Target/XCore/XCoreISelDAGToDAG.cpp =================================================================== --- lib/Target/XCore/XCoreISelDAGToDAG.cpp +++ lib/Target/XCore/XCoreISelDAGToDAG.cpp @@ -65,7 +65,7 @@ // Complex Pattern Selectors. bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset); - bool SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, + bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) override; const char *getPassName() const override { @@ -108,12 +108,12 @@ } bool XCoreDAGToDAGISel:: -SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, +SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) { SDValue Reg; - switch (ConstraintCode) { + switch (ConstraintID) { default: return true; - case 'm': // Memory. + case InlineAsm::Constraint_m: // Memory. switch (Op.getOpcode()) { default: return true; case XCoreISD::CPRelativeWrapper: