split register class handling from explicit physreg handling.

llvm-svn: 26308
This commit is contained in:
Chris Lattner 2006-02-22 00:56:39 +00:00
parent cd78df1e85
commit 7ad77dfc2a
7 changed files with 124 additions and 63 deletions

View File

@ -481,6 +481,7 @@ public:
// //
enum ConstraintType { enum ConstraintType {
C_Register, // Constraint represents a single register.
C_RegisterClass, // Constraint represents one or more registers. C_RegisterClass, // Constraint represents one or more registers.
C_Other, // Something else. C_Other, // Something else.
C_Unknown // Unsupported constraint. C_Unknown // Unsupported constraint.
@ -491,13 +492,22 @@ public:
/// constraint it is for this target. /// constraint it is for this target.
virtual ConstraintType getConstraintType(char ConstraintLetter) const; 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 /// getRegClassForInlineAsmConstraint - Given a constraint letter (e.g. "r"),
/// satisfy the constraint. This should only be used for physregs and /// return a list of registers that can be used to satisfy the constraint.
/// C_RegisterClass constraints. /// This should only be used for C_RegisterClass constraints.
virtual std::vector<unsigned> virtual std::vector<unsigned>
getRegForInlineAsmConstraint(const std::string &Constraint, getRegClassForInlineAsmConstraint(const std::string &Constraint,
MVT::ValueType VT) const; 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<unsigned, const TargetRegisterClass*>
getRegForInlineAsmConstraint(const std::string &Constraint,
MVT::ValueType VT) const;
/// isOperandValidForConstraint - Return true if the specified SDOperand is /// isOperandValidForConstraint - Return true if the specified SDOperand is
/// valid for the specified target constraint letter. /// valid for the specified target constraint letter.

View File

@ -1187,6 +1187,7 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) {
bool hasSideEffects = IA->hasSideEffects(); bool hasSideEffects = IA->hasSideEffects();
std::vector<InlineAsm::ConstraintInfo> Constraints = IA->ParseConstraints(); std::vector<InlineAsm::ConstraintInfo> Constraints = IA->ParseConstraints();
std::vector<MVT::ValueType> ConstraintVTs;
/// AsmNodeOperands - A list of pairs. The first element is a register, the /// 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 /// 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 // 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. // over the constraints, collecting fixed registers that we know we can't use.
std::set<unsigned> OutputRegs, InputRegs; std::set<unsigned> OutputRegs, InputRegs;
unsigned OpNum = 1;
for (unsigned i = 0, e = Constraints.size(); i != e; ++i) { for (unsigned i = 0, e = Constraints.size(); i != e; ++i) {
assert(Constraints[i].Codes.size() == 1 && "Only handles one code so far!"); assert(Constraints[i].Codes.size() == 1 && "Only handles one code so far!");
std::string &ConstraintCode = Constraints[i].Codes[0]; std::string &ConstraintCode = Constraints[i].Codes[0];
std::vector<unsigned> Regs = MVT::ValueType OpVT;
TLI.getRegForInlineAsmConstraint(ConstraintCode, MVT::Other);
if (Regs.size() != 1) continue; // Not assigned a fixed reg. // Compute the value type for each operand and add it to ConstraintVTs.
unsigned TheReg = Regs[0]; 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<PointerType>(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<unsigned, const TargetRegisterClass*> 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) { switch (Constraints[i].Type) {
case InlineAsm::isOutput: case InlineAsm::isOutput:
@ -1221,15 +1251,15 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) {
if (Constraints[i].isEarlyClobber || Constraints[i].hasMatchingInput) if (Constraints[i].isEarlyClobber || Constraints[i].hasMatchingInput)
InputRegs.insert(TheReg); InputRegs.insert(TheReg);
break; break;
case InlineAsm::isInput:
// We can't assign any other input to this register.
InputRegs.insert(TheReg);
break;
case InlineAsm::isClobber: case InlineAsm::isClobber:
// Clobbered regs cannot be used as inputs or outputs. // Clobbered regs cannot be used as inputs or outputs.
InputRegs.insert(TheReg); InputRegs.insert(TheReg);
OutputRegs.insert(TheReg); OutputRegs.insert(TheReg);
break; 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; unsigned RetValReg = 0;
std::vector<std::pair<unsigned, Value*> > IndirectStoresToEmit; std::vector<std::pair<unsigned, Value*> > IndirectStoresToEmit;
bool FoundOutputConstraint = false; bool FoundOutputConstraint = false;
unsigned OpNum = 1; OpNum = 1;
for (unsigned i = 0, e = Constraints.size(); i != e; ++i) { for (unsigned i = 0, e = Constraints.size(); i != e; ++i) {
assert(Constraints[i].Codes.size() == 1 && "Only handles one code so far!"); assert(Constraints[i].Codes.size() == 1 && "Only handles one code so far!");
std::string &ConstraintCode = Constraints[i].Codes[0]; std::string &ConstraintCode = Constraints[i].Codes[0];
Value *CallOperand = I.getOperand(OpNum);
MVT::ValueType CallOpVT = TLI.getValueType(CallOperand->getType());
switch (Constraints[i].Type) { switch (Constraints[i].Type) {
case InlineAsm::isOutput: { case InlineAsm::isOutput: {
// Copy the output from the appropriate register. // Copy the output from the appropriate register. Find a regsister that
std::vector<unsigned> Regs = // we can use.
TLI.getRegForInlineAsmConstraint(ConstraintCode, CallOpVT);
// Check to see if this is a physreg reference.
// Find a regsister that we can use. std::pair<unsigned, const TargetRegisterClass*> PhysReg =
TLI.getRegForInlineAsmConstraint(ConstraintCode, ConstraintVTs[i]);
unsigned DestReg; unsigned DestReg;
if (Regs.size() == 1) if (PhysReg.first)
DestReg = Regs[0]; DestReg = PhysReg.first;
else { else {
bool UsesInputRegister = false; std::vector<unsigned> Regs =
TLI.getRegClassForInlineAsmConstraint(ConstraintCode,
ConstraintVTs[i]);
// If this is an early-clobber output, or if there is an input // If this is an early-clobber output, or if there is an input
// constraint that matches this, we need to reserve the input register // constraint that matches this, we need to reserve the input register
// so no other inputs allocate to it. // so no other inputs allocate to it.
bool UsesInputRegister = false;
if (Constraints[i].isEarlyClobber || Constraints[i].hasMatchingInput) if (Constraints[i].isEarlyClobber || Constraints[i].hasMatchingInput)
UsesInputRegister = true; UsesInputRegister = true;
DestReg = GetAvailableRegister(true, UsesInputRegister, DestReg = GetAvailableRegister(true, UsesInputRegister,
@ -1276,24 +1310,21 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) {
assert(I.getType() != Type::VoidTy && "Bad inline asm!"); assert(I.getType() != Type::VoidTy && "Bad inline asm!");
RetValReg = DestReg; RetValReg = DestReg;
OpTy = I.getType();
} else { } else {
Value *CallOperand = I.getOperand(OpNum);
IndirectStoresToEmit.push_back(std::make_pair(DestReg, CallOperand)); IndirectStoresToEmit.push_back(std::make_pair(DestReg, CallOperand));
OpTy = CallOperand->getType();
OpTy = cast<PointerType>(OpTy)->getElementType();
OpNum++; // Consumes a call operand. OpNum++; // Consumes a call operand.
} }
// Add information to the INLINEASM node to know that this register is // Add information to the INLINEASM node to know that this register is
// set. // set.
AsmNodeOperands.push_back(DAG.getRegister(DestReg, AsmNodeOperands.push_back(DAG.getRegister(DestReg, ConstraintVTs[i]));
TLI.getValueType(OpTy)));
AsmNodeOperands.push_back(DAG.getConstant(2, MVT::i32)); // ISDEF AsmNodeOperands.push_back(DAG.getConstant(2, MVT::i32)); // ISDEF
break; break;
} }
case InlineAsm::isInput: { case InlineAsm::isInput: {
const Type *OpTy = CallOperand->getType(); Value *CallOperand = I.getOperand(OpNum);
OpNum++; // Consumes a call operand. OpNum++; // Consumes a call operand.
unsigned SrcReg; unsigned SrcReg;
@ -1306,33 +1337,45 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) {
// just use its register. // just use its register.
unsigned OperandNo = atoi(ConstraintCode.c_str()); unsigned OperandNo = atoi(ConstraintCode.c_str());
SrcReg = cast<RegisterSDNode>(AsmNodeOperands[OperandNo*2+2])->getReg(); SrcReg = cast<RegisterSDNode>(AsmNodeOperands[OperandNo*2+2])->getReg();
ResOp = DAG.getRegister(SrcReg, CallOpVT); ResOp = DAG.getRegister(SrcReg, ConstraintVTs[i]);
ResOpType = 1; ResOpType = 1;
Chain = DAG.getCopyToReg(Chain, SrcReg, InOperandVal, Flag); Chain = DAG.getCopyToReg(Chain, SrcReg, InOperandVal, Flag);
Flag = Chain.getValue(1); Flag = Chain.getValue(1);
} else { } else {
TargetLowering::ConstraintType CTy = TargetLowering::C_RegisterClass; TargetLowering::ConstraintType CTy = TargetLowering::C_Register;
if (ConstraintCode.size() == 1) // not a physreg name. if (ConstraintCode.size() == 1) // not a physreg name.
CTy = TLI.getConstraintType(ConstraintCode[0]); CTy = TLI.getConstraintType(ConstraintCode[0]);
switch (CTy) { switch (CTy) {
default: assert(0 && "Unknown constraint type! FAIL!"); default: assert(0 && "Unknown constraint type! FAIL!");
case TargetLowering::C_Register: {
std::pair<unsigned, const TargetRegisterClass*> 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: { case TargetLowering::C_RegisterClass: {
// Copy the input into the appropriate register. // Copy the input into the appropriate register.
std::vector<unsigned> Regs = std::vector<unsigned> Regs =
TLI.getRegForInlineAsmConstraint(ConstraintCode, CallOpVT); TLI.getRegClassForInlineAsmConstraint(ConstraintCode,
if (Regs.size() == 1) ConstraintVTs[i]);
SrcReg = Regs[0]; SrcReg = GetAvailableRegister(false, true, Regs,
else OutputRegs, InputRegs);
SrcReg = GetAvailableRegister(false, true, Regs,
OutputRegs, InputRegs);
// FIXME: should be match fail. // FIXME: should be match fail.
assert(SrcReg && "Wasn't able to allocate register!"); assert(SrcReg && "Wasn't able to allocate register!");
Chain = DAG.getCopyToReg(Chain, SrcReg, InOperandVal, Flag); Chain = DAG.getCopyToReg(Chain, SrcReg, InOperandVal, Flag);
Flag = Chain.getValue(1); Flag = Chain.getValue(1);
ResOp = DAG.getRegister(SrcReg, CallOpVT); ResOp = DAG.getRegister(SrcReg, ConstraintVTs[i]);
ResOpType = 1; ResOpType = 1;
break; break;
} }

View File

@ -999,8 +999,8 @@ PPCTargetLowering::getConstraintType(char ConstraintLetter) const {
std::vector<unsigned> PPCTargetLowering:: std::vector<unsigned> PPCTargetLowering::
getRegForInlineAsmConstraint(const std::string &Constraint, getRegClassForInlineAsmConstraint(const std::string &Constraint,
MVT::ValueType VT) const { MVT::ValueType VT) const {
if (Constraint.size() == 1) { if (Constraint.size() == 1) {
switch (Constraint[0]) { // GCC RS6000 Constraint Letters switch (Constraint[0]) { // GCC RS6000 Constraint Letters
default: break; // Unknown constriant letter default: break; // Unknown constriant letter
@ -1051,8 +1051,7 @@ getRegForInlineAsmConstraint(const std::string &Constraint,
} }
} }
// Handle explicit register names. return std::vector<unsigned>();
return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT);
} }
// isOperandValidForConstraint // isOperandValidForConstraint

View File

@ -99,8 +99,8 @@ namespace llvm {
ConstraintType getConstraintType(char ConstraintLetter) const; ConstraintType getConstraintType(char ConstraintLetter) const;
std::vector<unsigned> std::vector<unsigned>
getRegForInlineAsmConstraint(const std::string &Constraint, getRegClassForInlineAsmConstraint(const std::string &Constraint,
MVT::ValueType VT) const; MVT::ValueType VT) const;
bool isOperandValidForConstraint(SDOperand Op, char ConstraintLetter); bool isOperandValidForConstraint(SDOperand Op, char ConstraintLetter);
}; };
} }

View File

@ -745,24 +745,34 @@ bool TargetLowering::isOperandValidForConstraint(SDOperand Op,
std::vector<unsigned> TargetLowering:: std::vector<unsigned> TargetLowering::
getRegClassForInlineAsmConstraint(const std::string &Constraint,
MVT::ValueType VT) const {
return std::vector<unsigned>();
}
std::pair<unsigned, const TargetRegisterClass*> TargetLowering::
getRegForInlineAsmConstraint(const std::string &Constraint, getRegForInlineAsmConstraint(const std::string &Constraint,
MVT::ValueType VT) const { MVT::ValueType VT) const {
// Not a physreg, must not be a register reference or something. if (Constraint[0] != '{')
if (Constraint[0] != '{') return std::vector<unsigned>(); return std::pair<unsigned, const TargetRegisterClass*>(0, 0);
assert(*(Constraint.end()-1) == '}' && "Not a brace enclosed constraint?"); assert(*(Constraint.end()-1) == '}' && "Not a brace enclosed constraint?");
// Remove the braces from around the name. // Remove the braces from around the name.
std::string RegName(Constraint.begin()+1, Constraint.end()-1); 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(); const MRegisterInfo *RI = TM.getRegisterInfo();
for (unsigned i = 1, e = RI->getNumRegs(); i != e; ++i) { for (MRegisterInfo::regclass_iterator RCI = RI->regclass_begin(),
if (const char *Name = RI->get(i).Name) E = RI->regclass_end(); RCI != E; ++RCI) {
if (StringsEqualNoCase(RegName, Name)) const TargetRegisterClass *RC = *RCI;
return std::vector<unsigned>(1, i); 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::pair<unsigned, const TargetRegisterClass*>(0, 0);
return std::vector<unsigned>();
} }

View File

@ -1961,8 +1961,8 @@ void X86TargetLowering::computeMaskedBitsForTargetNode(const SDOperand Op,
} }
std::vector<unsigned> X86TargetLowering:: std::vector<unsigned> X86TargetLowering::
getRegForInlineAsmConstraint(const std::string &Constraint, getRegClassForInlineAsmConstraint(const std::string &Constraint,
MVT::ValueType VT) const { MVT::ValueType VT) const {
if (Constraint.size() == 1) { if (Constraint.size() == 1) {
// FIXME: not handling fp-stack yet! // FIXME: not handling fp-stack yet!
// FIXME: not handling MMX registers yet ('y' constraint). // FIXME: not handling MMX registers yet ('y' constraint).
@ -1993,6 +1993,5 @@ getRegForInlineAsmConstraint(const std::string &Constraint,
} }
} }
// Handle explicit register names. return std::vector<unsigned>();
return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT);
} }

View File

@ -224,8 +224,8 @@ namespace llvm {
SDOperand getReturnAddressFrameIndex(SelectionDAG &DAG); SDOperand getReturnAddressFrameIndex(SelectionDAG &DAG);
std::vector<unsigned> std::vector<unsigned>
getRegForInlineAsmConstraint(const std::string &Constraint, getRegClassForInlineAsmConstraint(const std::string &Constraint,
MVT::ValueType VT) const; MVT::ValueType VT) const;
private: private:
// C Calling Convention implementation. // C Calling Convention implementation.
std::vector<SDOperand> LowerCCCArguments(Function &F, SelectionDAG &DAG); std::vector<SDOperand> LowerCCCArguments(Function &F, SelectionDAG &DAG);