Fix wrong logic in promotion of signed mul-with-overflow (I pointed this out at
authorDuncan Sands <baldrick@free.fr>
Thu, 17 Feb 2011 12:42:48 +0000 (12:42 +0000)
committerDuncan Sands <baldrick@free.fr>
Thu, 17 Feb 2011 12:42:48 +0000 (12:42 +0000)
the time but presumably my email got lost).  Examples where the previous logic
got it wrong: (1) a signed i8 multiply of 64 by 2 overflows, but the high part is
zero; (2) a signed i8 multiple of -128 by 2 overflows, but the high part is all
ones.

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

lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp

index 7f860e4d0557ed47386f30f81d3fd9b51b5bede2..f0752df80f129ff3cdeca70898a562d10b95bc47 100644 (file)
@@ -548,16 +548,15 @@ 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();
-  
+  EVT SmallVT = LHS.getValueType();
+
   // 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.
@@ -568,26 +567,22 @@ SDValue DAGTypeLegalizer::PromoteIntRes_XMULO(SDNode *N, unsigned ResNo) {
     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;
+
+  // Overflow occurred iff the high part of the result does not zero/sign-extend
+  // the low part.
   SDValue Overflow;
   if (N->getOpcode() == ISD::UMULO) {
+    // Unsigned overflow occurred iff the high part is non-zero.
     SDValue Hi = DAG.getNode(ISD::SRL, DL, Mul.getValueType(), Mul,
-                             DAG.getIntPtrConstant(SmallSize));
-    // Overflowed if and only if this is not equal to Res.
+                             DAG.getIntPtrConstant(SmallVT.getSizeInBits()));
     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);
+    // Signed overflow occurred iff the high part does not sign extend the low.
+    SDValue SExt = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Mul.getValueType(),
+                               Mul, DAG.getValueType(SmallVT));
+    Overflow = DAG.getSetCC(DL, N->getValueType(1), SExt, Mul, ISD::SETNE);
   }
 
   // Use the calculated overflow everywhere.
@@ -595,7 +590,6 @@ SDValue DAGTypeLegalizer::PromoteIntRes_XMULO(SDNode *N, unsigned ResNo) {
   return Mul;
 }
 
-
 SDValue DAGTypeLegalizer::PromoteIntRes_UDIV(SDNode *N) {
   // Zero extend the input.
   SDValue LHS = ZExtPromotedInteger(N->getOperand(0));