]> granicus.if.org Git - llvm/commitdiff
[InstCombine] prevent possible miscompile with negate+sdiv of vector op
authorSanjay Patel <spatel@rotateright.com>
Tue, 9 Apr 2019 14:09:06 +0000 (14:09 +0000)
committerSanjay Patel <spatel@rotateright.com>
Tue, 9 Apr 2019 14:09:06 +0000 (14:09 +0000)
// 0 - (X sdiv C)  -> (X sdiv -C)  provided the negation doesn't overflow.

This fold has been around for many years and nobody noticed the potential
vector miscompile from overflow until recently...
So it seems unlikely that there's much demand for a vector sdiv optimization
on arbitrary vector constants, so just limit the matching to splat constants
to avoid the possible bug.

Differential Revision: https://reviews.llvm.org/D60426

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

lib/Transforms/InstCombine/InstCombineAddSub.cpp
test/Transforms/InstCombine/div.ll

index d5a36e025f66e704bb58018989eac06274b1e13b..19766d502c40a76d28105874944db66d8281e061 100644 (file)
@@ -1692,9 +1692,12 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) {
                                   Builder.CreateNot(Y, Y->getName() + ".not"));
 
     // 0 - (X sdiv C)  -> (X sdiv -C)  provided the negation doesn't overflow.
-    if (match(Op1, m_SDiv(m_Value(X), m_Constant(C))) && match(Op0, m_Zero()) &&
-        C->isNotMinSignedValue() && !C->isOneValue()) {
-      auto *BO = BinaryOperator::CreateSDiv(X, ConstantExpr::getNeg(C));
+    // TODO: This could be extended to match arbitrary vector constants.
+    const APInt *DivC;
+    if (match(Op0, m_Zero()) && match(Op1, m_SDiv(m_Value(X), m_APInt(DivC))) &&
+        !DivC->isMinSignedValue() && *DivC != 1) {
+      Constant *NegDivC = ConstantInt::get(I.getType(), -(*DivC));
+      Instruction *BO = BinaryOperator::CreateSDiv(X, NegDivC);
       BO->setIsExact(cast<BinaryOperator>(Op1)->isExact());
       return BO;
     }
index 00d4bd7ce28cc4b368a3ad78428ada3e94e7530d..215d16c1213627e172bb9bb052114aa844e4636b 100644 (file)
@@ -772,7 +772,8 @@ define i32 @test_exact_nsw_exact(i32 %x) {
 
 define <2 x i64> @test_exact_vec(<2 x i64> %x) {
 ; CHECK-LABEL: @test_exact_vec(
-; CHECK-NEXT:    [[NEG:%.*]] = sdiv exact <2 x i64> [[X:%.*]], <i64 -3, i64 -4>
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv exact <2 x i64> [[X:%.*]], <i64 3, i64 4>
+; CHECK-NEXT:    [[NEG:%.*]] = sub nsw <2 x i64> zeroinitializer, [[DIV]]
 ; CHECK-NEXT:    ret <2 x i64> [[NEG]]
 ;
   %div = sdiv exact <2 x i64> %x, <i64 3, i64 4>
@@ -832,7 +833,8 @@ define <2 x i8> @negate_sdiv_vec_splat_signed_min(<2 x i8> %x) {
 
 define <2 x i8> @negate_sdiv_vec_one_element(<2 x i8> %x) {
 ; CHECK-LABEL: @negate_sdiv_vec_one_element(
-; CHECK-NEXT:    [[NEG:%.*]] = sdiv <2 x i8> [[X:%.*]], <i8 1, i8 -1>
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv <2 x i8> [[X:%.*]], <i8 -1, i8 1>
+; CHECK-NEXT:    [[NEG:%.*]] = sub <2 x i8> zeroinitializer, [[DIV]]
 ; CHECK-NEXT:    ret <2 x i8> [[NEG]]
 ;
   %div = sdiv <2 x i8> %x, <i8 -1, i8 1>
@@ -840,7 +842,7 @@ define <2 x i8> @negate_sdiv_vec_one_element(<2 x i8> %x) {
   ret <2 x i8> %neg
 }
 
-; Division by -1 may be UB and can't negate signed-min.
+; Can't negate signed-min constant for any element of a vector.
 
 define <2 x i8> @negate_sdiv_vec_signed_min_elt(<2 x i8> %x) {
 ; CHECK-LABEL: @negate_sdiv_vec_signed_min_elt(
@@ -853,7 +855,7 @@ define <2 x i8> @negate_sdiv_vec_signed_min_elt(<2 x i8> %x) {
   ret <2 x i8> %neg
 }
 
-; Can't negate signed-min constant for any element of a vector.
+; Division by -1 may be UB and can't negate signed-min.
 
 define <2 x i8> @negate_sdiv_vec_signed_min_and_one_elt(<2 x i8> %x) {
 ; CHECK-LABEL: @negate_sdiv_vec_signed_min_and_one_elt(