From 70490db22f12308a8e9086235d74f99a5c964f8c Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Thu, 28 Aug 2025 11:12:57 -0700 Subject: [PATCH 01/14] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20?= =?UTF-8?q?initial=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 41 ++- .../ScalarEvolution/unreachable-exit.ll | 291 ++++++++++++++++++ 2 files changed, 330 insertions(+), 2 deletions(-) create mode 100644 llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp index c32731185afd0..ddec84698cb35 100644 --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -53,6 +53,7 @@ #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/PatternMatch.h" @@ -1816,11 +1817,20 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) { // suggestions on how to improve this? I can obviously bail out for outer // loops, but that seems less than ideal. MemorySSA can find memory writes, // is that enough for *all* side effects? + bool HasLocalSideEffects = false; for (BasicBlock *BB : L->blocks()) for (auto &I : *BB) // TODO:isGuaranteedToTransfer - if (I.mayHaveSideEffects()) - return false; + if (I.mayHaveSideEffects()) { + HasLocalSideEffects = true; + if (StoreInst *SI = dyn_cast(&I)) { + if (findAllocaForValue(SI->getPointerOperand(), false) == nullptr) { + return false; + } + } else { + return false; + } + } bool Changed = false; // Finally, do the actual predication for all predicatable blocks. A couple @@ -1840,6 +1850,33 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) { const SCEV *ExitCount = SE->getExitCount(L, ExitingBB); auto *BI = cast(ExitingBB->getTerminator()); + if (HasLocalSideEffects) { + BasicBlock *Unreachable = nullptr; + BasicBlock *InLoop = nullptr; + for (BasicBlock *Succ : BI->successors()) { + if (isa(Succ->getTerminator())) + Unreachable = Succ; + if (L->contains(Succ)) + InLoop = Succ; + } + // Exit BB which have one branch back into the loop and another one to + // a trap can still be optimized, because local side effects cannot + // be observed in the exit case (the trap). + if (Unreachable == nullptr || InLoop == nullptr) + continue; + if (llvm::any_of(*Unreachable, [](Instruction &I) { + if (auto *II = dyn_cast(&I)) { + if (II->getIntrinsicID() != Intrinsic::trap && + II->getIntrinsicID() != Intrinsic::ubsantrap) + return true; + } else if (!isa(I)) { + return true; + } + return false; + })) { + continue; + } + } Value *NewCond; if (ExitCount == ExactBTC) { NewCond = L->contains(BI->getSuccessor(0)) ? diff --git a/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll b/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll new file mode 100644 index 0000000000000..eaf6ad9f0d4f7 --- /dev/null +++ b/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll @@ -0,0 +1,291 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -S -passes=indvars < %s | FileCheck %s + +source_filename = "/usr/local/google/home/fmayer/loop/src3.cc" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: mustprogress uwtable +define dso_local void @foo(i32 noundef %block_size) local_unnamed_addr #0 { +; CHECK-LABEL: define dso_local void @foo( +; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [1024 x i8], align 16 +; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [1025 x i8], align 16 +; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6:[0-9]+]] +; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @x(ptr noundef nonnull [[FOO_ARR]]) +; CHECK-NEXT: [[CMP14_NOT:%.*]] = icmp eq i32 [[BLOCK_SIZE]], 0 +; CHECK-NEXT: br i1 [[CMP14_NOT]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY_PREHEADER:.*]] +; CHECK: [[FOR_BODY_PREHEADER]]: +; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[BLOCK_SIZE]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[BLOCK_SIZE]], -1 +; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 1024) +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 1024, [[UMIN]] +; CHECK-NEXT: br label %[[FOR_BODY:.*]] +; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]: +; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] +; CHECK: [[FOR_COND_CLEANUP]]: +; CHECK-NEXT: call void @x(ptr noundef nonnull [[BAR_ARR]]) +; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] +; CHECK-NEXT: ret void +; CHECK: [[FOR_BODY]]: +; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: br i1 [[TMP2]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: call void @llvm.trap() +; CHECK-NEXT: unreachable +; CHECK: [[IF_END4]]: +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i64 [[INDVARS_IV]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA5:![0-9]+]] +; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 +; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i64 [[INDVARS_IV]] +; CHECK-NEXT: store i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA5]] +; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], [[TMP0]] +; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP8:![0-9]+]] +; +entry: + %foo_arr = alloca [1024 x i8], align 16 + %bar_arr = alloca [1025 x i8], align 16 + call void @llvm.lifetime.start.p0(ptr nonnull %foo_arr) #4 + call void @llvm.lifetime.start.p0(ptr nonnull %bar_arr) #4 + call void @x(ptr noundef nonnull %foo_arr) + %cmp14.not = icmp eq i32 %block_size, 0 + br i1 %cmp14.not, label %for.cond.cleanup, label %for.body.preheader + +for.body.preheader: ; preds = %entry + br label %for.body + +for.cond.cleanup.loopexit: ; preds = %if.end4 + br label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry + call void @x(ptr noundef nonnull %bar_arr) + call void @llvm.lifetime.end.p0(ptr nonnull %bar_arr) #4 + call void @llvm.lifetime.end.p0(ptr nonnull %foo_arr) #4 + ret void + +for.body: ; preds = %for.body.preheader, %if.end4 + %i.015 = phi i32 [ %inc, %if.end4 ], [ 0, %for.body.preheader ] + %cmp1 = icmp samesign ugt i32 %i.015, 1023 + br i1 %cmp1, label %if.then, label %if.end4 + +if.then: ; preds = %for.body + call void @llvm.trap() + unreachable + +if.end4: ; preds = %for.body + %idxprom = zext nneg i32 %i.015 to i64 + %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i64 %idxprom + %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 + %1 = xor i8 %0, 54 + %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i64 %idxprom + store i8 %1, ptr %arrayidx7, align 1, !tbaa !5 + %inc = add nuw nsw i32 %i.015, 1 + %cmp = icmp ult i32 %inc, %block_size + br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 +} + +define dso_local void @foo_ubsan(i32 noundef %block_size) local_unnamed_addr #0 { +; CHECK-LABEL: define dso_local void @foo_ubsan( +; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [1024 x i8], align 16 +; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [1025 x i8], align 16 +; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @x(ptr noundef nonnull [[FOO_ARR]]) +; CHECK-NEXT: [[CMP14_NOT:%.*]] = icmp eq i32 [[BLOCK_SIZE]], 0 +; CHECK-NEXT: br i1 [[CMP14_NOT]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY_PREHEADER:.*]] +; CHECK: [[FOR_BODY_PREHEADER]]: +; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[BLOCK_SIZE]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[BLOCK_SIZE]], -1 +; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 1024) +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 1024, [[UMIN]] +; CHECK-NEXT: br label %[[FOR_BODY:.*]] +; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]: +; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] +; CHECK: [[FOR_COND_CLEANUP]]: +; CHECK-NEXT: call void @x(ptr noundef nonnull [[BAR_ARR]]) +; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] +; CHECK-NEXT: ret void +; CHECK: [[FOR_BODY]]: +; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: br i1 [[TMP2]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: call void @llvm.ubsantrap(i8 1) +; CHECK-NEXT: unreachable +; CHECK: [[IF_END4]]: +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i64 [[INDVARS_IV]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA5]] +; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 +; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i64 [[INDVARS_IV]] +; CHECK-NEXT: store i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA5]] +; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], [[TMP0]] +; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP8]] +; +entry: + %foo_arr = alloca [1024 x i8], align 16 + %bar_arr = alloca [1025 x i8], align 16 + call void @llvm.lifetime.start.p0(ptr nonnull %foo_arr) #4 + call void @llvm.lifetime.start.p0(ptr nonnull %bar_arr) #4 + call void @x(ptr noundef nonnull %foo_arr) + %cmp14.not = icmp eq i32 %block_size, 0 + br i1 %cmp14.not, label %for.cond.cleanup, label %for.body.preheader + +for.body.preheader: ; preds = %entry + br label %for.body + +for.cond.cleanup.loopexit: ; preds = %if.end4 + br label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry + call void @x(ptr noundef nonnull %bar_arr) + call void @llvm.lifetime.end.p0(ptr nonnull %bar_arr) #4 + call void @llvm.lifetime.end.p0(ptr nonnull %foo_arr) #4 + ret void + +for.body: ; preds = %for.body.preheader, %if.end4 + %i.015 = phi i32 [ %inc, %if.end4 ], [ 0, %for.body.preheader ] + %cmp1 = icmp samesign ugt i32 %i.015, 1023 + br i1 %cmp1, label %if.then, label %if.end4 + +if.then: ; preds = %for.body + call void @llvm.ubsantrap(i8 1) + unreachable + +if.end4: ; preds = %for.body + %idxprom = zext nneg i32 %i.015 to i64 + %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i64 %idxprom + %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 + %1 = xor i8 %0, 54 + %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i64 %idxprom + store i8 %1, ptr %arrayidx7, align 1, !tbaa !5 + %inc = add nuw nsw i32 %i.015, 1 + %cmp = icmp ult i32 %inc, %block_size + br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 +} + +define dso_local void @foo_randomcall(i32 noundef %block_size) local_unnamed_addr #0 { +; CHECK-LABEL: define dso_local void @foo_randomcall( +; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [1024 x i8], align 16 +; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [1025 x i8], align 16 +; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @x(ptr noundef nonnull [[FOO_ARR]]) +; CHECK-NEXT: [[CMP14_NOT:%.*]] = icmp eq i32 [[BLOCK_SIZE]], 0 +; CHECK-NEXT: br i1 [[CMP14_NOT]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY_PREHEADER:.*]] +; CHECK: [[FOR_BODY_PREHEADER]]: +; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[BLOCK_SIZE]] to i64 +; CHECK-NEXT: br label %[[FOR_BODY:.*]] +; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]: +; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] +; CHECK: [[FOR_COND_CLEANUP]]: +; CHECK-NEXT: call void @x(ptr noundef nonnull [[BAR_ARR]]) +; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] +; CHECK-NEXT: ret void +; CHECK: [[FOR_BODY]]: +; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp eq i64 [[INDVARS_IV]], 1024 +; CHECK-NEXT: br i1 [[EXITCOND1]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: call void @noreturn(ptr [[FOO_ARR]]) +; CHECK-NEXT: unreachable +; CHECK: [[IF_END4]]: +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i64 [[INDVARS_IV]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA5]] +; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 +; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i64 [[INDVARS_IV]] +; CHECK-NEXT: store i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA5]] +; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], [[TMP0]] +; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP8]] +; +entry: + %foo_arr = alloca [1024 x i8], align 16 + %bar_arr = alloca [1025 x i8], align 16 + call void @llvm.lifetime.start.p0(ptr nonnull %foo_arr) #4 + call void @llvm.lifetime.start.p0(ptr nonnull %bar_arr) #4 + call void @x(ptr noundef nonnull %foo_arr) + %cmp14.not = icmp eq i32 %block_size, 0 + br i1 %cmp14.not, label %for.cond.cleanup, label %for.body.preheader + +for.body.preheader: ; preds = %entry + br label %for.body + +for.cond.cleanup.loopexit: ; preds = %if.end4 + br label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry + call void @x(ptr noundef nonnull %bar_arr) + call void @llvm.lifetime.end.p0(ptr nonnull %bar_arr) #4 + call void @llvm.lifetime.end.p0(ptr nonnull %foo_arr) #4 + ret void + +for.body: ; preds = %for.body.preheader, %if.end4 + %i.015 = phi i32 [ %inc, %if.end4 ], [ 0, %for.body.preheader ] + %cmp1 = icmp samesign ugt i32 %i.015, 1023 + br i1 %cmp1, label %if.then, label %if.end4 + +if.then: ; preds = %for.body + call void @noreturn(ptr %foo_arr) + unreachable + +if.end4: ; preds = %for.body + %idxprom = zext nneg i32 %i.015 to i64 + %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i64 %idxprom + %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 + %1 = xor i8 %0, 54 + %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i64 %idxprom + store i8 %1, ptr %arrayidx7, align 1, !tbaa !5 + %inc = add nuw nsw i32 %i.015, 1 + %cmp = icmp ult i32 %inc, %block_size + br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 +} + +; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +declare void @llvm.lifetime.start.p0(ptr captures(none)) #1 + +declare void @x(ptr noundef) local_unnamed_addr #2 + +; Function Attrs: cold noreturn nounwind memory(inaccessiblemem: write) +declare void @llvm.trap() #3 + +declare void @noreturn(ptr) #3 + +; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +declare void @llvm.lifetime.end.p0(ptr captures(none)) #1 + +attributes #0 = { mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +attributes #2 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #3 = { cold noreturn nounwind memory(inaccessiblemem: write) } +attributes #4 = { nounwind } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"PIE Level", i32 2} +!3 = !{i32 7, !"uwtable", i32 2} +!4 = !{!"clang version 22.0.0git (/usr/local/google/home/fmayer/large/llvm-project/clang 9bebffa6127aff780f20cc05694c31230580d4ff)"} +!5 = !{!6, !6, i64 0} +!6 = !{!"omnipotent char", !7, i64 0} +!7 = !{!"Simple C++ TBAA"} +!8 = distinct !{!8, !9} +!9 = !{!"llvm.loop.mustprogress"} +;. +; CHECK: [[TBAA5]] = !{[[META6:![0-9]+]], [[META6]], i64 0} +; CHECK: [[META6]] = !{!"omnipotent char", [[META7:![0-9]+]], i64 0} +; CHECK: [[META7]] = !{!"Simple C++ TBAA"} +; CHECK: [[LOOP8]] = distinct !{[[LOOP8]], [[META9:![0-9]+]]} +; CHECK: [[META9]] = !{!"llvm.loop.mustprogress"} +;. From 78851f9355ff76704769c42e4b340d2ec45ef7fe Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Thu, 28 Aug 2025 11:17:49 -0700 Subject: [PATCH 02/14] comment Created using spr 1.3.4 --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp index ddec84698cb35..4a3bcd95050c5 100644 --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -1861,7 +1861,8 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) { } // Exit BB which have one branch back into the loop and another one to // a trap can still be optimized, because local side effects cannot - // be observed in the exit case (the trap). + // be observed in the exit case (the trap). We could be smarter about + // this, but for now lets pattern match common cases that directly trap. if (Unreachable == nullptr || InLoop == nullptr) continue; if (llvm::any_of(*Unreachable, [](Instruction &I) { From 5d1e1abb2b413e8917f01143ebe697e3b671275c Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Thu, 28 Aug 2025 11:21:46 -0700 Subject: [PATCH 03/14] add flag Created using spr 1.3.4 --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp index 4a3bcd95050c5..4a2d30fb882d3 100644 --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -118,6 +118,10 @@ static cl::opt LoopPredication("indvars-predicate-loops", cl::Hidden, cl::init(true), cl::desc("Predicate conditions in read only loops")); +static cl::opt LoopPredicationTraps( + "indvars-predicate-loop-traps", cl::Hidden, cl::init(true), + cl::desc("Predicate conditions that trap in loops with only local writes")); + static cl::opt AllowIVWidening("indvars-widen-indvars", cl::Hidden, cl::init(true), cl::desc("Allow widening of indvars to eliminate s/zext")); @@ -1822,11 +1826,12 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) { for (auto &I : *BB) // TODO:isGuaranteedToTransfer if (I.mayHaveSideEffects()) { + if (!LoopPredicationTraps) + return false; HasLocalSideEffects = true; if (StoreInst *SI = dyn_cast(&I)) { - if (findAllocaForValue(SI->getPointerOperand(), false) == nullptr) { + if (findAllocaForValue(SI->getPointerOperand(), false) == nullptr) return false; - } } else { return false; } From f896688ac0f376e5930b490b32a599ba1a2bfbf8 Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Thu, 28 Aug 2025 13:28:08 -0700 Subject: [PATCH 04/14] atomic and volatile Created using spr 1.3.4 --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 9 +- .../ScalarEvolution/unreachable-exit.ll | 162 ++++++++++++++++++ 2 files changed, 170 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp index 4a2d30fb882d3..91e06f10fbe4c 100644 --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -1830,7 +1830,14 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) { return false; HasLocalSideEffects = true; if (StoreInst *SI = dyn_cast(&I)) { - if (findAllocaForValue(SI->getPointerOperand(), false) == nullptr) + // The local could have leaked out of the function, so we need to + // consider atomic operations as effects. + // Because we need to preserve the relative order of volatile + // accesses, turn off this optimization if we see any of them. + // We could be smarter about volatile, and check whether the + // reordering is valid. + if (SI->isAtomic() || SI->isVolatile() || + findAllocaForValue(SI->getPointerOperand(), false) == nullptr) return false; } else { return false; diff --git a/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll b/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll index eaf6ad9f0d4f7..4a035ce1a63a5 100644 --- a/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll +++ b/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll @@ -88,6 +88,168 @@ if.end4: ; preds = %for.body br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 } +; Function Attrs: mustprogress uwtable +define dso_local void @foo_atomic(i32 noundef %block_size) local_unnamed_addr #0 { +; CHECK-LABEL: define dso_local void @foo_atomic( +; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [1024 x i8], align 16 +; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [1025 x i8], align 16 +; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @x(ptr noundef nonnull [[FOO_ARR]]) +; CHECK-NEXT: [[CMP14_NOT:%.*]] = icmp eq i32 [[BLOCK_SIZE]], 0 +; CHECK-NEXT: br i1 [[CMP14_NOT]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY_PREHEADER:.*]] +; CHECK: [[FOR_BODY_PREHEADER]]: +; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[BLOCK_SIZE]] to i64 +; CHECK-NEXT: br label %[[FOR_BODY:.*]] +; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]: +; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] +; CHECK: [[FOR_COND_CLEANUP]]: +; CHECK-NEXT: call void @x(ptr noundef nonnull [[BAR_ARR]]) +; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] +; CHECK-NEXT: ret void +; CHECK: [[FOR_BODY]]: +; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp eq i64 [[INDVARS_IV]], 1024 +; CHECK-NEXT: br i1 [[EXITCOND1]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: call void @llvm.trap() +; CHECK-NEXT: unreachable +; CHECK: [[IF_END4]]: +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i64 [[INDVARS_IV]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA5]] +; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 +; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i64 [[INDVARS_IV]] +; CHECK-NEXT: store atomic i8 [[TMP4]], ptr [[ARRAYIDX7]] unordered, align 1, !tbaa [[TBAA5]] +; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], [[TMP0]] +; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP8]] +; +entry: + %foo_arr = alloca [1024 x i8], align 16 + %bar_arr = alloca [1025 x i8], align 16 + call void @llvm.lifetime.start.p0(ptr nonnull %foo_arr) #4 + call void @llvm.lifetime.start.p0(ptr nonnull %bar_arr) #4 + call void @x(ptr noundef nonnull %foo_arr) + %cmp14.not = icmp eq i32 %block_size, 0 + br i1 %cmp14.not, label %for.cond.cleanup, label %for.body.preheader + +for.body.preheader: ; preds = %entry + br label %for.body + +for.cond.cleanup.loopexit: ; preds = %if.end4 + br label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry + call void @x(ptr noundef nonnull %bar_arr) + call void @llvm.lifetime.end.p0(ptr nonnull %bar_arr) #4 + call void @llvm.lifetime.end.p0(ptr nonnull %foo_arr) #4 + ret void + +for.body: ; preds = %for.body.preheader, %if.end4 + %i.015 = phi i32 [ %inc, %if.end4 ], [ 0, %for.body.preheader ] + %cmp1 = icmp samesign ugt i32 %i.015, 1023 + br i1 %cmp1, label %if.then, label %if.end4 + +if.then: ; preds = %for.body + call void @llvm.trap() + unreachable + +if.end4: ; preds = %for.body + %idxprom = zext nneg i32 %i.015 to i64 + %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i64 %idxprom + %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 + %1 = xor i8 %0, 54 + %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i64 %idxprom + store atomic i8 %1, ptr %arrayidx7 unordered, align 1, !tbaa !5 + %inc = add nuw nsw i32 %i.015, 1 + %cmp = icmp ult i32 %inc, %block_size + br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 +} + +; Function Attrs: mustprogress uwtable +define dso_local void @foo_volatile(i32 noundef %block_size) local_unnamed_addr #0 { +; CHECK-LABEL: define dso_local void @foo_volatile( +; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [1024 x i8], align 16 +; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [1025 x i8], align 16 +; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @x(ptr noundef nonnull [[FOO_ARR]]) +; CHECK-NEXT: [[CMP14_NOT:%.*]] = icmp eq i32 [[BLOCK_SIZE]], 0 +; CHECK-NEXT: br i1 [[CMP14_NOT]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY_PREHEADER:.*]] +; CHECK: [[FOR_BODY_PREHEADER]]: +; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[BLOCK_SIZE]] to i64 +; CHECK-NEXT: br label %[[FOR_BODY:.*]] +; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]: +; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] +; CHECK: [[FOR_COND_CLEANUP]]: +; CHECK-NEXT: call void @x(ptr noundef nonnull [[BAR_ARR]]) +; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] +; CHECK-NEXT: ret void +; CHECK: [[FOR_BODY]]: +; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp eq i64 [[INDVARS_IV]], 1024 +; CHECK-NEXT: br i1 [[EXITCOND1]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: call void @llvm.trap() +; CHECK-NEXT: unreachable +; CHECK: [[IF_END4]]: +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i64 [[INDVARS_IV]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA5]] +; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 +; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i64 [[INDVARS_IV]] +; CHECK-NEXT: store volatile i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA5]] +; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], [[TMP0]] +; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP8]] +; +entry: + %foo_arr = alloca [1024 x i8], align 16 + %bar_arr = alloca [1025 x i8], align 16 + call void @llvm.lifetime.start.p0(ptr nonnull %foo_arr) #4 + call void @llvm.lifetime.start.p0(ptr nonnull %bar_arr) #4 + call void @x(ptr noundef nonnull %foo_arr) + %cmp14.not = icmp eq i32 %block_size, 0 + br i1 %cmp14.not, label %for.cond.cleanup, label %for.body.preheader + +for.body.preheader: ; preds = %entry + br label %for.body + +for.cond.cleanup.loopexit: ; preds = %if.end4 + br label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry + call void @x(ptr noundef nonnull %bar_arr) + call void @llvm.lifetime.end.p0(ptr nonnull %bar_arr) #4 + call void @llvm.lifetime.end.p0(ptr nonnull %foo_arr) #4 + ret void + +for.body: ; preds = %for.body.preheader, %if.end4 + %i.015 = phi i32 [ %inc, %if.end4 ], [ 0, %for.body.preheader ] + %cmp1 = icmp samesign ugt i32 %i.015, 1023 + br i1 %cmp1, label %if.then, label %if.end4 + +if.then: ; preds = %for.body + call void @llvm.trap() + unreachable + +if.end4: ; preds = %for.body + %idxprom = zext nneg i32 %i.015 to i64 + %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i64 %idxprom + %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 + %1 = xor i8 %0, 54 + %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i64 %idxprom + store volatile i8 %1, ptr %arrayidx7, align 1, !tbaa !5 + %inc = add nuw nsw i32 %i.015, 1 + %cmp = icmp ult i32 %inc, %block_size + br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 +} + define dso_local void @foo_ubsan(i32 noundef %block_size) local_unnamed_addr #0 { ; CHECK-LABEL: define dso_local void @foo_ubsan( ; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { From a4f857bb7b216d9c36b637f05538c421dbc25967 Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Thu, 28 Aug 2025 13:29:08 -0700 Subject: [PATCH 05/14] TODO Created using spr 1.3.4 --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp index 91e06f10fbe4c..e0b8a0c92d4a3 100644 --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -1834,8 +1834,11 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) { // consider atomic operations as effects. // Because we need to preserve the relative order of volatile // accesses, turn off this optimization if we see any of them. + // TODO: // We could be smarter about volatile, and check whether the // reordering is valid. + // We also could be smarter about atomic, and check whether the + // local has leaked. if (SI->isAtomic() || SI->isVolatile() || findAllocaForValue(SI->getPointerOperand(), false) == nullptr) return false; From c278bd46393f8cd43f62459e31d401d783a6b688 Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Thu, 28 Aug 2025 13:49:06 -0700 Subject: [PATCH 06/14] style Created using spr 1.3.4 --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp index e0b8a0c92d4a3..55b12dd2d34c3 100644 --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -1871,7 +1871,7 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) { for (BasicBlock *Succ : BI->successors()) { if (isa(Succ->getTerminator())) Unreachable = Succ; - if (L->contains(Succ)) + else if (L->contains(Succ)) InLoop = Succ; } // Exit BB which have one branch back into the loop and another one to From 6d51827a842bda4d1d0d5d4da4961309b454a9c7 Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Thu, 28 Aug 2025 14:32:22 -0700 Subject: [PATCH 07/14] change Created using spr 1.3.4 --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp index 55b12dd2d34c3..dc14bfe857a76 100644 --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -1879,7 +1879,7 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) { // be observed in the exit case (the trap). We could be smarter about // this, but for now lets pattern match common cases that directly trap. if (Unreachable == nullptr || InLoop == nullptr) - continue; + return Changed; if (llvm::any_of(*Unreachable, [](Instruction &I) { if (auto *II = dyn_cast(&I)) { if (II->getIntrinsicID() != Intrinsic::trap && @@ -1890,7 +1890,7 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) { } return false; })) { - continue; + return Changed; } } Value *NewCond; From 3992eace1163620bacbe2a9b3fa5ce8f451351b8 Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Thu, 28 Aug 2025 14:42:51 -0700 Subject: [PATCH 08/14] more test Created using spr 1.3.4 --- .../ScalarEvolution/unreachable-exit.ll | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll b/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll index 4a035ce1a63a5..c44d5de1503eb 100644 --- a/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll +++ b/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll @@ -250,6 +250,89 @@ if.end4: ; preds = %for.body br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 } +; Function Attrs: mustprogress uwtable +define dso_local void @foo_call(i32 noundef %block_size) local_unnamed_addr #0 { +; CHECK-LABEL: define dso_local void @foo_call( +; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [1024 x i8], align 16 +; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [1025 x i8], align 16 +; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @x(ptr noundef nonnull [[FOO_ARR]]) +; CHECK-NEXT: [[CMP14_NOT:%.*]] = icmp eq i32 [[BLOCK_SIZE]], 0 +; CHECK-NEXT: br i1 [[CMP14_NOT]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY_PREHEADER:.*]] +; CHECK: [[FOR_BODY_PREHEADER]]: +; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[BLOCK_SIZE]] to i64 +; CHECK-NEXT: br label %[[FOR_BODY:.*]] +; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]: +; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] +; CHECK: [[FOR_COND_CLEANUP]]: +; CHECK-NEXT: call void @x(ptr noundef nonnull [[BAR_ARR]]) +; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] +; CHECK-NEXT: ret void +; CHECK: [[FOR_BODY]]: +; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp eq i64 [[INDVARS_IV]], 1024 +; CHECK-NEXT: br i1 [[EXITCOND1]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: call void @llvm.trap() +; CHECK-NEXT: unreachable +; CHECK: [[IF_END4]]: +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i64 [[INDVARS_IV]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA5]] +; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 +; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i64 [[INDVARS_IV]] +; CHECK-NEXT: call void @x(ptr null) +; CHECK-NEXT: store volatile i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA5]] +; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], [[TMP0]] +; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP8]] +; +entry: + %foo_arr = alloca [1024 x i8], align 16 + %bar_arr = alloca [1025 x i8], align 16 + call void @llvm.lifetime.start.p0(ptr nonnull %foo_arr) #4 + call void @llvm.lifetime.start.p0(ptr nonnull %bar_arr) #4 + call void @x(ptr noundef nonnull %foo_arr) + %cmp14.not = icmp eq i32 %block_size, 0 + br i1 %cmp14.not, label %for.cond.cleanup, label %for.body.preheader + +for.body.preheader: ; preds = %entry + br label %for.body + +for.cond.cleanup.loopexit: ; preds = %if.end4 + br label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry + call void @x(ptr noundef nonnull %bar_arr) + call void @llvm.lifetime.end.p0(ptr nonnull %bar_arr) #4 + call void @llvm.lifetime.end.p0(ptr nonnull %foo_arr) #4 + ret void + +for.body: ; preds = %for.body.preheader, %if.end4 + %i.015 = phi i32 [ %inc, %if.end4 ], [ 0, %for.body.preheader ] + %cmp1 = icmp samesign ugt i32 %i.015, 1023 + br i1 %cmp1, label %if.then, label %if.end4 + +if.then: ; preds = %for.body + call void @llvm.trap() + unreachable + +if.end4: ; preds = %for.body + %idxprom = zext nneg i32 %i.015 to i64 + %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i64 %idxprom + %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 + %1 = xor i8 %0, 54 + %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i64 %idxprom + call void @x(ptr null) + store volatile i8 %1, ptr %arrayidx7, align 1, !tbaa !5 + %inc = add nuw nsw i32 %i.015, 1 + %cmp = icmp ult i32 %inc, %block_size + br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 +} + define dso_local void @foo_ubsan(i32 noundef %block_size) local_unnamed_addr #0 { ; CHECK-LABEL: define dso_local void @foo_ubsan( ; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { From 4817d7c8a031172300761b496a28915713b7bf47 Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Fri, 29 Aug 2025 13:15:48 -0700 Subject: [PATCH 09/14] address comments Created using spr 1.3.4 --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 2 +- .../ScalarEvolution/unreachable-exit.ll | 321 +++++++----------- 2 files changed, 126 insertions(+), 197 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp index dc14bfe857a76..124ab7e59d912 100644 --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -1839,7 +1839,7 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) { // reordering is valid. // We also could be smarter about atomic, and check whether the // local has leaked. - if (SI->isAtomic() || SI->isVolatile() || + if (!SI->isSimple() || findAllocaForValue(SI->getPointerOperand(), false) == nullptr) return false; } else { diff --git a/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll b/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll index c44d5de1503eb..c2746506267b7 100644 --- a/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll +++ b/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll @@ -3,54 +3,46 @@ source_filename = "/usr/local/google/home/fmayer/loop/src3.cc" target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" ; Function Attrs: mustprogress uwtable -define dso_local void @foo(i32 noundef %block_size) local_unnamed_addr #0 { -; CHECK-LABEL: define dso_local void @foo( +define dso_local void @can_optimize_trap(i32 noundef %block_size) local_unnamed_addr #0 { +; CHECK-LABEL: define dso_local void @can_optimize_trap( ; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [1024 x i8], align 16 -; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [1025 x i8], align 16 -; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6:[0-9]+]] -; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [2 x i8], align 16 +; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [2 x i8], align 16 ; CHECK-NEXT: call void @x(ptr noundef nonnull [[FOO_ARR]]) ; CHECK-NEXT: [[CMP14_NOT:%.*]] = icmp eq i32 [[BLOCK_SIZE]], 0 ; CHECK-NEXT: br i1 [[CMP14_NOT]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY_PREHEADER:.*]] ; CHECK: [[FOR_BODY_PREHEADER]]: -; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[BLOCK_SIZE]] to i64 ; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[BLOCK_SIZE]], -1 -; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 1024) -; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 1024, [[UMIN]] +; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 3) +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 3, [[UMIN]] ; CHECK-NEXT: br label %[[FOR_BODY:.*]] ; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]: ; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] ; CHECK: [[FOR_COND_CLEANUP]]: ; CHECK-NEXT: call void @x(ptr noundef nonnull [[BAR_ARR]]) -; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] -; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] ; CHECK-NEXT: ret void ; CHECK: [[FOR_BODY]]: -; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: [[I_015:%.*]] = phi i32 [ [[INC:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] ; CHECK-NEXT: br i1 [[TMP2]], label %[[IF_THEN:.*]], label %[[IF_END4]] ; CHECK: [[IF_THEN]]: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; CHECK: [[IF_END4]]: -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i64 [[INDVARS_IV]] -; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA5:![0-9]+]] +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA4:![0-9]+]] ; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 -; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i64 [[INDVARS_IV]] -; CHECK-NEXT: store i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA5]] -; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 -; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], [[TMP0]] -; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP8:![0-9]+]] +; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: store i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_015]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INC]], [[BLOCK_SIZE]] +; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP7:![0-9]+]] ; entry: - %foo_arr = alloca [1024 x i8], align 16 - %bar_arr = alloca [1025 x i8], align 16 - call void @llvm.lifetime.start.p0(ptr nonnull %foo_arr) #4 - call void @llvm.lifetime.start.p0(ptr nonnull %bar_arr) #4 + %foo_arr = alloca [2 x i8], align 16 + %bar_arr = alloca [2 x i8], align 16 call void @x(ptr noundef nonnull %foo_arr) %cmp14.not = icmp eq i32 %block_size, 0 br i1 %cmp14.not, label %for.cond.cleanup, label %for.body.preheader @@ -63,13 +55,11 @@ for.cond.cleanup.loopexit: ; preds = %if.end4 for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry call void @x(ptr noundef nonnull %bar_arr) - call void @llvm.lifetime.end.p0(ptr nonnull %bar_arr) #4 - call void @llvm.lifetime.end.p0(ptr nonnull %foo_arr) #4 ret void for.body: ; preds = %for.body.preheader, %if.end4 %i.015 = phi i32 [ %inc, %if.end4 ], [ 0, %for.body.preheader ] - %cmp1 = icmp samesign ugt i32 %i.015, 1023 + %cmp1 = icmp samesign ugt i32 %i.015, 2 br i1 %cmp1, label %if.then, label %if.end4 if.then: ; preds = %for.body @@ -77,11 +67,10 @@ if.then: ; preds = %for.body unreachable if.end4: ; preds = %for.body - %idxprom = zext nneg i32 %i.015 to i64 - %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i64 %idxprom + %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i32 %i.015 %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 %1 = xor i8 %0, 54 - %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i64 %idxprom + %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i32 %i.015 store i8 %1, ptr %arrayidx7, align 1, !tbaa !5 %inc = add nuw nsw i32 %i.015, 1 %cmp = icmp ult i32 %inc, %block_size @@ -89,49 +78,42 @@ if.end4: ; preds = %for.body } ; Function Attrs: mustprogress uwtable -define dso_local void @foo_atomic(i32 noundef %block_size) local_unnamed_addr #0 { -; CHECK-LABEL: define dso_local void @foo_atomic( +define dso_local void @cannot_optimize_atomic(i32 noundef %block_size) local_unnamed_addr #0 { +; CHECK-LABEL: define dso_local void @cannot_optimize_atomic( ; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { ; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [1024 x i8], align 16 -; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [1025 x i8], align 16 -; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] -; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [2 x i8], align 16 +; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [2 x i8], align 16 ; CHECK-NEXT: call void @x(ptr noundef nonnull [[FOO_ARR]]) ; CHECK-NEXT: [[CMP14_NOT:%.*]] = icmp eq i32 [[BLOCK_SIZE]], 0 ; CHECK-NEXT: br i1 [[CMP14_NOT]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY_PREHEADER:.*]] ; CHECK: [[FOR_BODY_PREHEADER]]: -; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[BLOCK_SIZE]] to i64 ; CHECK-NEXT: br label %[[FOR_BODY:.*]] ; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]: ; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] ; CHECK: [[FOR_COND_CLEANUP]]: ; CHECK-NEXT: call void @x(ptr noundef nonnull [[BAR_ARR]]) -; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] -; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] ; CHECK-NEXT: ret void ; CHECK: [[FOR_BODY]]: -; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] -; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp eq i64 [[INDVARS_IV]], 1024 -; CHECK-NEXT: br i1 [[EXITCOND1]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK-NEXT: [[I_015:%.*]] = phi i32 [ [[INC:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[I_015]], 3 +; CHECK-NEXT: br i1 [[EXITCOND]], label %[[IF_THEN:.*]], label %[[IF_END4]] ; CHECK: [[IF_THEN]]: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; CHECK: [[IF_END4]]: -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i64 [[INDVARS_IV]] -; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA5]] +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA4]] ; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 -; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i64 [[INDVARS_IV]] -; CHECK-NEXT: store atomic i8 [[TMP4]], ptr [[ARRAYIDX7]] unordered, align 1, !tbaa [[TBAA5]] -; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 -; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], [[TMP0]] -; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP8]] +; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: store atomic i8 [[TMP4]], ptr [[ARRAYIDX7]] unordered, align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_015]], 1 +; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[INC]], [[BLOCK_SIZE]] +; CHECK-NEXT: br i1 [[EXITCOND1]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP7]] ; entry: - %foo_arr = alloca [1024 x i8], align 16 - %bar_arr = alloca [1025 x i8], align 16 - call void @llvm.lifetime.start.p0(ptr nonnull %foo_arr) #4 - call void @llvm.lifetime.start.p0(ptr nonnull %bar_arr) #4 + %foo_arr = alloca [2 x i8], align 16 + %bar_arr = alloca [2 x i8], align 16 call void @x(ptr noundef nonnull %foo_arr) %cmp14.not = icmp eq i32 %block_size, 0 br i1 %cmp14.not, label %for.cond.cleanup, label %for.body.preheader @@ -144,13 +126,11 @@ for.cond.cleanup.loopexit: ; preds = %if.end4 for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry call void @x(ptr noundef nonnull %bar_arr) - call void @llvm.lifetime.end.p0(ptr nonnull %bar_arr) #4 - call void @llvm.lifetime.end.p0(ptr nonnull %foo_arr) #4 ret void for.body: ; preds = %for.body.preheader, %if.end4 %i.015 = phi i32 [ %inc, %if.end4 ], [ 0, %for.body.preheader ] - %cmp1 = icmp samesign ugt i32 %i.015, 1023 + %cmp1 = icmp samesign ugt i32 %i.015, 2 br i1 %cmp1, label %if.then, label %if.end4 if.then: ; preds = %for.body @@ -158,11 +138,10 @@ if.then: ; preds = %for.body unreachable if.end4: ; preds = %for.body - %idxprom = zext nneg i32 %i.015 to i64 - %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i64 %idxprom + %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i32 %i.015 %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 %1 = xor i8 %0, 54 - %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i64 %idxprom + %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i32 %i.015 store atomic i8 %1, ptr %arrayidx7 unordered, align 1, !tbaa !5 %inc = add nuw nsw i32 %i.015, 1 %cmp = icmp ult i32 %inc, %block_size @@ -170,49 +149,42 @@ if.end4: ; preds = %for.body } ; Function Attrs: mustprogress uwtable -define dso_local void @foo_volatile(i32 noundef %block_size) local_unnamed_addr #0 { -; CHECK-LABEL: define dso_local void @foo_volatile( +define dso_local void @cannot_optimize_volatile(i32 noundef %block_size) local_unnamed_addr #0 { +; CHECK-LABEL: define dso_local void @cannot_optimize_volatile( ; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { ; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [1024 x i8], align 16 -; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [1025 x i8], align 16 -; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] -; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [2 x i8], align 16 +; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [2 x i8], align 16 ; CHECK-NEXT: call void @x(ptr noundef nonnull [[FOO_ARR]]) ; CHECK-NEXT: [[CMP14_NOT:%.*]] = icmp eq i32 [[BLOCK_SIZE]], 0 ; CHECK-NEXT: br i1 [[CMP14_NOT]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY_PREHEADER:.*]] ; CHECK: [[FOR_BODY_PREHEADER]]: -; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[BLOCK_SIZE]] to i64 ; CHECK-NEXT: br label %[[FOR_BODY:.*]] ; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]: ; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] ; CHECK: [[FOR_COND_CLEANUP]]: ; CHECK-NEXT: call void @x(ptr noundef nonnull [[BAR_ARR]]) -; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] -; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] ; CHECK-NEXT: ret void ; CHECK: [[FOR_BODY]]: -; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] -; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp eq i64 [[INDVARS_IV]], 1024 -; CHECK-NEXT: br i1 [[EXITCOND1]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK-NEXT: [[I_015:%.*]] = phi i32 [ [[INC:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[I_015]], 3 +; CHECK-NEXT: br i1 [[EXITCOND]], label %[[IF_THEN:.*]], label %[[IF_END4]] ; CHECK: [[IF_THEN]]: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; CHECK: [[IF_END4]]: -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i64 [[INDVARS_IV]] -; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA5]] +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA4]] ; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 -; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i64 [[INDVARS_IV]] -; CHECK-NEXT: store volatile i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA5]] -; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 -; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], [[TMP0]] -; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP8]] +; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: store volatile i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_015]], 1 +; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[INC]], [[BLOCK_SIZE]] +; CHECK-NEXT: br i1 [[EXITCOND1]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP7]] ; entry: - %foo_arr = alloca [1024 x i8], align 16 - %bar_arr = alloca [1025 x i8], align 16 - call void @llvm.lifetime.start.p0(ptr nonnull %foo_arr) #4 - call void @llvm.lifetime.start.p0(ptr nonnull %bar_arr) #4 + %foo_arr = alloca [2 x i8], align 16 + %bar_arr = alloca [2 x i8], align 16 call void @x(ptr noundef nonnull %foo_arr) %cmp14.not = icmp eq i32 %block_size, 0 br i1 %cmp14.not, label %for.cond.cleanup, label %for.body.preheader @@ -225,13 +197,11 @@ for.cond.cleanup.loopexit: ; preds = %if.end4 for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry call void @x(ptr noundef nonnull %bar_arr) - call void @llvm.lifetime.end.p0(ptr nonnull %bar_arr) #4 - call void @llvm.lifetime.end.p0(ptr nonnull %foo_arr) #4 ret void for.body: ; preds = %for.body.preheader, %if.end4 %i.015 = phi i32 [ %inc, %if.end4 ], [ 0, %for.body.preheader ] - %cmp1 = icmp samesign ugt i32 %i.015, 1023 + %cmp1 = icmp samesign ugt i32 %i.015, 2 br i1 %cmp1, label %if.then, label %if.end4 if.then: ; preds = %for.body @@ -239,11 +209,10 @@ if.then: ; preds = %for.body unreachable if.end4: ; preds = %for.body - %idxprom = zext nneg i32 %i.015 to i64 - %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i64 %idxprom + %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i32 %i.015 %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 %1 = xor i8 %0, 54 - %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i64 %idxprom + %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i32 %i.015 store volatile i8 %1, ptr %arrayidx7, align 1, !tbaa !5 %inc = add nuw nsw i32 %i.015, 1 %cmp = icmp ult i32 %inc, %block_size @@ -251,50 +220,43 @@ if.end4: ; preds = %for.body } ; Function Attrs: mustprogress uwtable -define dso_local void @foo_call(i32 noundef %block_size) local_unnamed_addr #0 { -; CHECK-LABEL: define dso_local void @foo_call( +define dso_local void @cannot_optimize_call(i32 noundef %block_size) local_unnamed_addr #0 { +; CHECK-LABEL: define dso_local void @cannot_optimize_call( ; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { ; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [1024 x i8], align 16 -; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [1025 x i8], align 16 -; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] -; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [2 x i8], align 16 +; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [2 x i8], align 16 ; CHECK-NEXT: call void @x(ptr noundef nonnull [[FOO_ARR]]) ; CHECK-NEXT: [[CMP14_NOT:%.*]] = icmp eq i32 [[BLOCK_SIZE]], 0 ; CHECK-NEXT: br i1 [[CMP14_NOT]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY_PREHEADER:.*]] ; CHECK: [[FOR_BODY_PREHEADER]]: -; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[BLOCK_SIZE]] to i64 ; CHECK-NEXT: br label %[[FOR_BODY:.*]] ; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]: ; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] ; CHECK: [[FOR_COND_CLEANUP]]: ; CHECK-NEXT: call void @x(ptr noundef nonnull [[BAR_ARR]]) -; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] -; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] ; CHECK-NEXT: ret void ; CHECK: [[FOR_BODY]]: -; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] -; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp eq i64 [[INDVARS_IV]], 1024 -; CHECK-NEXT: br i1 [[EXITCOND1]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK-NEXT: [[I_015:%.*]] = phi i32 [ [[INC:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[I_015]], 3 +; CHECK-NEXT: br i1 [[EXITCOND]], label %[[IF_THEN:.*]], label %[[IF_END4]] ; CHECK: [[IF_THEN]]: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; CHECK: [[IF_END4]]: -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i64 [[INDVARS_IV]] -; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA5]] +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA4]] ; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 -; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i64 [[INDVARS_IV]] +; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i32 [[I_015]] ; CHECK-NEXT: call void @x(ptr null) -; CHECK-NEXT: store volatile i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA5]] -; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 -; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], [[TMP0]] -; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP8]] +; CHECK-NEXT: store volatile i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_015]], 1 +; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[INC]], [[BLOCK_SIZE]] +; CHECK-NEXT: br i1 [[EXITCOND1]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP7]] ; entry: - %foo_arr = alloca [1024 x i8], align 16 - %bar_arr = alloca [1025 x i8], align 16 - call void @llvm.lifetime.start.p0(ptr nonnull %foo_arr) #4 - call void @llvm.lifetime.start.p0(ptr nonnull %bar_arr) #4 + %foo_arr = alloca [2 x i8], align 16 + %bar_arr = alloca [2 x i8], align 16 call void @x(ptr noundef nonnull %foo_arr) %cmp14.not = icmp eq i32 %block_size, 0 br i1 %cmp14.not, label %for.cond.cleanup, label %for.body.preheader @@ -307,13 +269,11 @@ for.cond.cleanup.loopexit: ; preds = %if.end4 for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry call void @x(ptr noundef nonnull %bar_arr) - call void @llvm.lifetime.end.p0(ptr nonnull %bar_arr) #4 - call void @llvm.lifetime.end.p0(ptr nonnull %foo_arr) #4 ret void for.body: ; preds = %for.body.preheader, %if.end4 %i.015 = phi i32 [ %inc, %if.end4 ], [ 0, %for.body.preheader ] - %cmp1 = icmp samesign ugt i32 %i.015, 1023 + %cmp1 = icmp samesign ugt i32 %i.015, 2 br i1 %cmp1, label %if.then, label %if.end4 if.then: ; preds = %for.body @@ -321,11 +281,10 @@ if.then: ; preds = %for.body unreachable if.end4: ; preds = %for.body - %idxprom = zext nneg i32 %i.015 to i64 - %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i64 %idxprom + %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i32 %i.015 %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 %1 = xor i8 %0, 54 - %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i64 %idxprom + %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i32 %i.015 call void @x(ptr null) store volatile i8 %1, ptr %arrayidx7, align 1, !tbaa !5 %inc = add nuw nsw i32 %i.015, 1 @@ -333,51 +292,44 @@ if.end4: ; preds = %for.body br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 } -define dso_local void @foo_ubsan(i32 noundef %block_size) local_unnamed_addr #0 { -; CHECK-LABEL: define dso_local void @foo_ubsan( +define dso_local void @can_optimize_ubsan_trap(i32 noundef %block_size) local_unnamed_addr #0 { +; CHECK-LABEL: define dso_local void @can_optimize_ubsan_trap( ; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { ; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [1024 x i8], align 16 -; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [1025 x i8], align 16 -; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] -; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [2 x i8], align 16 +; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [2 x i8], align 16 ; CHECK-NEXT: call void @x(ptr noundef nonnull [[FOO_ARR]]) ; CHECK-NEXT: [[CMP14_NOT:%.*]] = icmp eq i32 [[BLOCK_SIZE]], 0 ; CHECK-NEXT: br i1 [[CMP14_NOT]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY_PREHEADER:.*]] ; CHECK: [[FOR_BODY_PREHEADER]]: -; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[BLOCK_SIZE]] to i64 ; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[BLOCK_SIZE]], -1 -; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 1024) -; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 1024, [[UMIN]] +; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP1]], i32 3) +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 3, [[UMIN]] ; CHECK-NEXT: br label %[[FOR_BODY:.*]] ; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]: ; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] ; CHECK: [[FOR_COND_CLEANUP]]: ; CHECK-NEXT: call void @x(ptr noundef nonnull [[BAR_ARR]]) -; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] -; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] ; CHECK-NEXT: ret void ; CHECK: [[FOR_BODY]]: -; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: [[I_015:%.*]] = phi i32 [ [[INC:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] ; CHECK-NEXT: br i1 [[TMP2]], label %[[IF_THEN:.*]], label %[[IF_END4]] ; CHECK: [[IF_THEN]]: ; CHECK-NEXT: call void @llvm.ubsantrap(i8 1) ; CHECK-NEXT: unreachable ; CHECK: [[IF_END4]]: -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i64 [[INDVARS_IV]] -; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA5]] +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA4]] ; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 -; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i64 [[INDVARS_IV]] -; CHECK-NEXT: store i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA5]] -; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 -; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], [[TMP0]] -; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP8]] +; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: store i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_015]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INC]], [[BLOCK_SIZE]] +; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP7]] ; entry: - %foo_arr = alloca [1024 x i8], align 16 - %bar_arr = alloca [1025 x i8], align 16 - call void @llvm.lifetime.start.p0(ptr nonnull %foo_arr) #4 - call void @llvm.lifetime.start.p0(ptr nonnull %bar_arr) #4 + %foo_arr = alloca [2 x i8], align 16 + %bar_arr = alloca [2 x i8], align 16 call void @x(ptr noundef nonnull %foo_arr) %cmp14.not = icmp eq i32 %block_size, 0 br i1 %cmp14.not, label %for.cond.cleanup, label %for.body.preheader @@ -390,13 +342,11 @@ for.cond.cleanup.loopexit: ; preds = %if.end4 for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry call void @x(ptr noundef nonnull %bar_arr) - call void @llvm.lifetime.end.p0(ptr nonnull %bar_arr) #4 - call void @llvm.lifetime.end.p0(ptr nonnull %foo_arr) #4 ret void for.body: ; preds = %for.body.preheader, %if.end4 %i.015 = phi i32 [ %inc, %if.end4 ], [ 0, %for.body.preheader ] - %cmp1 = icmp samesign ugt i32 %i.015, 1023 + %cmp1 = icmp samesign ugt i32 %i.015, 2 br i1 %cmp1, label %if.then, label %if.end4 if.then: ; preds = %for.body @@ -404,60 +354,52 @@ if.then: ; preds = %for.body unreachable if.end4: ; preds = %for.body - %idxprom = zext nneg i32 %i.015 to i64 - %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i64 %idxprom + %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i32 %i.015 %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 %1 = xor i8 %0, 54 - %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i64 %idxprom + %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i32 %i.015 store i8 %1, ptr %arrayidx7, align 1, !tbaa !5 %inc = add nuw nsw i32 %i.015, 1 %cmp = icmp ult i32 %inc, %block_size br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 } -define dso_local void @foo_randomcall(i32 noundef %block_size) local_unnamed_addr #0 { -; CHECK-LABEL: define dso_local void @foo_randomcall( +define dso_local void @cannot_optimize_arbitrary_call(i32 noundef %block_size) local_unnamed_addr #0 { +; CHECK-LABEL: define dso_local void @cannot_optimize_arbitrary_call( ; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { ; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [1024 x i8], align 16 -; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [1025 x i8], align 16 -; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] -; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] +; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [2 x i8], align 16 +; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [2 x i8], align 16 ; CHECK-NEXT: call void @x(ptr noundef nonnull [[FOO_ARR]]) ; CHECK-NEXT: [[CMP14_NOT:%.*]] = icmp eq i32 [[BLOCK_SIZE]], 0 ; CHECK-NEXT: br i1 [[CMP14_NOT]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY_PREHEADER:.*]] ; CHECK: [[FOR_BODY_PREHEADER]]: -; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[BLOCK_SIZE]] to i64 ; CHECK-NEXT: br label %[[FOR_BODY:.*]] ; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]: ; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] ; CHECK: [[FOR_COND_CLEANUP]]: ; CHECK-NEXT: call void @x(ptr noundef nonnull [[BAR_ARR]]) -; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[BAR_ARR]]) #[[ATTR6]] -; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[FOO_ARR]]) #[[ATTR6]] ; CHECK-NEXT: ret void ; CHECK: [[FOR_BODY]]: -; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] -; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp eq i64 [[INDVARS_IV]], 1024 -; CHECK-NEXT: br i1 [[EXITCOND1]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK-NEXT: [[I_015:%.*]] = phi i32 [ [[INC:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[I_015]], 3 +; CHECK-NEXT: br i1 [[EXITCOND]], label %[[IF_THEN:.*]], label %[[IF_END4]] ; CHECK: [[IF_THEN]]: ; CHECK-NEXT: call void @noreturn(ptr [[FOO_ARR]]) ; CHECK-NEXT: unreachable ; CHECK: [[IF_END4]]: -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i64 [[INDVARS_IV]] -; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA5]] +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA4]] ; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 -; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i64 [[INDVARS_IV]] -; CHECK-NEXT: store i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA5]] -; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 -; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], [[TMP0]] -; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP8]] +; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: store i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_015]], 1 +; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[INC]], [[BLOCK_SIZE]] +; CHECK-NEXT: br i1 [[EXITCOND1]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP7]] ; entry: - %foo_arr = alloca [1024 x i8], align 16 - %bar_arr = alloca [1025 x i8], align 16 - call void @llvm.lifetime.start.p0(ptr nonnull %foo_arr) #4 - call void @llvm.lifetime.start.p0(ptr nonnull %bar_arr) #4 + %foo_arr = alloca [2 x i8], align 16 + %bar_arr = alloca [2 x i8], align 16 call void @x(ptr noundef nonnull %foo_arr) %cmp14.not = icmp eq i32 %block_size, 0 br i1 %cmp14.not, label %for.cond.cleanup, label %for.body.preheader @@ -470,13 +412,11 @@ for.cond.cleanup.loopexit: ; preds = %if.end4 for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry call void @x(ptr noundef nonnull %bar_arr) - call void @llvm.lifetime.end.p0(ptr nonnull %bar_arr) #4 - call void @llvm.lifetime.end.p0(ptr nonnull %foo_arr) #4 ret void for.body: ; preds = %for.body.preheader, %if.end4 %i.015 = phi i32 [ %inc, %if.end4 ], [ 0, %for.body.preheader ] - %cmp1 = icmp samesign ugt i32 %i.015, 1023 + %cmp1 = icmp samesign ugt i32 %i.015, 2 br i1 %cmp1, label %if.then, label %if.end4 if.then: ; preds = %for.body @@ -484,53 +424,42 @@ if.then: ; preds = %for.body unreachable if.end4: ; preds = %for.body - %idxprom = zext nneg i32 %i.015 to i64 - %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i64 %idxprom + %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i32 %i.015 %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 %1 = xor i8 %0, 54 - %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i64 %idxprom + %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i32 %i.015 store i8 %1, ptr %arrayidx7, align 1, !tbaa !5 %inc = add nuw nsw i32 %i.015, 1 %cmp = icmp ult i32 %inc, %block_size br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 } -; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) -declare void @llvm.lifetime.start.p0(ptr captures(none)) #1 - -declare void @x(ptr noundef) local_unnamed_addr #2 +declare void @x(ptr noundef) local_unnamed_addr ; Function Attrs: cold noreturn nounwind memory(inaccessiblemem: write) -declare void @llvm.trap() #3 - -declare void @noreturn(ptr) #3 - -; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) -declare void @llvm.lifetime.end.p0(ptr captures(none)) #1 +declare void @llvm.trap() #2 +declare void @noreturn(ptr) #2 -attributes #0 = { mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #0 = { mustprogress } attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } -attributes #2 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } -attributes #3 = { cold noreturn nounwind memory(inaccessiblemem: write) } -attributes #4 = { nounwind } +attributes #2 = { cold noreturn nounwind memory(inaccessiblemem: write) } +attributes #3 = { nounwind } !llvm.module.flags = !{!0, !1, !2, !3} -!llvm.ident = !{!4} !0 = !{i32 1, !"wchar_size", i32 4} !1 = !{i32 8, !"PIC Level", i32 2} !2 = !{i32 7, !"PIE Level", i32 2} !3 = !{i32 7, !"uwtable", i32 2} -!4 = !{!"clang version 22.0.0git (/usr/local/google/home/fmayer/large/llvm-project/clang 9bebffa6127aff780f20cc05694c31230580d4ff)"} !5 = !{!6, !6, i64 0} !6 = !{!"omnipotent char", !7, i64 0} !7 = !{!"Simple C++ TBAA"} !8 = distinct !{!8, !9} !9 = !{!"llvm.loop.mustprogress"} ;. -; CHECK: [[TBAA5]] = !{[[META6:![0-9]+]], [[META6]], i64 0} -; CHECK: [[META6]] = !{!"omnipotent char", [[META7:![0-9]+]], i64 0} -; CHECK: [[META7]] = !{!"Simple C++ TBAA"} -; CHECK: [[LOOP8]] = distinct !{[[LOOP8]], [[META9:![0-9]+]]} -; CHECK: [[META9]] = !{!"llvm.loop.mustprogress"} +; CHECK: [[TBAA4]] = !{[[META5:![0-9]+]], [[META5]], i64 0} +; CHECK: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0} +; CHECK: [[META6]] = !{!"Simple C++ TBAA"} +; CHECK: [[LOOP7]] = distinct !{[[LOOP7]], [[META8:![0-9]+]]} +; CHECK: [[META8]] = !{!"llvm.loop.mustprogress"} ;. From f1d9f8e1f5c9c236c45f83e20cc644d280990523 Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Wed, 17 Sep 2025 12:54:57 -0700 Subject: [PATCH 10/14] fixup Created using spr 1.3.4 --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp index f121beb7f6aa9..ca2a73c54916c 100644 --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -1884,7 +1884,7 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) { if (!I.mayHaveSideEffects()) return false; if (auto *CB = dyn_cast(&I)) { - if (CB->onlyAccessesInaccessibleMemOrArgMem() && + if (CB->onlyAccessesInaccessibleMemory() && llvm::all_of(CB->args(), [](const llvm::Use &U) { return isa(U.get()); })) From 7f6c0449e245ddc1c7aabbaafbe16fed683a870c Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Mon, 22 Sep 2025 19:56:03 -0700 Subject: [PATCH 11/14] fmt Created using spr 1.3.4 --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp index a2b2331c089f8..ceb1acdb72675 100644 --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -1852,8 +1852,9 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) { HasThreadLocalSideEffects = true; if (StoreInst *SI = dyn_cast(&I)) { // Simple stores cannot be observed by other threads. - // If HasThreadLocalSideEffects is set, we check crashingBBWithoutEffect - // to make sure that the crashing BB cannot observe them either. + // If HasThreadLocalSideEffects is set, we check + // crashingBBWithoutEffect to make sure that the crashing BB cannot + // observe them either. if (!SI->isSimple()) return false; } else { From 0aaf4d3349e802d97ef6dd6afdea04d6dab0145c Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Tue, 23 Sep 2025 14:29:20 -0700 Subject: [PATCH 12/14] review comments Created using spr 1.3.4 --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 6 +- .../ScalarEvolution/unreachable-exit.ll | 396 +++++++++++++----- 2 files changed, 300 insertions(+), 102 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp index ceb1acdb72675..d6eb49e4fdc90 100644 --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -1882,19 +1882,15 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) { auto *BI = cast(ExitingBB->getTerminator()); if (HasThreadLocalSideEffects) { const BasicBlock *Unreachable = nullptr; - const BasicBlock *InLoop = nullptr; for (const BasicBlock *Succ : BI->successors()) { if (isa(Succ->getTerminator())) Unreachable = Succ; - else if (L->contains(Succ)) - InLoop = Succ; } // Exit BB which have one branch back into the loop and another one to // a trap can still be optimized, because local side effects cannot // be observed in the exit case (the trap). We could be smarter about // this, but for now lets pattern match common cases that directly trap. - if (Unreachable == nullptr || InLoop == nullptr || - !crashingBBWithoutEffect(*Unreachable)) + if (Unreachable == nullptr || !crashingBBWithoutEffect(*Unreachable)) return Changed; } Value *NewCond; diff --git a/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll b/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll index c2746506267b7..1736c4160b3f8 100644 --- a/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll +++ b/llvm/test/Analysis/ScalarEvolution/unreachable-exit.ll @@ -1,13 +1,10 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt -S -passes=indvars < %s | FileCheck %s -source_filename = "/usr/local/google/home/fmayer/loop/src3.cc" -target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" - ; Function Attrs: mustprogress uwtable -define dso_local void @can_optimize_trap(i32 noundef %block_size) local_unnamed_addr #0 { -; CHECK-LABEL: define dso_local void @can_optimize_trap( -; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +define dso_local void @optimize_trap(i32 noundef %block_size) local_unnamed_addr { +; CHECK-LABEL: define dso_local void @optimize_trap( +; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [2 x i8], align 16 ; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [2 x i8], align 16 @@ -32,13 +29,13 @@ define dso_local void @can_optimize_trap(i32 noundef %block_size) local_unnamed_ ; CHECK-NEXT: unreachable ; CHECK: [[IF_END4]]: ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] -; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA4:![0-9]+]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1 ; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 ; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i32 [[I_015]] -; CHECK-NEXT: store i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: store i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1 ; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_015]], 1 -; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INC]], [[BLOCK_SIZE]] -; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP7:![0-9]+]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[INC]], [[BLOCK_SIZE]] +; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]] ; entry: %foo_arr = alloca [2 x i8], align 16 @@ -68,19 +65,19 @@ if.then: ; preds = %for.body if.end4: ; preds = %for.body %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i32 %i.015 - %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 + %0 = load i8, ptr %arrayidx, align 1 %1 = xor i8 %0, 54 %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i32 %i.015 - store i8 %1, ptr %arrayidx7, align 1, !tbaa !5 + store i8 %1, ptr %arrayidx7, align 1 %inc = add nuw nsw i32 %i.015, 1 %cmp = icmp ult i32 %inc, %block_size - br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 + br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit } ; Function Attrs: mustprogress uwtable -define dso_local void @cannot_optimize_atomic(i32 noundef %block_size) local_unnamed_addr #0 { -; CHECK-LABEL: define dso_local void @cannot_optimize_atomic( -; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { +define dso_local void @no_optimize_atomic(i32 noundef %block_size) local_unnamed_addr { +; CHECK-LABEL: define dso_local void @no_optimize_atomic( +; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [2 x i8], align 16 ; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [2 x i8], align 16 @@ -96,20 +93,20 @@ define dso_local void @cannot_optimize_atomic(i32 noundef %block_size) local_unn ; CHECK-NEXT: ret void ; CHECK: [[FOR_BODY]]: ; CHECK-NEXT: [[I_015:%.*]] = phi i32 [ [[INC:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] -; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[I_015]], 3 -; CHECK-NEXT: br i1 [[EXITCOND]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp samesign ugt i32 [[I_015]], 2 +; CHECK-NEXT: br i1 [[CMP1]], label %[[IF_THEN:.*]], label %[[IF_END4]] ; CHECK: [[IF_THEN]]: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; CHECK: [[IF_END4]]: ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] -; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1 ; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 ; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i32 [[I_015]] -; CHECK-NEXT: store atomic i8 [[TMP4]], ptr [[ARRAYIDX7]] unordered, align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: store atomic i8 [[TMP4]], ptr [[ARRAYIDX7]] unordered, align 1 ; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_015]], 1 -; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[INC]], [[BLOCK_SIZE]] -; CHECK-NEXT: br i1 [[EXITCOND1]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP7]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[INC]], [[BLOCK_SIZE]] +; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]] ; entry: %foo_arr = alloca [2 x i8], align 16 @@ -139,19 +136,19 @@ if.then: ; preds = %for.body if.end4: ; preds = %for.body %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i32 %i.015 - %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 + %0 = load i8, ptr %arrayidx, align 1 %1 = xor i8 %0, 54 %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i32 %i.015 - store atomic i8 %1, ptr %arrayidx7 unordered, align 1, !tbaa !5 + store atomic i8 %1, ptr %arrayidx7 unordered, align 1 %inc = add nuw nsw i32 %i.015, 1 %cmp = icmp ult i32 %inc, %block_size - br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 + br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit } ; Function Attrs: mustprogress uwtable -define dso_local void @cannot_optimize_volatile(i32 noundef %block_size) local_unnamed_addr #0 { -; CHECK-LABEL: define dso_local void @cannot_optimize_volatile( -; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { +define dso_local void @no_optimize_volatile(i32 noundef %block_size) local_unnamed_addr { +; CHECK-LABEL: define dso_local void @no_optimize_volatile( +; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [2 x i8], align 16 ; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [2 x i8], align 16 @@ -167,20 +164,20 @@ define dso_local void @cannot_optimize_volatile(i32 noundef %block_size) local_u ; CHECK-NEXT: ret void ; CHECK: [[FOR_BODY]]: ; CHECK-NEXT: [[I_015:%.*]] = phi i32 [ [[INC:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] -; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[I_015]], 3 -; CHECK-NEXT: br i1 [[EXITCOND]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp samesign ugt i32 [[I_015]], 2 +; CHECK-NEXT: br i1 [[CMP1]], label %[[IF_THEN:.*]], label %[[IF_END4]] ; CHECK: [[IF_THEN]]: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; CHECK: [[IF_END4]]: ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] -; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1 ; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 ; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i32 [[I_015]] -; CHECK-NEXT: store volatile i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: store volatile i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1 ; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_015]], 1 -; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[INC]], [[BLOCK_SIZE]] -; CHECK-NEXT: br i1 [[EXITCOND1]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP7]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[INC]], [[BLOCK_SIZE]] +; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]] ; entry: %foo_arr = alloca [2 x i8], align 16 @@ -210,19 +207,19 @@ if.then: ; preds = %for.body if.end4: ; preds = %for.body %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i32 %i.015 - %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 + %0 = load i8, ptr %arrayidx, align 1 %1 = xor i8 %0, 54 %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i32 %i.015 - store volatile i8 %1, ptr %arrayidx7, align 1, !tbaa !5 + store volatile i8 %1, ptr %arrayidx7, align 1 %inc = add nuw nsw i32 %i.015, 1 %cmp = icmp ult i32 %inc, %block_size - br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 + br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit } ; Function Attrs: mustprogress uwtable -define dso_local void @cannot_optimize_call(i32 noundef %block_size) local_unnamed_addr #0 { -; CHECK-LABEL: define dso_local void @cannot_optimize_call( -; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { +define dso_local void @no_optimize_call(i32 noundef %block_size) local_unnamed_addr { +; CHECK-LABEL: define dso_local void @no_optimize_call( +; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [2 x i8], align 16 ; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [2 x i8], align 16 @@ -238,21 +235,21 @@ define dso_local void @cannot_optimize_call(i32 noundef %block_size) local_unnam ; CHECK-NEXT: ret void ; CHECK: [[FOR_BODY]]: ; CHECK-NEXT: [[I_015:%.*]] = phi i32 [ [[INC:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] -; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[I_015]], 3 -; CHECK-NEXT: br i1 [[EXITCOND]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp samesign ugt i32 [[I_015]], 2 +; CHECK-NEXT: br i1 [[CMP1]], label %[[IF_THEN:.*]], label %[[IF_END4]] ; CHECK: [[IF_THEN]]: ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; CHECK: [[IF_END4]]: ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] -; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1 ; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 ; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i32 [[I_015]] ; CHECK-NEXT: call void @x(ptr null) -; CHECK-NEXT: store volatile i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: store volatile i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1 ; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_015]], 1 -; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[INC]], [[BLOCK_SIZE]] -; CHECK-NEXT: br i1 [[EXITCOND1]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP7]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[INC]], [[BLOCK_SIZE]] +; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]] ; entry: %foo_arr = alloca [2 x i8], align 16 @@ -282,19 +279,19 @@ if.then: ; preds = %for.body if.end4: ; preds = %for.body %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i32 %i.015 - %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 + %0 = load i8, ptr %arrayidx, align 1 %1 = xor i8 %0, 54 %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i32 %i.015 call void @x(ptr null) - store volatile i8 %1, ptr %arrayidx7, align 1, !tbaa !5 + store volatile i8 %1, ptr %arrayidx7, align 1 %inc = add nuw nsw i32 %i.015, 1 %cmp = icmp ult i32 %inc, %block_size - br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 + br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit } -define dso_local void @can_optimize_ubsan_trap(i32 noundef %block_size) local_unnamed_addr #0 { -; CHECK-LABEL: define dso_local void @can_optimize_ubsan_trap( -; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { +define dso_local void @optimize_ubsan_trap(i32 noundef %block_size) local_unnamed_addr { +; CHECK-LABEL: define dso_local void @optimize_ubsan_trap( +; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [2 x i8], align 16 ; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [2 x i8], align 16 @@ -319,13 +316,13 @@ define dso_local void @can_optimize_ubsan_trap(i32 noundef %block_size) local_un ; CHECK-NEXT: unreachable ; CHECK: [[IF_END4]]: ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] -; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1 ; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 ; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i32 [[I_015]] -; CHECK-NEXT: store i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: store i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1 ; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_015]], 1 -; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INC]], [[BLOCK_SIZE]] -; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP7]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[INC]], [[BLOCK_SIZE]] +; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]] ; entry: %foo_arr = alloca [2 x i8], align 16 @@ -355,18 +352,18 @@ if.then: ; preds = %for.body if.end4: ; preds = %for.body %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i32 %i.015 - %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 + %0 = load i8, ptr %arrayidx, align 1 %1 = xor i8 %0, 54 %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i32 %i.015 - store i8 %1, ptr %arrayidx7, align 1, !tbaa !5 + store i8 %1, ptr %arrayidx7, align 1 %inc = add nuw nsw i32 %i.015, 1 %cmp = icmp ult i32 %inc, %block_size - br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 + br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit } -define dso_local void @cannot_optimize_arbitrary_call(i32 noundef %block_size) local_unnamed_addr #0 { -; CHECK-LABEL: define dso_local void @cannot_optimize_arbitrary_call( -; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] { +define dso_local void @no_optimize_arbitrary_call(i32 noundef %block_size) local_unnamed_addr { +; CHECK-LABEL: define dso_local void @no_optimize_arbitrary_call( +; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [2 x i8], align 16 ; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [2 x i8], align 16 @@ -382,20 +379,20 @@ define dso_local void @cannot_optimize_arbitrary_call(i32 noundef %block_size) l ; CHECK-NEXT: ret void ; CHECK: [[FOR_BODY]]: ; CHECK-NEXT: [[I_015:%.*]] = phi i32 [ [[INC:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] -; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[I_015]], 3 -; CHECK-NEXT: br i1 [[EXITCOND]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp samesign ugt i32 [[I_015]], 2 +; CHECK-NEXT: br i1 [[CMP1]], label %[[IF_THEN:.*]], label %[[IF_END4]] ; CHECK: [[IF_THEN]]: ; CHECK-NEXT: call void @noreturn(ptr [[FOO_ARR]]) ; CHECK-NEXT: unreachable ; CHECK: [[IF_END4]]: ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] -; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: [[TMP3:%.*]] = load i8, ptr [[ARRAYIDX]], align 1 ; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[TMP3]], 54 ; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i32 [[I_015]] -; CHECK-NEXT: store i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1, !tbaa [[TBAA4]] +; CHECK-NEXT: store i8 [[TMP4]], ptr [[ARRAYIDX7]], align 1 ; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_015]], 1 -; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[INC]], [[BLOCK_SIZE]] -; CHECK-NEXT: br i1 [[EXITCOND1]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]], !llvm.loop [[LOOP7]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[INC]], [[BLOCK_SIZE]] +; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]] ; entry: %foo_arr = alloca [2 x i8], align 16 @@ -425,41 +422,246 @@ if.then: ; preds = %for.body if.end4: ; preds = %for.body %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i32 %i.015 - %0 = load i8, ptr %arrayidx, align 1, !tbaa !5 + %0 = load i8, ptr %arrayidx, align 1 + %1 = xor i8 %0, 54 + %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i32 %i.015 + store i8 %1, ptr %arrayidx7, align 1 + %inc = add nuw nsw i32 %i.015, 1 + %cmp = icmp ult i32 %inc, %block_size + br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit +} + +define dso_local void @no_optimize_two_exits(i32 noundef %block_size) local_unnamed_addr { +; CHECK-LABEL: define dso_local void @no_optimize_two_exits( +; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [2 x i8], align 16 +; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [2 x i8], align 16 +; CHECK-NEXT: call void @x(ptr noundef nonnull [[FOO_ARR]]) +; CHECK-NEXT: [[CMP14_NOT:%.*]] = icmp eq i32 [[BLOCK_SIZE]], 0 +; CHECK-NEXT: br i1 [[CMP14_NOT]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY_PREHEADER:.*]] +; CHECK: [[FOR_BODY_PREHEADER]]: +; CHECK-NEXT: br label %[[FOR_BODY:.*]] +; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]: +; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] +; CHECK: [[FOR_COND_CLEANUP]]: +; CHECK-NEXT: call void @x(ptr noundef nonnull [[BAR_ARR]]) +; CHECK-NEXT: ret void +; CHECK: [[FOR_BODY]]: +; CHECK-NEXT: [[I_015:%.*]] = phi i32 [ [[INC:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: [[P:%.*]] = call i1 @pred() +; CHECK-NEXT: br i1 [[P]], label %[[FOR_BODY_CONT:.*]], label %[[FOR_COND_CLEANUP_LOOPEXIT]] +; CHECK: [[FOR_BODY_CONT]]: +; CHECK-NEXT: [[CMP1:%.*]] = icmp samesign ugt i32 [[I_015]], 2 +; CHECK-NEXT: br i1 [[CMP1]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: call void @noreturn(ptr [[FOO_ARR]]) +; CHECK-NEXT: unreachable +; CHECK: [[IF_END4]]: +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[ARRAYIDX]], align 1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[TMP0]], 54 +; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: store i8 [[TMP1]], ptr [[ARRAYIDX7]], align 1 +; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_015]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[INC]], [[BLOCK_SIZE]] +; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]] +; +entry: + %foo_arr = alloca [2 x i8], align 16 + %bar_arr = alloca [2 x i8], align 16 + call void @x(ptr noundef nonnull %foo_arr) + %cmp14.not = icmp eq i32 %block_size, 0 + br i1 %cmp14.not, label %for.cond.cleanup, label %for.body.preheader + +for.body.preheader: ; preds = %entry + br label %for.body + +for.cond.cleanup.loopexit: ; preds = %if.end4 + br label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry + call void @x(ptr noundef nonnull %bar_arr) + ret void + +for.body: + %i.015 = phi i32 [ %inc, %if.end4 ], [ 0, %for.body.preheader ] + %p = call i1 @pred() + br i1 %p, label %for.body.cont, label %for.cond.cleanup.loopexit + +for.body.cont: ; preds = %for.body.preheader, %if.end4 + %cmp1 = icmp samesign ugt i32 %i.015, 2 + br i1 %cmp1, label %if.then, label %if.end4 + +if.then: ; preds = %for.body + call void @noreturn(ptr %foo_arr) + unreachable + +if.end4: ; preds = %for.body + %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i32 %i.015 + %0 = load i8, ptr %arrayidx, align 1 + %1 = xor i8 %0, 54 + %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i32 %i.015 + store i8 %1, ptr %arrayidx7, align 1 + %inc = add nuw nsw i32 %i.015, 1 + %cmp = icmp ult i32 %inc, %block_size + br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit +} + +define dso_local void @no_optimize_two_exits2(i32 noundef %block_size) local_unnamed_addr { +; CHECK-LABEL: define dso_local void @no_optimize_two_exits2( +; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [2 x i8], align 16 +; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [2 x i8], align 16 +; CHECK-NEXT: call void @x(ptr noundef nonnull [[FOO_ARR]]) +; CHECK-NEXT: [[CMP14_NOT:%.*]] = icmp eq i32 [[BLOCK_SIZE]], 0 +; CHECK-NEXT: br i1 [[CMP14_NOT]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY_PREHEADER:.*]] +; CHECK: [[FOR_BODY_PREHEADER]]: +; CHECK-NEXT: br label %[[FOR_BODY:.*]] +; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]: +; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] +; CHECK: [[FOR_COND_CLEANUP]]: +; CHECK-NEXT: call void @x(ptr noundef nonnull [[BAR_ARR]]) +; CHECK-NEXT: ret void +; CHECK: [[FOR_BODY]]: +; CHECK-NEXT: [[I_015:%.*]] = phi i32 [ [[INC:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: [[CMP1:%.*]] = icmp samesign ugt i32 [[I_015]], 2 +; CHECK-NEXT: br i1 [[CMP1]], label %[[IF_THEN:.*]], label %[[FOR_BODY_CONT:.*]] +; CHECK: [[FOR_BODY_CONT]]: +; CHECK-NEXT: [[P:%.*]] = call i1 @pred() +; CHECK-NEXT: br i1 [[P]], label %[[IF_END4]], label %[[FOR_COND_CLEANUP_LOOPEXIT]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: call void @noreturn(ptr [[FOO_ARR]]) +; CHECK-NEXT: unreachable +; CHECK: [[IF_END4]]: +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[ARRAYIDX]], align 1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[TMP0]], 54 +; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: store i8 [[TMP1]], ptr [[ARRAYIDX7]], align 1 +; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_015]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[INC]], [[BLOCK_SIZE]] +; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]] +; +entry: + %foo_arr = alloca [2 x i8], align 16 + %bar_arr = alloca [2 x i8], align 16 + call void @x(ptr noundef nonnull %foo_arr) + %cmp14.not = icmp eq i32 %block_size, 0 + br i1 %cmp14.not, label %for.cond.cleanup, label %for.body.preheader + +for.body.preheader: ; preds = %entry + br label %for.body + +for.cond.cleanup.loopexit: ; preds = %if.end4 + br label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry + call void @x(ptr noundef nonnull %bar_arr) + ret void + +for.body: + %i.015 = phi i32 [ %inc, %if.end4 ], [ 0, %for.body.preheader ] + %cmp1 = icmp samesign ugt i32 %i.015, 2 + br i1 %cmp1, label %if.then, label %for.body.cont + +for.body.cont: ; preds = %for.body.preheader, %if.end4 + %p = call i1 @pred() + br i1 %p, label %if.end4, label %for.cond.cleanup.loopexit + +if.then: ; preds = %for.body + call void @noreturn(ptr %foo_arr) + unreachable + +if.end4: ; preds = %for.body + %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i32 %i.015 + %0 = load i8, ptr %arrayidx, align 1 %1 = xor i8 %0, 54 %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i32 %i.015 - store i8 %1, ptr %arrayidx7, align 1, !tbaa !5 + store i8 %1, ptr %arrayidx7, align 1 %inc = add nuw nsw i32 %i.015, 1 %cmp = icmp ult i32 %inc, %block_size - br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit, !llvm.loop !8 + br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit +} + +define dso_local void @no_optimize_depdendent_ubsan_trap(i32 noundef %block_size) local_unnamed_addr { +; CHECK-LABEL: define dso_local void @no_optimize_depdendent_ubsan_trap( +; CHECK-SAME: i32 noundef [[BLOCK_SIZE:%.*]]) local_unnamed_addr { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [2 x i8], align 16 +; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [2 x i8], align 16 +; CHECK-NEXT: call void @x(ptr noundef nonnull [[FOO_ARR]]) +; CHECK-NEXT: [[CMP14_NOT:%.*]] = icmp eq i32 [[BLOCK_SIZE]], 0 +; CHECK-NEXT: br i1 [[CMP14_NOT]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY_PREHEADER:.*]] +; CHECK: [[FOR_BODY_PREHEADER]]: +; CHECK-NEXT: br label %[[FOR_BODY:.*]] +; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]: +; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] +; CHECK: [[FOR_COND_CLEANUP]]: +; CHECK-NEXT: call void @x(ptr noundef nonnull [[BAR_ARR]]) +; CHECK-NEXT: ret void +; CHECK: [[FOR_BODY]]: +; CHECK-NEXT: [[I_015:%.*]] = phi i32 [ [[INC:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: [[CMP1:%.*]] = icmp samesign ugt i32 [[I_015]], 2 +; CHECK-NEXT: br i1 [[CMP1]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: [[I_015_LCSSA:%.*]] = phi i32 [ [[I_015]], %[[FOR_BODY]] ] +; CHECK-NEXT: call void @noreturn_with_i32(i32 [[I_015_LCSSA]]) +; CHECK-NEXT: unreachable +; CHECK: [[IF_END4]]: +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[ARRAYIDX]], align 1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[TMP0]], 54 +; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: store i8 [[TMP1]], ptr [[ARRAYIDX7]], align 1 +; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_015]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[INC]], [[BLOCK_SIZE]] +; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]] +; +entry: + %foo_arr = alloca [2 x i8], align 16 + %bar_arr = alloca [2 x i8], align 16 + call void @x(ptr noundef nonnull %foo_arr) + %cmp14.not = icmp eq i32 %block_size, 0 + br i1 %cmp14.not, label %for.cond.cleanup, label %for.body.preheader + +for.body.preheader: ; preds = %entry + br label %for.body + +for.cond.cleanup.loopexit: ; preds = %if.end4 + br label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry + call void @x(ptr noundef nonnull %bar_arr) + ret void + +for.body: ; preds = %for.body.preheader, %if.end4 + %i.015 = phi i32 [ %inc, %if.end4 ], [ 0, %for.body.preheader ] + %cmp1 = icmp samesign ugt i32 %i.015, 2 + br i1 %cmp1, label %if.then, label %if.end4 + +if.then: ; preds = %for.body + call void @noreturn_with_i32(i32 %i.015) + unreachable + +if.end4: ; preds = %for.body + %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i32 %i.015 + %0 = load i8, ptr %arrayidx, align 1 + %1 = xor i8 %0, 54 + %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i32 %i.015 + store i8 %1, ptr %arrayidx7, align 1 + %inc = add nuw nsw i32 %i.015, 1 + %cmp = icmp ult i32 %inc, %block_size + br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit } declare void @x(ptr noundef) local_unnamed_addr +declare i1 @pred() local_unnamed_addr ; Function Attrs: cold noreturn nounwind memory(inaccessiblemem: write) -declare void @llvm.trap() #2 -declare void @noreturn(ptr) #2 - -attributes #0 = { mustprogress } -attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } -attributes #2 = { cold noreturn nounwind memory(inaccessiblemem: write) } -attributes #3 = { nounwind } - -!llvm.module.flags = !{!0, !1, !2, !3} - -!0 = !{i32 1, !"wchar_size", i32 4} -!1 = !{i32 8, !"PIC Level", i32 2} -!2 = !{i32 7, !"PIE Level", i32 2} -!3 = !{i32 7, !"uwtable", i32 2} -!5 = !{!6, !6, i64 0} -!6 = !{!"omnipotent char", !7, i64 0} -!7 = !{!"Simple C++ TBAA"} -!8 = distinct !{!8, !9} -!9 = !{!"llvm.loop.mustprogress"} -;. -; CHECK: [[TBAA4]] = !{[[META5:![0-9]+]], [[META5]], i64 0} -; CHECK: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0} -; CHECK: [[META6]] = !{!"Simple C++ TBAA"} -; CHECK: [[LOOP7]] = distinct !{[[LOOP7]], [[META8:![0-9]+]]} -; CHECK: [[META8]] = !{!"llvm.loop.mustprogress"} -;. +declare void @llvm.trap() #0 +declare void @noreturn(ptr) #0 +declare void @noreturn_with_i32(i32) #0 + +attributes #0 = { cold noreturn nounwind memory(inaccessiblemem: write) } From 97ab69d53cb531f191056dce266c642cf674fa73 Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Mon, 13 Oct 2025 15:36:40 -0700 Subject: [PATCH 13/14] test update Created using spr 1.3.7 --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 5 +- .../IndVarSimplify/unreachable-exit.ll | 80 ++++++++++++++++++- 2 files changed, 79 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp index d6eb49e4fdc90..7ebcc219efc15 100644 --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -1720,10 +1720,7 @@ static bool crashingBBWithoutEffect(const BasicBlock &BB) { // Now if the loop stored a non-nullptr to %a, we could cause a nullptr // dereference by skipping over loop iterations. if (const auto *CB = dyn_cast(&I)) { - if (CB->onlyAccessesInaccessibleMemory() && - llvm::all_of(CB->args(), [](const llvm::Use &U) { - return isa(U.get()); - })) + if (CB->onlyAccessesInaccessibleMemory()) return true; } return isa(I); diff --git a/llvm/test/Transforms/IndVarSimplify/unreachable-exit.ll b/llvm/test/Transforms/IndVarSimplify/unreachable-exit.ll index ed91d4c87a658..d4822bf98b70e 100644 --- a/llvm/test/Transforms/IndVarSimplify/unreachable-exit.ll +++ b/llvm/test/Transforms/IndVarSimplify/unreachable-exit.ll @@ -382,7 +382,7 @@ define void @no_optimize_arbitrary_call(i32 %block_size) { ; CHECK-NEXT: [[CMP1:%.*]] = icmp samesign ugt i32 [[I_015]], 2 ; CHECK-NEXT: br i1 [[CMP1]], label %[[IF_THEN:.*]], label %[[IF_END4]] ; CHECK: [[IF_THEN]]: -; CHECK-NEXT: call void @noreturn(ptr [[FOO_ARR]]) +; CHECK-NEXT: call void @noreturn_with_argmem(ptr [[FOO_ARR]]) ; CHECK-NEXT: unreachable ; CHECK: [[IF_END4]]: ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] @@ -417,7 +417,7 @@ for.body: ; preds = %for.body.preheader, br i1 %cmp1, label %if.then, label %if.end4 if.then: ; preds = %for.body - call void @noreturn(ptr %foo_arr) + call void @noreturn_with_argmem(ptr %foo_arr) unreachable if.end4: ; preds = %for.body @@ -656,6 +656,79 @@ if.end4: ; preds = %for.body br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit } +define void @no_optimize_depdendent_load_trap(i32 %block_size) { +; CHECK-LABEL: define void @no_optimize_depdendent_load_trap( +; CHECK-SAME: i32 [[BLOCK_SIZE:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[FOO_ARR:%.*]] = alloca [2 x i8], align 16 +; CHECK-NEXT: [[BAR_ARR:%.*]] = alloca [2 x i8], align 16 +; CHECK-NEXT: call void @x(ptr nonnull [[FOO_ARR]]) +; CHECK-NEXT: [[CMP14_NOT:%.*]] = icmp eq i32 [[BLOCK_SIZE]], 0 +; CHECK-NEXT: br i1 [[CMP14_NOT]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY_PREHEADER:.*]] +; CHECK: [[FOR_BODY_PREHEADER]]: +; CHECK-NEXT: br label %[[FOR_BODY:.*]] +; CHECK: [[FOR_COND_CLEANUP_LOOPEXIT:.*]]: +; CHECK-NEXT: br label %[[FOR_COND_CLEANUP]] +; CHECK: [[FOR_COND_CLEANUP]]: +; CHECK-NEXT: call void @x(ptr nonnull [[BAR_ARR]]) +; CHECK-NEXT: ret void +; CHECK: [[FOR_BODY]]: +; CHECK-NEXT: [[I_015:%.*]] = phi i32 [ [[INC:%.*]], %[[IF_END4:.*]] ], [ 0, %[[FOR_BODY_PREHEADER]] ] +; CHECK-NEXT: [[CMP1:%.*]] = icmp samesign ugt i32 [[I_015]], 2 +; CHECK-NEXT: br i1 [[CMP1]], label %[[IF_THEN:.*]], label %[[IF_END4]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: [[I_015_LCSSA:%.*]] = load i8, ptr [[FOO_ARR]], align 1 +; CHECK-NEXT: call void @noreturn_with_i8(i8 [[I_015_LCSSA]]) +; CHECK-NEXT: unreachable +; CHECK: [[IF_END4]]: +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [1024 x i8], ptr [[FOO_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[ARRAYIDX]], align 1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[TMP0]], 54 +; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds nuw [1025 x i8], ptr [[BAR_ARR]], i64 0, i32 [[I_015]] +; CHECK-NEXT: store i8 [[TMP1]], ptr [[ARRAYIDX7]], align 1 +; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_015]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[INC]], [[BLOCK_SIZE]] +; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_COND_CLEANUP_LOOPEXIT]] +; +entry: + %foo_arr = alloca [2 x i8], align 16 + %bar_arr = alloca [2 x i8], align 16 + call void @x(ptr nonnull %foo_arr) + %cmp14.not = icmp eq i32 %block_size, 0 + br i1 %cmp14.not, label %for.cond.cleanup, label %for.body.preheader + +for.body.preheader: ; preds = %entry + br label %for.body + +for.cond.cleanup.loopexit: ; preds = %if.end4 + br label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry + call void @x(ptr nonnull %bar_arr) + ret void + +for.body: ; preds = %for.body.preheader, %if.end4 + %i.015 = phi i32 [ %inc, %if.end4 ], [ 0, %for.body.preheader ] + %cmp1 = icmp samesign ugt i32 %i.015, 2 + br i1 %cmp1, label %if.then, label %if.end4 + +if.then: ; preds = %for.body + %r = load i8, ptr %foo_arr, align 1 + call void @noreturn_with_i8(i8 %r) + unreachable + +if.end4: ; preds = %for.body + %arrayidx = getelementptr inbounds nuw [1024 x i8], ptr %foo_arr, i64 0, i32 %i.015 + %0 = load i8, ptr %arrayidx, align 1 + %1 = xor i8 %0, 54 + %arrayidx7 = getelementptr inbounds nuw [1025 x i8], ptr %bar_arr, i64 0, i32 %i.015 + store i8 %1, ptr %arrayidx7, align 1 + %inc = add nuw nsw i32 %i.015, 1 + %cmp = icmp ult i32 %inc, %block_size + br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit +} + + declare void @x(ptr noundef) local_unnamed_addr declare i1 @pred() local_unnamed_addr @@ -663,5 +736,8 @@ declare i1 @pred() local_unnamed_addr declare void @llvm.trap() #0 declare void @noreturn(ptr) #0 declare void @noreturn_with_i32(i32) #0 +declare void @noreturn_with_i8(i8) #0 +declare void @noreturn_with_argmem(ptr) #1 attributes #0 = { cold noreturn nounwind memory(inaccessiblemem: write) } +attributes #1 = { cold noreturn nounwind memory(argmem: read) } From e17b5a7e61372a4b6fedf360127eeb22e0cea5ba Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Tue, 14 Oct 2025 09:37:22 -0700 Subject: [PATCH 14/14] comment Created using spr 1.3.7 --- llvm/test/Transforms/IndVarSimplify/unreachable-exit.ll | 5 ----- 1 file changed, 5 deletions(-) diff --git a/llvm/test/Transforms/IndVarSimplify/unreachable-exit.ll b/llvm/test/Transforms/IndVarSimplify/unreachable-exit.ll index d4822bf98b70e..b9c92288b18c1 100644 --- a/llvm/test/Transforms/IndVarSimplify/unreachable-exit.ll +++ b/llvm/test/Transforms/IndVarSimplify/unreachable-exit.ll @@ -1,7 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt -S -passes=indvars < %s | FileCheck %s -; Function Attrs: mustprogress uwtable define void @optimize_trap(i32 %block_size) { ; CHECK-LABEL: define void @optimize_trap( ; CHECK-SAME: i32 [[BLOCK_SIZE:%.*]]) { @@ -74,7 +73,6 @@ if.end4: ; preds = %for.body br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit } -; Function Attrs: mustprogress uwtable define void @no_optimize_atomic(i32 %block_size) { ; CHECK-LABEL: define void @no_optimize_atomic( ; CHECK-SAME: i32 [[BLOCK_SIZE:%.*]]) { @@ -145,7 +143,6 @@ if.end4: ; preds = %for.body br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit } -; Function Attrs: mustprogress uwtable define void @no_optimize_volatile(i32 %block_size) { ; CHECK-LABEL: define void @no_optimize_volatile( ; CHECK-SAME: i32 [[BLOCK_SIZE:%.*]]) { @@ -216,7 +213,6 @@ if.end4: ; preds = %for.body br i1 %cmp, label %for.body, label %for.cond.cleanup.loopexit } -; Function Attrs: mustprogress uwtable define void @no_optimize_call(i32 %block_size) { ; CHECK-LABEL: define void @no_optimize_call( ; CHECK-SAME: i32 [[BLOCK_SIZE:%.*]]) { @@ -732,7 +728,6 @@ if.end4: ; preds = %for.body declare void @x(ptr noundef) local_unnamed_addr declare i1 @pred() local_unnamed_addr -; Function Attrs: cold noreturn nounwind memory(inaccessiblemem: write) declare void @llvm.trap() #0 declare void @noreturn(ptr) #0 declare void @noreturn_with_i32(i32) #0