; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals ; RUN: opt < %s -passes='require,chr' -S | FileCheck %s declare void @foo() declare void @bar() declare void @baz(i64) ; Test that when we have a static alloca in an entry block that will get split, ; the alloca remains static and we preserve its lifetime annotations. define void @test_chr_with_lifetimes(ptr %i) !prof !14 { ; CHECK-LABEL: @test_chr_with_lifetimes( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TEST:%.*]] = alloca i32, align 8 ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[I:%.*]], align 4 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[TMP0]], 0 ; CHECK-NEXT: [[TMP9:%.*]] = freeze i1 [[TMP1]] ; CHECK-NEXT: [[TMP8:%.*]] = select i1 true, i1 [[TMP9]], i1 false, !prof [[PROF15:![0-9]+]] ; CHECK-NEXT: [[TMP11:%.*]] = freeze i1 [[TMP1]] ; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP8]], i1 [[TMP11]], i1 false, !prof [[PROF15]] ; CHECK-NEXT: br i1 [[TMP5]], label [[ENTRY_SPLIT:%.*]], label [[ENTRY_SPLIT_NONCHR:%.*]], !prof [[PROF16:![0-9]+]] ; CHECK: entry.split: ; CHECK-NEXT: [[TMP6:%.*]] = select i1 true, i64 0, i64 4, !prof [[PROF17:![0-9]+]] ; CHECK-NEXT: call void @baz(i64 [[TMP6]]) ; CHECK-NEXT: br i1 false, label [[BB1:%.*]], label [[BB0:%.*]], !prof [[PROF18:![0-9]+]] ; CHECK: bb0: ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: br label [[BB1]] ; CHECK: entry.split.nonchr: ; CHECK-NEXT: [[TMP7:%.*]] = select i1 [[TMP1]], i64 0, i64 4, !prof [[PROF17]] ; CHECK-NEXT: call void @baz(i64 [[TMP7]]) ; CHECK-NEXT: br i1 [[TMP1]], label [[BB0_NONCHR:%.*]], label [[BB1]], !prof [[PROF17]] ; CHECK: bb0.nonchr: ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: br label [[BB1]] ; CHECK: bb1: ; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[TEST]]) ; CHECK-NEXT: store ptr [[TEST]], ptr [[I]], align 8 ; CHECK-NEXT: br label [[BB2:%.*]] ; CHECK: bb2: ; CHECK-NEXT: [[TMP2:%.*]] = phi ptr [ [[TMP3:%.*]], [[BB2]] ], [ null, [[BB1]] ] ; CHECK-NEXT: [[TMP3]] = getelementptr i8, ptr [[TMP2]], i64 24 ; CHECK-NEXT: [[TMP4:%.*]] = icmp eq ptr [[TMP2]], [[I]] ; CHECK-NEXT: br i1 [[TMP4]], label [[BB3:%.*]], label [[BB2]] ; CHECK: bb3: ; CHECK-NEXT: ret void ; entry: %1 = load i32, ptr %i %2 = icmp eq i32 %1, 0 %3 = select i1 %2, i64 4, i64 0, !prof !15 %test = alloca i32, align 8 call void @baz(i64 %3) br i1 %2, label %bb1, label %bb0, !prof !15 bb0: call void @foo() br label %bb1 bb1: call void @llvm.lifetime.start.p0(ptr %test) store ptr %test, ptr %i, align 8 br label %bb2 bb2: %4 = phi ptr [ %5, %bb2 ], [ null, %bb1 ] %5 = getelementptr i8, ptr %4, i64 24 %6 = icmp eq ptr %4, %i br i1 %6, label %bb3, label %bb2 bb3: ret void } ; Test that we remove lifetime markers that would otherwise refer to phi ; nodes given the dynamic allocas they referred to have been duplicated. define void @test_chr_dynamic_alloca(ptr %i) !prof !14 { ; CHECK-LABEL: @test_chr_dynamic_alloca( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TEST1:%.*]] = load i32, ptr [[I:%.*]], align 4 ; CHECK-NEXT: [[TEST2:%.*]] = icmp eq i32 [[TEST1]], 5 ; CHECK-NEXT: br i1 [[TEST2]], label [[BB4:%.*]], label [[BB3:%.*]] ; CHECK: bb4: ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[I]], align 4 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[TMP0]], 0 ; CHECK-NEXT: [[TMP2:%.*]] = freeze i1 [[TMP1]] ; CHECK-NEXT: [[TMP3:%.*]] = select i1 true, i1 [[TMP2]], i1 false, !prof [[PROF15]] ; CHECK-NEXT: [[TMP4:%.*]] = freeze i1 [[TMP1]] ; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i1 [[TMP4]], i1 false, !prof [[PROF15]] ; CHECK-NEXT: br i1 [[TMP5]], label [[BB4_SPLIT:%.*]], label [[BB4_SPLIT_NONCHR:%.*]], !prof [[PROF16]] ; CHECK: bb4.split: ; CHECK-NEXT: [[TMP6:%.*]] = select i1 true, i64 0, i64 4, !prof [[PROF17]] ; CHECK-NEXT: [[TEST:%.*]] = alloca i32, align 8 ; CHECK-NEXT: call void @baz(i64 [[TMP6]]) ; CHECK-NEXT: br i1 false, label [[BB1:%.*]], label [[BB0:%.*]], !prof [[PROF18]] ; CHECK: bb0: ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: store ptr [[TEST]], ptr [[I]], align 8 ; CHECK-NEXT: br label [[BB1]] ; CHECK: bb4.split.nonchr: ; CHECK-NEXT: [[TMP7:%.*]] = select i1 [[TMP1]], i64 0, i64 4, !prof [[PROF17]] ; CHECK-NEXT: [[TEST_NONCHR:%.*]] = alloca i32, align 8 ; CHECK-NEXT: call void @baz(i64 [[TMP7]]) ; CHECK-NEXT: br i1 [[TMP1]], label [[BB0_NONCHR:%.*]], label [[BB1]], !prof [[PROF17]] ; CHECK: bb0.nonchr: ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: store ptr [[TEST_NONCHR]], ptr [[I]], align 8 ; CHECK-NEXT: br label [[BB1]] ; CHECK: bb1: ; CHECK-NEXT: [[TMP8:%.*]] = phi ptr [ [[TEST]], [[BB0]] ], [ [[TEST]], [[BB4_SPLIT]] ], [ [[TEST_NONCHR]], [[BB0_NONCHR]] ], [ [[TEST_NONCHR]], [[BB4_SPLIT_NONCHR]] ] ; CHECK-NEXT: call void @bar() ; CHECK-NEXT: store ptr [[TMP8]], ptr [[I]], align 8 ; CHECK-NEXT: br label [[BB2:%.*]] ; CHECK: bb2: ; CHECK-NEXT: [[TMP9:%.*]] = phi ptr [ [[TMP10:%.*]], [[BB2]] ], [ null, [[BB1]] ] ; CHECK-NEXT: [[TMP10]] = getelementptr i8, ptr [[TMP9]], i64 24 ; CHECK-NEXT: [[TEST5:%.*]] = load ptr, ptr [[TMP8]], align 8 ; CHECK-NEXT: [[TMP11:%.*]] = icmp eq ptr [[TMP9]], [[TEST5]] ; CHECK-NEXT: br i1 [[TMP11]], label [[BB3]], label [[BB2]] ; CHECK: bb3: ; CHECK-NEXT: ret void ; entry: %test1 = load i32, ptr %i %test2 = icmp eq i32 %test1, 5 br i1 %test2, label %bb4, label %bb3 bb4: %1 = load i32, ptr %i %2 = icmp eq i32 %1, 0 %3 = select i1 %2, i64 4, i64 0, !prof !15 %test = alloca i32, align 8 call void @baz(i64 %3) br i1 %2, label %bb1, label %bb0, !prof !15 bb0: call void @foo() call void @llvm.lifetime.start.p0(ptr %test) store ptr %test, ptr %i, align 8 br label %bb1 bb1: call void @bar() call void @llvm.lifetime.start.p0(ptr %test) store ptr %test, ptr %i, align 8 br label %bb2 bb2: %4 = phi ptr [ %5, %bb2 ], [ null, %bb1 ] %5 = getelementptr i8, ptr %4, i64 24 %test5 = load ptr, ptr %test call void @llvm.lifetime.end.p0(ptr %test) %6 = icmp eq ptr %4, %test5 br i1 %6, label %bb3, label %bb2 bb3: ret void } ; Test that we do not move around allocas that occur in the entry block ; before splitting. If we accidentally sink them, we can move them after ; their users. define void @test_no_move_allocas(ptr %i) !prof !14 { ; CHECK-LABEL: @test_no_move_allocas( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TEST:%.*]] = alloca i32, align 8 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[TEST]]) ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[I:%.*]], align 4 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[TMP0]], 0 ; CHECK-NEXT: [[TMP2:%.*]] = freeze i1 [[TMP1]] ; CHECK-NEXT: [[TMP3:%.*]] = select i1 true, i1 [[TMP2]], i1 false, !prof [[PROF15]] ; CHECK-NEXT: [[TMP4:%.*]] = freeze i1 [[TMP1]] ; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP3]], i1 [[TMP4]], i1 false, !prof [[PROF15]] ; CHECK-NEXT: br i1 [[TMP5]], label [[ENTRY_SPLIT:%.*]], label [[ENTRY_SPLIT_NONCHR:%.*]], !prof [[PROF16]] ; CHECK: entry.split: ; CHECK-NEXT: [[TMP6:%.*]] = select i1 true, i64 0, i64 4, !prof [[PROF17]] ; CHECK-NEXT: call void @baz(i64 [[TMP6]]) ; CHECK-NEXT: br i1 false, label [[BB1:%.*]], label [[BB0:%.*]], !prof [[PROF18]] ; CHECK: bb0: ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: br label [[BB1]] ; CHECK: entry.split.nonchr: ; CHECK-NEXT: [[TMP7:%.*]] = select i1 [[TMP1]], i64 0, i64 4, !prof [[PROF17]] ; CHECK-NEXT: call void @baz(i64 [[TMP7]]) ; CHECK-NEXT: br i1 [[TMP1]], label [[BB0_NONCHR:%.*]], label [[BB1]], !prof [[PROF17]] ; CHECK: bb0.nonchr: ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: br label [[BB1]] ; CHECK: bb1: ; CHECK-NEXT: call void @bar() ; CHECK-NEXT: br label [[BB2:%.*]] ; CHECK: bb2: ; CHECK-NEXT: [[TMP8:%.*]] = phi ptr [ [[TMP9:%.*]], [[BB2]] ], [ null, [[BB1]] ] ; CHECK-NEXT: [[TMP9]] = getelementptr i8, ptr [[TMP8]], i64 24 ; CHECK-NEXT: [[TMP10:%.*]] = icmp eq ptr [[TMP8]], [[I]] ; CHECK-NEXT: br i1 [[TMP10]], label [[BB3:%.*]], label [[BB2]] ; CHECK: bb3: ; CHECK-NEXT: ret void ; entry: %test = alloca i32, align 8 call void @llvm.lifetime.start.p0(ptr %test) %1 = load i32, ptr %i %2 = icmp eq i32 %1, 0 %3 = select i1 %2, i64 4, i64 0, !prof !15 call void @baz(i64 %3) br i1 %2, label %bb1, label %bb0, !prof !15 bb0: call void @foo() br label %bb1 bb1: call void @bar() br label %bb2 bb2: %4 = phi ptr [ %5, %bb2 ], [ null, %bb1 ] %5 = getelementptr i8, ptr %4, i64 24 %6 = icmp eq ptr %4, %i br i1 %6, label %bb3, label %bb2 bb3: ret void } !llvm.module.flags = !{!0} !0 = !{i32 1, !"ProfileSummary", !1} !1 = !{!2, !3, !4, !5, !6, !7, !8, !9} !2 = !{!"ProfileFormat", !"InstrProf"} !3 = !{!"TotalCount", i64 10000} !4 = !{!"MaxCount", i64 10} !5 = !{!"MaxInternalCount", i64 1} !6 = !{!"MaxFunctionCount", i64 1000} !7 = !{!"NumCounts", i64 3} !8 = !{!"NumFunctions", i64 3} !9 = !{!"DetailedSummary", !10} !10 = !{!11, !12, !13} !11 = !{i32 10000, i64 100, i32 1} !12 = !{i32 999000, i64 100, i32 1} !13 = !{i32 999999, i64 1, i32 2} !14 = !{!"function_entry_count", i64 100} !15 = !{!"branch_weights", i32 0, i32 1} ;. ; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } ;. ; CHECK: [[META0:![0-9]+]] = !{i32 1, !"ProfileSummary", [[META1:![0-9]+]]} ; CHECK: [[META1]] = !{[[META2:![0-9]+]], [[META3:![0-9]+]], [[META4:![0-9]+]], [[META5:![0-9]+]], [[META6:![0-9]+]], [[META7:![0-9]+]], [[META8:![0-9]+]], [[META9:![0-9]+]]} ; CHECK: [[META2]] = !{!"ProfileFormat", !"InstrProf"} ; CHECK: [[META3]] = !{!"TotalCount", i64 10000} ; CHECK: [[META4]] = !{!"MaxCount", i64 10} ; CHECK: [[META5]] = !{!"MaxInternalCount", i64 1} ; CHECK: [[META6]] = !{!"MaxFunctionCount", i64 1000} ; CHECK: [[META7]] = !{!"NumCounts", i64 3} ; CHECK: [[META8]] = !{!"NumFunctions", i64 3} ; CHECK: [[META9]] = !{!"DetailedSummary", [[META10:![0-9]+]]} ; CHECK: [[META10]] = !{[[META11:![0-9]+]], [[META12:![0-9]+]], [[META13:![0-9]+]]} ; CHECK: [[META11]] = !{i32 10000, i64 100, i32 1} ; CHECK: [[META12]] = !{i32 999000, i64 100, i32 1} ; CHECK: [[META13]] = !{i32 999999, i64 1, i32 2} ; CHECK: [[META14:![0-9]+]] = !{!"function_entry_count", i64 100} ; CHECK: [[PROF15]] = !{!"unknown", !"chr"} ; CHECK: [[PROF16]] = !{!"branch_weights", i32 1000, i32 0} ; CHECK: [[PROF17]] = !{!"branch_weights", i32 1, i32 0} ; CHECK: [[PROF18]] = !{!"branch_weights", i32 0, i32 1} ;.