Skip to content

Commit 20e754b

Browse files
[IPO] Optimise variadic functions
1 parent 560c2fd commit 20e754b

28 files changed

+4502
-2
lines changed

clang/test/CodeGen/aarch64-ABI-align-packed.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// REQUIRES: aarch64-registered-target
2-
// RUN: %clang_cc1 -triple aarch64 -target-feature +neon -emit-llvm -O2 -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple aarch64 -target-feature +neon -emit-llvm -O2 -o - %s -mllvm -expand-variadics-override=disable | FileCheck %s
3+
34
#include <stdarg.h>
45
#include <arm_neon.h>
56

clang/test/CodeGen/voidptr-vaarg.c

Lines changed: 478 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature
2+
3+
// Simple calls to known variadic functions that are completely elided when optimisations are on
4+
// This is a functional check that the expand-variadic pass is consistent with clang's va_arg handling
5+
6+
// -Wno-varargs avoids warning second argument to 'va_start' is not the last named parameter
7+
8+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -Wno-varargs -O1 -emit-llvm -o - %s | FileCheck %s
9+
10+
// RUN: %clang_cc1 -triple wasm32-unknown-unknown -Wno-varargs -O1 -emit-llvm -o - %s | FileCheck %s
11+
12+
// x64 needs O2 to remove the extra SROA layer
13+
// RUN: %clang_cc1 -triple x86_64-linux-gnu -Wno-varargs -O2 -emit-llvm -o - %s | FileCheck %s
14+
15+
16+
#include <stdarg.h>
17+
#include <stdint.h>
18+
19+
template <typename X, typename Y>
20+
static X first(...) {
21+
va_list va;
22+
__builtin_va_start(va, 0);
23+
X r = va_arg(va, X);
24+
va_end(va);
25+
return r;
26+
}
27+
28+
template <typename X, typename Y>
29+
static Y second(...) {
30+
va_list va;
31+
__builtin_va_start(va, 0);
32+
va_arg(va, X);
33+
Y r = va_arg(va, Y);
34+
va_end(va);
35+
return r;
36+
}
37+
38+
39+
extern "C"
40+
{
41+
42+
// CHECK-LABEL: define {{[^@]+}}@first_pair_i32
43+
// CHECK-SAME: (i32 noundef returned [[X:%.*]], i32 noundef [[Y:%.*]])
44+
// CHECK-LABEL:{{.}}:
45+
// CHECK-NEXT: ret i32 [[X]]
46+
//
47+
int first_pair_i32(int x, int y)
48+
{
49+
return first<int,int>(x, y);
50+
}
51+
52+
// CHECK-LABEL: define {{[^@]+}}@second_pair_i32
53+
// CHECK-SAME: (i32 noundef [[X:%.*]], i32 noundef returned [[Y:%.*]])
54+
// CHECK-LABEL:{{.}}:
55+
// CHECK-NEXT: ret i32 [[Y]]
56+
//
57+
int second_pair_i32(int x, int y)
58+
{
59+
return second<int,int>(x, y);
60+
}
61+
62+
// CHECK-LABEL: define {{[^@]+}}@first_pair_f64
63+
// CHECK-SAME: (double noundef returned [[X:%.*]], double noundef [[Y:%.*]])
64+
// CHECK-LABEL:{{.}}:
65+
// CHECK-NEXT: ret double [[X]]
66+
//
67+
double first_pair_f64(double x, double y)
68+
{
69+
return first<double,double>(x, y);
70+
}
71+
72+
// CHECK-LABEL: define {{[^@]+}}@second_pair_f64
73+
// CHECK-SAME: (double noundef [[X:%.*]], double noundef returned [[Y:%.*]])
74+
// CHECK-LABEL:{{.}}:
75+
// CHECK-NEXT: ret double [[Y]]
76+
//
77+
double second_pair_f64(double x, double y)
78+
{
79+
return second<double,double>(x, y);
80+
}
81+
82+
}
83+
84+
85+
86+
extern "C"
87+
{
88+
// CHECK-LABEL: define {{[^@]+}}@first_i32_f64
89+
// CHECK-SAME: (i32 noundef returned [[X:%.*]], double noundef [[Y:%.*]])
90+
// CHECK-LABEL:{{.}}:
91+
// CHECK-NEXT: ret i32 [[X]]
92+
//
93+
int first_i32_f64(int x, double y)
94+
{
95+
return first<int,double>(x, y);
96+
}
97+
98+
99+
// CHECK-LABEL: define {{[^@]+}}@second_i32_f64
100+
// CHECK-SAME: (i32 noundef [[X:%.*]], double noundef returned [[Y:%.*]])
101+
// CHECK-LABEL:{{.}}:
102+
// CHECK-NEXT: ret double [[Y]]
103+
//
104+
double second_i32_f64(int x, double y)
105+
{
106+
return second<int,double>(x, y);
107+
}
108+
109+
// CHECK-LABEL: define {{[^@]+}}@first_f64_i32
110+
// CHECK-SAME: (double noundef returned [[X:%.*]], i32 noundef [[Y:%.*]])
111+
// CHECK-LABEL:{{.}}:
112+
// CHECK-NEXT: ret double [[X]]
113+
//
114+
double first_f64_i32(double x, int y)
115+
{
116+
return first<double,int>(x, y);
117+
}
118+
119+
// CHECK-LABEL: define {{[^@]+}}@second_f64_i32
120+
// CHECK-SAME: (double noundef [[X:%.*]], i32 noundef returned [[Y:%.*]])
121+
// CHECK-LABEL:{{.}}:
122+
// CHECK-NEXT: ret i32 [[Y]]
123+
//
124+
int second_f64_i32(double x, int y)
125+
{
126+
return second<double,int>(x, y);
127+
}
128+
}

