Add sub/mul overflow intrinsics. This currently doesn't have a
target-independent way of determining overflow on multiplication. It's very
tricky. Patch by Zoltan Varga!


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@60800 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index c13e84b..c33a8ff 100644
--- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -4234,7 +4234,8 @@
     break;
   }
 
-  case ISD::SADDO: {
+  case ISD::SADDO:
+  case ISD::SSUBO: {
     MVT VT = Node->getValueType(0);
     switch (TLI.getOperationAction(Node->getOpcode(), VT)) {
     default: assert(0 && "This action not supported for this op yet!");
@@ -4246,7 +4247,9 @@
       SDValue LHS = LegalizeOp(Node->getOperand(0));
       SDValue RHS = LegalizeOp(Node->getOperand(1));
 
-      SDValue Sum = DAG.getNode(ISD::ADD, LHS.getValueType(), LHS, RHS);
+      SDValue Sum = DAG.getNode(Node->getOpcode() == ISD::SADDO ? 
+                                ISD::ADD : ISD::SUB, LHS.getValueType(),
+                                LHS, RHS);
       MVT OType = Node->getValueType(1);
 
       SDValue Zero = DAG.getConstant(0, LHS.getValueType());
@@ -4255,16 +4258,21 @@
       //   RHSSign -> RHS >= 0
       //   SumSign -> Sum >= 0
       //
+      //   Add:
       //   Overflow -> (LHSSign == RHSSign) && (LHSSign != SumSign)
+      //   Sub:
+      //   Overflow -> (LHSSign != RHSSign) && (LHSSign != SumSign)
       //
       SDValue LHSSign = DAG.getSetCC(OType, LHS, Zero, ISD::SETGE);
       SDValue RHSSign = DAG.getSetCC(OType, RHS, Zero, ISD::SETGE);
-      SDValue SignsEq = DAG.getSetCC(OType, LHSSign, RHSSign, ISD::SETEQ);
+      SDValue SignsMatch = DAG.getSetCC(OType, LHSSign, RHSSign, 
+                                        Node->getOpcode() == ISD::SADDO ? 
+                                        ISD::SETEQ : ISD::SETNE);
 
       SDValue SumSign = DAG.getSetCC(OType, Sum, Zero, ISD::SETGE);
       SDValue SumSignNE = DAG.getSetCC(OType, LHSSign, SumSign, ISD::SETNE);
 
-      SDValue Cmp = DAG.getNode(ISD::AND, OType, SignsEq, SumSignNE);
+      SDValue Cmp = DAG.getNode(ISD::AND, OType, SignsMatch, SumSignNE);
 
       MVT ValueVTs[] = { LHS.getValueType(), OType };
       SDValue Ops[] = { Sum, Cmp };
@@ -4280,7 +4288,8 @@
 
     break;
   }
-  case ISD::UADDO: {
+  case ISD::UADDO:
+  case ISD::USUBO: {
     MVT VT = Node->getValueType(0);
     switch (TLI.getOperationAction(Node->getOpcode(), VT)) {
     default: assert(0 && "This action not supported for this op yet!");
@@ -4292,9 +4301,13 @@
       SDValue LHS = LegalizeOp(Node->getOperand(0));
       SDValue RHS = LegalizeOp(Node->getOperand(1));
 
-      SDValue Sum = DAG.getNode(ISD::ADD, LHS.getValueType(), LHS, RHS);
+      SDValue Sum = DAG.getNode(Node->getOpcode() == ISD::UADDO ?
+                                ISD::ADD : ISD::SUB, LHS.getValueType(),
+                                LHS, RHS);
       MVT OType = Node->getValueType(1);
-      SDValue Cmp = DAG.getSetCC(OType, Sum, LHS, ISD::SETULT);
+      SDValue Cmp = DAG.getSetCC(OType, Sum, LHS,
+                                 Node->getOpcode () == ISD::UADDO ? 
+                                 ISD::SETULT : ISD::SETUGT);
 
       MVT ValueVTs[] = { LHS.getValueType(), OType };
       SDValue Ops[] = { Sum, Cmp };
@@ -4310,6 +4323,25 @@
 
     break;
   }
+  case ISD::SMULO:
+  case ISD::UMULO: {
+    MVT VT = Node->getValueType(0);
+    switch (TLI.getOperationAction(Node->getOpcode(), VT)) {
+    default: assert(0 && "This action is not supported at all!");
+    case TargetLowering::Custom:
+      Result = TLI.LowerOperation(Op, DAG);
+      if (Result.getNode()) break;
+      // Fall Thru
+    case TargetLowering::Legal:
+      // FIXME: According to Hacker's Delight, this can be implemented in
+      // target independent lowering, but it would be inefficient, since it
+      // requires a division + a branch
+      assert(0 && "Target independent lowering is not supported for SMULO/UMULO!");	
+    break;
+    }
+    break;
+  }
+
   }
   
   assert(Result.getValueType() == Op.getValueType() &&
diff --git a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
index 62fcff3..10cfdc6 100644
--- a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
+++ b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
@@ -92,7 +92,11 @@
   case ISD::UREM:        Result = PromoteIntRes_UDIV(N); break;
 
   case ISD::SADDO:
-  case ISD::UADDO:       Result = PromoteIntRes_XADDO(N, ResNo); break;
+  case ISD::UADDO:
+  case ISD::SSUBO:
+  case ISD::USUBO:
+  case ISD::SMULO:
+  case ISD::UMULO:       Result = PromoteIntRes_XALUO(N, ResNo); break;
 
   case ISD::ATOMIC_LOAD_ADD_8:
   case ISD::ATOMIC_LOAD_SUB_8:
@@ -518,7 +522,7 @@
   return DAG.getNode(N->getOpcode(), LHS.getValueType(), LHS, RHS);
 }
 
-SDValue DAGTypeLegalizer::PromoteIntRes_XADDO(SDNode *N, unsigned ResNo) {
+SDValue DAGTypeLegalizer::PromoteIntRes_XALUO(SDNode *N, unsigned ResNo) {
   assert(ResNo == 1 && "Only boolean result promotion currently supported!");
 
   // Simply change the return type of the boolean result.
diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/lib/CodeGen/SelectionDAG/LegalizeTypes.h
index d2365d2..d46fccd 100644
--- a/lib/CodeGen/SelectionDAG/LegalizeTypes.h
+++ b/lib/CodeGen/SelectionDAG/LegalizeTypes.h
@@ -270,7 +270,7 @@
   SDValue PromoteIntRes_UDIV(SDNode *N);
   SDValue PromoteIntRes_UNDEF(SDNode *N);
   SDValue PromoteIntRes_VAARG(SDNode *N);
-  SDValue PromoteIntRes_XADDO(SDNode *N, unsigned ResNo);
+  SDValue PromoteIntRes_XALUO(SDNode *N, unsigned ResNo);
 
   // Integer Operand Promotion.
   bool PromoteIntegerOperand(SDNode *N, unsigned OperandNo);
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 979dea0..bb3b42c 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -1511,6 +1511,10 @@
     return;
   case ISD::SADDO:
   case ISD::UADDO:
+  case ISD::SSUBO:
+  case ISD::USUBO:
+  case ISD::SMULO:
+  case ISD::UMULO:
     if (Op.getResNo() != 1)
       return;
     // The boolean result conforms to getBooleanContents.  Fall through.
@@ -1919,6 +1923,10 @@
 
   case ISD::SADDO:
   case ISD::UADDO:
+  case ISD::SSUBO:
+  case ISD::USUBO:
+  case ISD::SMULO:
+  case ISD::UMULO:
     if (Op.getResNo() != 1)
       break;
     // The boolean result conforms to getBooleanContents.  Fall through.
@@ -5216,6 +5224,10 @@
   case ISD::ADDE:        return "adde";
   case ISD::SADDO:       return "saddo";
   case ISD::UADDO:       return "uaddo";
+  case ISD::SSUBO:       return "ssubo";
+  case ISD::USUBO:       return "usubo";
+  case ISD::SMULO:       return "smulo";
+  case ISD::UMULO:       return "umulo";
   case ISD::SUBC:        return "subc";
   case ISD::SUBE:        return "sube";
   case ISD::SHL_PARTS:   return "shl_parts";
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp
index e8987c5..5d81d22 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp
@@ -2968,6 +2968,23 @@
   return 0;
 }
 
+// implVisitAluOverflow - Lower an overflow instrinsics
+const char *
+SelectionDAGLowering::implVisitAluOverflow(CallInst &I, ISD::NodeType Op) {
+    SDValue Op1 = getValue(I.getOperand(1));
+    SDValue Op2 = getValue(I.getOperand(2));
+
+    MVT ValueVTs[] = { Op1.getValueType(), MVT::i1 };
+    SDValue Ops[] = { Op1, Op2 };
+
+    SDValue Result =
+      DAG.getNode(Op,
+                  DAG.getVTList(&ValueVTs[0], 2), &Ops[0], 2);
+
+    setValue(&I, Result);
+    return 0;
+  }
+
 /// visitExp - Lower an exp intrinsic. Handles the special sequences for
 /// limited-precision mode.
 void
@@ -4097,21 +4114,17 @@
   }
 
   case Intrinsic::uadd_with_overflow:
-  case Intrinsic::sadd_with_overflow: {
-    SDValue Op1 = getValue(I.getOperand(1));
-    SDValue Op2 = getValue(I.getOperand(2));
-
-    MVT ValueVTs[] = { Op1.getValueType(), MVT::i1 };
-    SDValue Ops[] = { Op1, Op2 };
-
-    SDValue Result =
-      DAG.getNode((Intrinsic == Intrinsic::sadd_with_overflow) ?
-                    ISD::SADDO : ISD::UADDO,
-                  DAG.getVTList(&ValueVTs[0], 2), &Ops[0], 2);
-
-    setValue(&I, Result);
-    return 0;
-  }
+    return implVisitAluOverflow(I, ISD::UADDO);
+  case Intrinsic::sadd_with_overflow:
+    return implVisitAluOverflow(I, ISD::SADDO);
+  case Intrinsic::usub_with_overflow:
+    return implVisitAluOverflow(I, ISD::USUBO);
+  case Intrinsic::ssub_with_overflow:
+    return implVisitAluOverflow(I, ISD::SSUBO);
+  case Intrinsic::umul_with_overflow:
+    return implVisitAluOverflow(I, ISD::UMULO);
+  case Intrinsic::smul_with_overflow:
+    return implVisitAluOverflow(I, ISD::SMULO);
 
   case Intrinsic::prefetch: {
     SDValue Ops[4];
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.h b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.h
index e614c30..db70f16 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.h
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.h
@@ -530,6 +530,7 @@
   }
   
   const char *implVisitBinaryAtomic(CallInst& I, ISD::NodeType Op);
+  const char *implVisitAluOverflow(CallInst &I, ISD::NodeType Op);
 };
 
 /// AddCatchInfo - Extract the personality and type infos from an eh.selector