diff options
| author | Chris Lattner <sabre@nondot.org> | 2006-02-01 18:59:47 +0000 | 
|---|---|---|
| committer | Chris Lattner <sabre@nondot.org> | 2006-02-01 18:59:47 +0000 | 
| commit | 1558fc64f9b55fc521c80869002e58868bc07c63 (patch) | |
| tree | bce2c2a24fb990547d9681cf591a32c40df992da /llvm/lib | |
| parent | ba56b5dc35b45bdf511bca3b0d379d884f3c97a0 (diff) | |
| download | bcm5719-llvm-1558fc64f9b55fc521c80869002e58868bc07c63.tar.gz bcm5719-llvm-1558fc64f9b55fc521c80869002e58868bc07c63.zip | |
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 <es:xyz $0, $1, $2>, %r2<def>, %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
llvm-svn: 25878
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 111 | 
1 files changed, 103 insertions, 8 deletions
| diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 8ab62190c05..8b7dca3f132 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -40,6 +40,7 @@  #include "llvm/Support/MathExtras.h"  #include "llvm/Support/Debug.h"  #include <map> +#include <set>  #include <iostream>  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<unsigned> &RegChoices, +                                std::set<unsigned> &OutputRegs,  +                                std::set<unsigned> &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<unsigned> &RegChoices, +                     std::set<unsigned> &OutputRegs, +                     std::set<unsigned> &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<std::pair<unsigned, Value*> > IndirectStoresToEmit;    unsigned OpNum = 1;    bool FoundOutputConstraint = false; -  //std::set<unsigned> OutputRegs; -  //std::set<unsigned> 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<unsigned> 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<unsigned> 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<unsigned> 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<unsigned> 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. | 

