All sorts of stuff.

Getting in on the custom lowering thing, yay
evilness with fp setcc, yuck
trivial int select, hmmm
in memory args for functions, yay
DIV and REM, always handy.  They should be custom lowered though.

Lots more stuff compiles now (go go single source!).  Of course, none of it
probably works, but that is what the nightly tester can find out :)


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@24533 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/Alpha/AlphaISelDAGToDAG.cpp b/lib/Target/Alpha/AlphaISelDAGToDAG.cpp
index b920bc4..50ff1b0 100644
--- a/lib/Target/Alpha/AlphaISelDAGToDAG.cpp
+++ b/lib/Target/Alpha/AlphaISelDAGToDAG.cpp
@@ -16,6 +16,7 @@
 #include "AlphaTargetMachine.h"
 #include "AlphaISelLowering.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/SSARegMap.h"
 #include "llvm/CodeGen/SelectionDAG.h"
@@ -278,6 +279,7 @@
       CurDAG->SelectNodeTo(N, Alpha::LDAr, MVT::i64, CPI, Tmp);
       return SDOperand(N, 0);
     }
+    break;
   }
   case ISD::ConstantFP:
     if (ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N)) {
@@ -296,7 +298,76 @@
       } else {
         abort();
       }
+      break;
     }
+  case ISD::SDIV:
+  case ISD::UDIV:
+  case ISD::UREM:
+  case ISD::SREM:
+    if (MVT::isInteger(N->getValueType(0))) {
+      const char* opstr = 0;
+      switch(N->getOpcode()) {
+      case ISD::UREM: opstr = "__remqu"; break;
+      case ISD::SREM: opstr = "__remq";  break;
+      case ISD::UDIV: opstr = "__divqu"; break;
+      case ISD::SDIV: opstr = "__divq";  break;
+      }
+      SDOperand Tmp1 = Select(N->getOperand(0)),
+        Tmp2 = Select(N->getOperand(1)),
+        Addr = CurDAG->getExternalSymbol(opstr, AlphaLowering.getPointerTy());
+      SDOperand Tmp3 = Select(Addr);
+      SDOperand Chain = CurDAG->getCopyToReg(CurDAG->getRoot(), Alpha::R24, 
+                                             Tmp1, SDOperand());
+      Chain = CurDAG->getCopyToReg(CurDAG->getRoot(), Alpha::R25, 
+                                   Tmp2, Chain.getValue(1));
+      Chain = CurDAG->getCopyToReg(CurDAG->getRoot(), Alpha::R27, 
+                                   Tmp3, Chain.getValue(1));
+      Chain = CurDAG->getTargetNode(Alpha::JSRs, MVT::i64, MVT::Flag,
+                                    CurDAG->getRegister(Alpha::R27, MVT::i64),
+                                    getI64Imm(0));
+      return CurDAG->getCopyFromReg(Chain.getValue(1), Alpha::R27, MVT::i64, 
+                                    Chain.getValue(1));
+    }
+    break;
+
+  case ISD::SETCC:
+    if (MVT::isFloatingPoint(N->getOperand(0).Val->getValueType(0))) {
+      unsigned Opc = Alpha::WTF;
+      ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
+      bool rev = false;
+      switch(CC) {
+      default: N->dump(); assert(0 && "Unknown FP comparison!");
+      case ISD::SETEQ: Opc = Alpha::CMPTEQ; break;
+      case ISD::SETLT: Opc = Alpha::CMPTLT; break;
+      case ISD::SETLE: Opc = Alpha::CMPTLE; break;
+      case ISD::SETGT: Opc = Alpha::CMPTLT; rev = true; break;
+      case ISD::SETGE: Opc = Alpha::CMPTLE; rev = true; break;
+        //case ISD::SETNE: Opc = Alpha::CMPTEQ; inv = true; break;
+      };
+      SDOperand tmp1 = Select(N->getOperand(0)),
+        tmp2 = Select(N->getOperand(1));
+      SDOperand cmp = CurDAG->getTargetNode(Opc, MVT::f64, 
+                                            rev?tmp2:tmp1,
+                                            rev?tmp1:tmp2);
+      SDOperand LD;
+      if (AlphaLowering.hasITOF()) {
+        LD = CurDAG->getNode(AlphaISD::FTOIT_, MVT::i64, cmp);
+      } else {
+        int FrameIdx =
+          CurDAG->getMachineFunction().getFrameInfo()->CreateStackObject(8, 8);
+        SDOperand FI = CurDAG->getFrameIndex(FrameIdx, MVT::i64);
+        SDOperand ST = CurDAG->getTargetNode(Alpha::STT, MVT::Other, 
+                                             cmp, FI, CurDAG->getRegister(Alpha::R31, MVT::i64));
+        LD = CurDAG->getTargetNode(Alpha::LDQ, MVT::i64, FI, 
+                                   CurDAG->getRegister(Alpha::R31, MVT::i64),
+                                   ST);
+      }
+      SDOperand FP = CurDAG->getTargetNode(Alpha::CMPULT, MVT::i64, 
+                                           CurDAG->getRegister(Alpha::R31, MVT::i64),
+                                           LD);
+      return FP;
+    }
+    break;
   }
   
   return SelectCode(Op);
