Teach sparc to fold loads/stores into copies.
[oota-llvm.git] / lib / Target / SparcV8 / SparcV8ISelDAGToDAG.cpp
index 62062185201d0eefc1e6633d12b9c70a13bfa206..c2741059b03a01ced677a102ed51f37b9e37fb6b 100644 (file)
@@ -33,30 +33,76 @@ using namespace llvm;
 namespace V8ISD {
   enum {
     FIRST_NUMBER = ISD::BUILTIN_OP_END+V8::INSTRUCTION_LIST_END,
-    CMPICC,   // Compare two GPR operands, set icc.
-    CMPFCC,   // Compare two FP operands, set fcc.
-    BRICC,    // Branch to dest on icc condition
-    BRFCC,    // Branch to dest on fcc condition
+    CMPICC,      // Compare two GPR operands, set icc.
+    CMPFCC,      // Compare two FP operands, set fcc.
+    BRICC,       // Branch to dest on icc condition
+    BRFCC,       // Branch to dest on fcc condition
+    SELECT_ICC,  // Select between two values using the current ICC flags.
+    SELECT_FCC,  // Select between two values using the current FCC flags.
     
-    Hi, Lo,   // Hi/Lo operations, typically on a global address.
+    Hi, Lo,      // Hi/Lo operations, typically on a global address.
     
-    FTOI,     // FP to Int within a FP register.
-    ITOF,     // Int to FP within a FP register.
-    
-    SELECT_ICC, // Select between two values using the current ICC flags.
-    SELECT_FCC, // Select between two values using the current FCC flags.
-    
-    CALL,       // A V8 call instruction.
-    RET_FLAG,   // Return with a flag operand.
+    FTOI,        // FP to Int within a FP register.
+    ITOF,        // Int to FP within a FP register.
+
+    CALL,        // A V8 call instruction.
+    RET_FLAG,    // Return with a flag operand.
   };
 }
 
+/// IntCondCCodeToICC - Convert a DAG integer condition code to a SPARC ICC
+/// condition.
+static V8CC::CondCodes IntCondCCodeToICC(ISD::CondCode CC) {
+  switch (CC) {
+  default: assert(0 && "Unknown integer condition code!");
+  case ISD::SETEQ:  return V8CC::ICC_E;
+  case ISD::SETNE:  return V8CC::ICC_NE;
+  case ISD::SETLT:  return V8CC::ICC_L;
+  case ISD::SETGT:  return V8CC::ICC_G;
+  case ISD::SETLE:  return V8CC::ICC_LE;
+  case ISD::SETGE:  return V8CC::ICC_GE;
+  case ISD::SETULT: return V8CC::ICC_CS;
+  case ISD::SETULE: return V8CC::ICC_LEU;
+  case ISD::SETUGT: return V8CC::ICC_GU;
+  case ISD::SETUGE: return V8CC::ICC_CC;
+  }
+}
+
+/// FPCondCCodeToFCC - Convert a DAG floatingp oint condition code to a SPARC
+/// FCC condition.
+static V8CC::CondCodes FPCondCCodeToFCC(ISD::CondCode CC) {
+  switch (CC) {
+  default: assert(0 && "Unknown fp condition code!");
+  case ISD::SETEQ:  return V8CC::FCC_E;
+  case ISD::SETNE:  return V8CC::FCC_NE;
+  case ISD::SETLT:  return V8CC::FCC_L;
+  case ISD::SETGT:  return V8CC::FCC_G;
+  case ISD::SETLE:  return V8CC::FCC_LE;
+  case ISD::SETGE:  return V8CC::FCC_GE;
+  case ISD::SETULT: return V8CC::FCC_UL;
+  case ISD::SETULE: return V8CC::FCC_ULE;
+  case ISD::SETUGT: return V8CC::FCC_UG;
+  case ISD::SETUGE: return V8CC::FCC_UGE;
+  case ISD::SETUO:  return V8CC::FCC_U;
+  case ISD::SETO:   return V8CC::FCC_O;
+  case ISD::SETONE: return V8CC::FCC_LG;
+  case ISD::SETUEQ: return V8CC::FCC_UE;
+  }
+}
+
 namespace {
   class SparcV8TargetLowering : public TargetLowering {
     int VarArgsFrameOffset;   // Frame offset to start of varargs area.
   public:
     SparcV8TargetLowering(TargetMachine &TM);
     virtual SDOperand LowerOperation(SDOperand Op, SelectionDAG &DAG);
+    
+    /// isMaskedValueZeroForTargetNode - Return true if 'Op & Mask' is known to
+    /// be zero. Op is expected to be a target specific node. Used by DAG
+    /// combiner.
+    virtual bool isMaskedValueZeroForTargetNode(const SDOperand &Op,
+                                                uint64_t Mask) const;
+    
     virtual std::vector<SDOperand>
       LowerArguments(Function &F, SelectionDAG &DAG);
     virtual std::pair<SDOperand, SDOperand>
@@ -166,10 +212,17 @@ SparcV8TargetLowering::SparcV8TargetLowering(TargetMachine &TM)
   setOperationAction(ISD::VAEND             , MVT::Other, Expand);
   setOperationAction(ISD::STACKSAVE         , MVT::Other, Expand); 
   setOperationAction(ISD::STACKRESTORE      , MVT::Other, Expand);
-  setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand);
+  setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32  , Expand);
 
