Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / unittests / Analysis / PluginInlineOrderAnalysisTest.cpp
blob46957af823fce43c3f9a87fd3046e6fc57c17a7a
1 #include "llvm/Analysis/CallGraph.h"
2 #include "llvm/AsmParser/Parser.h"
3 #include "llvm/Config/config.h"
4 #include "llvm/Passes/PassBuilder.h"
5 #include "llvm/Passes/PassPlugin.h"
6 #include "llvm/Support/CommandLine.h"
7 #include "llvm/Support/raw_ostream.h"
8 #include "llvm/Testing/Support/Error.h"
9 #include "gtest/gtest.h"
11 #include "llvm/Analysis/InlineOrder.h"
13 namespace llvm {
15 namespace {
17 void anchor() {}
19 std::string libPath(const std::string Name = "InlineOrderPlugin") {
20 const auto &Argvs = testing::internal::GetArgvs();
21 const char *Argv0 =
22 Argvs.size() > 0 ? Argvs[0].c_str() : "PluginInlineOrderAnalysisTest";
23 void *Ptr = (void *)(intptr_t)anchor;
24 std::string Path = sys::fs::getMainExecutable(Argv0, Ptr);
25 llvm::SmallString<256> Buf{sys::path::parent_path(Path)};
26 sys::path::append(Buf, (Name + LLVM_PLUGIN_EXT).c_str());
27 return std::string(Buf.str());
30 struct CompilerInstance {
31 LLVMContext Ctx;
32 ModulePassManager MPM;
33 InlineParams IP;
35 PassBuilder PB;
36 LoopAnalysisManager LAM;
37 FunctionAnalysisManager FAM;
38 CGSCCAnalysisManager CGAM;
39 ModuleAnalysisManager MAM;
41 SMDiagnostic Error;
43 // Connect the plugin to our compiler instance.
44 void setupPlugin() {
45 auto PluginPath = libPath();
46 ASSERT_NE("", PluginPath);
47 Expected<PassPlugin> Plugin = PassPlugin::Load(PluginPath);
48 ASSERT_TRUE(!!Plugin) << "Plugin path: " << PluginPath;
49 Plugin->registerPassBuilderCallbacks(PB);
52 CompilerInstance() {
53 IP = getInlineParams(3, 0);
54 PB.registerModuleAnalyses(MAM);
55 PB.registerCGSCCAnalyses(CGAM);
56 PB.registerFunctionAnalyses(FAM);
57 PB.registerLoopAnalyses(LAM);
58 PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
59 MPM.addPass(ModuleInlinerPass(IP, InliningAdvisorMode::Default,
60 ThinOrFullLTOPhase::None));
63 ~CompilerInstance() {
64 // Reset the static variable that tracks if the plugin has been registered.
65 // This is needed to allow the test to run multiple times.
66 PluginInlineOrderAnalysis::unregister();
69 std::string Output;
70 std::unique_ptr<Module> OutputM;
72 // Run with the dynamic inline order.
73 auto run(StringRef IR) {
74 OutputM = parseAssemblyString(IR, Error, Ctx);
75 MPM.run(*OutputM, MAM);
76 ASSERT_TRUE(OutputM);
77 Output.clear();
78 raw_string_ostream OStream{Output};
79 OutputM->print(OStream, nullptr);
80 ASSERT_TRUE(true);
84 StringRef TestIRS[] = {
85 // Simple 3 function inline case.
86 R"(
87 define void @f1() {
88 call void @foo()
89 ret void
91 define void @foo() {
92 call void @f3()
93 ret void
95 define void @f3() {
96 ret void
98 )",
99 // Test that has 5 functions of which 2 are recursive.
101 define void @f1() {
102 call void @foo()
103 ret void
105 define void @f2() {
106 call void @foo()
107 ret void
109 define void @foo() {
110 call void @f4()
111 call void @f5()
112 ret void
114 define void @f4() {
115 ret void
117 define void @f5() {
118 call void @foo()
119 ret void
122 // Test with 2 mutually recursive functions and 1 function with a loop.
124 define void @f1() {
125 call void @f2()
126 ret void
128 define void @f2() {
129 call void @foo()
130 ret void
132 define void @foo() {
133 call void @f1()
134 ret void
136 define void @f4() {
137 br label %loop
138 loop:
139 call void @f5()
140 br label %loop
142 define void @f5() {
143 ret void
146 // Test that has a function that computes fibonacci in a loop, one in a
147 // recursive manner, and one that calls both and compares them.
149 define i32 @fib_loop(i32 %n){
150 %curr = alloca i32
151 %last = alloca i32
152 %i = alloca i32
153 store i32 1, i32* %curr
154 store i32 1, i32* %last
155 store i32 2, i32* %i
156 br label %loop_cond
157 loop_cond:
158 %i_val = load i32, i32* %i
159 %cmp = icmp slt i32 %i_val, %n
160 br i1 %cmp, label %loop_body, label %loop_end
161 loop_body:
162 %curr_val = load i32, i32* %curr
163 %last_val = load i32, i32* %last
164 %add = add i32 %curr_val, %last_val
165 store i32 %add, i32* %last
166 store i32 %curr_val, i32* %curr
167 %i_val2 = load i32, i32* %i
168 %add2 = add i32 %i_val2, 1
169 store i32 %add2, i32* %i
170 br label %loop_cond
171 loop_end:
172 %curr_val3 = load i32, i32* %curr
173 ret i32 %curr_val3
176 define i32 @foo(i32 %n){
177 %cmp = icmp eq i32 %n, 0
178 %cmp2 = icmp eq i32 %n, 1
179 %or = or i1 %cmp, %cmp2
180 br i1 %or, label %if_true, label %if_false
181 if_true:
182 ret i32 1
183 if_false:
184 %sub = sub i32 %n, 1
185 %call = call i32 @foo(i32 %sub)
186 %sub2 = sub i32 %n, 2
187 %call2 = call i32 @foo(i32 %sub2)
188 %add = add i32 %call, %call2
189 ret i32 %add
192 define i32 @fib_check(){
193 %correct = alloca i32
194 %i = alloca i32
195 store i32 1, i32* %correct
196 store i32 0, i32* %i
197 br label %loop_cond
198 loop_cond:
199 %i_val = load i32, i32* %i
200 %cmp = icmp slt i32 %i_val, 10
201 br i1 %cmp, label %loop_body, label %loop_end
202 loop_body:
203 %i_val2 = load i32, i32* %i
204 %call = call i32 @fib_loop(i32 %i_val2)
205 %i_val3 = load i32, i32* %i
206 %call2 = call i32 @foo(i32 %i_val3)
207 %cmp2 = icmp ne i32 %call, %call2
208 br i1 %cmp2, label %if_true, label %if_false
209 if_true:
210 store i32 0, i32* %correct
211 br label %if_end
212 if_false:
213 br label %if_end
214 if_end:
215 %i_val4 = load i32, i32* %i
216 %add = add i32 %i_val4, 1
217 store i32 %add, i32* %i
218 br label %loop_cond
219 loop_end:
220 %correct_val = load i32, i32* %correct
221 ret i32 %correct_val
223 )"};
225 } // namespace
227 // Check that the behaviour of a custom inline order is correct.
228 // The custom order drops any functions named "foo" so all tests
229 // should contain at least one function named foo.
230 TEST(PluginInlineOrderTest, NoInlineFoo) {
231 #if !defined(LLVM_ENABLE_PLUGINS)
232 // Skip the test if plugins are disabled.
233 GTEST_SKIP();
234 #endif
235 CompilerInstance CI{};
236 CI.setupPlugin();
238 for (StringRef IR : TestIRS) {
239 bool FoundFoo = false;
240 CI.run(IR);
241 CallGraph CGraph = CallGraph(*CI.OutputM);
242 for (auto &Node : CGraph) {
243 for (auto &Edge : *Node.second) {
244 FoundFoo |= Edge.second->getFunction()->getName() == "foo";
247 ASSERT_TRUE(FoundFoo);
251 } // namespace llvm