@@ -328,13 +399,26 @@
    for (int i = 0; i < std::min(6, count); ++i) {
      if (MVT::isInteger(TypeOperands[i])) {
        Chain = CurDAG->getCopyToReg(Chain, args_int[i], CallOperands[i]);
-     } else if (TypeOperands[i] == MVT::f64 || TypeOperands[i] == MVT::f64) {
+     } else if (TypeOperands[i] == MVT::f32 || TypeOperands[i] == MVT::f64) {
        Chain = CurDAG->getCopyToReg(Chain, args_float[i], CallOperands[i]);
      } else
        assert(0 && "Unknown operand"); 
    }
-
-   assert(CallOperands.size() <= 6 && "Too big a call");
+   for (int i = 6; i < count; ++i) {
+     unsigned Opc = Alpha::WTF;
+     if (MVT::isInteger(TypeOperands[i])) {
+       Opc = Alpha::STQ;
+     } else if (TypeOperands[i] == MVT::f32) {
+       Opc = Alpha::STS;
+     } else if (TypeOperands[i] == MVT::f64) {
+       Opc = Alpha::STT;
+     } else
+       assert(0 && "Unknown operand"); 
+     Chain = CurDAG->getTargetNode(Opc, MVT::Other, CallOperands[i], 
+                                   getI64Imm((i - 6) * 8), 
+                                   CurDAG->getRegister(Alpha::R30, MVT::i64),
+                                   Chain);
+   }
 
    Chain = CurDAG->getCopyToReg(Chain, Alpha::R27, Addr);
    // Finally, once everything is in registers to pass to the call, emit the
diff --git a/lib/Target/Alpha/AlphaISelLowering.cpp b/lib/Target/Alpha/AlphaISelLowering.cpp
index 021c92d..92ba16e 100644
--- a/lib/Target/Alpha/AlphaISelLowering.cpp
+++ b/lib/Target/Alpha/AlphaISelLowering.cpp
@@ -72,6 +72,7 @@
   setOperationAction(ISD::FREM, MVT::f64, Expand);
   
   setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand);
+  setOperationAction(ISD::SINT_TO_FP, MVT::i64, Custom);
   
   if (!TM.getSubtarget<AlphaSubtarget>().hasCT()) {
     setOperationAction(ISD::CTPOP    , MVT::i64  , Expand);
@@ -101,10 +102,12 @@
   // We don't have line number support yet.
   setOperationAction(ISD::LOCATION, MVT::Other, Expand);
   
-  computeRegisterProperties();
-  
   addLegalFPImmediate(+0.0); //F31
   addLegalFPImmediate(-0.0); //-F31
+
+  computeRegisterProperties();
+
+  useITOF = TM.getSubtarget<AlphaSubtarget>().hasF2I();
 }
 
 
