From f62dcea7ed69df95b037712b1860bb99c553c808 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Tue, 9 Apr 2019 14:09:06 +0000 Subject: [PATCH] [InstCombine] prevent possible miscompile with negate+sdiv of vector op // 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 llvm-svn: 358005 --- llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp | 9 ++++++--- llvm/test/Transforms/InstCombine/div.ll | 10 ++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp index d5a36e0..19766d5 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -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(Op1)->isExact()); return BO; } diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll index 00d4bd7..215d16c 100644 --- a/llvm/test/Transforms/InstCombine/div.ll +++ b/llvm/test/Transforms/InstCombine/div.ll @@ -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:%.*]], +; CHECK-NEXT: [[DIV:%.*]] = sdiv exact <2 x i64> [[X:%.*]], +; CHECK-NEXT: [[NEG:%.*]] = sub nsw <2 x i64> zeroinitializer, [[DIV]] ; CHECK-NEXT: ret <2 x i64> [[NEG]] ; %div = sdiv exact <2 x i64> %x, @@ -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:%.*]], +; CHECK-NEXT: [[DIV:%.*]] = sdiv <2 x i8> [[X:%.*]], +; CHECK-NEXT: [[NEG:%.*]] = sub <2 x i8> zeroinitializer, [[DIV]] ; CHECK-NEXT: ret <2 x i8> [[NEG]] ; %div = sdiv <2 x i8> %x, @@ -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( -- 2.7.4