From 864635ad7b3046d3042311423071152c613961de Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Wed, 22 Feb 2006 22:37:12 +0000 Subject: [PATCH] Change a whole bunch of code to be built around RegsForValue instead of a single register number. This fully implements promotion for inline asms, expand is close but not quite right yet. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@26316 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 384 ++++++++++++------ 1 file changed, 254 insertions(+), 130 deletions(-) diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index d16b070c51f..0060de4a4ac 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -78,6 +78,43 @@ namespace { clEnumValEnd)); } // namespace +namespace { + /// RegsForValue - This struct represents the physical registers that a + /// particular value is assigned and the type information about the value. + /// This is needed because values can be promoted into larger registers and + /// expanded into multiple smaller registers than the value. + struct RegsForValue { + /// Regs - This list hold the register (for legal and promoted values) + /// or register set (for expanded values) that the value should be assigned + /// to. + std::vector Regs; + + /// RegVT - The value type of each register. + /// + MVT::ValueType RegVT; + + /// ValueVT - The value type of the LLVM value, which may be promoted from + /// RegVT or made from merging the two expanded parts. + MVT::ValueType ValueVT; + + RegsForValue() : RegVT(MVT::Other), ValueVT(MVT::Other) {} + + RegsForValue(unsigned Reg, MVT::ValueType regvt, MVT::ValueType valuevt) + : RegVT(regvt), ValueVT(valuevt) { + Regs.push_back(Reg); + } + RegsForValue(const std::vector ®s, + MVT::ValueType regvt, MVT::ValueType valuevt) + : Regs(regs), RegVT(regvt), ValueVT(valuevt) { + } + + /// getCopyFromRegs - Emit a series of CopyFromReg nodes that copies from + /// this value and returns the result as a ValueVT value. This uses + /// Chain/Flag as the input and updates them for the output Chain/Flag. + SDOperand getCopyFromRegs(SelectionDAG &DAG, + SDOperand &Chain, SDOperand &Flag); + }; +} namespace llvm { //===--------------------------------------------------------------------===// @@ -120,7 +157,7 @@ namespace llvm { } // If this value is represented with multiple target registers, make sure - // to create enough consequtive registers of the right (smaller) type. + // to create enough consecutive registers of the right (smaller) type. unsigned NT = VT-1; // Find the type to use. while (TLI.getNumElements((MVT::ValueType)NT) != 1) --NT; @@ -412,11 +449,12 @@ public: return N = NewN; } - unsigned GetAvailableRegister(bool OutReg, bool InReg, - const std::vector &RegChoices, - std::set &OutputRegs, - std::set &InputRegs); - + RegsForValue GetRegistersForValue(const std::string &ConstrCode, + MVT::ValueType VT, + bool OutReg, bool InReg, + std::set &OutputRegs, + std::set &InputRegs); + // Terminator instructions. void visitRet(ReturnInst &I); void visitBr(BranchInst &I); @@ -1130,49 +1168,145 @@ void SelectionDAGLowering::visitCall(CallInst &I) { DAG.setRoot(Result.second); } -/// GetAvailableRegister - Pick a register from RegChoices that is available -/// for input and/or output as specified by isOutReg/isInReg. If an allocatable -/// register is found, it is returned and added to the specified set of used -/// registers. If not, zero is returned. -unsigned SelectionDAGLowering:: -GetAvailableRegister(bool isOutReg, bool isInReg, - const std::vector &RegChoices, - std::set &OutputRegs, - std::set &InputRegs) { - const MRegisterInfo *MRI = DAG.getTarget().getRegisterInfo(); - MachineFunction &MF = *CurMBB->getParent(); - for (unsigned i = 0, e = RegChoices.size(); i != e; ++i) { - unsigned Reg = RegChoices[i]; - // See if this register is available. - if (isOutReg && OutputRegs.count(Reg)) continue; // Already used. - if (isInReg && InputRegs.count(Reg)) continue; // Already used. +SDOperand RegsForValue::getCopyFromRegs(SelectionDAG &DAG, + SDOperand &Chain, SDOperand &Flag) { + SDOperand Val = DAG.getCopyFromReg(Chain, Regs[0], RegVT, Flag); + Chain = Val.getValue(1); + Flag = Val.getValue(2); + + // If the result was expanded, copy from the top part. + if (Regs.size() > 1) { + assert(Regs.size() == 2 && + "Cannot expand to more than 2 elts yet!"); + SDOperand Hi = DAG.getCopyFromReg(Chain, Regs[1], RegVT, Flag); + Chain = Val.getValue(1); + Flag = Val.getValue(2); + return DAG.getNode(ISD::MERGE_VALUES, ValueVT, Val, Hi); + } - // Check to see if this register is allocatable (i.e. don't give out the - // stack pointer). - bool Found = false; - for (MRegisterInfo::regclass_iterator RC = MRI->regclass_begin(), - E = MRI->regclass_end(); !Found && RC != E; ++RC) { - // NOTE: This isn't ideal. In particular, this might allocate the - // frame pointer in functions that need it (due to them not being taken - // out of allocation, because a variable sized allocation hasn't been seen - // yet). This is a slight code pessimization, but should still work. - for (TargetRegisterClass::iterator I = (*RC)->allocation_order_begin(MF), - E = (*RC)->allocation_order_end(MF); I != E; ++I) - if (*I == Reg) { - Found = true; - break; - } - } - if (!Found) continue; - - // Okay, this register is good, return it. - if (isOutReg) OutputRegs.insert(Reg); // Mark used. - if (isInReg) InputRegs.insert(Reg); // Mark used. - return Reg; + // Otherwise, if the return value was promoted, truncate it to the + // appropriate type. + if (RegVT == ValueVT) + return Val; + + if (MVT::isInteger(RegVT)) + return DAG.getNode(ISD::TRUNCATE, ValueVT, Val); + else + return DAG.getNode(ISD::FP_ROUND, ValueVT, Val); +} + + + +/// isAllocatableRegister - If the specified register is safe to allocate, +/// i.e. it isn't a stack pointer or some other special register, return the +/// register class for the register. Otherwise, return null. +static const TargetRegisterClass * +isAllocatableRegister(unsigned Reg, MachineFunction &MF, + const MRegisterInfo *MRI) { + for (MRegisterInfo::regclass_iterator RC = MRI->regclass_begin(), + E = MRI->regclass_end(); RC != E; ++RC) { + // NOTE: This isn't ideal. In particular, this might allocate the + // frame pointer in functions that need it (due to them not being taken + // out of allocation, because a variable sized allocation hasn't been seen + // yet). This is a slight code pessimization, but should still work. + for (TargetRegisterClass::iterator I = (*RC)->allocation_order_begin(MF), + E = (*RC)->allocation_order_end(MF); I != E; ++I) + if (*I == Reg) + return *RC; } return 0; +} + +RegsForValue SelectionDAGLowering:: +GetRegistersForValue(const std::string &ConstrCode, + MVT::ValueType VT, bool isOutReg, bool isInReg, + std::set &OutputRegs, + std::set &InputRegs) { + std::pair PhysReg = + TLI.getRegForInlineAsmConstraint(ConstrCode, VT); + std::vector Regs; + + unsigned NumRegs = VT != MVT::Other ? TLI.getNumElements(VT) : 1; + MVT::ValueType RegVT; + MVT::ValueType ValueVT = VT; + + if (PhysReg.first) { + if (VT == MVT::Other) + ValueVT = *PhysReg.second->vt_begin(); + RegVT = VT; + + // This is a explicit reference to a physical register. + Regs.push_back(PhysReg.first); + + // If this is an expanded reference, add the rest of the regs to Regs. + if (NumRegs != 1) { + RegVT = *PhysReg.second->vt_begin(); + TargetRegisterClass::iterator I = PhysReg.second->begin(); + TargetRegisterClass::iterator E = PhysReg.second->end(); + for (; *I != PhysReg.first; ++I) + assert(I != E && "Didn't find reg!"); + + // Already added the first reg. + --NumRegs; ++I; + for (; NumRegs; --NumRegs, ++I) { + assert(I != E && "Ran out of registers to allocate!"); + Regs.push_back(*I); + } + } + return RegsForValue(Regs, RegVT, ValueVT); + } + + // This is a reference to a register class. Allocate NumRegs consecutive, + // available, registers from the class. + std::vector RegClassRegs = + TLI.getRegClassForInlineAsmConstraint(ConstrCode, VT); + + const MRegisterInfo *MRI = DAG.getTarget().getRegisterInfo(); + MachineFunction &MF = *CurMBB->getParent(); + unsigned NumAllocated = 0; + for (unsigned i = 0, e = RegClassRegs.size(); i != e; ++i) { + unsigned Reg = RegClassRegs[i]; + // See if this register is available. + if ((isOutReg && OutputRegs.count(Reg)) || // Already used. + (isInReg && InputRegs.count(Reg))) { // Already used. + // Make sure we find consecutive registers. + NumAllocated = 0; + continue; + } + + // Check to see if this register is allocatable (i.e. don't give out the + // stack pointer). + const TargetRegisterClass *RC = isAllocatableRegister(Reg, MF, MRI); + if (!RC) { + // Make sure we find consecutive registers. + NumAllocated = 0; + continue; + } + + // Okay, this register is good, we can use it. + ++NumAllocated; + + // If we allocated enough consecutive + if (NumAllocated == NumRegs) { + unsigned RegStart = (i-NumAllocated)+1; + unsigned RegEnd = i+1; + // Mark all of the allocated registers used. + for (unsigned i = RegStart; i != RegEnd; ++i) { + unsigned Reg = RegClassRegs[i]; + Regs.push_back(Reg); + if (isOutReg) OutputRegs.insert(Reg); // Mark reg used. + if (isInReg) InputRegs.insert(Reg); // Mark reg used. + } + + return RegsForValue(Regs, *RC->vt_begin(), VT); + } + } + + // Otherwise, we couldn't allocate enough registers for this. + return RegsForValue(); } + /// visitInlineAsm - Handle a call to an InlineAsm object. /// void SelectionDAGLowering::visitInlineAsm(CallInst &I) { @@ -1235,39 +1369,40 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { 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; + if (TLI.getRegForInlineAsmConstraint(ConstraintCode, OpVT).first == 0) + continue; // Not assigned a fixed reg. - // FIXME: Handle expanded physreg refs! + // Build a list of regs that this operand uses. This always has a single + // element for promoted/expanded operands. + RegsForValue Regs = GetRegistersForValue(ConstraintCode, OpVT, + false, false, + OutputRegs, InputRegs); switch (Constraints[i].Type) { case InlineAsm::isOutput: // We can't assign any other output to this register. - OutputRegs.insert(TheReg); + OutputRegs.insert(Regs.Regs.begin(), Regs.Regs.end()); // If this is an early-clobber output, it cannot be assigned to the same // value as the input reg. if (Constraints[i].isEarlyClobber || Constraints[i].hasMatchingInput) - InputRegs.insert(TheReg); + InputRegs.insert(Regs.Regs.begin(), Regs.Regs.end()); break; case InlineAsm::isInput: // We can't assign any other input to this register. - InputRegs.insert(TheReg); + InputRegs.insert(Regs.Regs.begin(), Regs.Regs.end()); break; case InlineAsm::isClobber: // Clobbered regs cannot be used as inputs or outputs. - InputRegs.insert(TheReg); - OutputRegs.insert(TheReg); + InputRegs.insert(Regs.Regs.begin(), Regs.Regs.end()); + OutputRegs.insert(Regs.Regs.begin(), Regs.Regs.end()); break; } } // Loop over all of the inputs, copying the operand values into the // appropriate registers and processing the output regs. - unsigned RetValReg = 0; - std::vector > IndirectStoresToEmit; - bool FoundOutputConstraint = false; + RegsForValue RetValRegs; + std::vector > IndirectStoresToEmit; OpNum = 1; for (unsigned i = 0, e = Constraints.size(); i != e; ++i) { @@ -1276,58 +1411,47 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { switch (Constraints[i].Type) { case InlineAsm::isOutput: { - // Copy the output from the appropriate register. Find a regsister that + // 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; + + // Copy the output from the appropriate register. Find a register that // we can use. - - // Check to see if this is a physreg reference. - std::pair PhysReg = - TLI.getRegForInlineAsmConstraint(ConstraintCode, ConstraintVTs[i]); - unsigned DestReg; - if (PhysReg.first) - DestReg = PhysReg.first; - else { - std::vector Regs = - TLI.getRegClassForInlineAsmConstraint(ConstraintCode, - ConstraintVTs[i]); + RegsForValue Regs = + GetRegistersForValue(ConstraintCode, ConstraintVTs[i], + true, UsesInputRegister, + OutputRegs, InputRegs); + assert(!Regs.Regs.empty() && "Couldn't allocate output reg!"); - // 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, - Regs, OutputRegs, InputRegs); - } - - assert(DestReg && "Couldn't allocate output reg!"); - - const Type *OpTy; if (!Constraints[i].isIndirectOutput) { - assert(!FoundOutputConstraint && + assert(RetValRegs.Regs.empty() && "Cannot have multiple output constraints yet!"); - FoundOutputConstraint = true; assert(I.getType() != Type::VoidTy && "Bad inline asm!"); - - RetValReg = DestReg; + RetValRegs = Regs; } else { Value *CallOperand = I.getOperand(OpNum); - IndirectStoresToEmit.push_back(std::make_pair(DestReg, CallOperand)); + IndirectStoresToEmit.push_back(std::make_pair(Regs, CallOperand)); OpNum++; // Consumes a call operand. } // Add information to the INLINEASM node to know that this register is // set. - AsmNodeOperands.push_back(DAG.getRegister(DestReg, ConstraintVTs[i])); - AsmNodeOperands.push_back(DAG.getConstant(2, MVT::i32)); // ISDEF + // FIXME: + // FIXME: Handle multiple regs here. + // FIXME: + unsigned DestReg = Regs.Regs[0]; + AsmNodeOperands.push_back(DAG.getRegister(DestReg, Regs.RegVT)); + AsmNodeOperands.push_back(DAG.getConstant(2, MVT::i32)); // ISDEF break; } case InlineAsm::isInput: { Value *CallOperand = I.getOperand(OpNum); OpNum++; // Consumes a call operand. - unsigned SrcReg; SDOperand ResOp; unsigned ResOpType; SDOperand InOperandVal = getValue(CallOperand); @@ -1336,6 +1460,7 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { // If this is required to match an output register we have already set, // just use its register. unsigned OperandNo = atoi(ConstraintCode.c_str()); + unsigned SrcReg; SrcReg = cast(AsmNodeOperands[OperandNo*2+2])->getReg(); ResOp = DAG.getRegister(SrcReg, ConstraintVTs[i]); ResOpType = 1; @@ -1343,39 +1468,46 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { Chain = DAG.getCopyToReg(Chain, SrcReg, InOperandVal, Flag); Flag = Chain.getValue(1); } else { - TargetLowering::ConstraintType CTy = TargetLowering::C_Register; + TargetLowering::ConstraintType CTy = TargetLowering::C_RegisterClass; 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.getRegClassForInlineAsmConstraint(ConstraintCode, - ConstraintVTs[i]); - SrcReg = GetAvailableRegister(false, true, Regs, - OutputRegs, InputRegs); + // Copy the input into the appropriate registers. + RegsForValue InRegs = + GetRegistersForValue(ConstraintCode, ConstraintVTs[i], + false, true, 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); + assert(!InRegs.Regs.empty() && "Couldn't allocate input reg!"); + + if (InRegs.Regs.size() == 1) { + // If there is a single register and the types differ, this must be + // a promotion. + if (InRegs.RegVT != InRegs.ValueVT) { + if (MVT::isInteger(InRegs.RegVT)) + InOperandVal = DAG.getNode(ISD::ANY_EXTEND, InRegs.RegVT, + InOperandVal); + else + InOperandVal = DAG.getNode(ISD::FP_EXTEND, InRegs.RegVT, + InOperandVal); + } + Chain = DAG.getCopyToReg(Chain, InRegs.Regs[0], InOperandVal, Flag); + Flag = Chain.getValue(1); + + ResOp = DAG.getRegister(InRegs.Regs[0], InRegs.RegVT); + } else { + for (unsigned i = 0, e = InRegs.Regs.size(); i != e; ++i) { + SDOperand Part = DAG.getNode(ISD::EXTRACT_ELEMENT, InRegs.RegVT, + InOperandVal, + DAG.getConstant(i, MVT::i32)); + Chain = DAG.getCopyToReg(Chain, InRegs.Regs[i], Part, Flag); + Flag = Chain.getValue(1); + } + ResOp = DAG.getRegister(InRegs.Regs[0], InRegs.RegVT); + } - ResOp = DAG.getRegister(SrcReg, ConstraintVTs[i]); ResOpType = 1; break; } @@ -1411,26 +1543,18 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { // If this asm returns a register value, copy the result from that register // and set it as the value of the call. - if (RetValReg) { - SDOperand Val = DAG.getCopyFromReg(Chain, RetValReg, - TLI.getValueType(I.getType()), Flag); - Chain = Val.getValue(1); - Flag = Val.getValue(2); - setValue(&I, Val); - } + if (!RetValRegs.Regs.empty()) + setValue(&I, RetValRegs.getCopyFromRegs(DAG, Chain, Flag)); std::vector > StoresToEmit; // Process indirect outputs, first output all of the flagged copies out of // physregs. for (unsigned i = 0, e = IndirectStoresToEmit.size(); i != e; ++i) { + RegsForValue &OutRegs = IndirectStoresToEmit[i].first; Value *Ptr = IndirectStoresToEmit[i].second; - const Type *Ty = cast(Ptr->getType())->getElementType(); - SDOperand Val = DAG.getCopyFromReg(Chain, IndirectStoresToEmit[i].first, - TLI.getValueType(Ty), Flag); - Chain = Val.getValue(1); - Flag = Val.getValue(2); - StoresToEmit.push_back(std::make_pair(Val, Ptr)); + SDOperand OutVal = OutRegs.getCopyFromRegs(DAG, Chain, Flag); + StoresToEmit.push_back(std::make_pair(OutVal, Ptr)); } // Emit the non-flagged stores from the physregs. @@ -1689,8 +1813,8 @@ void SelectionDAGLowering::visitMemIntrinsic(CallInst &I, unsigned Op) { SDOperand Value = getMemsetValue(Op2, VT, DAG); SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, getRoot(), Value, - getMemBasePlusOffset(Op1, Offset, DAG, TLI), - DAG.getSrcValue(I.getOperand(1), Offset)); + getMemBasePlusOffset(Op1, Offset, DAG, TLI), + DAG.getSrcValue(I.getOperand(1), Offset)); OutChains.push_back(Store); Offset += VTSize; }