Bump version to 19.1.0-rc3
[llvm-project.git] / llvm / unittests / Analysis / PluginInlineOrderAnalysisTest.cpp
blobca860a0dd5584343f6fbd1dc3cf163ff25b1ed65
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"
14 namespace llvm {
16 namespace {
18 void anchor() {}
20 std::string libPath(const std::string Name = "InlineOrderPlugin") {
21 const auto &Argvs = testing::internal::GetArgvs();
22 const char *Argv0 =
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 {
32 LLVMContext Ctx;
33 ModulePassManager MPM;
34 InlineParams IP;
36 PassBuilder PB;
37 LoopAnalysisManager LAM;
38 FunctionAnalysisManager FAM;
39 CGSCCAnalysisManager CGAM;
40 ModuleAnalysisManager MAM;
42 SMDiagnostic Error;
44 // Connect the plugin to our compiler instance.
45 void setupPlugin() {
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);
53 CompilerInstance() {
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));
64 ~CompilerInstance() {
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();
70 std::string Output;
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);
77 ASSERT_TRUE(OutputM);
78 Output.clear();
79 raw_string_ostream OStream{Output};
80 OutputM->print(OStream, nullptr);
81 ASSERT_TRUE(true);
85 StringRef TestIRS[] = {
86 // Simple 3 function inline case.
87 R"(
88 define void @f1() {
89 call void @foo()
90 ret void
92 define void @foo() {
93 call void @f3()
94 ret void
96 define void @f3() {
97 ret void
99 )",
100 // Test that has 5 functions of which 2 are recursive.
102 define void @f1() {
103 call void @foo()
104 ret void
106 define void @f2() {
107 call void @foo()
108 ret void
110 define void @foo() {
111 call void @f4()
112 call void @f5()
113 ret void
115 define void @f4() {
116 ret void
118 define void @f5() {
119 call void @foo()
120 ret void
123 // Test with 2 mutually recursive functions and 1 function with a loop.
125 define void @f1() {
126 call void @f2()
127 ret void
129 define void @f2() {
130 call void @foo()
131 ret void
133 define void @foo() {
134 call void @f1()
135 ret void
137 define void @f4() {
138 br label %loop
139 loop:
140 call void @f5()
141 br label %loop
143 define void @f5() {
144 ret void
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){
151 %curr = alloca i32
152 %last = alloca i32
153 %i = alloca i32
154 store i32 1, i32* %curr
155 store i32 1, i32* %last
156 store i32 2, i32* %i
157 br label %loop_cond
158 loop_cond:
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
162 loop_body:
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
171 br label %loop_cond
172 loop_end:
173 %curr_val3 = load i32, i32* %curr
174 ret i32 %curr_val3
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
182 if_true:
183 ret i32 1
184 if_false:
185 %sub = sub i32 %n, 1
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
190 ret i32 %add
193 define i32 @fib_check(){
194 %correct = alloca i32
195 %i = alloca i32
196 store i32 1, i32* %correct
197 store i32 0, i32* %i
198 br label %loop_cond
199 loop_cond:
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
203 loop_body:
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
210 if_true:
211 store i32 0, i32* %correct
212 br label %if_end
213 if_false:
214 br label %if_end
215 if_end:
216 %i_val4 = load i32, i32* %i
217 %add = add i32 %i_val4, 1
218 store i32 %add, i32* %i
219 br label %loop_cond
220 loop_end:
221 %correct_val = load i32, i32* %correct
222 ret i32 %correct_val
224 )"};
226 } // namespace
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.
234 GTEST_SKIP();
235 #endif
236 CompilerInstance CI{};
237 CI.setupPlugin();
239 for (StringRef IR : TestIRS) {
240 bool FoundFoo = false;
241 CI.run(IR);
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);
252 } // namespace llvm