implement a ArgumentLayout class to factor code common to LowerFORMAL_ARGUMENTS and...
authorRafael Espindola <rafael.espindola@gmail.com>
Thu, 5 Oct 2006 16:48:49 +0000 (16:48 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Thu, 5 Oct 2006 16:48:49 +0000 (16:48 +0000)
implement FMDRR
add support for f64 function arguments

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@30754 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMISelDAGToDAG.cpp
lib/Target/ARM/ARMInstrInfo.td
test/CodeGen/ARM/fp.ll

index 2adf4073ba02134c039c1a1773e622b018f3a892..ffcdbc1180b7ac6fca651c066ec9c807e709316b 100644 (file)
@@ -27,8 +27,7 @@
 #include "llvm/Target/TargetLowering.h"
 #include "llvm/Support/Debug.h"
 #include <iostream>
-#include <queue>
-#include <set>
+#include <vector>
 using namespace llvm;
 
 namespace {
@@ -89,7 +88,9 @@ namespace llvm {
 
       FSITOD,
 
-      FMRRD
+      FMRRD,
+
+      FMDRR
     };
   }
 }
@@ -124,9 +125,87 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const {
   case ARMISD::FSITOS:        return "ARMISD::FSITOS";
   case ARMISD::FSITOD:        return "ARMISD::FSITOD";
   case ARMISD::FMRRD:         return "ARMISD::FMRRD";
+  case ARMISD::FMDRR:         return "ARMISD::FMDRR";
   }
 }
 
+class ArgumentLayout {
+  std::vector<bool>           is_reg;
+  std::vector<unsigned>       pos;
+  std::vector<MVT::ValueType> types;
+public:
+  ArgumentLayout(std::vector<MVT::ValueType> Types) {
+    types = Types;
+
+    unsigned      RegNum = 0;
+    unsigned StackOffset = 0;
+    for(std::vector<MVT::ValueType>::iterator I = Types.begin();
+        I != Types.end();
+        ++I) {
+      MVT::ValueType VT = *I;
+      assert(VT == MVT::i32 || VT == MVT::f32 || VT == MVT::f64);
+      unsigned     size = MVT::getSizeInBits(VT)/32;
+
+      RegNum = ((RegNum + size - 1) / size) * size;
+      if (RegNum < 4) {
+        pos.push_back(RegNum);
+        is_reg.push_back(true);
+        RegNum += size;
+      } else {
+        unsigned bytes = size * 32/8;
+        StackOffset = ((StackOffset + bytes - 1) / bytes) * bytes;
+        pos.push_back(StackOffset);
+        is_reg.push_back(false);
+        StackOffset += bytes;
+      }
+    }
+  }
+  unsigned getRegisterNum(unsigned argNum) {
+    assert(isRegister(argNum));
+    return pos[argNum];
+  }
+  unsigned getOffset(unsigned argNum) {
+    assert(isOffset(argNum));
+    return pos[argNum];
+  }
+  unsigned isRegister(unsigned argNum) {
+    assert(argNum < is_reg.size());
+    return is_reg[argNum];
+  }
+  unsigned isOffset(unsigned argNum) {
+    return !isRegister(argNum);
+  }
+  MVT::ValueType getType(unsigned argNum) {
+    assert(argNum < types.size());
+    return types[argNum];
+  }
+  unsigned getStackSize(void) {
+    int last = is_reg.size() - 1;
+    if (isRegister(last))
+      return 0;
+    return getOffset(last) + MVT::getSizeInBits(getType(last))/8;
+  }
+  int lastRegArg(void) {
+    int size = is_reg.size();
+    int last = 0;
+    while(last < size && isRegister(last))
+      last++;
+    last--;
+    return last;
+  }
+  unsigned lastRegNum(void) {
+    int            l = lastRegArg();
+    if (l < 0)
+      return -1;
+    unsigned       r = getRegisterNum(l);
+    MVT::ValueType t = getType(l);
+    assert(t == MVT::i32 || t == MVT::f32 || t == MVT::f64);
+    if (t == MVT::f64)
+      return r + 1;
+    return r;
+  }
+};
+
 // This transforms a ISD::CALL node into a
 // callseq_star <- ARMISD:CALL <- callseq_end
 // chain