@@ -385,3 +388,31 @@
 }
 
 
+/// LowerOperation - Provide custom lowering hooks for some operations.
+///
+SDOperand AlphaTargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
+  switch (Op.getOpcode()) {
+  default: assert(0 && "Wasn't expecting to be able to lower this!"); 
+  case ISD::SINT_TO_FP: {
+    assert(MVT::i64 == Op.getOperand(0).getValueType() && 
+           "Unhandled SINT_TO_FP type in custom expander!");
+    SDOperand LD;
+    bool isDouble = MVT::f64 == Op.getValueType();
+    if (useITOF) {
+      LD = DAG.getNode(AlphaISD::ITOFT_, MVT::f64, Op.getOperand(0));
+    } else {
+      int FrameIdx =
+        DAG.getMachineFunction().getFrameInfo()->CreateStackObject(8, 8);
+      SDOperand FI = DAG.getFrameIndex(FrameIdx, MVT::i64);
+      SDOperand ST = DAG.getNode(ISD::STORE, MVT::Other, DAG.getEntryNode(),
+                                 Op.getOperand(0), FI, DAG.getSrcValue(0));
+      LD = DAG.getLoad(MVT::f64, ST, FI, DAG.getSrcValue(0));
+      }
+    SDOperand FP = DAG.getNode(isDouble?AlphaISD::CVTQT_:AlphaISD::CVTQS_,
+                               isDouble?MVT::f64:MVT::f32, LD);
+    return FP;
+  }
+  }
+  return SDOperand();
+}
+
diff --git a/lib/Target/Alpha/AlphaISelLowering.h b/lib/Target/Alpha/AlphaISelLowering.h
index 2bcd526..378ec0f 100644
--- a/lib/Target/Alpha/AlphaISelLowering.h
+++ b/lib/Target/Alpha/AlphaISelLowering.h
@@ -25,6 +25,8 @@
     enum NodeType {
       // Start the numbering where the builting ops and target ops leave off.
       FIRST_NUMBER = ISD::BUILTIN_OP_END+Alpha::INSTRUCTION_LIST_END,
+      //These corrospond to the identical Instruction
+      ITOFT_, FTOIT_, CVTQT_, CVTQS_,
     };
   }
 
@@ -33,9 +35,14 @@
     int VarArgsBase;    // What is the base FrameIndex
     unsigned GP; //GOT vreg
     unsigned RA; //Return Address
+    bool useITOF;
   public:
     AlphaTargetLowering(TargetMachine &TM);
-
+    
+    /// LowerOperation - Provide custom lowering hooks for some operations.
+    ///
+    virtual SDOperand LowerOperation(SDOperand Op, SelectionDAG &DAG);
+    
     /// LowerArguments - This hook must be implemented to indicate how we should
     /// lower the arguments for the specified function, into the specified DAG.
     virtual std::vector<SDOperand>
@@ -61,6 +68,7 @@
     void restoreRA(MachineBasicBlock* BB);
     unsigned getVRegGP() { return GP; }
     unsigned getVRegRA() { return RA; }
+    bool hasITOF() { return useITOF; }
   };
 }
 
diff --git a/lib/Target/Alpha/AlphaISelPattern.cpp b/lib/Target/Alpha/AlphaISelPattern.cpp
index 6c2e3a6..05ed61f 100644
--- a/lib/Target/Alpha/AlphaISelPattern.cpp
+++ b/lib/Target/Alpha/AlphaISelPattern.cpp
@@ -1559,17 +1559,17 @@
     }
     return Result;
 
