Forward progress: crtbegin.c now compiles successfully!

Fixed CellSPU's A-form (local store) address mode, so that all globals,
externals, constant pool and jump table symbols are now wrapped within
a SPUISD::AFormAddr pseudo-instruction. This now identifies all local
store memory addresses, although it requires a bit of legerdemain during
instruction selection to properly select loads to and stores from local
store, properly generating "LQA" instructions.

Also added mul_ops.ll test harness for exercising integer multiplication.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@46142 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/CellSPU/SPUISelLowering.cpp b/lib/Target/CellSPU/SPUISelLowering.cpp
index e2a1b43..0f1d045 100644
--- a/lib/Target/CellSPU/SPUISelLowering.cpp
+++ b/lib/Target/CellSPU/SPUISelLowering.cpp
@@ -100,6 +100,14 @@
             || Opc == ISD::TargetExternalSymbol
             || Opc == SPUISD::AFormAddr);
   }
+
+  //! Predicate that returns true if the operand is an indirect target
+  bool isIndirectOperand(const SDOperand &Op)
+  {
+    const unsigned Opc = Op.getOpcode();
+    return (Opc == ISD::Register
+	    || Opc == SPUISD::LDRESULT);
+  }
 }
 
 SPUTargetLowering::SPUTargetLowering(SPUTargetMachine &TM)
@@ -126,7 +134,7 @@
   addRegisterClass(MVT::i128, SPU::GPRCRegisterClass);
   
   // SPU has no sign or zero extended loads for i1, i8, i16:
-  setLoadXAction(ISD::EXTLOAD,  MVT::i1, Custom);
+  setLoadXAction(ISD::EXTLOAD,  MVT::i1, Promote);
   setLoadXAction(ISD::SEXTLOAD, MVT::i1, Promote);
   setLoadXAction(ISD::ZEXTLOAD, MVT::i1, Promote);
   setTruncStoreAction(MVT::i8, MVT::i1, Custom);
@@ -160,10 +168,9 @@
     setOperationAction(ISD::STORE, sctype, Custom);
   }
 
-  // SPU supports BRCOND, although DAGCombine will convert BRCONDs
-  // into BR_CCs. BR_CC instructions are custom selected in
-  // SPUDAGToDAGISel.
-  setOperationAction(ISD::BRCOND, MVT::Other, Legal);
+  // Custom lower BRCOND for i1, i8 to "promote" the result to
+  // i32 and i16, respectively.
+  setOperationAction(ISD::BRCOND, MVT::Other, Custom);
 
   // Expand the jumptable branches
   setOperationAction(ISD::BR_JT,        MVT::Other, Expand);