+  setOperationAction(ISD::ConstantFP, MVT::f64, Expand);
+  setOperationAction(ISD::ConstantFP, MVT::f32, Expand);
+  
   setStackPointerRegisterToSaveRestore(V8::O6);
 
+  if (TM.getSubtarget<SparcV8Subtarget>().isV9()) {
+    setOperationAction(ISD::CTPOP, MVT::i32, Legal);
+  }
+  
   computeRegisterProperties();
 }
 
@@ -180,17 +233,34 @@ const char *SparcV8TargetLowering::getTargetNodeName(unsigned Opcode) const {
   case V8ISD::CMPFCC:     return "V8ISD::CMPFCC";
   case V8ISD::BRICC:      return "V8ISD::BRICC";
   case V8ISD::BRFCC:      return "V8ISD::BRFCC";
+  case V8ISD::SELECT_ICC: return "V8ISD::SELECT_ICC";
+  case V8ISD::SELECT_FCC: return "V8ISD::SELECT_FCC";
   case V8ISD::Hi:         return "V8ISD::Hi";
   case V8ISD::Lo:         return "V8ISD::Lo";
   case V8ISD::FTOI:       return "V8ISD::FTOI";
   case V8ISD::ITOF:       return "V8ISD::ITOF";
-  case V8ISD::SELECT_ICC: return "V8ISD::SELECT_ICC";
-  case V8ISD::SELECT_FCC: return "V8ISD::SELECT_FCC";
   case V8ISD::CALL:       return "V8ISD::CALL";
   case V8ISD::RET_FLAG:   return "V8ISD::RET_FLAG";
   }
 }
 
+/// isMaskedValueZeroForTargetNode - Return true if 'Op & Mask' is known to
+/// be zero. Op is expected to be a target specific node. Used by DAG
+/// combiner.
+bool SparcV8TargetLowering::
+isMaskedValueZeroForTargetNode(const SDOperand &Op, uint64_t Mask) const {
+  switch (Op.getOpcode()) {
+  default: return false; 
+  case V8ISD::SELECT_ICC:
+  case V8ISD::SELECT_FCC:
+    assert(MVT::isInteger(Op.getValueType()) && "Not an integer select!");
+    // These operations are masked zero if both the left and the right are zero.
+    return MaskedValueIsZero(Op.getOperand(0), Mask) &&
+           MaskedValueIsZero(Op.getOperand(1), Mask);
+  }
+}
+
+
 /// LowerArguments - V8 uses a very simple ABI, where all values are passed in
 /// either one or two GPRs, including FP values.  TODO: we should pass FP values
 /// in FP registers for fastcc functions.
