[InstCombine] Invert `add A, sext(B) --> sub A, zext(B)` canonicalization (to `sub A, zext B -> add A, sext B`)

Summary:
D68408 proposes to greatly improve our negation sinking abilities.
But in current canonicalization, we produce `sub A, zext(B)`,
which we will consider non-canonical and try to sink that negation,
undoing the existing canonicalization.
So unless we explicitly stop producing previous canonicalization,
we will have two conflicting folds, and will end up endlessly looping.

This inverts canonicalization, and adds back the obvious fold
that we'd miss:
* `sub [nsw] Op0, sext/zext (bool Y) -> add [nsw] Op0, zext/sext (bool Y)`
  https://rise4fun.com/Alive/xx4
* `sext(bool) + C -> bool ? C - 1 : C`
  https://rise4fun.com/Alive/fBl

It is obvious that `@ossfuzz_9880()` / `@lshr_out_of_range()`/`@ashr_out_of_range()`
(oss-fuzz 4871) are no longer folded as much, though those aren't really worrying.

Reviewers: spatel, efriedma, t.p.northover, hfinkel

Reviewed By: spatel

Subscribers: hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D71064
This commit is contained in:
Roman Lebedev 2019-12-05 20:44:22 +03:00
parent c8f0d3e130
commit 796fa662f1
No known key found for this signature in database
GPG Key ID: 083C3EBB4A1689E0
6 changed files with 51 additions and 25 deletions

View File

@ -890,6 +890,10 @@ Instruction *InstCombiner::foldAddWithConstant(BinaryOperator &Add) {
if (match(Op0, m_ZExt(m_Value(X))) &&
X->getType()->getScalarSizeInBits() == 1)
return SelectInst::Create(X, AddOne(Op1C), Op1);
// sext(bool) + C -> bool ? C - 1 : C
if (match(Op0, m_SExt(m_Value(X))) &&
X->getType()->getScalarSizeInBits() == 1)
return SelectInst::Create(X, SubOne(Op1C), Op1);
// ~X + C --> (C-1) - X
if (match(Op0, m_Not(m_Value(X))))
@ -1288,12 +1292,6 @@ Instruction *InstCombiner::visitAdd(BinaryOperator &I) {
return BinaryOperator::CreateSub(RHS, A);
}
// Canonicalize sext to zext for better value tracking potential.
// add A, sext(B) --> sub A, zext(B)
if (match(&I, m_c_Add(m_Value(A), m_OneUse(m_SExt(m_Value(B))))) &&
B->getType()->isIntOrIntVectorTy(1))
return BinaryOperator::CreateSub(A, Builder.CreateZExt(B, Ty));
// A + -B --> A - B
if (match(RHS, m_Neg(m_Value(B))))
return BinaryOperator::CreateSub(LHS, B);
@ -1923,6 +1921,14 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) {
Add->setHasNoSignedWrap(I.hasNoSignedWrap());
return Add;
}
// sub [nsw] X, zext(bool Y) -> add [nsw] X, sext(bool Y)
// 'nuw' is dropped in favor of the canonical form.
if (match(Op1, m_ZExt(m_Value(Y))) && Y->getType()->isIntOrIntVectorTy(1)) {
Value *Sext = Builder.CreateSExt(Y, I.getType());
BinaryOperator *Add = BinaryOperator::CreateAdd(Op0, Sext);
Add->setHasNoSignedWrap(I.hasNoSignedWrap());
return Add;
}
// X - A*-B -> X + A*B
// X - -A*B -> X + A*B

View File

