[llvm] ab1b42a - [InstCombine] Add simplifications for div/rem with `i1` operands; PR62607
Noah Goldstein via llvm-commits
llvm-commits at lists.llvm.org
Sat May 13 12:36:33 PDT 2023
Author: Noah Goldstein
Date: 2023-05-13T14:35:57-05:00
New Revision: ab1b42ac5cb82cd7d541caa06e7929825b4fed84
URL: https://github.com/llvm/llvm-project/commit/ab1b42ac5cb82cd7d541caa06e7929825b4fed84
DIFF: https://github.com/llvm/llvm-project/commit/ab1b42ac5cb82cd7d541caa06e7929825b4fed84.diff
LOG: [InstCombine] Add simplifications for div/rem with `i1` operands; PR62607
This is generally handled already in early CSE.
If a specialized pipeline is used, however, its possible for `i1`
operand with known-zero denominator to slip through. Generally the
known-zero denominator is caught and poison is returned, but if it is
indirect enough (known zero through a phi node) we can miss this case
in `InstructionSimplify` and then miss handling `i1`. This is because
`i1` is current handled with the following check:
`if(Known.countMinLeadingZeros() == Known.getBitWidth() - 1)`
which only works on the assumption we don't know the denominator to be
zero. If we know the denominator to be zero, this check fails:
https://github.com/llvm/llvm-project/issues/62607
This patch simply adds an explicit `if(Known.isZero) return poison;`
which fixes the issue.
Alive2 Link for tests:
https://alive2.llvm.org/ce/z/VTw54n
Reviewed By: nikic
Differential Revision: https://reviews.llvm.org/D150142
Added:
llvm/test/Transforms/InstCombine/div-i1.ll
Modified:
llvm/lib/Analysis/InstructionSimplify.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 75fa94fb02165..fd0ba395b2937 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -1130,12 +1130,21 @@ static Value *simplifyDivRem(Instruction::BinaryOps Opcode, Value *Op0,
if (Op0 == Op1)
return IsDiv ? ConstantInt::get(Ty, 1) : Constant::getNullValue(Ty);
+
+ KnownBits Known = computeKnownBits(Op1, Q.DL, 0, Q.AC, Q.CxtI, Q.DT);
+ // X / 0 -> poison
+ // X % 0 -> poison
+ // If the divisor is known to be zero, just return poison. This can happen in
+ // some cases where its provable indirectly the denominator is zero but it's
+ // not trivially simplifiable (i.e known zero through a phi node).
+ if (Known.isZero())
+ return PoisonValue::get(Ty);
+
// X / 1 -> X
// X % 1 -> 0
// If the divisor can only be zero or one, we can't have division-by-zero
// or remainder-by-zero, so assume the divisor is 1.
// e.g. 1, zext (i8 X), sdiv X (Y and 1)
- KnownBits Known = computeKnownBits(Op1, Q.DL, 0, Q.AC, Q.CxtI, Q.DT);
if (Known.countMinLeadingZeros() == Known.getBitWidth() - 1)
return IsDiv ? Op0 : Constant::getNullValue(Ty);
diff --git a/llvm/test/Transforms/InstCombine/div-i1.ll b/llvm/test/Transforms/InstCombine/div-i1.ll
new file mode 100644
index 0000000000000..a54a2b8874f38
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/div-i1.ll
@@ -0,0 +1,153 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+define i1 @sdiv_by_zero_indirect_is_poison(i1 %c, i1 %x, i1 %y) {
+; CHECK-LABEL: @sdiv_by_zero_indirect_is_poison(
+; CHECK-NEXT: br i1 [[C:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]]
+; CHECK: true:
+; CHECK-NEXT: br label [[DONE:%.*]]
+; CHECK: false:
+; CHECK-NEXT: br label [[DONE]]
+; CHECK: done:
+; CHECK-NEXT: ret i1 poison
+;
+ br i1 %c, label %true, label %false
+true:
+ %y_true = and i1 %y, 0
+ br label %done
+false:
+ %y_false = and i1 %y, 0
+ br label %done
+done:
+ %yy = phi i1 [ %y_false, %false ], [ %y_true, %true ]
+ %r = sdiv i1 %x, %yy
+ ret i1 %r
+}
+
+define i1 @udiv_by_zero_indirect_is_poison(i1 %c, i1 %x, i1 %y) {
+; CHECK-LABEL: @udiv_by_zero_indirect_is_poison(
+; CHECK-NEXT: br i1 [[C:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]]
+; CHECK: true:
+; CHECK-NEXT: br label [[DONE:%.*]]
+; CHECK: false:
+; CHECK-NEXT: br label [[DONE]]
+; CHECK: done:
+; CHECK-NEXT: ret i1 poison
+;
+ br i1 %c, label %true, label %false
+true:
+ %y_true = and i1 %y, 0
+ br label %done
+false:
+ %y_false = and i1 %y, 0
+ br label %done
+done:
+ %yy = phi i1 [ %y_false, %false ], [ %y_true, %true ]
+ %r = udiv i1 %x, %yy
+ ret i1 %r
+}
+
+define i1 @srem_by_zero_indirect_is_poison(i1 %c, i1 %x, i1 %y) {
+; CHECK-LABEL: @srem_by_zero_indirect_is_poison(
+; CHECK-NEXT: br i1 [[C:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]]
+; CHECK: true:
+; CHECK-NEXT: br label [[DONE:%.*]]
+; CHECK: false:
+; CHECK-NEXT: br label [[DONE]]
+; CHECK: done:
+; CHECK-NEXT: ret i1 poison
+;
+ br i1 %c, label %true, label %false
+true:
+ %y_true = and i1 %y, 0
+ br label %done
+false:
+ %y_false = and i1 %y, 0
+ br label %done
+done:
+ %yy = phi i1 [ %y_false, %false ], [ %y_true, %true ]
+ %r = srem i1 %x, %yy
+ ret i1 %r
+}
+
+define i1 @urem_by_zero_indirect_is_poison(i1 %c, i1 %x, i1 %y) {
+; CHECK-LABEL: @urem_by_zero_indirect_is_poison(
+; CHECK-NEXT: br i1 [[C:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]]
+; CHECK: true:
+; CHECK-NEXT: br label [[DONE:%.*]]
+; CHECK: false:
+; CHECK-NEXT: br label [[DONE]]
+; CHECK: done:
+; CHECK-NEXT: ret i1 poison
+;
+ br i1 %c, label %true, label %false
+true:
+ %y_true = and i1 %y, 0
+ br label %done
+false:
+ %y_false = and i1 %y, 0
+ br label %done
+done:
+ %yy = phi i1 [ %y_false, %false ], [ %y_true, %true ]
+ %r = urem i1 %x, %yy
+ ret i1 %r
+}
+
+define i1 @sdiv_i1_is_op0(i1 %x, i1 %y) {
+; CHECK-LABEL: @sdiv_i1_is_op0(
+; CHECK-NEXT: ret i1 [[X:%.*]]
+;
+ %r = sdiv i1 %x, %y
+ ret i1 %r
+}
+
+define i1 @udiv_i1_is_op0(i1 %x, i1 %y) {
+; CHECK-LABEL: @udiv_i1_is_op0(
+; CHECK-NEXT: ret i1 [[X:%.*]]
+;
+ %r = udiv i1 %x, %y
+ ret i1 %r
+}
+
+define i1 @srem_i1_is_zero(i1 %x, i1 %y) {
+; CHECK-LABEL: @srem_i1_is_zero(
+; CHECK-NEXT: ret i1 false
+;
+ %r = srem i1 %x, %y
+ ret i1 %r
+}
+
+define i1 @urem_i1_is_zero(i1 %x, i1 %y) {
+; CHECK-LABEL: @urem_i1_is_zero(
+; CHECK-NEXT: ret i1 false
+;
+ %r = urem i1 %x, %y
+ ret i1 %r
+}
+
+declare void @llvm.assume(i1 noundef)
+
+define i1 @pt62607() {
+; CHECK-LABEL: @pt62607(
+; CHECK-NEXT: entry_1:
+; CHECK-NEXT: br label [[LOOP_5:%.*]]
+; CHECK: loop_5:
+; CHECK-NEXT: [[LOOP_CNT_I1_26_0:%.*]] = phi i1 [ false, [[ENTRY_1:%.*]] ], [ [[VAL_I1_55:%.*]], [[LOOP_5]] ]
+; CHECK-NEXT: [[VAL_I1_55]] = xor i1 [[LOOP_CNT_I1_26_0]], true
+; CHECK-NEXT: call void @llvm.assume(i1 [[VAL_I1_55]])
+; CHECK-NEXT: br i1 poison, label [[LOOP_5]], label [[LOOP_EXIT_8:%.*]]
+; CHECK: loop_exit_8:
+; CHECK-NEXT: ret i1 false
+;
+entry_1:
+ %val_i1_38 = trunc i8 109 to i1
+ br label %loop_5
+loop_5: ; preds = %loop_5, %entry_1
+ %loop_cnt_i1_26.0 = phi i1 [ false, %entry_1 ], [ %val_i1_55, %loop_5 ]
+ %val_i1_55 = add i1 %loop_cnt_i1_26.0, true
+ call void @llvm.assume(i1 %val_i1_55)
+ %val_i1_67 = udiv i1 %val_i1_38, %loop_cnt_i1_26.0
+ br i1 %val_i1_67, label %loop_5, label %loop_exit_8
+loop_exit_8: ; preds = %loop_5
+ ret i1 false
+}
More information about the llvm-commits
mailing list