@@ -139,59 +218,37 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
   assert(isTailCall == false && "tail call not supported");
   SDOperand Callee   = Op.getOperand(4);
   unsigned NumOps    = (Op.getNumOperands() - 5) / 2;
+  SDOperand StackPtr = DAG.getRegister(ARM::R13, MVT::i32);
+  static const unsigned regs[] = {
+    ARM::R0, ARM::R1, ARM::R2, ARM::R3
+  };
 
-  // Count how many bytes are to be pushed on the stack.
-  unsigned NumBytes = 0;
+  std::vector<MVT::ValueType> Types;
+  for (unsigned i = 0; i < NumOps; ++i) {
+    MVT::ValueType VT = Op.getOperand(5+2*i).getValueType();
+    Types.push_back(VT);
+  }
+  ArgumentLayout Layout(Types);
 
-  // Add up all the space actually used.
-  for (unsigned i = 4; i < NumOps; ++i)
-    NumBytes += MVT::getSizeInBits(Op.getOperand(5+2*i).getValueType())/8;
+  unsigned NumBytes = Layout.getStackSize();
 
-  // Adjust the stack pointer for the new arguments...
-  // These operations are automatically eliminated by the prolog/epilog pass
   Chain = DAG.getCALLSEQ_START(Chain,
                                DAG.getConstant(NumBytes, MVT::i32));
 
-  SDOperand StackPtr = DAG.getRegister(ARM::R13, MVT::i32);
-
-  static const unsigned int num_regs = 4;
-  static const unsigned regs[num_regs] = {
-    ARM::R0, ARM::R1, ARM::R2, ARM::R3
-  };
-
-  std::vector<std::pair<unsigned, SDOperand> > RegsToPass;
+  //Build a sequence of stores
   std::vector<SDOperand> MemOpChains;
-
-  for (unsigned i = 0; i != NumOps; ++i) {
-    SDOperand Arg = Op.getOperand(5+2*i);
-    assert(Arg.getValueType() == MVT::i32);
-    if (i < num_regs)
-      RegsToPass.push_back(std::make_pair(regs[i], Arg));
-    else {
-      unsigned ArgOffset = (i - num_regs) * 4;
-      SDOperand PtrOff = DAG.getConstant(ArgOffset, StackPtr.getValueType());
-      PtrOff = DAG.getNode(ISD::ADD, MVT::i32, StackPtr, PtrOff);
-      MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
-                                          Arg, PtrOff, DAG.getSrcValue(NULL)));
-    }
+  for (unsigned i = Layout.lastRegArg() + 1; i < NumOps; ++i) {
+    SDOperand      Arg = Op.getOperand(5+2*i);
+    unsigned ArgOffset = Layout.getOffset(i);
+    SDOperand   PtrOff = DAG.getConstant(ArgOffset, StackPtr.getValueType());
+    PtrOff             = DAG.getNode(ISD::ADD, MVT::i32, StackPtr, PtrOff);
+    MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
+                                      Arg, PtrOff, DAG.getSrcValue(NULL)));
   }
   if (!MemOpChains.empty())
     Chain = DAG.getNode(ISD::TokenFactor, MVT::Other,
                         &MemOpChains[0], MemOpChains.size());
 
-  // Build a sequence of copy-to-reg nodes chained together with token chain
-  // and flag operands which copy the outgoing args into the appropriate regs.
-  SDOperand InFlag;
-  for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
-    Chain = DAG.getCopyToReg(Chain, RegsToPass[i].first, RegsToPass[i].second,
-                             InFlag);
-    InFlag = Chain.getValue(1);
-  }
-
-  std::vector<MVT::ValueType> NodeTys;
-  NodeTys.push_back(MVT::Other);   // Returns a chain
-  NodeTys.push_back(MVT::Flag);    // Returns a flag for retval copy to use.
-
   // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every
   // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol
   // node so that legalize doesn't hack it.
@@ -204,11 +261,25 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
   Ops.push_back(Chain);
   Ops.push_back(Callee);
 