-  case ISD::SINT_TO_FP:
-    {
-      assert (N.getOperand(0).getValueType() == MVT::i64
-              && "only quads can be loaded from");
-      Tmp1 = SelectExpr(N.getOperand(0));  // Get the operand register
-      Tmp2 = MakeReg(MVT::f64);
-      MoveInt2FP(Tmp1, Tmp2, true);
-      Opc = DestType == MVT::f64 ? Alpha::CVTQT : Alpha::CVTQS;
-      BuildMI(BB, Opc, 1, Result).addReg(Tmp2);
-      return Result;
-    }
+  case AlphaISD::CVTQT_:
+    BuildMI(BB, Alpha::CVTQT, 1, Result).addReg(SelectExpr(N.getOperand(0)));
+    return Result;
+
+  case AlphaISD::CVTQS_:
+    BuildMI(BB, Alpha::CVTQS, 1, Result).addReg(SelectExpr(N.getOperand(0)));
+    return Result;
+
+  case AlphaISD::ITOFT_:
+    BuildMI(BB, Alpha::ITOFT, 1, Result).addReg(SelectExpr(N.getOperand(0)));
+    return Result;
 
   case ISD::AssertSext:
   case ISD::AssertZext:
diff --git a/lib/Target/Alpha/AlphaInstrFormats.td b/lib/Target/Alpha/AlphaInstrFormats.td
index 1f44607..1d4c11d 100644
--- a/lib/Target/Alpha/AlphaInstrFormats.td
+++ b/lib/Target/Alpha/AlphaInstrFormats.td
@@ -40,6 +40,16 @@
 }
 
 //3.3.1
