From f55daa8b6a33671a26b6ac60340d8629262a1f03 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Fri, 16 May 2025 20:37:32 +0800 Subject: [PATCH 1/2] [InstCombine] Add pre-commit tests. NFC. --- llvm/test/Transforms/InstCombine/vararg.ll | 50 +++++++++++++++++----- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/llvm/test/Transforms/InstCombine/vararg.ll b/llvm/test/Transforms/InstCombine/vararg.ll index ef75b0c91ce27..9709e94442416 100644 --- a/llvm/test/Transforms/InstCombine/vararg.ll +++ b/llvm/test/Transforms/InstCombine/vararg.ll @@ -1,17 +1,14 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s %struct.__va_list = type { ptr, ptr, ptr, i32, i32 } -declare void @llvm.lifetime.start.p0(i64, ptr nocapture) -declare void @llvm.lifetime.end.p0(i64, ptr nocapture) -declare void @llvm.va_start(ptr) -declare void @llvm.va_end(ptr) -declare void @llvm.va_copy(ptr, ptr) - -define i32 @func(ptr nocapture readnone %fmt, ...) { -; CHECK-LABEL: @func( -; CHECK: entry: -; CHECK-NEXT: ret i32 0 +define void @func(ptr nocapture readnone %fmt, ...) { +; CHECK-LABEL: define void @func( +; CHECK-SAME: ptr readnone captures(none) [[FMT:%.*]], ...) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: ret void +; entry: %va0 = alloca %struct.__va_list, align 8 %va1 = alloca %struct.__va_list, align 8 @@ -23,6 +20,37 @@ entry: call void @llvm.lifetime.end.p0(i64 32, ptr %va1) call void @llvm.va_end(ptr %va0) call void @llvm.lifetime.end.p0(i64 32, ptr %va0) - ret i32 0 + ret void } +declare void @callee(ptr) + +define void @func_destroy_copy_src(ptr nocapture readnone %fmt, ...) { +; CHECK-LABEL: define void @func_destroy_copy_src( +; CHECK-SAME: ptr readnone captures(none) [[FMT:%.*]], ...) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[VA0:%.*]] = alloca [[STRUCT___VA_LIST:%.*]], align 8 +; CHECK-NEXT: [[VA1:%.*]] = alloca [[STRUCT___VA_LIST]], align 8 +; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 32, ptr nonnull [[VA0]]) +; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 32, ptr nonnull [[VA1]]) +; CHECK-NEXT: call void @llvm.va_copy.p0(ptr nonnull [[VA1]], ptr nonnull [[VA0]]) +; CHECK-NEXT: call void @callee(ptr nonnull [[VA1]]) +; CHECK-NEXT: call void @llvm.va_end.p0(ptr [[VA1]]) +; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 32, ptr nonnull [[VA1]]) +; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 32, ptr nonnull [[VA0]]) +; CHECK-NEXT: ret void +; +entry: + %va0 = alloca %struct.__va_list, align 8 + %va1 = alloca %struct.__va_list, align 8 + call void @llvm.lifetime.start.p0(i64 32, ptr %va0) + call void @llvm.lifetime.start.p0(i64 32, ptr %va1) + call void @llvm.va_start(ptr %va0) + call void @llvm.va_copy(ptr %va1, ptr %va0) + call void @llvm.va_end(ptr %va0) + call void @callee(ptr %va1) + call void @llvm.va_end(ptr %va1) + call void @llvm.lifetime.end.p0(i64 32, ptr %va1) + call void @llvm.lifetime.end.p0(i64 32, ptr %va0) + ret void +} From fd48c14e347c9d75fd20e65e26ddd8ab8e266e5d Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Fri, 16 May 2025 21:15:06 +0800 Subject: [PATCH 2/2] [InstCombine] Special handle `va_copy(dst, src) + va_end(src)` --- llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 9 ++++++--- llvm/test/Transforms/InstCombine/vararg.ll | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index 3d35bf753c40e..12e08c09ea67d 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -816,9 +816,12 @@ removeTriviallyEmptyRange(IntrinsicInst &EndI, InstCombinerImpl &IC, } Instruction *InstCombinerImpl::visitVAEndInst(VAEndInst &I) { - removeTriviallyEmptyRange(I, *this, [](const IntrinsicInst &I) { - return I.getIntrinsicID() == Intrinsic::vastart || - I.getIntrinsicID() == Intrinsic::vacopy; + removeTriviallyEmptyRange(I, *this, [&I](const IntrinsicInst &II) { + // Bail out on the case where the source va_list of a va_copy is destroyed + // immediately by a follow-up va_end. + return II.getIntrinsicID() == Intrinsic::vastart || + (II.getIntrinsicID() == Intrinsic::vacopy && + I.getArgOperand(0) != II.getArgOperand(1)); }); return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/vararg.ll b/llvm/test/Transforms/InstCombine/vararg.ll index 9709e94442416..eb24256cfa9bc 100644 --- a/llvm/test/Transforms/InstCombine/vararg.ll +++ b/llvm/test/Transforms/InstCombine/vararg.ll @@ -33,7 +33,9 @@ define void @func_destroy_copy_src(ptr nocapture readnone %fmt, ...) { ; CHECK-NEXT: [[VA1:%.*]] = alloca [[STRUCT___VA_LIST]], align 8 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 32, ptr nonnull [[VA0]]) ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 32, ptr nonnull [[VA1]]) +; CHECK-NEXT: call void @llvm.va_start.p0(ptr nonnull [[VA0]]) ; CHECK-NEXT: call void @llvm.va_copy.p0(ptr nonnull [[VA1]], ptr nonnull [[VA0]]) +; CHECK-NEXT: call void @llvm.va_end.p0(ptr [[VA0]]) ; CHECK-NEXT: call void @callee(ptr nonnull [[VA1]]) ; CHECK-NEXT: call void @llvm.va_end.p0(ptr [[VA1]]) ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 32, ptr nonnull [[VA1]])