diff --git a/llvm/test/Transforms/GuardWidening/pr60234.ll b/llvm/test/Transforms/GuardWidening/pr60234.ll new file mode 100644 index 0000000000000..f428d04e0ca2f --- /dev/null +++ b/llvm/test/Transforms/GuardWidening/pr60234.ll @@ -0,0 +1,76 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -passes=indvars,guard-widening -S < %s | FileCheck %s + +declare i32 @llvm.experimental.deoptimize.i32(...) + +; FIXME: Make sure that guard widening does not turn loop-invariant condition +; (that then gets optimized basing on this fact) into non-invariant. +; https://github.com/llvm/llvm-project/issues/60234 explains how it causes +; a miscompile. +define i32 @test(i32 %start) { +; CHECK-LABEL: @test( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[WC1:%.*]] = call i1 @llvm.experimental.widenable.condition() +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] +; CHECK-NEXT: [[START_PLUS_1:%.*]] = add i32 [[START]], 1 +; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[START_PLUS_1]], [[IV]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 true, [[COND]] +; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[WIDE_CHK]], [[WC1]] +; CHECK-NEXT: br i1 [[TMP0]], label [[GUARD_BLOCK:%.*]], label [[EXIT_BY_WC:%.*]] +; CHECK: exit_by_wc: +; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[START]], [[LOOP]] ] +; CHECK-NEXT: [[RVAL1:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV_LCSSA]]) ] +; CHECK-NEXT: ret i32 [[RVAL1]] +; CHECK: guard_block: +; CHECK-NEXT: [[WC2:%.*]] = call i1 @llvm.experimental.widenable.condition() +; CHECK-NEXT: [[GUARD:%.*]] = and i1 [[COND]], [[WC2]] +; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[FAILURE:%.*]] +; CHECK: backedge: +; CHECK-NEXT: call void @side_effect() +; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 +; CHECK-NEXT: br label [[LOOP]] +; CHECK: exit: +; CHECK-NEXT: ret i32 -1 +; CHECK: failure: +; CHECK-NEXT: [[IV_LCSSA1:%.*]] = phi i32 [ [[IV]], [[GUARD_BLOCK]] ] +; CHECK-NEXT: [[RVAL2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV_LCSSA1]]) ] +; CHECK-NEXT: ret i32 [[RVAL2]] +; +entry: + %wc1 = call i1 @llvm.experimental.widenable.condition() + br label %loop + +loop: + %iv = phi i32 [ %start, %entry ], [ %iv.next, %backedge ] + br i1 %wc1, label %guard_block, label %exit_by_wc + +exit_by_wc: + %rval1 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %iv) ] + ret i32 %rval1 + +guard_block: + %start_plus_1 = add i32 %start, 1 + %cond = icmp ne i32 %start_plus_1, %iv + %wc2 = call i1 @llvm.experimental.widenable.condition() + %guard = and i1 %cond, %wc2 + br i1 %guard, label %backedge, label %failure + +backedge: + call void @side_effect() + %iv.next = add i32 %iv, 1 + br label %loop + +exit: + ret i32 -1 + +failure: + %rval2 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %iv) ] + ret i32 %rval2 +} + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(inaccessiblemem: readwrite) +declare i1 @llvm.experimental.widenable.condition() + +declare void @side_effect()