+class MFormAlt<bits<6> opcode, string asmstr> 
+        : InstAlphaAlt<opcode, asmstr> {
+  bits<5> Ra;
+  bits<16> disp;
+  bits<5> Rb;
+
+  let Inst{25-21} = Ra;
+  let Inst{20-16} = Rb;
+  let Inst{15-0} = disp;
+}
 class MForm<bits<6> opcode, string asmstr> 
         : InstAlpha<opcode, (ops GPRC:$RA, s16imm:$DISP, GPRC:$RB), asmstr> {
   bits<5> Ra;
diff --git a/lib/Target/Alpha/AlphaInstrInfo.td b/lib/Target/Alpha/AlphaInstrInfo.td
index aea2861..6bd9d78 100644
--- a/lib/Target/Alpha/AlphaInstrInfo.td
+++ b/lib/Target/Alpha/AlphaInstrInfo.td
@@ -13,6 +13,20 @@
 include "AlphaInstrFormats.td"
 
 //********************
+//Custom DAG Nodes
+//********************
+
+def SDTFPUnaryOpUnC  : SDTypeProfile<1, 1, [
+  SDTCisFP<1>, SDTCisFP<0>
+]>;
+
+def Alpha_itoft : SDNode<"AlphaISD::ITOFT_", SDTIntToFPOp, []>;
+def Alpha_ftoit : SDNode<"AlphaISD::FTOIT_", SDTFPToIntOp, []>;
+def Alpha_cvtqt : SDNode<"AlphaISD::CVTQT_", SDTFPUnaryOpUnC, []>;
+def Alpha_cvtqs : SDNode<"AlphaISD::CVTQS_", SDTFPUnaryOpUnC, []>;
+
+
+//********************
 //Paterns for matching
 //********************
 
@@ -143,6 +157,10 @@
 def CMOVNE   : OForm4<  0x11, 0x26, "cmovne $RCOND,$RSRC,$RDEST">; //CMOVE if RCOND != zero
 def CMOVNEi  : OForm4L< 0x11, 0x26, "cmovne $RCOND,$L,$RDEST">; //CMOVE if RCOND != zero
 
+//FIXME: fold setcc with select
+def : Pat<(select GPRC:$which, GPRC:$src1, GPRC:$src2),
+      (CMOVEQ GPRC:$src1, GPRC:$src2, GPRC:$which)>;
+
 //conditional moves, fp
 let OperandList = (ops F8RC:$RDEST, F8RC:$RSRC2, F8RC:$RSRC, F8RC:$RCOND),
     isTwoAddress = 1 in {
@@ -409,12 +427,16 @@
 def LDWU : MForm<0x0C, "ldwu $RA,$DISP($RB)">; //Load zero-extended word
 
 //Stores, float
-def STS : MForm<0x26, "sts $RA,$DISP($RB)">; //Store S_floating
-def STT : MForm<0x27, "stt $RA,$DISP($RB)">; //Store T_floating
+let OperandList = (ops F4RC:$RA, s16imm:$DISP, GPRC:$RB) in
+def STS : MFormAlt<0x26, "sts $RA,$DISP($RB)">; //Store S_floating
+let OperandList = (ops F8RC:$RA, s16imm:$DISP, GPRC:$RB) in
+def STT : MFormAlt<0x27, "stt $RA,$DISP($RB)">; //Store T_floating
 
 //Loads, float
-def LDS : MForm<0x22, "lds $RA,$DISP($RB)">; //Load S_floating
-def LDT : MForm<0x23, "ldt $RA,$DISP($RB)">; //Load T_floating
+let OperandList = (ops F4RC:$RA, s16imm:$DISP, GPRC:$RB) in
+def LDS : MFormAlt<0x22, "lds $RA,$DISP($RB)">; //Load S_floating
+let OperandList = (ops F8RC:$RA, s16imm:$DISP, GPRC:$RB) in
+def LDT : MFormAlt<0x23, "ldt $RA,$DISP($RB)">; //Load T_floating
 
 //Load address
 def LDA : MForm<0x08,  "lda $RA,$DISP($RB)">;  //Load address
@@ -428,8 +450,10 @@
 def LDWUr : MForm<0x0C, "ldwu $RA,$DISP($RB)\t\t!gprellow">; //Load zero-extended word
 
 //Loads, float, Rellocated Low form
-def LDSr : MForm<0x22, "lds $RA,$DISP($RB)\t\t!gprellow">; //Load S_floating
-def LDTr : MForm<0x23, "ldt $RA,$DISP($RB)\t\t!gprellow">; //Load T_floating
+let OperandList = (ops F4RC:$RA, s16imm:$DISP, GPRC:$RB) in
+def LDSr : MFormAlt<0x22, "lds $RA,$DISP($RB)\t\t!gprellow">; //Load S_floating
+let OperandList = (ops F8RC:$RA, s16imm:$DISP, GPRC:$RB) in
+def LDTr : MFormAlt<0x23, "ldt $RA,$DISP($RB)\t\t!gprellow">; //Load T_floating
 
 //Load address, rellocated low and high form
 def LDAr : MForm<0x08,  "lda $RA,$DISP($RB)\t\t!gprellow">;  //Load address
@@ -450,8 +474,10 @@
 def STQr : MForm<0x2D, "stq $RA,$DISP($RB)\t\t!gprellow">; //Store quadword
 
 //Stores, float
-def STSr : MForm<0x26, "sts $RA,$DISP($RB)\t\t!gprellow">; //Store S_floating
-def STTr : MForm<0x27, "stt $RA,$DISP($RB)\t\t!gprellow">; //Store T_floating
+let OperandList = (ops F4RC:$RA, s16imm:$DISP, GPRC:$RB) in
+def STSr : MFormAlt<0x26, "sts $RA,$DISP($RB)\t\t!gprellow">; //Store S_floating
+let OperandList = (ops F8RC:$RA, s16imm:$DISP, GPRC:$RB) in
+def STTr : MFormAlt<0x27, "stt $RA,$DISP($RB)\t\t!gprellow">; //Store T_floating
 
 
 //Branches, int
@@ -533,17 +559,21 @@
 let OperandList = (ops GPRC:$RC, F4RC:$RA), Fb = 31 in 
 def FTOIS : FPForm<0x1C, 0x078, "ftois $RA,$RC",[]>; //Floating to integer move, S_floating
 let OperandList = (ops GPRC:$RC, F8RC:$RA), Fb = 31 in 
-def FTOIT : FPForm<0x1C, 0x070, "ftoit $RA,$RC",[]>; //Floating to integer move, T_floating
+def FTOIT : FPForm<0x1C, 0x070, "ftoit $RA,$RC",
+        [(set GPRC:$RC, (Alpha_ftoit F8RC:$RA))]>; //Floating to integer move
 let OperandList = (ops F4RC:$RC, GPRC:$RA), Fb = 31 in 
 def ITOFS : FPForm<0x14, 0x004, "itofs $RA,$RC",[]>; //Integer to floating move, S_floating
 let OperandList = (ops F8RC:$RC, GPRC:$RA), Fb = 31 in 
-def ITOFT : FPForm<0x14, 0x024, "itoft $RA,$RC",[]>; //Integer to floating move, T_floating
+def ITOFT : FPForm<0x14, 0x024, "itoft $RA,$RC",
+        [(set F8RC:$RC, (Alpha_itoft GPRC:$RA))]>; //Integer to floating move
 
 
 let OperandList = (ops F4RC:$RC, F8RC:$RB), Fa = 31 in 
-def CVTQS : FPForm<0x16, 0x7BC, "cvtqs/sui $RB,$RC",[]>; //Convert quadword to S_floating
+def CVTQS : FPForm<0x16, 0x7BC, "cvtqs/sui $RB,$RC",
+        [(set F4RC:$RC, (Alpha_cvtqs F8RC:$RB))]>;
 let OperandList = (ops F8RC:$RC, F8RC:$RB), Fa = 31 in 
-def CVTQT : FPForm<0x16, 0x7BE, "cvtqt/sui $RB,$RC",[]>; //Convert quadword to T_floating
+def CVTQT : FPForm<0x16, 0x7BE, "cvtqt/sui $RB,$RC",
+        [(set F8RC:$RC, (Alpha_cvtqt F8RC:$RB))]>;
 let OperandList = (ops F8RC:$RC, F8RC:$RB), Fa = 31 in 
 def CVTTQ : FPForm<0x16, 0x52F, "cvttq/svc $RB,$RC",[]>; //Convert T_floating to quadword
 let OperandList = (ops F8RC:$RC, F4RC:$RB), Fa = 31 in 
@@ -648,3 +678,11 @@
 def : Pat<(select GPRC:$which, GPRC:$src1, GPRC:$src2),
           (CMOVEQ GPRC:$src1, GPRC:$src2, GPRC:$which)>; //may be CMOVNE
 
+def : Pat<(fabs F8RC:$RB),
+          (CPYST F31, F8RC:$RB)>;
+def : Pat<(fabs F4RC:$RB),
+          (CPYSS F31, F4RC:$RB)>;
+def : Pat<(fneg F8RC:$RB),
+          (CPYSNT F8RC:$RB, F8RC:$RB)>;
+def : Pat<(fneg F4RC:$RB),
+          (CPYSNS F4RC:$RB, F4RC:$RB)>;
diff --git a/lib/Target/Alpha/AlphaRegisterInfo.td b/lib/Target/Alpha/AlphaRegisterInfo.td
index b990865..b088436 100644
--- a/lib/Target/Alpha/AlphaRegisterInfo.td
+++ b/lib/Target/Alpha/AlphaRegisterInfo.td
@@ -78,7 +78,6 @@
   // $28 is undefined after any and all calls
 
 /// Register classes
-// Don't allocate 15, 28, 30, 31
 def GPRC : RegisterClass<"Alpha", i64, 64,
      // Volatile
      [R0, R1, R2, R3, R4, R5, R6, R7, R8, R16, R17, R18, R19, R20, R21, R22,
@@ -89,7 +88,8 @@
      R29, //global offset table address
      // Non-volatile
      R9, R10, R11, R12, R13, R14,
-     R31 ]> //zero
+// Don't allocate 15, 30, 31
+     R15, R30, R31 ]> //zero
 {
   let MethodProtos = [{
     iterator allocation_order_end(MachineFunction &MF) const;
@@ -97,7 +97,7 @@
   let MethodBodies = [{
     GPRCClass::iterator
     GPRCClass::allocation_order_end(MachineFunction &MF) const {
-        return end()-1;
+        return end()-3;
     }
   }];
 }