From 9d1f8b1b21a75732d6060ae3a9278244b0b49a08 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Mon, 25 Aug 2014 23:58:48 +0000 Subject: [PATCH] ArgPromotion: Don't touch variadic functions Adding, removing, or changing non-pack parameters can change the ABI classification of pack parameters. Clang and other frontends encode the classification in the IR of the call site, but the callee side determines it dynamically based on the number of registers consumed so far. Changing the prototype affects the number of registers consumed would break such code. Dead argument elimination performs a similar task and already has a similar check to avoid this problem. Patch by Thomas Jablin! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@216421 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/IPO/ArgumentPromotion.cpp | 7 +++++ test/Transforms/ArgumentPromotion/variadic.ll | 28 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 test/Transforms/ArgumentPromotion/variadic.ll diff --git a/lib/Transforms/IPO/ArgumentPromotion.cpp b/lib/Transforms/IPO/ArgumentPromotion.cpp index 7c40ecd98d1..d2f407b9e55 100644 --- a/lib/Transforms/IPO/ArgumentPromotion.cpp +++ b/lib/Transforms/IPO/ArgumentPromotion.cpp @@ -156,6 +156,13 @@ CallGraphNode *ArgPromotion::PromoteArguments(CallGraphNode *CGN) { isSelfRecursive = true; } + // Don't promote arguments for variadic functions. Adding, removing, or + // changing non-pack parameters can change the classification of pack + // parameters. Frontends encode that classification at the call site in the + // IR, while in the callee the classification is determined dynamically based + // on the number of registers consumed so far. + if (F->isVarArg()) return nullptr; + // Check to see which arguments are promotable. If an argument is promotable, // add it to ArgsToPromote. SmallPtrSet ArgsToPromote; diff --git a/test/Transforms/ArgumentPromotion/variadic.ll b/test/Transforms/ArgumentPromotion/variadic.ll new file mode 100644 index 00000000000..0ae52b3bbbd --- /dev/null +++ b/test/Transforms/ArgumentPromotion/variadic.ll @@ -0,0 +1,28 @@ +; RUN: opt < %s -argpromotion -S | FileCheck %s + +; Unused arguments from variadic functions cannot be eliminated as that changes +; their classiciation according to the SysV amd64 ABI. Clang and other frontends +; bake in the classification when they use things like byval, as in this test. + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%struct.tt0 = type { i64, i64 } +%struct.__va_list_tag = type { i32, i32, i8*, i8* } + +@t45 = internal global %struct.tt0 { i64 1335139741, i64 438042995 }, align 8 + +; Function Attrs: nounwind uwtable +define i32 @main(i32 %argc, i8** nocapture readnone %argv) #0 { +entry: + tail call void (i8*, i8*, i8*, i8*, i8*, ...)* @callee_t0f(i8* undef, i8* undef, i8* undef, i8* undef, i8* undef, %struct.tt0* byval align 8 @t45) + ret i32 0 +} + +; Function Attrs: nounwind uwtable +define internal void @callee_t0f(i8* nocapture readnone %tp13, i8* nocapture readnone %tp14, i8* nocapture readnone %tp15, i8* nocapture readnone %tp16, i8* nocapture readnone %tp17, ...) { +entry: + ret void +} + +; CHECK-LABEL: define internal void @callee_t0f(i8* nocapture readnone %tp13, i8* nocapture readnone %tp14, i8* nocapture readnone %tp15, i8* nocapture readnone %tp16, i8* nocapture readnone %tp17, ...)