@@ -284,7 +354,8 @@ SparcV8TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
         if (CurArgReg < ArgRegEnd) ++CurArgReg;
         if (CurArgReg < ArgRegEnd) ++CurArgReg;
         ArgValues.push_back(DAG.getNode(ISD::UNDEF, ObjectVT));
-      } else if (CurArgReg == ArgRegEnd && ObjectVT == MVT::f64 &&
+      } else if (/* FIXME: Apparently this isn't safe?? */
+                 0 && CurArgReg == ArgRegEnd && ObjectVT == MVT::f64 &&
                  ((CurArgReg-ArgRegs) & 1) == 0) {
         // If this is a double argument and the whole thing lives on the stack,
         // and the argument is aligned, load the double straight from the stack.
@@ -587,6 +658,28 @@ LowerFrameReturnAddress(bool isFrameAddr, SDOperand Chain, unsigned Depth,
   abort();
 }
 
+// Look at LHS/RHS/CC and see if they are a lowered V8 setcc instruction.  If so
+// set LHS/RHS and V8CC to the LHS/RHS of the setcc and V8CC to the condition.
+static void LookThroughSetCC(SDOperand &LHS, SDOperand &RHS,
+                             ISD::CondCode CC, unsigned &V8CC) {
+  if (isa<ConstantSDNode>(RHS) && cast<ConstantSDNode>(RHS)->getValue() == 0 &&
+      CC == ISD::SETNE && 
+      ((LHS.getOpcode() == V8ISD::SELECT_ICC &&
+        LHS.getOperand(3).getOpcode() == V8ISD::CMPICC) ||
+       (LHS.getOpcode() == V8ISD::SELECT_FCC &&
+        LHS.getOperand(3).getOpcode() == V8ISD::CMPFCC)) &&
+      isa<ConstantSDNode>(LHS.getOperand(0)) &&
+      isa<ConstantSDNode>(LHS.getOperand(1)) &&
+      cast<ConstantSDNode>(LHS.getOperand(0))->getValue() == 1 &&
+      cast<ConstantSDNode>(LHS.getOperand(1))->getValue() == 0) {
+    SDOperand CMPCC = LHS.getOperand(3);
+    V8CC = cast<ConstantSDNode>(LHS.getOperand(2))->getValue();
+    LHS = CMPCC.getOperand(0);
+    RHS = CMPCC.getOperand(1);
+  }
+}
+
+
 SDOperand SparcV8TargetLowering::
 LowerOperation(SDOperand Op, SelectionDAG &DAG) {
   switch (Op.getOpcode()) {
@@ -600,7 +693,8 @@ LowerOperation(SDOperand Op, SelectionDAG &DAG) {
   }
   case ISD::ConstantPool: {
     Constant *C = cast<ConstantPoolSDNode>(Op)->get();
-    SDOperand CP = DAG.getTargetConstantPool(C, MVT::i32);
+    SDOperand CP = DAG.getTargetConstantPool(C, MVT::i32,
+                                  cast<ConstantPoolSDNode>(Op)->getAlignment());
     SDOperand Hi = DAG.getNode(V8ISD::Hi, MVT::i32, CP);
     SDOperand Lo = DAG.getNode(V8ISD::Lo, MVT::i32, CP);
     return DAG.getNode(ISD::ADD, MVT::i32, Lo, Hi);
@@ -618,12 +712,18 @@ LowerOperation(SDOperand Op, SelectionDAG &DAG) {
   }
   case ISD::BR_CC: {
     SDOperand Chain = Op.getOperand(0);
-    SDOperand CC = Op.getOperand(1);
+    ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
     SDOperand LHS = Op.getOperand(2);
     SDOperand RHS = Op.getOperand(3);
     SDOperand Dest = Op.getOperand(4);
+    unsigned Opc, V8CC = ~0U;
+    
+    // If this is a br_cc of a "setcc", and if the setcc got lowered into
+    // an CMP[IF]CC/SELECT_[IF]CC pair, find the original compared values.
+    LookThroughSetCC(LHS, RHS, CC, V8CC);
     
     // Get the condition flag.
+    SDOperand CompareFlag;
     if (LHS.getValueType() == MVT::i32) {
       std::vector<MVT::ValueType> VTs;
       VTs.push_back(MVT::i32);
@@ -631,22 +731,30 @@ LowerOperation(SDOperand Op, SelectionDAG &DAG) {
       std::vector<SDOperand> Ops;
       Ops.push_back(LHS);
       Ops.push_back(RHS);
-      SDOperand Cond = DAG.getNode(V8ISD::CMPICC, VTs, Ops).getValue(1);
-      return DAG.getNode(V8ISD::BRICC, MVT::Other, Chain, Dest, CC, Cond);
+      CompareFlag = DAG.getNode(V8ISD::CMPICC, VTs, Ops).getValue(1);
+      if (V8CC == ~0U) V8CC = IntCondCCodeToICC(CC);
+      Opc = V8ISD::BRICC;
     } else {
-      SDOperand Cond = DAG.getNode(V8ISD::CMPFCC, MVT::Flag, LHS, RHS);
-      return DAG.getNode(V8ISD::BRFCC, MVT::Other, Chain, Dest, CC, Cond);
+      CompareFlag = DAG.getNode(V8ISD::CMPFCC, MVT::Flag, LHS, RHS);
+      if (V8CC == ~0U) V8CC = FPCondCCodeToFCC(CC);
+      Opc = V8ISD::BRFCC;
     }
+    return DAG.getNode(Opc, MVT::Other, Chain, Dest,
+                       DAG.getConstant(V8CC, MVT::i32), CompareFlag);
   }
   case ISD::SELECT_CC: {
     SDOperand LHS = Op.getOperand(0);
     SDOperand RHS = Op.getOperand(1);
-    unsigned CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
+    ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
     SDOperand TrueVal = Op.getOperand(2);
     SDOperand FalseVal = Op.getOperand(3);
+    unsigned Opc, V8CC = ~0U;
+
+    // If this is a select_cc of a "setcc", and if the setcc got lowered into
+    // an CMP[IF]CC/SELECT_[IF]CC pair, find the original compared values.
+    LookThroughSetCC(LHS, RHS, CC, V8CC);
     
     SDOperand CompareFlag;
-    unsigned Opc;
     if (LHS.getValueType() == MVT::i32) {
       std::vector<MVT::ValueType> VTs;
       VTs.push_back(LHS.getValueType());   // subcc returns a value
@@ -656,12 +764,14 @@ LowerOperation(SDOperand Op, SelectionDAG &DAG) {
       Ops.push_back(RHS);
       CompareFlag = DAG.getNode(V8ISD::CMPICC, VTs, Ops).getValue(1);
       Opc = V8ISD::SELECT_ICC;
+      if (V8CC == ~0U) V8CC = IntCondCCodeToICC(CC);
     } else {
       CompareFlag = DAG.getNode(V8ISD::CMPFCC, MVT::Flag, LHS, RHS);
       Opc = V8ISD::SELECT_FCC;
+      if (V8CC == ~0U) V8CC = FPCondCCodeToFCC(CC);
     }
     return DAG.getNode(Opc, TrueVal.getValueType(), TrueVal, FalseVal, 
-                       DAG.getConstant(CC, MVT::i32), CompareFlag);
+                       DAG.getConstant(V8CC, MVT::i32), CompareFlag);
   }
   case ISD::VASTART: {
     // vastart just stores the address of the VarArgsFrameIndex slot into the
@@ -708,50 +818,23 @@ MachineBasicBlock *
 SparcV8TargetLowering::InsertAtEndOfBasicBlock(MachineInstr *MI,
                                                MachineBasicBlock *BB) {
   unsigned BROpcode;
+  unsigned CC;
   // Figure out the conditional branch opcode to use for this select_cc.
   switch (MI->getOpcode()) {
   default: assert(0 && "Unknown SELECT_CC!");
   case V8::SELECT_CC_Int_ICC:
   case V8::SELECT_CC_FP_ICC:
   case V8::SELECT_CC_DFP_ICC:
-    // Integer compare.
-    switch ((ISD::CondCode)MI->getOperand(3).getImmedValue()) {
-    default: assert(0 && "Unknown integer condition code!");
-    case ISD::SETEQ:  BROpcode = V8::BE; break;
-    case ISD::SETNE:  BROpcode = V8::BNE; break;
-    case ISD::SETLT:  BROpcode = V8::BL; break;
-    case ISD::SETGT:  BROpcode = V8::BG; break;
-    case ISD::SETLE:  BROpcode = V8::BLE; break;
-    case ISD::SETGE:  BROpcode = V8::BGE; break;
-    case ISD::SETULT: BROpcode = V8::BCS; break;
-    case ISD::SETULE: BROpcode = V8::BLEU; break;
-    case ISD::SETUGT: BROpcode = V8::BGU; break;
-    case ISD::SETUGE: BROpcode = V8::BCC; break;
-    }
+    BROpcode = V8::BCOND;
     break;
   case V8::SELECT_CC_Int_FCC:
   case V8::SELECT_CC_FP_FCC:
   case V8::SELECT_CC_DFP_FCC:
-    // FP compare.
-    switch ((ISD::CondCode)MI->getOperand(3).getImmedValue()) {
-    default: assert(0 && "Unknown fp condition code!");
-    case ISD::SETEQ:  BROpcode = V8::FBE; break;
-    case ISD::SETNE:  BROpcode = V8::FBNE; break;
-    case ISD::SETLT:  BROpcode = V8::FBL; break;
-    case ISD::SETGT:  BROpcode = V8::FBG; break;
-    case ISD::SETLE:  BROpcode = V8::FBLE; break;
-    case ISD::SETGE:  BROpcode = V8::FBGE; break;
-    case ISD::SETULT: BROpcode = V8::FBUL; break;
-    case ISD::SETULE: BROpcode = V8::FBULE; break;
-    case ISD::SETUGT: BROpcode = V8::FBUG; break;
-    case ISD::SETUGE: BROpcode = V8::FBUGE; break;
-    case ISD::SETUO:  BROpcode = V8::FBU; break;
-    case ISD::SETO:   BROpcode = V8::FBO; break;
-    case ISD::SETONE: BROpcode = V8::FBLG; break;
-    case ISD::SETUEQ: BROpcode = V8::FBUE; break;
-    }
+    BROpcode = V8::FBCOND;
     break;
   }
+
+  CC = (V8CC::CondCodes)MI->getOperand(3).getImmedValue();
   
   // To "insert" a SELECT_CC instruction, we actually have to insert the diamond
   // control-flow pattern.  The incoming instruction knows the destination vreg
@@ -769,7 +852,7 @@ SparcV8TargetLowering::InsertAtEndOfBasicBlock(MachineInstr *MI,
   MachineBasicBlock *thisMBB = BB;
   MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
   MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
-  BuildMI(BB, BROpcode, 1).addMBB(sinkMBB);
+  BuildMI(BB, BROpcode, 2).addMBB(sinkMBB).addImm(CC);
   MachineFunction *F = BB->getParent();
   F->getBasicBlockList().insert(It, copy0MBB);
   F->getBasicBlockList().insert(It, sinkMBB);
@@ -808,9 +891,15 @@ SparcV8TargetLowering::InsertAtEndOfBasicBlock(MachineInstr *MI,
 namespace {
 class SparcV8DAGToDAGISel : public SelectionDAGISel {
   SparcV8TargetLowering V8Lowering;
+
+  /// Subtarget - Keep a pointer to the Sparc Subtarget around so that we can
+  /// make the right decision when generating code for different targets.
+  const SparcV8Subtarget &Subtarget;
 public:
   SparcV8DAGToDAGISel(TargetMachine &TM)
-    : SelectionDAGISel(V8Lowering), V8Lowering(TM) {}
+    : SelectionDAGISel(V8Lowering), V8Lowering(TM),
+      Subtarget(TM.getSubtarget<SparcV8Subtarget>()) {
+  }
 
   SDOperand Select(SDOperand Op);