@ -533,8 +533,11 @@ define i177 @ossfuzz_9880(i177 %X) {
; CHECK-LABEL: @ossfuzz_9880(
; CHECK-NEXT: [[A:%.*]] = alloca i177, align 8
; CHECK-NEXT: [[L1:%.*]] = load i177, i177* [[A]], align 8
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i177 [[L1]], 0
; CHECK-NEXT: [[B1:%.*]] = zext i1 [[TMP1]] to i177
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i177 [[L1]], -1
; CHECK-NEXT: [[TMP2:%.*]] = sext i1 [[TMP1]] to i177
; CHECK-NEXT: [[B14:%.*]] = add i177 [[L1]], [[TMP2]]
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i177 [[B14]], -1
; CHECK-NEXT: [[B1:%.*]] = zext i1 [[TMP3]] to i177
; CHECK-NEXT: ret i177 [[B1]]
;
%A = alloca i177

View File

@ -515,10 +515,10 @@ define <4 x i32> @vec_sel_xor(<4 x i32> %a, <4 x i32> %b, <4 x i1> %c) {
define <4 x i32> @vec_sel_xor_multi_use(<4 x i32> %a, <4 x i32> %b, <4 x i1> %c) {
; CHECK-LABEL: @vec_sel_xor_multi_use(
; CHECK-NEXT: [[TMP1:%.*]] = xor <4 x i1> [[C:%.*]], <i1 true, i1 false, i1 false, i1 false>
; CHECK-NEXT: [[MASK_FLIP1:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i32>
; CHECK-NEXT: [[TMP2:%.*]] = xor <4 x i1> [[C]], <i1 false, i1 true, i1 true, i1 true>
; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> [[TMP2]], <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]
; CHECK-NEXT: [[TMP4:%.*]] = zext <4 x i1> [[TMP1]] to <4 x i32>
; CHECK-NEXT: [[ADD:%.*]] = sub <4 x i32> [[TMP3]], [[TMP4]]
; CHECK-NEXT: [[ADD:%.*]] = add <4 x i32> [[TMP3]], [[MASK_FLIP1]]
; CHECK-NEXT: ret <4 x i32> [[ADD]]
;
%mask = sext <4 x i1> %c to <4 x i32>

View File

@ -694,8 +694,8 @@ define i32 @test41(i1 %cond, i32 %x, i32 %y) {
define i32 @test42(i32 %x, i32 %y) {
; CHECK-LABEL: @test42(
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[X:%.*]], 0
; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[COND]] to i32
; CHECK-NEXT: [[C:%.*]] = sub i32 [[Y:%.*]], [[TMP1]]
; CHECK-NEXT: [[B:%.*]] = sext i1 [[COND]] to i32
; CHECK-NEXT: [[C:%.*]] = add i32 [[B]], [[Y:%.*]]
; CHECK-NEXT: ret i32 [[C]]
;
%b = add i32 %y, -1
@ -707,8 +707,8 @@ define i32 @test42(i32 %x, i32 %y) {
define <2 x i32> @test42vec(<2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @test42vec(
; CHECK-NEXT: [[COND:%.*]] = icmp eq <2 x i32> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[TMP1:%.*]] = zext <2 x i1> [[COND]] to <2 x i32>
; CHECK-NEXT: [[C:%.*]] = sub <2 x i32> [[Y:%.*]], [[TMP1]]
; CHECK-NEXT: [[B:%.*]] = sext <2 x i1> [[COND]] to <2 x i32>
; CHECK-NEXT: [[C:%.*]] = add <2 x i32> [[B]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x i32> [[C]]
;
%b = add <2 x i32> %y, <i32 -1, i32 -1>

View File

@ -1628,7 +1628,12 @@ define i32 @ashr_select_xor_false(i32 %x, i1 %cond) {
; https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=4871
define i177 @lshr_out_of_range(i177 %Y, i177** %A2) {
; CHECK-LABEL: @lshr_out_of_range(
; CHECK-NEXT: store i177** [[A2:%.*]], i177*** undef, align 8
; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i177 [[Y:%.*]], -1
; CHECK-NEXT: [[B4:%.*]] = sext i1 [[TMP1]] to i177
; CHECK-NEXT: [[C8:%.*]] = icmp ult i177 [[B4]], [[Y]]
; CHECK-NEXT: [[TMP2:%.*]] = sext i1 [[C8]] to i64
; CHECK-NEXT: [[G18:%.*]] = getelementptr i177*, i177** [[A2:%.*]], i64 [[TMP2]]
; CHECK-NEXT: store i177** [[G18]], i177*** undef, align 8
; CHECK-NEXT: ret i177 0
;
%B5 = udiv i177 %Y, -1
@ -1649,6 +1654,18 @@ define i177 @lshr_out_of_range(i177 %Y, i177** %A2) {
; https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=5032
define void @ashr_out_of_range(i177* %A) {
; CHECK-LABEL: @ashr_out_of_range(
; CHECK-NEXT: [[L:%.*]] = load i177, i177* [[A:%.*]], align 4
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i177 [[L]], -1
; CHECK-NEXT: [[B2:%.*]] = select i1 [[TMP1]], i64 -1, i64 -2
; CHECK-NEXT: [[G11:%.*]] = getelementptr i177, i177* [[A]], i64 [[B2]]
; CHECK-NEXT: [[L7:%.*]] = load i177, i177* [[G11]], align 4
; CHECK-NEXT: [[B36:%.*]] = select i1 [[TMP1]], i177 0, i177 [[L7]]
; CHECK-NEXT: [[C17:%.*]] = icmp sgt i177 [[B36]], [[L7]]
; CHECK-NEXT: [[TMP2:%.*]] = sext i1 [[C17]] to i64
; CHECK-NEXT: [[G62:%.*]] = getelementptr i177, i177* [[G11]], i64 [[TMP2]]
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i177 [[L7]], -1
; CHECK-NEXT: [[B28:%.*]] = select i1 [[TMP3]], i177 0, i177 [[L7]]
; CHECK-NEXT: store i177 [[B28]], i177* [[G62]], align 4
; CHECK-NEXT: ret void
;
%L = load i177, i177* %A

View File

@ -5,9 +5,9 @@
define i32 @a(i1 zeroext %x, i1 zeroext %y) {
; CHECK-LABEL: @a(
; CHECK-NEXT: [[CONV3_NEG:%.*]] = sext i1 [[Y:%.*]] to i32
; CHECK-NEXT: [[SUB:%.*]] = select i1 [[X:%.*]], i32 2, i32 1
; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[Y:%.*]] to i32
; CHECK-NEXT: [[ADD:%.*]] = sub nsw i32 [[SUB]], [[TMP1]]
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[SUB]], [[CONV3_NEG]]
; CHECK-NEXT: ret i32 [[ADD]]
;
%conv = zext i1 %x to i32
@ -317,8 +317,8 @@ define i8 @sext_sub_nuw(i8 %x, i1 %y) {
define i32 @sextbool_add(i1 %c, i32 %x) {
; CHECK-LABEL: @sextbool_add(
; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[C:%.*]] to i32
; CHECK-NEXT: [[S:%.*]] = sub i32 [[X:%.*]], [[TMP1]]
; CHECK-NEXT: [[B:%.*]] = sext i1 [[C:%.*]] to i32
; CHECK-NEXT: [[S:%.*]] = add i32 [[B]], [[X:%.*]]
; CHECK-NEXT: ret i32 [[S]]
;
%b = sext i1 %c to i32
@ -329,8 +329,8 @@ define i32 @sextbool_add(i1 %c, i32 %x) {
define i32 @sextbool_add_commute(i1 %c, i32 %px) {
; CHECK-LABEL: @sextbool_add_commute(
; CHECK-NEXT: [[X:%.*]] = urem i32 [[PX:%.*]], 42
; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[C:%.*]] to i32
; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[X]], [[TMP1]]
; CHECK-NEXT: [[B:%.*]] = sext i1 [[C:%.*]] to i32
; CHECK-NEXT: [[S:%.*]] = add nsw i32 [[X]], [[B]]
; CHECK-NEXT: ret i32 [[S]]
;
%x = urem i32 %px, 42 ; thwart complexity-based canonicalization
@ -358,8 +358,8 @@ define i32 @sextbool_add_uses(i1 %c, i32 %x) {
define <4 x i32> @sextbool_add_vector(<4 x i1> %c, <4 x i32> %x) {
; CHECK-LABEL: @sextbool_add_vector(
; CHECK-NEXT: [[TMP1:%.*]] = zext <4 x i1> [[C:%.*]] to <4 x i32>
; CHECK-NEXT: [[S:%.*]] = sub <4 x i32> [[X:%.*]], [[TMP1]]
; CHECK-NEXT: [[B:%.*]] = sext <4 x i1> [[C:%.*]] to <4 x i32>
; CHECK-NEXT: [[S:%.*]] = add <4 x i32> [[B]], [[X:%.*]]
; CHECK-NEXT: ret <4 x i32> [[S]]
;
%b = sext <4 x i1> %c to <4 x i32>
@ -393,8 +393,8 @@ define i32 @zextbool_sub_uses(i1 %c, i32 %x) {
define <4 x i32> @zextbool_sub_vector(<4 x i1> %c, <4 x i32> %x) {
; CHECK-LABEL: @zextbool_sub_vector(
; CHECK-NEXT: [[B:%.*]] = zext <4 x i1> [[C:%.*]] to <4 x i32>
; CHECK-NEXT: [[S:%.*]] = sub <4 x i32> [[X:%.*]], [[B]]
; CHECK-NEXT: [[TMP1:%.*]] = sext <4 x i1> [[C:%.*]] to <4 x i32>
; CHECK-NEXT: [[S:%.*]] = add <4 x i32> [[TMP1]], [[X:%.*]]
; CHECK-NEXT: ret <4 x i32> [[S]]
;
%b = zext <4 x i1> %c to <4 x i32>