-  // Add argument registers to the end of the list so that they are known live
-  // into the call.
-  for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i)
-    Ops.push_back(DAG.getRegister(RegsToPass[i].first,
-                                  RegsToPass[i].second.getValueType()));
+  // Build a sequence of copy-to-reg nodes chained together with token chain
+  // and flag operands which copy the outgoing args into the appropriate regs.
+  SDOperand InFlag;
+  for (unsigned i = 0, e = Layout.lastRegArg(); i <= e; ++i) {
+    SDOperand Arg = Op.getOperand(5+2*i);
+    unsigned  Reg = regs[Layout.getRegisterNum(i)];
+    assert(Layout.getType(i) == Arg.getValueType());
+    assert(Layout.getType(i) == MVT::i32);
+    Chain         = DAG.getCopyToReg(Chain, Reg, Arg, InFlag);
+    InFlag        = Chain.getValue(1);
+
+    // Add argument register to the end of the list so that it is known live
+    // into the call.
+    Ops.push_back(DAG.getRegister(Reg, Arg.getValueType()));
+  }
+
+  std::vector<MVT::ValueType> NodeTys;
+  NodeTys.push_back(MVT::Other);   // Returns a chain
+  NodeTys.push_back(MVT::Flag);    // Returns a flag for retval copy to use.
 
   unsigned CallOpc = ARMISD::CALL;
   if (InFlag.Val)
@@ -295,44 +366,6 @@ static SDOperand LowerRET(SDOperand Op, SelectionDAG &DAG) {
   return DAG.getNode(ARMISD::RET_FLAG, MVT::Other, Copy, Copy.getValue(1));
 }
 
-static SDOperand LowerFORMAL_ARGUMENT(SDOperand Op, SelectionDAG &DAG,
-                                     unsigned *vRegs,
-                                     unsigned ArgNo) {
-  MachineFunction &MF = DAG.getMachineFunction();
-  MVT::ValueType ObjectVT = Op.getValue(ArgNo).getValueType();
-  assert (ObjectVT == MVT::i32);
-  SDOperand Root = Op.getOperand(0);
-  SSARegMap *RegMap = MF.getSSARegMap();
-
-  unsigned num_regs = 4;
-  static const unsigned REGS[] = {
-    ARM::R0, ARM::R1, ARM::R2, ARM::R3
-  };
-
-  if(ArgNo < num_regs) {
-    unsigned VReg = RegMap->createVirtualRegister(&ARM::IntRegsRegClass);
-    MF.addLiveIn(REGS[ArgNo], VReg);
-    vRegs[ArgNo] = VReg;
-    return DAG.getCopyFromReg(Root, VReg, MVT::i32);
-  } else {
-    // If the argument is actually used, emit a load from the right stack
-      // slot.
-    if (!Op.Val->hasNUsesOfValue(0, ArgNo)) {
-      unsigned ArgOffset = (ArgNo - num_regs) * 4;
-
-      MachineFrameInfo *MFI = MF.getFrameInfo();
-      unsigned ObjSize = MVT::getSizeInBits(ObjectVT)/8;
-      int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
-      SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32);
-      return DAG.getLoad(ObjectVT, Root, FIN,
-                        DAG.getSrcValue(NULL));
-    } else {
-      // Don't emit a dead load.
-      return DAG.getNode(ISD::UNDEF, ObjectVT);
-    }
-  }
-}
-
 static SDOperand LowerConstantPool(SDOperand Op, SelectionDAG &DAG) {
   MVT::ValueType PtrVT = Op.getValueType();
   ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op);
