Skip to content

Commit 8d0ebd8

Browse files
authored
[InstCombine] Special handle va_copy(dst, src) + va_end(src) (#140250)
Closes #140215.
1 parent 21c878e commit 8d0ebd8

File tree

2 files changed

+47
-14
lines changed

2 files changed

+47
-14
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -816,9 +816,12 @@ removeTriviallyEmptyRange(IntrinsicInst &EndI, InstCombinerImpl &IC,
816816
}
817817

818818
Instruction *InstCombinerImpl::visitVAEndInst(VAEndInst &I) {
819-
removeTriviallyEmptyRange(I, *this, [](const IntrinsicInst &I) {
820-
return I.getIntrinsicID() == Intrinsic::vastart ||
821-
I.getIntrinsicID() == Intrinsic::vacopy;
819+
removeTriviallyEmptyRange(I, *this, [&I](const IntrinsicInst &II) {
820+
// Bail out on the case where the source va_list of a va_copy is destroyed
821+
// immediately by a follow-up va_end.
822+
return II.getIntrinsicID() == Intrinsic::vastart ||
823+
(II.getIntrinsicID() == Intrinsic::vacopy &&
824+
I.getArgOperand(0) != II.getArgOperand(1));
822825
});
823826
return nullptr;
824827
}
Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
12
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
23

34
%struct.__va_list = type { ptr, ptr, ptr, i32, i32 }
45

5-
declare void @llvm.lifetime.start.p0(i64, ptr nocapture)
6-
declare void @llvm.lifetime.end.p0(i64, ptr nocapture)
7-
declare void @llvm.va_start(ptr)
8-
declare void @llvm.va_end(ptr)
9-
declare void @llvm.va_copy(ptr, ptr)
10-
11-
define i32 @func(ptr nocapture readnone %fmt, ...) {
12-
; CHECK-LABEL: @func(
13-
; CHECK: entry:
14-
; CHECK-NEXT: ret i32 0
6+
define void @func(ptr nocapture readnone %fmt, ...) {
7+
; CHECK-LABEL: define void @func(
8+
; CHECK-SAME: ptr readnone captures(none) [[FMT:%.*]], ...) {
9+
; CHECK-NEXT: [[ENTRY:.*:]]
10+
; CHECK-NEXT: ret void
11+
;
1512
entry:
1613
%va0 = alloca %struct.__va_list, align 8
1714
%va1 = alloca %struct.__va_list, align 8
@@ -23,6 +20,39 @@ entry:
2320
call void @llvm.lifetime.end.p0(i64 32, ptr %va1)
2421
call void @llvm.va_end(ptr %va0)
2522
call void @llvm.lifetime.end.p0(i64 32, ptr %va0)
26-
ret i32 0
23+
ret void
2724
}
2825

26+
declare void @callee(ptr)
27+
28+
define void @func_destroy_copy_src(ptr nocapture readnone %fmt, ...) {
29+
; CHECK-LABEL: define void @func_destroy_copy_src(
30+
; CHECK-SAME: ptr readnone captures(none) [[FMT:%.*]], ...) {
31+
; CHECK-NEXT: [[ENTRY:.*:]]
32+
; CHECK-NEXT: [[VA0:%.*]] = alloca [[STRUCT___VA_LIST:%.*]], align 8
33+
; CHECK-NEXT: [[VA1:%.*]] = alloca [[STRUCT___VA_LIST]], align 8
34+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 32, ptr nonnull [[VA0]])
35+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 32, ptr nonnull [[VA1]])
36+
; CHECK-NEXT: call void @llvm.va_start.p0(ptr nonnull [[VA0]])
37+
; CHECK-NEXT: call void @llvm.va_copy.p0(ptr nonnull [[VA1]], ptr nonnull [[VA0]])
38+
; CHECK-NEXT: call void @llvm.va_end.p0(ptr [[VA0]])
39+
; CHECK-NEXT: call void @callee(ptr nonnull [[VA1]])
40+
; CHECK-NEXT: call void @llvm.va_end.p0(ptr [[VA1]])
41+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 32, ptr nonnull [[VA1]])
42+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 32, ptr nonnull [[VA0]])
43+
; CHECK-NEXT: ret void
44+
;
45+
entry:
46+
%va0 = alloca %struct.__va_list, align 8
47+
%va1 = alloca %struct.__va_list, align 8
48+
call void @llvm.lifetime.start.p0(i64 32, ptr %va0)
49+
call void @llvm.lifetime.start.p0(i64 32, ptr %va1)
50+
call void @llvm.va_start(ptr %va0)
51+
call void @llvm.va_copy(ptr %va1, ptr %va0)
52+
call void @llvm.va_end(ptr %va0)
53+
call void @callee(ptr %va1)
54+
call void @llvm.va_end(ptr %va1)
55+
call void @llvm.lifetime.end.p0(i64 32, ptr %va1)
56+
call void @llvm.lifetime.end.p0(i64 32, ptr %va0)
57+
ret void
58+
}

0 commit comments

Comments
 (0)