diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -1130,12 +1130,21 @@ 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 --- /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 +}