llvm/include/llvm/InitializePasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ void initializeExpandLargeDivRemLegacyPassPass(PassRegistry&);
106106
void initializeExpandMemCmpLegacyPassPass(PassRegistry &);
107107
void initializeExpandPostRAPass(PassRegistry&);
108108
void initializeExpandReductionsPass(PassRegistry&);
109+
void initializeExpandVariadicsPass(PassRegistry &);
109110
void initializeExpandVectorPredicationPass(PassRegistry &);
110111
void initializeExternalAAWrapperPassPass(PassRegistry&);
111112
void initializeFEntryInserterPass(PassRegistry&);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===- ExpandVariadics.h - expand variadic functions ------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
#ifndef LLVM_TRANSFORMS_IPO_EXPANDVARIADICS_H
9+
#define LLVM_TRANSFORMS_IPO_EXPANDVARIADICS_H
10+
11+
#include "llvm/IR/PassManager.h"
12+
13+
namespace llvm {
14+
15+
class Module;
16+
class ModulePass;
17+
class OptimizationLevel;
18+
19+
enum class ExpandVariadicsMode {
20+
Unspecified, // Use the implementation defaults
21+
Disable, // Disable the pass entirely
22+
Optimize, // Optimise without changing ABI
23+
Lowering, // Change variadic calling convention
24+
};
25+
26+
class ExpandVariadicsPass : public PassInfoMixin<ExpandVariadicsPass> {
27+
const ExpandVariadicsMode Mode;
28+
29+
public:
30+
// Operates under passed mode unless overridden on commandline
31+
ExpandVariadicsPass(ExpandVariadicsMode Mode);
32+
33+
// Chooses disable or optimize based on optimization level
34+
ExpandVariadicsPass(OptimizationLevel Level);
35+
36+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
37+
};
38+
39+
ModulePass *createExpandVariadicsPass(ExpandVariadicsMode);
40+
41+
} // end namespace llvm
42+
43+
#endif // LLVM_TRANSFORMS_IPO_EXPANDVARIADICS_H

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@
137137
#include "llvm/Transforms/IPO/DeadArgumentElimination.h"
138138
#include "llvm/Transforms/IPO/ElimAvailExtern.h"
139139
#include "llvm/Transforms/IPO/EmbedBitcodePass.h"
140+
#include "llvm/Transforms/IPO/ExpandVariadics.h"
140141
#include "llvm/Transforms/IPO/ForceFunctionAttrs.h"
141142
#include "llvm/Transforms/IPO/FunctionAttrs.h"
142143
#include "llvm/Transforms/IPO/FunctionImport.h"

llvm/lib/Passes/PassBuilderPipelines.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "llvm/Transforms/IPO/DeadArgumentElimination.h"
4949
#include "llvm/Transforms/IPO/ElimAvailExtern.h"
5050
#include "llvm/Transforms/IPO/EmbedBitcodePass.h"
51+
#include "llvm/Transforms/IPO/ExpandVariadics.h"
5152
#include "llvm/Transforms/IPO/ForceFunctionAttrs.h"
5253
#include "llvm/Transforms/IPO/FunctionAttrs.h"
5354
#include "llvm/Transforms/IPO/GlobalDCE.h"
@@ -1195,6 +1196,9 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
11951196
if (EnablePGOForceFunctionAttrs && PGOOpt)
11961197
MPM.addPass(PGOForceFunctionAttrsPass(PGOOpt->ColdOptType));
11971198

1199+
// ExpandVariadics interacts well with the function inliner.
1200+
MPM.addPass(ExpandVariadicsPass(Level));
1201+
11981202
MPM.addPass(AlwaysInlinerPass(/*InsertLifetimeIntrinsics=*/true));
11991203

12001204
if (EnableModuleInliner)

llvm/lib/Passes/PassRegistry.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ MODULE_PASS("dot-callgraph", CallGraphDOTPrinterPass())
5959
MODULE_PASS("dxil-upgrade", DXILUpgradePass())
6060
MODULE_PASS("elim-avail-extern", EliminateAvailableExternallyPass())
6161
MODULE_PASS("extract-blocks", BlockExtractorPass({}, false))
62+
MODULE_PASS("expand-variadics", ExpandVariadicsPass(OptimizationLevel::O0))
6263
MODULE_PASS("forceattrs", ForceFunctionAttrsPass())
6364
MODULE_PASS("function-import", FunctionImportPass())
6465
MODULE_PASS("globalopt", GlobalOptPass())

llvm/lib/Transforms/IPO/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ add_llvm_component_library(LLVMipo
1212
DeadArgumentElimination.cpp
1313
ElimAvailExtern.cpp
1414
EmbedBitcodePass.cpp
15+
ExpandVariadics.cpp
1516
ExtractGV.cpp
1617
ForceFunctionAttrs.cpp
1718
FunctionAttrs.cpp

0 commit comments

Comments
 (0)