1 #include "llvm/Analysis/CallGraph.h"
2 #include "llvm/AsmParser/Parser.h"
3 #include "llvm/Config/config.h"
4 #include "llvm/IR/Module.h"
5 #include "llvm/Passes/PassBuilder.h"
6 #include "llvm/Passes/PassPlugin.h"
7 #include "llvm/Support/CommandLine.h"
8 #include "llvm/Support/raw_ostream.h"
9 #include "llvm/Testing/Support/Error.h"
10 #include "gtest/gtest.h"
12 #include "llvm/Analysis/InlineOrder.h"
20 std::string
libPath(const std::string Name
= "InlineOrderPlugin") {
21 const auto &Argvs
= testing::internal::GetArgvs();
23 Argvs
.size() > 0 ? Argvs
[0].c_str() : "PluginInlineOrderAnalysisTest";
24 void *Ptr
= (void *)(intptr_t)anchor
;
25 std::string Path
= sys::fs::getMainExecutable(Argv0
, Ptr
);
26 llvm::SmallString
<256> Buf
{sys::path::parent_path(Path
)};
27 sys::path::append(Buf
, (Name
+ LLVM_PLUGIN_EXT
).c_str());
28 return std::string(Buf
.str());
31 struct CompilerInstance
{
33 ModulePassManager MPM
;
37 LoopAnalysisManager LAM
;
38 FunctionAnalysisManager FAM
;
39 CGSCCAnalysisManager CGAM
;
40 ModuleAnalysisManager MAM
;
44 // Connect the plugin to our compiler instance.
46 auto PluginPath
= libPath();
47 ASSERT_NE("", PluginPath
);
48 Expected
<PassPlugin
> Plugin
= PassPlugin::Load(PluginPath
);
49 ASSERT_TRUE(!!Plugin
) << "Plugin path: " << PluginPath
;
50 Plugin
->registerPassBuilderCallbacks(PB
);
54 IP
= getInlineParams(3, 0);
55 PB
.registerModuleAnalyses(MAM
);
56 PB
.registerCGSCCAnalyses(CGAM
);
57 PB
.registerFunctionAnalyses(FAM
);
58 PB
.registerLoopAnalyses(LAM
);
59 PB
.crossRegisterProxies(LAM
, FAM
, CGAM
, MAM
);
60 MPM
.addPass(ModuleInlinerPass(IP
, InliningAdvisorMode::Default
,
61 ThinOrFullLTOPhase::None
));
65 // Reset the static variable that tracks if the plugin has been registered.
66 // This is needed to allow the test to run multiple times.
67 PluginInlineOrderAnalysis::unregister();
71 std::unique_ptr
<Module
> OutputM
;
73 // Run with the dynamic inline order.
74 auto run(StringRef IR
) {
75 OutputM
= parseAssemblyString(IR
, Error
, Ctx
);
76 MPM
.run(*OutputM
, MAM
);
79 raw_string_ostream OStream
{Output
};
80 OutputM
->print(OStream
, nullptr);
85 StringRef TestIRS
[] = {
86 // Simple 3 function inline case.
100 // Test that has 5 functions of which 2 are recursive.
123 // Test with 2 mutually recursive functions and 1 function with a loop.
147 // Test that has a function that computes fibonacci in a loop, one in a
148 // recursive manner, and one that calls both and compares them.
150 define i32 @fib_loop(i32 %n){
154 store i32 1, i32* %curr
155 store i32 1, i32* %last
159 %i_val = load i32, i32* %i
160 %cmp = icmp slt i32 %i_val, %n
161 br i1 %cmp, label %loop_body, label %loop_end
163 %curr_val = load i32, i32* %curr
164 %last_val = load i32, i32* %last
165 %add = add i32 %curr_val, %last_val
166 store i32 %add, i32* %last
167 store i32 %curr_val, i32* %curr
168 %i_val2 = load i32, i32* %i
169 %add2 = add i32 %i_val2, 1
170 store i32 %add2, i32* %i
173 %curr_val3 = load i32, i32* %curr
177 define i32 @foo(i32 %n){
178 %cmp = icmp eq i32 %n, 0
179 %cmp2 = icmp eq i32 %n, 1
180 %or = or i1 %cmp, %cmp2
181 br i1 %or, label %if_true, label %if_false
186 %call = call i32 @foo(i32 %sub)
187 %sub2 = sub i32 %n, 2
188 %call2 = call i32 @foo(i32 %sub2)
189 %add = add i32 %call, %call2
193 define i32 @fib_check(){
194 %correct = alloca i32
196 store i32 1, i32* %correct
200 %i_val = load i32, i32* %i
201 %cmp = icmp slt i32 %i_val, 10
202 br i1 %cmp, label %loop_body, label %loop_end
204 %i_val2 = load i32, i32* %i
205 %call = call i32 @fib_loop(i32 %i_val2)
206 %i_val3 = load i32, i32* %i
207 %call2 = call i32 @foo(i32 %i_val3)
208 %cmp2 = icmp ne i32 %call, %call2
209 br i1 %cmp2, label %if_true, label %if_false
211 store i32 0, i32* %correct
216 %i_val4 = load i32, i32* %i
217 %add = add i32 %i_val4, 1
218 store i32 %add, i32* %i
221 %correct_val = load i32, i32* %correct
228 // Check that the behaviour of a custom inline order is correct.
229 // The custom order drops any functions named "foo" so all tests
230 // should contain at least one function named foo.
231 TEST(PluginInlineOrderTest
, NoInlineFoo
) {
232 #if !defined(LLVM_ENABLE_PLUGINS)
233 // Skip the test if plugins are disabled.
236 CompilerInstance CI
{};
239 for (StringRef IR
: TestIRS
) {
240 bool FoundFoo
= false;
242 CallGraph CGraph
= CallGraph(*CI
.OutputM
);
243 for (auto &Node
: CGraph
) {
244 for (auto &Edge
: *Node
.second
) {
245 FoundFoo
|= Edge
.second
->getFunction()->getName() == "foo";
248 ASSERT_TRUE(FoundFoo
);