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 @@ -1136,6 +1136,11 @@ // 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 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); 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,126 @@ +; 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 +} diff --git a/llvm/test/Transforms/InstCombine/pr62607.ll b/llvm/test/Transforms/InstCombine/pr62607.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/pr62607.ll @@ -0,0 +1,86 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -passes=instcombine < %s | FileCheck %s + +source_filename = "gen_06283" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare i1 @llvm.umax.i1(i1, i1) #0 + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare i8 @llvm.smin.i8(i8, i8) #0 + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare i8 @llvm.umin.i8(i8, i8) #0 + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare i16 @llvm.umax.i16(i16, i16) #0 + +; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) +declare void @llvm.assume(i1 noundef) #1 + +define i1 @function_0(i8 %val_i8_9, i8 %val_i8_10, i16 %val_i16_11, i1 %val_i1_12) { +; CHECK-LABEL: @function_0( +; CHECK-NEXT: entry_1: +; CHECK-NEXT: br label [[BB_3:%.*]] +; CHECK: bb_2: +; CHECK-NEXT: br i1 [[VAL_I1_12:%.*]], label [[BB_2:%.*]], label [[BB_3]] +; CHECK: bb_3: +; CHECK-NEXT: br label [[PRHDR_LOOP_4:%.*]] +; CHECK: prhdr_loop_4: +; CHECK-NEXT: br label [[LOOP_5:%.*]] +; CHECK: loop_5: +; CHECK-NEXT: [[LOOP_CNT_I1_26_0:%.*]] = phi i1 [ false, [[PRHDR_LOOP_4]] ], [ [[VAL_I1_55:%.*]], [[BE_7:%.*]] ] +; CHECK-NEXT: call void @llvm.assume(i1 [[VAL_I1_12]]) +; CHECK-NEXT: br i1 [[VAL_I1_12]], label [[BE_7]], label [[LOOP_EXIT_8:%.*]] +; CHECK: bb_6: +; CHECK-NEXT: br i1 [[LOOP_CNT_I1_26_0]], label [[BB_6:%.*]], label [[BB_2]] +; CHECK: be_7: +; 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 true, label [[LOOP_5]], label [[LOOP_EXIT_8]] +; CHECK: loop_exit_8: +; CHECK-NEXT: br label [[BB_6]] +; +entry_1: + %val_i16_22 = freeze i16 %val_i16_11 + %val_i1_38 = trunc i8 109 to i1 + %val_i8_39 = sext i1 %val_i1_12 to i8 + %val_i64_41 = zext i32 1870136903 to i64 + br label %bb_3 +bb_2: ; preds = %bb_6, %bb_2 + %val_i64_44 = sext i16 %val_i16_11 to i64 + %val_i8_45 = trunc i32 378764218 to i8 + %val_i16_46 = trunc i32 -1932311229 to i16 + %val_i1_47 = icmp sgt i32 -1106208892, -764213229 + %val_i64_49 = xor i64 %val_i64_41, %val_i64_44 + %val_i1_51 = trunc i16 %val_i16_46 to i1 + br i1 %val_i1_12, label %bb_2, label %bb_3 +bb_3: ; preds = %bb_2, %entry_1 + br label %prhdr_loop_4 +prhdr_loop_4: ; preds = %bb_3 + br label %loop_5 +loop_5: ; preds = %be_7, %prhdr_loop_4 + %loop_cnt_i1_26.0 = phi i1 [ false, %prhdr_loop_4 ], [ %val_i1_55, %be_7 ] + %val_i1_55 = add i1 %loop_cnt_i1_26.0, true + call void @llvm.assume(i1 %val_i1_12) + %val_i16_56 = call i16 @llvm.umax.i16(i16 %val_i16_22, i16 %val_i16_11) + br i1 %val_i1_12, label %be_7, label %loop_exit_8 +bb_6: ; preds = %loop_exit_8, %bb_6 + %val_i16_57 = zext i8 undef to i16 + br i1 %loop_cnt_i1_26.0, label %bb_6, label %bb_2 +be_7: ; preds = %loop_5 + %val_i1_58 = call i1 @llvm.umax.i1(i1 %val_i1_38, i1 %val_i1_55) + %val_i8_60 = trunc i64 %val_i64_41 to i8 + %val_i8_61 = call i8 @llvm.smin.i8(i8 %val_i8_60, i8 undef) + %val_i1_62 = icmp sle i32 -1472218002, 1177808965 + %val_i8_64 = call i8 @llvm.umin.i8(i8 %val_i8_61, i8 %val_i8_60) + %val_i1_65 = icmp ule i8 %val_i8_61, undef + %val_i16_66 = call i16 @llvm.umax.i16(i16 %val_i16_11, i16 %val_i16_22) + 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 = %be_7, %loop_5 + br label %bb_6 +}