@@ -472,7 +479,7 @@
     SDOperand Op1 = basePtr.Val->getOperand(1);
 
     if (Op1.getOpcode() == ISD::Constant || Op1.getOpcode() == ISD::TargetConstant) {
-      const ConstantSDNode *CN = cast<ConstantSDNode>(basePtr.Val->getOperand(1));
+      const ConstantSDNode *CN = cast<ConstantSDNode>(basePtr.getOperand(1));
 
       alignOffs = (int) CN->getValue();
       prefSlotOffs = (int) (alignOffs & 0xf);
@@ -482,15 +489,13 @@
       prefSlotOffs -= vtm->prefslot_byte;
       basePtr = basePtr.getOperand(0);
 
-      // Modify alignment, since the ADD is likely from getElementPtr:
-      switch (basePtr.getOpcode()) {
-      case ISD::GlobalAddress:
-      case ISD::TargetGlobalAddress: {
-        GlobalAddressSDNode *GN = cast<GlobalAddressSDNode>(basePtr.Val);
-        const GlobalValue *GV = GN->getGlobal();
-        alignment = GV->getAlignment();
-        break;
-      }
+      // Loading from memory, can we adjust alignment?
+      if (basePtr.getOpcode() == SPUISD::AFormAddr) {
+        SDOperand APtr = basePtr.getOperand(0);
+        if (APtr.getOpcode() == ISD::TargetGlobalAddress) {
+          GlobalAddressSDNode *GSDN = cast<GlobalAddressSDNode>(APtr);
+          alignment = GSDN->getGlobal()->getAlignment();
+        }
       }
     } else {
       alignOffs = 0;
@@ -504,15 +509,9 @@
   if (alignment == 16) {
     // Realign the base pointer as a D-Form address:
     if (!isMemoryOperand(basePtr) || (alignOffs & ~0xf) != 0) {
-      if (isMemoryOperand(basePtr)) {
-        SDOperand Zero = DAG.getConstant(0, PtrVT);
-        unsigned Opc = (!ST->usingLargeMem()
-                        ? SPUISD::AFormAddr
-                        : SPUISD::XFormAddr);
-        basePtr = DAG.getNode(Opc, PtrVT, basePtr, Zero);
-      }
-      basePtr = DAG.getNode(SPUISD::DFormAddr, PtrVT,
-                          basePtr, DAG.getConstant((alignOffs & ~0xf), PtrVT));
+      basePtr = DAG.getNode(ISD::ADD, PtrVT,
+                            basePtr,
+			    DAG.getConstant((alignOffs & ~0xf), PtrVT));
     }
 
     // Emit the vector load:
@@ -524,7 +523,7 @@
 
   // Unaligned load or we're using the "large memory" model, which means that
   // we have to be very pessimistic:
-  if (isMemoryOperand(basePtr)) {
+  if (isMemoryOperand(basePtr) || isIndirectOperand(basePtr)) {
     basePtr = DAG.getNode(SPUISD::XFormAddr, PtrVT, basePtr, DAG.getConstant(0, PtrVT));
   }
 
@@ -551,13 +550,6 @@
   unsigned alignment = LN->getAlignment();
   SDOperand Ops[8];
 
-  // For an extending load of an i1 variable, just call it i8 (or whatever we
-  // were passed) and make it zero-extended:
-  if (VT == MVT::i1) {
-    VT = OpVT;
-    ExtType = ISD::ZEXTLOAD;
-  }
-
   switch (LN->getAddressingMode()) {
   case ISD::UNINDEXED: {
     int offset, rotamt;
@@ -575,15 +567,13 @@
     if (rotamt != 0 || !was16aligned) {
       SDVTList vecvts = DAG.getVTList(MVT::v16i8, MVT::Other);
 
+      Ops[0] = the_chain;
+      Ops[1] = result;
       if (was16aligned) {
-        Ops[0] = the_chain;
-        Ops[1] = result;
         Ops[2] = DAG.getConstant(rotamt, MVT::i16);
       } else {
 	MVT::ValueType PtrVT = DAG.getTargetLoweringInfo().getPointerTy();
         LoadSDNode *LN1 = cast<LoadSDNode>(result);
-        Ops[0] = the_chain;
-        Ops[1] = result;
         Ops[2] = DAG.getNode(ISD::ADD, PtrVT, LN1->getBasePtr(),
 			     DAG.getConstant(rotamt, PtrVT));
       }
@@ -628,9 +618,14 @@
     }
 
     SDVTList retvts = DAG.getVTList(OpVT, MVT::Other);
-    SDOperand retops[2] = { result, the_chain };
+    SDOperand retops[3] = {
+      result,
+      the_chain,
+      DAG.getConstant(alignment, MVT::i32)
+    };
 
-    result = DAG.getNode(SPUISD::LDRESULT, retvts, retops, 2);
+    result = DAG.getNode(SPUISD::LDRESULT, retvts,
+                         retops, sizeof(retops) / sizeof(retops[0]));
     return result;
   }
   case ISD::PRE_INC:
@@ -712,6 +707,7 @@
     DEBUG(cerr << "\n");
 
     if (basePtr.getOpcode() == SPUISD::DFormAddr) {
+      // Hmmmm... do we ever actually hit this code?
       insertEltPtr = DAG.getNode(SPUISD::DFormAddr, PtrVT,
 				 basePtr.getOperand(0),
 				 insertEltOffs);
@@ -720,6 +716,8 @@
 		&& basePtr.getOperand(0).getOpcode() == SPUISD::XFormAddr)) {
       insertEltPtr = basePtr;
     } else {
+      // $sp is always aligned, so use it instead of potentially loading an
+      // address into a new register:
       insertEltPtr = DAG.getNode(SPUISD::DFormAddr, PtrVT,
 				 DAG.getRegister(SPU::R1, PtrVT),
 				 insertEltOffs);
@@ -766,10 +764,9 @@
   if (TM.getRelocationModel() == Reloc::Static) {
     if (!ST->usingLargeMem()) {
       // Just return the SDOperand with the constant pool address in it.
-      return CPI;
+      return DAG.getNode(SPUISD::AFormAddr, PtrVT, CPI, Zero);
     } else {
 #if 1
-      // Generate hi/lo address pair
       SDOperand Hi = DAG.getNode(SPUISD::Hi, PtrVT, CPI, Zero);
       SDOperand Lo = DAG.getNode(SPUISD::Lo, PtrVT, CPI, Zero);
 
@@ -795,7 +792,7 @@
 
   if (TM.getRelocationModel() == Reloc::Static) {
     return (!ST->usingLargeMem()
-            ? JTI
+            ? DAG.getNode(SPUISD::AFormAddr, PtrVT, JTI, Zero)
             : DAG.getNode(SPUISD::XFormAddr, PtrVT, JTI, Zero));
   }
 
@@ -815,7 +812,7 @@
   
   if (TM.getRelocationModel() == Reloc::Static) {
     return (!ST->usingLargeMem()
-            ? GA
+            ? DAG.getNode(SPUISD::AFormAddr, PtrVT, GA, Zero)
             : DAG.getNode(SPUISD::XFormAddr, PtrVT, GA, Zero));
   } else {
     cerr << "LowerGlobalAddress: Relocation model other than static not "
@@ -880,6 +877,24 @@
   return SDOperand();
 }
 
+//! Lower MVT::i1, MVT::i8 brcond to a promoted type (MVT::i32, MVT::i16)
+static SDOperand
+LowerBRCOND(SDOperand Op, SelectionDAG &DAG)
+{
+  SDOperand Cond = Op.getOperand(1);
+  MVT::ValueType CondVT = Cond.getValueType();
+  MVT::ValueType CondNVT;
+
+  if (CondVT == MVT::i1 || CondVT == MVT::i8) {
+    CondNVT = (CondVT == MVT::i1 ? MVT::i32 : MVT::i16);
+    return DAG.getNode(ISD::BRCOND, Op.getValueType(),
+                      Op.getOperand(0),
+                      DAG.getNode(ISD::ZERO_EXTEND, CondNVT, Op.getOperand(1)),
+                      Op.getOperand(2));
+  } else
+    return SDOperand();                // Unchanged
+}
+
 static SDOperand
 LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG, int &VarArgsFrameIndex)
 {
@@ -2458,8 +2473,10 @@
     return LowerConstant(Op, DAG);
   case ISD::ConstantFP:
     return LowerConstantFP(Op, DAG);
+  case ISD::BRCOND:
+    return LowerBRCOND(Op, DAG);
   case ISD::FORMAL_ARGUMENTS:
-      return LowerFORMAL_ARGUMENTS(Op, DAG, VarArgsFrameIndex);
+    return LowerFORMAL_ARGUMENTS(Op, DAG, VarArgsFrameIndex);
   case ISD::CALL:
     return LowerCALL(Op, DAG, SPUTM.getSubtargetImpl());
   case ISD::RET:
@@ -2537,48 +2554,16 @@
 #if 0
   TargetMachine &TM = getTargetMachine();
   SelectionDAG &DAG = DCI.DAG;
-#endif
   SDOperand N0 = N->getOperand(0);	// everything has at least one operand
 
   switch (N->getOpcode()) {
   default: break;
-
-  // Look for obvious optimizations for shift left:
-  // a) Replace 0 << V with 0
-  // b) Replace V << 0 with V
-  //
-  // N.B: llvm will generate an undef node if the shift amount is greater than
-  // 15 (e.g.: V << 16), which will naturally trigger an assert.
-  case SPU::SHLIr32:
-  case SPU::SHLHIr16:
-  case SPU::SHLQBIIvec:
-  case SPU::ROTHIr16:
-  case SPU::ROTHIr16_i32:
-  case SPU::ROTIr32:
-  case SPU::ROTIr32_i16:
-  case SPU::ROTQBYIvec:
-  case SPU::ROTQBYBIvec:
-  case SPU::ROTQBIIvec:
-  case SPU::ROTHMIr16:
-  case SPU::ROTMIr32:
-  case SPU::ROTQMBYIvec: {
-    if (N0.getOpcode() == ISD::Constant) {
-      if (ConstantSDNode *C = cast<ConstantSDNode>(N0)) {
-	if (C->getValue() == 0)   	// 0 << V -> 0.
-	  return N0;
-      }
-    }
-    SDOperand N1 = N->getOperand(1);
-    if (N1.getOpcode() == ISD::Constant) {
-      if (ConstantSDNode *C = cast<ConstantSDNode>(N1)) {
-	if (C->getValue() == 0)		// V << 0 -> V
-	  return N1;
-      }
-    }
-    break;
+    // Do something creative here for ISD nodes that can be coalesced in unique
+    // ways.
   }
-  }
+#endif
   
+  // Otherwise, return unchanged.
   return SDOperand();
 }