@@ -363,45 +396,75 @@ static SDOperand LowerVASTART(SDOperand Op, SelectionDAG &DAG,
 
 static SDOperand LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG,
                                       int &VarArgsFrameIndex) {
-  std::vector<SDOperand> ArgValues;
-  SDOperand Root = Op.getOperand(0);
-  unsigned VRegs[4];
+  MachineFunction   &MF = DAG.getMachineFunction();
+  MachineFrameInfo *MFI = MF.getFrameInfo();
+  SSARegMap     *RegMap = MF.getSSARegMap();
+  unsigned      NumArgs = Op.Val->getNumValues()-1;
+  SDOperand        Root = Op.getOperand(0);
+  bool         isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
+  static const unsigned REGS[] = {
+    ARM::R0, ARM::R1, ARM::R2, ARM::R3
+  };
 
-  unsigned NumArgs = Op.Val->getNumValues()-1;
-  for (unsigned ArgNo = 0; ArgNo < NumArgs; ++ArgNo) {
-    SDOperand ArgVal = LowerFORMAL_ARGUMENT(Op, DAG, VRegs, ArgNo);
+  std::vector<MVT::ValueType> Types(Op.Val->value_begin(), Op.Val->value_end() - 1);
+  ArgumentLayout Layout(Types);
 
-    ArgValues.push_back(ArgVal);
+  std::vector<SDOperand> ArgValues;
+  for (unsigned ArgNo = 0; ArgNo < NumArgs; ++ArgNo) {
+    MVT::ValueType VT = Types[ArgNo];
+
+    SDOperand Value;
+    if (Layout.isRegister(ArgNo)) {
+      assert(VT == MVT::i32 || VT == MVT::f32 || VT == MVT::f64);
+      unsigned  RegNum = Layout.getRegisterNum(ArgNo);
+      unsigned    Reg1 = REGS[RegNum];
+      unsigned   VReg1 = RegMap->createVirtualRegister(&ARM::IntRegsRegClass);
+      SDOperand Value1 = DAG.getCopyFromReg(Root, VReg1, MVT::i32);
+      MF.addLiveIn(Reg1, VReg1);
+      if (VT == MVT::f64) {
+        unsigned    Reg2 = REGS[RegNum + 1];
+        unsigned   VReg2 = RegMap->createVirtualRegister(&ARM::IntRegsRegClass);
+        SDOperand Value2 = DAG.getCopyFromReg(Root, VReg2, MVT::i32);
+        MF.addLiveIn(Reg2, VReg2);
+        Value            = DAG.getNode(ARMISD::FMDRR, MVT::f64, Value1, Value2);
+      } else {
+        Value = Value1;
+        if (VT == MVT::f32)
+          Value = DAG.getNode(ISD::BIT_CONVERT, VT, Value);
+      }
+    } else {
+      // If the argument is actually used, emit a load from the right stack
+      // slot.
+      if (!Op.Val->hasNUsesOfValue(0, ArgNo)) {
+        unsigned Offset = Layout.getOffset(ArgNo);
+        unsigned   Size = MVT::getSizeInBits(VT)/8;
+        int          FI = MFI->CreateFixedObject(Size, Offset);
+        SDOperand   FIN = DAG.getFrameIndex(FI, VT);
+        Value = DAG.getLoad(VT, Root, FIN, DAG.getSrcValue(NULL));
+      } else {
+        Value = DAG.getNode(ISD::UNDEF, VT);
+      }
+    }
+    ArgValues.push_back(Value);
   }
 
-  bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
+  unsigned NextRegNum = Layout.lastRegNum() + 1;
+
   if (isVarArg) {
-    MachineFunction &MF = DAG.getMachineFunction();
-    SSARegMap *RegMap = MF.getSSARegMap();
-    MachineFrameInfo *MFI = MF.getFrameInfo();
+    //If this function is vararg we must store the remaing
+    //registers so that they can be acessed with va_start
     VarArgsFrameIndex = MFI->CreateFixedObject(MVT::getSizeInBits(MVT::i32)/8,
-                                               -16 + NumArgs * 4);
+                                               -16 + NextRegNum * 4);
 
-
-    static const unsigned REGS[] = {
-      ARM::R0, ARM::R1, ARM::R2, ARM::R3
-    };
-    // If this function is vararg, store r0-r3 to their spots on the stack
-    // so that they may be loaded by deferencing the result of va_next.
     SmallVector<SDOperand, 4> MemOps;
-    for (unsigned ArgNo = 0; ArgNo < 4; ++ArgNo) {
-      int ArgOffset = - (4 - ArgNo) * 4;
+    for (unsigned RegNo = NextRegNum; RegNo < 4; ++RegNo) {
+      int RegOffset = - (4 - RegNo) * 4;
       int FI = MFI->CreateFixedObject(MVT::getSizeInBits(MVT::i32)/8,
-                                     ArgOffset);
+                                     RegOffset);
       SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32);
 
-      unsigned VReg;
-      if (ArgNo < NumArgs)
-       VReg = VRegs[ArgNo];
-      else
-       VReg = RegMap->createVirtualRegister(&ARM::IntRegsRegClass);
-      if (ArgNo >= NumArgs)
-       MF.addLiveIn(REGS[ArgNo], VReg);
+      unsigned VReg = RegMap->createVirtualRegister(&ARM::IntRegsRegClass);
+      MF.addLiveIn(REGS[RegNo], VReg);
 
       SDOperand Val = DAG.getCopyFromReg(Root, VReg, MVT::i32);
       SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Val.getValue(1),
index 55128de930d54912bb21710e9ddf0530126cb0f3..cf08487b3ceefb4077bcc747edbde267acb1dfd4 100644 (file)
@@ -80,6 +80,9 @@ def armfsitod      : SDNode<"ARMISD::FSITOD", SDTUnaryOp>;
 def SDTarmfmrrd    : SDTypeProfile<0, 3, [SDTCisInt<0>, SDTCisInt<1>, SDTCisFP<2>]>;
 def armfmrrd       : SDNode<"ARMISD::FMRRD", SDTarmfmrrd, [SDNPHasChain, SDNPOutFlag]>;
 
+def SDTarmfmdrr    : SDTypeProfile<1, 2, [SDTCisFP<0>, SDTCisInt<1>, SDTCisInt<2>]>;
+def armfmdrr       : SDNode<"ARMISD::FMDRR", SDTarmfmdrr, []>;
+
 def ADJCALLSTACKUP : InstARM<(ops i32imm:$amt),
                             "!ADJCALLSTACKUP $amt",
                             [(callseq_end imm:$amt)]>;
@@ -175,6 +178,9 @@ def FMRS    : InstARM<(ops IntRegs:$dst, FPRegs:$src),
 def FMRRD   : InstARM<(ops IntRegs:$i0, IntRegs:$i1, DFPRegs:$src),
                        "fmrrd $i0, $i1, $src", [(armfmrrd IntRegs:$i0, IntRegs:$i1, DFPRegs:$src)]>;
 
+def FMDRR   : InstARM<(ops DFPRegs:$dst, IntRegs:$i0, IntRegs:$i1),
+                       "fmdrr $dst, $i0, $i1", [(set DFPRegs:$dst, (armfmdrr IntRegs:$i0, IntRegs:$i1))]>;
+
 def FSITOS  : InstARM<(ops FPRegs:$dst, FPRegs:$src),
                        "fsitos $dst, $src", [(set FPRegs:$dst, (armfsitos FPRegs:$src))]>;
 
index 3cf45fcddb2bf03d96d3bd9aedb2cc62263d0ff3..313e83f2566812f49bd902f730b267056234f698 100644 (file)
@@ -1,9 +1,10 @@
 ; RUN: llvm-as < %s | llc -march=arm &&
-; RUN: llvm-as < %s | llc -march=arm | grep fmsr | wc -l | grep 2 &&
+; RUN: llvm-as < %s | llc -march=arm | grep fmsr  | wc -l | grep 2 &&
 ; RUN: llvm-as < %s | llc -march=arm | grep fsitos &&
 ; RUN: llvm-as < %s | llc -march=arm | grep fmrs &&
 ; RUN: llvm-as < %s | llc -march=arm | grep fsitod &&
-; RUN: llvm-as < %s | llc -march=arm | grep fmrrd &&
+; RUN: llvm-as < %s | llc -march=arm | grep fmrrd | wc -l | grep 2 &&
+; RUN: llvm-as < %s | llc -march=arm | grep fmdrr | wc -l | grep 1 &&
 ; RUN: llvm-as < %s | llc -march=arm | grep flds &&
 ; RUN: llvm-as < %s | llc -march=arm | grep ".word.*1065353216"
 
@@ -23,3 +24,7 @@ float %h() {
 entry:
         ret float 1.000000e+00
 }
+
+double %f2(double %a) {
+        ret double %a
+}