diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 0e51930442e..4757a4a56a7 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -481,6 +481,7 @@ public: // enum ConstraintType { + C_Register, // Constraint represents a single register. C_RegisterClass, // Constraint represents one or more registers. C_Other, // Something else. C_Unknown // Unsupported constraint. @@ -491,13 +492,22 @@ public: /// constraint it is for this target. virtual ConstraintType getConstraintType(char ConstraintLetter) const; - /// getRegForInlineAsmConstraint - Given a constraint letter or register - /// name (e.g. "r" or "edx"), return a list of registers that can be used to - /// satisfy the constraint. This should only be used for physregs and - /// C_RegisterClass constraints. + + /// getRegClassForInlineAsmConstraint - Given a constraint letter (e.g. "r"), + /// return a list of registers that can be used to satisfy the constraint. + /// This should only be used for C_RegisterClass constraints. virtual std::vector - getRegForInlineAsmConstraint(const std::string &Constraint, - MVT::ValueType VT) const; + getRegClassForInlineAsmConstraint(const std::string &Constraint, + MVT::ValueType VT) const; + + /// getRegForInlineAsmConstraint - Given a physical register constraint (e.g. + /// {edx}), return the register number and the register class for the + /// register. This should only be used for C_Register constraints. On error, + /// this returns a register number of 0. + virtual std::pair + getRegForInlineAsmConstraint(const std::string &Constraint, + MVT::ValueType VT) const; + /// isOperandValidForConstraint - Return true if the specified SDOperand is /// valid for the specified target constraint letter. diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index c8e94019e32..d16b070c51f 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -1187,6 +1187,7 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { bool hasSideEffects = IA->hasSideEffects(); std::vector Constraints = IA->ParseConstraints(); + std::vector ConstraintVTs; /// AsmNodeOperands - A list of pairs. The first element is a register, the /// second is a bitfield where bit #0 is set if it is a use and bit #1 is set @@ -1203,14 +1204,43 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { // could let the LLVM RA do its thing, but we currently don't. Do a prepass // over the constraints, collecting fixed registers that we know we can't use. std::set OutputRegs, InputRegs; + unsigned OpNum = 1; for (unsigned i = 0, e = Constraints.size(); i != e; ++i) { assert(Constraints[i].Codes.size() == 1 && "Only handles one code so far!"); std::string &ConstraintCode = Constraints[i].Codes[0]; - std::vector Regs = - TLI.getRegForInlineAsmConstraint(ConstraintCode, MVT::Other); - if (Regs.size() != 1) continue; // Not assigned a fixed reg. - unsigned TheReg = Regs[0]; + MVT::ValueType OpVT; + + // Compute the value type for each operand and add it to ConstraintVTs. + switch (Constraints[i].Type) { + case InlineAsm::isOutput: + if (!Constraints[i].isIndirectOutput) { + assert(I.getType() != Type::VoidTy && "Bad inline asm!"); + OpVT = TLI.getValueType(I.getType()); + } else { + Value *CallOperand = I.getOperand(OpNum); + const Type *OpTy = CallOperand->getType(); + OpVT = TLI.getValueType(cast(OpTy)->getElementType()); + OpNum++; // Consumes a call operand. + } + break; + case InlineAsm::isInput: + OpVT = TLI.getValueType(I.getOperand(OpNum)->getType()); + OpNum++; // Consumes a call operand. + break; + case InlineAsm::isClobber: + OpVT = MVT::Other; + break; + } + + ConstraintVTs.push_back(OpVT); + + std::pair Reg = + TLI.getRegForInlineAsmConstraint(ConstraintCode, OpVT); + if (Reg.first == 0) continue; // Not assigned a fixed reg. + unsigned TheReg = Reg.first; + + // FIXME: Handle expanded physreg refs! switch (Constraints[i].Type) { case InlineAsm::isOutput: @@ -1221,15 +1251,15 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { if (Constraints[i].isEarlyClobber || Constraints[i].hasMatchingInput) InputRegs.insert(TheReg); break; + case InlineAsm::isInput: + // We can't assign any other input to this register. + InputRegs.insert(TheReg); + break; case InlineAsm::isClobber: // Clobbered regs cannot be used as inputs or outputs. InputRegs.insert(TheReg); OutputRegs.insert(TheReg); break; - case InlineAsm::isInput: - // We can't assign any other input to this register. - InputRegs.insert(TheReg); - break; } } @@ -1238,28 +1268,32 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { unsigned RetValReg = 0; std::vector > IndirectStoresToEmit; bool FoundOutputConstraint = false; - unsigned OpNum = 1; + OpNum = 1; for (unsigned i = 0, e = Constraints.size(); i != e; ++i) { assert(Constraints[i].Codes.size() == 1 && "Only handles one code so far!"); std::string &ConstraintCode = Constraints[i].Codes[0]; - Value *CallOperand = I.getOperand(OpNum); - MVT::ValueType CallOpVT = TLI.getValueType(CallOperand->getType()); + switch (Constraints[i].Type) { case InlineAsm::isOutput: { - // Copy the output from the appropriate register. - std::vector Regs = - TLI.getRegForInlineAsmConstraint(ConstraintCode, CallOpVT); - - // Find a regsister that we can use. + // Copy the output from the appropriate register. Find a regsister that + // we can use. + + // Check to see if this is a physreg reference. + std::pair PhysReg = + TLI.getRegForInlineAsmConstraint(ConstraintCode, ConstraintVTs[i]); unsigned DestReg; - if (Regs.size() == 1) - DestReg = Regs[0]; + if (PhysReg.first) + DestReg = PhysReg.first; else { - bool UsesInputRegister = false; + std::vector Regs = + TLI.getRegClassForInlineAsmConstraint(ConstraintCode, + ConstraintVTs[i]); + // If this is an early-clobber output, or if there is an input // constraint that matches this, we need to reserve the input register // so no other inputs allocate to it. + bool UsesInputRegister = false; if (Constraints[i].isEarlyClobber || Constraints[i].hasMatchingInput) UsesInputRegister = true; DestReg = GetAvailableRegister(true, UsesInputRegister, @@ -1276,24 +1310,21 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { assert(I.getType() != Type::VoidTy && "Bad inline asm!"); RetValReg = DestReg; - OpTy = I.getType(); } else { + Value *CallOperand = I.getOperand(OpNum); IndirectStoresToEmit.push_back(std::make_pair(DestReg, CallOperand)); - OpTy = CallOperand->getType(); - OpTy = cast(OpTy)->getElementType(); OpNum++; // Consumes a call operand. } // Add information to the INLINEASM node to know that this register is // set. - AsmNodeOperands.push_back(DAG.getRegister(DestReg, - TLI.getValueType(OpTy))); + AsmNodeOperands.push_back(DAG.getRegister(DestReg, ConstraintVTs[i])); AsmNodeOperands.push_back(DAG.getConstant(2, MVT::i32)); // ISDEF break; } case InlineAsm::isInput: { - const Type *OpTy = CallOperand->getType(); + Value *CallOperand = I.getOperand(OpNum); OpNum++; // Consumes a call operand. unsigned SrcReg; @@ -1306,33 +1337,45 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { // just use its register. unsigned OperandNo = atoi(ConstraintCode.c_str()); SrcReg = cast(AsmNodeOperands[OperandNo*2+2])->getReg(); - ResOp = DAG.getRegister(SrcReg, CallOpVT); + ResOp = DAG.getRegister(SrcReg, ConstraintVTs[i]); ResOpType = 1; Chain = DAG.getCopyToReg(Chain, SrcReg, InOperandVal, Flag); Flag = Chain.getValue(1); } else { - TargetLowering::ConstraintType CTy = TargetLowering::C_RegisterClass; + TargetLowering::ConstraintType CTy = TargetLowering::C_Register; if (ConstraintCode.size() == 1) // not a physreg name. CTy = TLI.getConstraintType(ConstraintCode[0]); switch (CTy) { default: assert(0 && "Unknown constraint type! FAIL!"); + case TargetLowering::C_Register: { + std::pair PhysReg = + TLI.getRegForInlineAsmConstraint(ConstraintCode, ConstraintVTs[i]); + // FIXME: should be match fail. + assert(PhysReg.first && "Unknown physical register name!"); + SrcReg = PhysReg.first; + + Chain = DAG.getCopyToReg(Chain, SrcReg, InOperandVal, Flag); + Flag = Chain.getValue(1); + + ResOp = DAG.getRegister(SrcReg, ConstraintVTs[i]); + ResOpType = 1; + break; + } case TargetLowering::C_RegisterClass: { // Copy the input into the appropriate register. std::vector Regs = - TLI.getRegForInlineAsmConstraint(ConstraintCode, CallOpVT); - if (Regs.size() == 1) - SrcReg = Regs[0]; - else - SrcReg = GetAvailableRegister(false, true, Regs, - OutputRegs, InputRegs); + TLI.getRegClassForInlineAsmConstraint(ConstraintCode, + ConstraintVTs[i]); + SrcReg = GetAvailableRegister(false, true, Regs, + OutputRegs, InputRegs); // FIXME: should be match fail. assert(SrcReg && "Wasn't able to allocate register!"); Chain = DAG.getCopyToReg(Chain, SrcReg, InOperandVal, Flag); Flag = Chain.getValue(1); - ResOp = DAG.getRegister(SrcReg, CallOpVT); + ResOp = DAG.getRegister(SrcReg, ConstraintVTs[i]); ResOpType = 1; break; } diff --git a/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 79211debc99..e82e7f768ea 100644 --- a/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -745,24 +745,34 @@ bool TargetLowering::isOperandValidForConstraint(SDOperand Op, std::vector TargetLowering:: +getRegClassForInlineAsmConstraint(const std::string &Constraint, + MVT::ValueType VT) const { + return std::vector(); +} + + +std::pair TargetLowering:: getRegForInlineAsmConstraint(const std::string &Constraint, MVT::ValueType VT) const { - // Not a physreg, must not be a register reference or something. - if (Constraint[0] != '{') return std::vector(); + if (Constraint[0] != '{') + return std::pair(0, 0); assert(*(Constraint.end()-1) == '}' && "Not a brace enclosed constraint?"); // Remove the braces from around the name. std::string RegName(Constraint.begin()+1, Constraint.end()-1); - - // Scan to see if this constraint is a register name. + + // Figure out which register class contains this reg. const MRegisterInfo *RI = TM.getRegisterInfo(); - for (unsigned i = 1, e = RI->getNumRegs(); i != e; ++i) { - if (const char *Name = RI->get(i).Name) - if (StringsEqualNoCase(RegName, Name)) - return std::vector(1, i); + for (MRegisterInfo::regclass_iterator RCI = RI->regclass_begin(), + E = RI->regclass_end(); RCI != E; ++RCI) { + const TargetRegisterClass *RC = *RCI; + for (TargetRegisterClass::iterator I = RC->begin(), E = RC->end(); + I != E; ++I) { + if (StringsEqualNoCase(RegName, RI->get(*I).Name)) { + return std::make_pair(*I, RC); + } + } } - // Unknown physreg. - return std::vector(); + return std::pair(0, 0); } - diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp index 243c51d7c9d..003d16c26b1 100644 --- a/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/lib/Target/PowerPC/PPCISelLowering.cpp @@ -999,8 +999,8 @@ PPCTargetLowering::getConstraintType(char ConstraintLetter) const { std::vector PPCTargetLowering:: -getRegForInlineAsmConstraint(const std::string &Constraint, - MVT::ValueType VT) const { +getRegClassForInlineAsmConstraint(const std::string &Constraint, + MVT::ValueType VT) const { if (Constraint.size() == 1) { switch (Constraint[0]) { // GCC RS6000 Constraint Letters default: break; // Unknown constriant letter @@ -1051,8 +1051,7 @@ getRegForInlineAsmConstraint(const std::string &Constraint, } } - // Handle explicit register names. - return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); + return std::vector(); } // isOperandValidForConstraint diff --git a/lib/Target/PowerPC/PPCISelLowering.h b/lib/Target/PowerPC/PPCISelLowering.h index a1ce5545c32..86264aec38b 100644 --- a/lib/Target/PowerPC/PPCISelLowering.h +++ b/lib/Target/PowerPC/PPCISelLowering.h @@ -99,8 +99,8 @@ namespace llvm { ConstraintType getConstraintType(char ConstraintLetter) const; std::vector - getRegForInlineAsmConstraint(const std::string &Constraint, - MVT::ValueType VT) const; + getRegClassForInlineAsmConstraint(const std::string &Constraint, + MVT::ValueType VT) const; bool isOperandValidForConstraint(SDOperand Op, char ConstraintLetter); }; } diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index bbf590b8ac3..e32cc0f2bd8 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -1961,8 +1961,8 @@ void X86TargetLowering::computeMaskedBitsForTargetNode(const SDOperand Op, } std::vector X86TargetLowering:: -getRegForInlineAsmConstraint(const std::string &Constraint, - MVT::ValueType VT) const { +getRegClassForInlineAsmConstraint(const std::string &Constraint, + MVT::ValueType VT) const { if (Constraint.size() == 1) { // FIXME: not handling fp-stack yet! // FIXME: not handling MMX registers yet ('y' constraint). @@ -1993,6 +1993,5 @@ getRegForInlineAsmConstraint(const std::string &Constraint, } } - // Handle explicit register names. - return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); + return std::vector(); } diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index 375320c7714..d45afa4a184 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -224,8 +224,8 @@ namespace llvm { SDOperand getReturnAddressFrameIndex(SelectionDAG &DAG); std::vector - getRegForInlineAsmConstraint(const std::string &Constraint, - MVT::ValueType VT) const; + getRegClassForInlineAsmConstraint(const std::string &Constraint, + MVT::ValueType VT) const; private: // C Calling Convention implementation. std::vector LowerCCCArguments(Function &F, SelectionDAG &DAG);