From: Chris Lattner Date: Wed, 1 Feb 2006 18:59:47 +0000 (+0000) Subject: Implement simple register assignment for inline asms. This allows us to compile: X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=4e4b576e2edfc7d40a3d7177c639acbe91cfd45f;p=oota-llvm.git Implement simple register assignment for inline asms. This allows us to compile: int %test(int %A, int %B) { %C = call int asm "xyz $0, $1, $2", "=r,r,r"(int %A, int %B) ret int %C } into: (0x8906130, LLVM BB @0x8902220): %r2 = OR4 %r3, %r3 %r3 = OR4 %r4, %r4 INLINEASM , %r2, %r2, %r3 %r3 = OR4 %r2, %r2 BLR which asmprints as: _test: or r2, r3, r3 or r3, r4, r4 xyz $0, $1, $2 ;; need to print the operands now :) or r3, r2, r2 blr git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@25878 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 8ab62190c05..8b7dca3f132 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -40,6 +40,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/Debug.h" #include +#include #include using namespace llvm; @@ -410,6 +411,11 @@ public: assert(N.Val == 0 && "Already set a value for this node!"); return N = NewN; } + + unsigned GetAvailableRegister(bool OutReg, bool InReg, + const std::vector &RegChoices, + std::set &OutputRegs, + std::set &InputRegs); // Terminator instructions. void visitRet(ReturnInst &I); @@ -1143,6 +1149,49 @@ 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. + + // 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; + } + return 0; +} + /// visitInlineAsm - Handle a call to an InlineAsm object. /// void SelectionDAGLowering::visitInlineAsm(CallInst &I) { @@ -1174,21 +1223,60 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { std::vector > IndirectStoresToEmit; unsigned OpNum = 1; bool FoundOutputConstraint = false; - //std::set OutputRegs; - //std::set InputRegs; + + // We fully assign registers here at isel time. This is not optimal, but + // should work. For register classes that correspond to LLVM classes, we + // 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; + 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); + if (Regs.size() != 1) continue; // Not assigned a fixed reg. + unsigned TheReg = Regs[0]; + + switch (Constraints[i].Type) { + case InlineAsm::isOutput: + // We can't assign any other output to this register. + OutputRegs.insert(TheReg); + // If this is an early-clobber output, it cannot be assigned to the same + // value as the input reg. + if (Constraints[i].isEarlyClobber) + 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; + } + } 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]; switch (Constraints[i].Type) { case InlineAsm::isOutput: { - bool isEarlyClobber = Constraints[i].isEarlyClobber; // Copy the output from the appropriate register. std::vector Regs = TLI.getRegForInlineAsmConstraint(ConstraintCode); - assert(Regs.size() == 1 && "Only handle simple regs right now!"); - unsigned DestReg = Regs[0]; + + // Find a regsister that we can use. + unsigned DestReg; + if (Regs.size() == 1) + DestReg = Regs[0]; + else + DestReg = GetAvailableRegister(true, Constraints[i].isEarlyClobber, + Regs, OutputRegs, InputRegs); + + assert(DestReg && "Couldn't allocate output reg!"); const Type *OpTy; if (!Constraints[i].isIndirectOutput) { @@ -1218,12 +1306,20 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { case InlineAsm::isInput: { Value *Operand = I.getOperand(OpNum); const Type *OpTy = Operand->getType(); + OpNum++; // Consumes a call operand. // Copy the input into the appropriate register. std::vector Regs = TLI.getRegForInlineAsmConstraint(ConstraintCode); - assert(Regs.size() == 1 && "Only handle simple regs right now!"); - unsigned SrcReg = Regs[0]; + unsigned SrcReg; + if (Regs.size() == 1) + SrcReg = Regs[0]; + else + SrcReg = GetAvailableRegister(false, true, Regs, + OutputRegs, InputRegs); + + assert(SrcReg && "Couldn't allocate input reg!"); + Chain = DAG.getCopyToReg(Chain, SrcReg, getValue(Operand), Flag); Flag = Chain.getValue(1); @@ -1271,7 +1367,6 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { Chain = Val.getValue(1); Flag = Val.getValue(2); StoresToEmit.push_back(std::make_pair(Val, Ptr)); - OpNum++; // Consumes a call operand. } // Emit the non-flagged stores from the physregs.