; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -S -hotcoldsplit -hotcoldsplit-threshold=0 < %s 2>&1 | FileCheck %s declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) declare void @cold_use(i8*) cold declare void @use(i8*) ; In this CFG, splitting will extract the blocks extract{1,2}. I.e., it will ; extract a lifetime.start marker, but not the corresponding lifetime.end ; marker. Make sure that a lifetime.start marker is emitted before the call to ; the split function, and *only* that marker. ; ; entry ; / \ ; extract1 no-extract1 ; (lt.start) | ; / | ; extract2 | ; \_____ | ; \ / ; exit ; (lt.end) ; ; After splitting, we should see: ; ; entry ; / \ ; codeRepl no-extract1 ; (lt.start) | ; \ / ; exit ; (lt.end) define void @only_lifetime_start_is_cold() { ; CHECK-LABEL: @only_lifetime_start_is_cold( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[LOCAL1:%.*]] = alloca i256 ; CHECK-NEXT: [[LOCAL1_CAST:%.*]] = bitcast i256* [[LOCAL1]] to i8* ; CHECK-NEXT: br i1 undef, label [[CODEREPL:%.*]], label [[NO_EXTRACT1:%.*]] ; CHECK: codeRepl: ; CHECK-NEXT: [[LT_CAST:%.*]] = bitcast i256* [[LOCAL1]] to i8* ; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 -1, i8* [[LT_CAST]]) ; CHECK-NEXT: [[TARGETBLOCK:%.*]] = call i1 @only_lifetime_start_is_cold.cold.1(i8* [[LOCAL1_CAST]]) #3 ; CHECK-NEXT: br i1 [[TARGETBLOCK]], label [[NO_EXTRACT1]], label [[EXIT:%.*]] ; CHECK: no-extract1: ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[LOCAL1_CAST]]) ; CHECK-NEXT: ret void ; entry: %local1 = alloca i256 %local1_cast = bitcast i256* %local1 to i8* br i1 undef, label %extract1, label %no-extract1 extract1: ; lt.start call void @llvm.lifetime.start.p0i8(i64 1, i8* %local1_cast) call void @cold_use(i8* %local1_cast) br i1 undef, label %extract2, label %no-extract1 extract2: br label %exit no-extract1: br label %exit exit: ; lt.end call void @llvm.lifetime.end.p0i8(i64 1, i8* %local1_cast) ret void } ; In this CFG, splitting will extract the block extract1. I.e., it will extract ; a lifetime.end marker, but not the corresponding lifetime.start marker. Do ; not emit a lifetime.end marker after the call to the split function. ; ; entry ; (lt.start) ; / \ ; no-extract1 extract1 ; (lt.end) (lt.end) ; \ / ; exit ; ; After splitting, we should see: ; ; entry ; (lt.start) ; / \ ; no-extract1 codeRepl ; (lt.end) ; \ / ; exit define void @only_lifetime_end_is_cold() { ; CHECK-LABEL: @only_lifetime_end_is_cold( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[LOCAL1:%.*]] = alloca i256 ; CHECK-NEXT: [[LOCAL1_CAST:%.*]] = bitcast i256* [[LOCAL1]] to i8* ; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[LOCAL1_CAST]]) ; CHECK-NEXT: br i1 undef, label [[NO_EXTRACT1:%.*]], label [[CODEREPL:%.*]] ; CHECK: no-extract1: ; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[LOCAL1_CAST]]) ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: codeRepl: ; CHECK-NEXT: call void @only_lifetime_end_is_cold.cold.1(i8* [[LOCAL1_CAST]]) #3 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: ; lt.start %local1 = alloca i256 %local1_cast = bitcast i256* %local1 to i8* call void @llvm.lifetime.start.p0i8(i64 1, i8* %local1_cast) br i1 undef, label %no-extract1, label %extract1 no-extract1: ; lt.end call void @llvm.lifetime.end.p0i8(i64 1, i8* %local1_cast) br label %exit extract1: ; lt.end call void @cold_use(i8* %local1_cast) call void @llvm.lifetime.end.p0i8(i64 1, i8* %local1_cast) br label %exit exit: ret void } ; In this CFG, splitting will extract the blocks extract{1,2,3}. Lifting the ; lifetime.end marker would be a miscompile. define void @do_not_lift_lifetime_end() { ; CHECK-LABEL: @do_not_lift_lifetime_end( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[LOCAL1:%.*]] = alloca i256 ; CHECK-NEXT: [[LOCAL1_CAST:%.*]] = bitcast i256* [[LOCAL1]] to i8* ; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[LOCAL1_CAST]]) ; CHECK-NEXT: br label [[HEADER:%.*]] ; CHECK: header: ; CHECK-NEXT: call void @use(i8* [[LOCAL1_CAST]]) ; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[CODEREPL:%.*]] ; CHECK: codeRepl: ; CHECK-NEXT: [[TARGETBLOCK:%.*]] = call i1 @do_not_lift_lifetime_end.cold.1(i8* [[LOCAL1_CAST]]) #3 ; CHECK-NEXT: br i1 [[TARGETBLOCK]], label [[HEADER]], label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: ; lt.start %local1 = alloca i256 %local1_cast = bitcast i256* %local1 to i8* call void @llvm.lifetime.start.p0i8(i64 1, i8* %local1_cast) br label %header header: ; If the lifetime.end marker is lifted, this use becomes dead the second time ; the header block is executed. call void @use(i8* %local1_cast) br i1 undef, label %exit, label %extract1 extract1: call void @cold_use(i8* %local1_cast) br i1 undef, label %extract2, label %extract3 extract2: ; Backedge. br label %header extract3: ; lt.end call void @llvm.lifetime.end.p0i8(i64 1, i8* %local1_cast) br label %exit exit: ret void }