Index: lib/Analysis/InlineCost.cpp =================================================================== --- lib/Analysis/InlineCost.cpp +++ lib/Analysis/InlineCost.cpp @@ -1239,7 +1239,6 @@ HasUninlineableIntrinsic = true; return false; case Intrinsic::vastart: - case Intrinsic::vaend: UsesVarArgs = true; return false; } @@ -2081,7 +2080,6 @@ case llvm::Intrinsic::localescape: // Disallow inlining of functions that access VarArgs. case llvm::Intrinsic::vastart: - case llvm::Intrinsic::vaend: return false; } } Index: test/Transforms/Inline/inline-func-vaend.ll =================================================================== --- /dev/null +++ test/Transforms/Inline/inline-func-vaend.ll @@ -0,0 +1,64 @@ +; RUN: opt < %s -inline -S | FileCheck %s + +; This test checks that we inline functions that have va_end, if +; they dob't have va_start. + +%struct.__va_list = type { i8* } + +; Function Attrs: noinline nounwind optnone +define dso_local void @caller(i32 %n, i8* noalias %args, ...) { +entry: + %n.addr = alloca i32, align 4 + %args.addr = alloca i8*, align 4 + %ap = alloca %struct.__va_list, align 4 + store i32 %n, i32* %n.addr, align 4 + store i8* %args, i8** %args.addr, align 4 + %ap1 = bitcast %struct.__va_list* %ap to i8* + call void @llvm.va_start(i8* %ap1) + %0 = load i32, i32* %n.addr, align 4 + %coerce.dive = getelementptr inbounds %struct.__va_list, %struct.__va_list* %ap, i32 0, i32 0 + %1 = bitcast i8** %coerce.dive to [1 x i32]* + %2 = load [1 x i32], [1 x i32]* %1, align 4 + call void @always_inlined(i32 %0, [1 x i32] %2) + %ap2 = bitcast %struct.__va_list* %ap to i8* + call void @llvm.va_end(i8* %ap2) + ret void +} + +; CHECK-LABEL: @caller +; CHECK-NOT: call void @always_inlined + + +; Function Attrs: nounwind +declare void @llvm.va_start(i8*) + +; Function Attrs: alwaysinline nounwind +define void @always_inlined(i32 %n, [1 x i32] %a.coerce) { +entry: + %a = alloca %struct.__va_list, align 4 + %n.addr = alloca i32, align 4 + %a_copy = alloca %struct.__va_list, align 4 + %coerce.dive = getelementptr inbounds %struct.__va_list, %struct.__va_list* %a, i32 0, i32 0 + %0 = bitcast i8** %coerce.dive to [1 x i32]* + store [1 x i32] %a.coerce, [1 x i32]* %0, align 4 + store i32 %n, i32* %n.addr, align 4 + %1 = bitcast %struct.__va_list* %a_copy to i8* + %2 = bitcast %struct.__va_list* %a to i8* + call void @llvm.va_copy(i8* %1, i8* %2) + %3 = load i32, i32* %n.addr, align 4 + %coerce.dive1 = getelementptr inbounds %struct.__va_list, %struct.__va_list* %a_copy, i32 0, i32 0 + %4 = bitcast i8** %coerce.dive1 to [1 x i32]* + %5 = load [1 x i32], [1 x i32]* %4, align 4 + call void @foo([1 x i32] %5, i32 %3) + %a_copy2 = bitcast %struct.__va_list* %a_copy to i8* + call void @llvm.va_end(i8* %a_copy2) + ret void +} + +; Function Attrs: nounwind +declare void @llvm.va_end(i8*) + +; Function Attrs: nounwind +declare void @llvm.va_copy(i8*, i8*) + +declare dso_local void @foo([1 x i32], i32)