implement type legalization promotion support for SMULO and UMULO, giving
authorChris Lattner <sabre@nondot.org>
Mon, 20 Dec 2010 02:05:39 +0000 (02:05 +0000)
committerChris Lattner <sabre@nondot.org>
Mon, 20 Dec 2010 02:05:39 +0000 (02:05 +0000)
ARM (and other 32-bit-only) targets support for i8 and i16 overflow
multiplies.  The generated code isn't great, but this at least fixes
CodeGen/Generic/overflow.ll when running on ARM hosts.

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

lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp

index abd21a35c73549a118defb7fe92b694af37b4328..b9e55992cca484565e8551090f2d716c49a26b92 100644 (file)
@@ -548,6 +548,54 @@ SDValue DAGTypeLegalizer::PromoteIntRes_UADDSUBO(SDNode *N, unsigned ResNo) {
   return Res;
 }
 
+
+SDValue DAGTypeLegalizer::PromoteIntRes_XMULO(SDNode *N, unsigned ResNo) {
+  // Promote the overflow bit trivially.
+  if (ResNo == 1)
+    return PromoteIntRes_Overflow(N);
+  
+  SDValue LHS = N->getOperand(0), RHS = N->getOperand(1);
+  DebugLoc DL = N->getDebugLoc();
+  unsigned SmallSize = LHS.getValueType().getSizeInBits();
+  
+  // To determine if the result overflowed in a larger type, we extend the input
+  // to the larger type, do the multiply, then check the high bits of the result
+  // to see if the overflow happened.
+  if (N->getOpcode() == ISD::SMULO) {
+    LHS = SExtPromotedInteger(LHS);
+    RHS = SExtPromotedInteger(RHS);
+  } else {
+    LHS = ZExtPromotedInteger(LHS);
+    RHS = ZExtPromotedInteger(RHS);
+  }
+  
+  SDValue Mul = DAG.getNode(ISD::MUL, DL, LHS.getValueType(), LHS, RHS);
+  
+  
+  // For an unsigned overflow, we check to see if the high part is != 0;
+  SDValue Overflow;
+  if (N->getOpcode() == ISD::UMULO) {
+    SDValue Hi = DAG.getNode(ISD::SRL, DL, Mul.getValueType(), Mul,
+                             DAG.getIntPtrConstant(SmallSize));
+    // Overflowed if and only if this is not equal to Res.
+    Overflow = DAG.getSetCC(DL, N->getValueType(1), Hi,
+                            DAG.getConstant(0, Hi.getValueType()), ISD::SETNE);
+  } else {
+    // Signed multiply overflowed if the high part is not 0 and not -1.
+    SDValue Hi = DAG.getNode(ISD::SRA, DL, Mul.getValueType(), Mul,
+                             DAG.getIntPtrConstant(SmallSize));
+    Hi = DAG.getNode(ISD::ADD, DL, Hi.getValueType(), Hi,
+                     DAG.getConstant(1, Hi.getValueType()));
+    Overflow = DAG.getSetCC(DL, N->getValueType(1), Hi,
+                            DAG.getConstant(1, Hi.getValueType()), ISD::SETUGT);
+  }
+
+  // Use the calculated overflow everywhere.
+  ReplaceValueWith(SDValue(N, 1), Overflow);
+  return Mul;
+}
+
+
 SDValue DAGTypeLegalizer::PromoteIntRes_UDIV(SDNode *N) {
   // Zero extend the input.
   SDValue LHS = ZExtPromotedInteger(N->getOperand(0));
@@ -601,11 +649,6 @@ SDValue DAGTypeLegalizer::PromoteIntRes_VAARG(SDNode *N) {
   return Res;
 }
 
-SDValue DAGTypeLegalizer::PromoteIntRes_XMULO(SDNode *N, unsigned ResNo) {
-  assert(ResNo == 1 && "Only boolean result promotion currently supported!");
-  return PromoteIntRes_Overflow(N);
-}
-
 //===----------------------------------------------------------------------===//
 //  Integer Operand Promotion
 //===----------------------------------------------------------------------===//