brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.2 KiB · ca4ea8b Raw
287 lines · cpp
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"11 12namespace llvm {13 14namespace {15 16void anchor() {}17 18static std::string libPath(const std::string Name = "InlineAdvisorPlugin") {19  const auto &Argvs = testing::internal::GetArgvs();20  const char *Argv0 =21      Argvs.size() > 0 ? Argvs[0].c_str() : "PluginInlineAdvisorAnalysisTest";22  void *Ptr = (void *)(intptr_t)anchor;23  std::string Path = sys::fs::getMainExecutable(Argv0, Ptr);24  llvm::SmallString<256> Buf{sys::path::parent_path(Path)};25  sys::path::append(Buf, (Name + LLVM_PLUGIN_EXT).c_str());26  return std::string(Buf.str());27}28 29// Example of a custom InlineAdvisor that only inlines calls to functions called30// "foo".31class FooOnlyInlineAdvisor : public InlineAdvisor {32public:33  FooOnlyInlineAdvisor(Module &M, FunctionAnalysisManager &FAM,34                       InlineParams Params, InlineContext IC)35      : InlineAdvisor(M, FAM, IC) {}36 37  std::unique_ptr<InlineAdvice> getAdviceImpl(CallBase &CB) override {38    if (CB.getCalledFunction()->getName() == "foo")39      return std::make_unique<InlineAdvice>(this, CB, getCallerORE(CB), true);40    return std::make_unique<InlineAdvice>(this, CB, getCallerORE(CB), false);41  }42};43 44static InlineAdvisor *fooOnlyFactory(Module &M, FunctionAnalysisManager &FAM,45                                     InlineParams Params, InlineContext IC) {46  return new FooOnlyInlineAdvisor(M, FAM, Params, IC);47}48 49struct CompilerInstance {50  LLVMContext Ctx;51  ModulePassManager MPM;52  InlineParams IP;53 54  PassBuilder PB;55  LoopAnalysisManager LAM;56  FunctionAnalysisManager FAM;57  CGSCCAnalysisManager CGAM;58  ModuleAnalysisManager MAM;59 60  SMDiagnostic Error;61 62  // connect the plugin to our compiler instance63  void setupPlugin() {64    auto PluginPath = libPath();65    ASSERT_NE("", PluginPath);66    Expected<PassPlugin> Plugin = PassPlugin::Load(PluginPath);67    ASSERT_TRUE(!!Plugin) << "Plugin path: " << PluginPath;68    Plugin->registerPassBuilderCallbacks(PB);69  }70 71  // connect the FooOnlyInlineAdvisor to our compiler instance72  void setupFooOnly() {73    MAM.registerPass(74        [&] { return PluginInlineAdvisorAnalysis(fooOnlyFactory); });75  }76 77  CompilerInstance() {78    IP = getInlineParams(3, 0);79    PB.registerModuleAnalyses(MAM);80    PB.registerCGSCCAnalyses(CGAM);81    PB.registerFunctionAnalyses(FAM);82    PB.registerLoopAnalyses(LAM);83    PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);84    MPM.addPass(ModuleInlinerPass(IP, InliningAdvisorMode::Default,85                                  ThinOrFullLTOPhase::None));86  }87 88  std::string output;89  std::unique_ptr<Module> outputM;90 91  auto run(StringRef IR) {92    outputM = parseAssemblyString(IR, Error, Ctx);93    MPM.run(*outputM, MAM);94    ASSERT_TRUE(outputM);95    output.clear();96    raw_string_ostream o_stream{output};97    outputM->print(o_stream, nullptr);98    ASSERT_TRUE(true);99  }100};101 102StringRef TestIRS[] = {103    // Simple 3 function inline case104    R"(105define void @f1() {106  call void @foo()107  ret void108}109define void @foo() {110  call void @f3()111  ret void112}113define void @f3() {114  ret void115}116  )",117    // Test that has 5 functions of which 2 are recursive118    R"(119define void @f1() {120  call void @foo()121  ret void122}123define void @f2() {124  call void @foo()125  ret void126}127define void @foo() {128  call void @f4()129  call void @f5()130  ret void131}132define void @f4() {133  ret void134}135define void @f5() {136  call void @foo()137  ret void138}139  )",140    // test with 2 mutually recursive functions and 1 function with a loop141    R"(142define void @f1() {143  call void @f2()144  ret void145}146define void @f2() {147  call void @f3()148  ret void149}150define void @f3() {151  call void @f1()152  ret void153}154define void @f4() {155  br label %loop156loop:157  call void @f5()158  br label %loop159}160define void @f5() {161  ret void162}163  )",164    // test that has a function that computes fibonacci in a loop, one in a165    // recurisve manner, and one that calls both and compares them166    R"(167define i32 @fib_loop(i32 %n){168    %curr = alloca i32169    %last = alloca i32170    %i = alloca i32171    store i32 1, i32* %curr172    store i32 1, i32* %last173    store i32 2, i32* %i174    br label %loop_cond175  loop_cond:176    %i_val = load i32, i32* %i177    %cmp = icmp slt i32 %i_val, %n178    br i1 %cmp, label %loop_body, label %loop_end179  loop_body:180    %curr_val = load i32, i32* %curr181    %last_val = load i32, i32* %last182    %add = add i32 %curr_val, %last_val183    store i32 %add, i32* %last184    store i32 %curr_val, i32* %curr185    %i_val2 = load i32, i32* %i186    %add2 = add i32 %i_val2, 1187    store i32 %add2, i32* %i188    br label %loop_cond189  loop_end:190    %curr_val3 = load i32, i32* %curr191    ret i32 %curr_val3192}193 194define i32 @fib_rec(i32 %n){195    %cmp = icmp eq i32 %n, 0196    %cmp2 = icmp eq i32 %n, 1197    %or = or i1 %cmp, %cmp2198    br i1 %or, label %if_true, label %if_false199  if_true:200    ret i32 1201  if_false:202    %sub = sub i32 %n, 1203    %call = call i32 @fib_rec(i32 %sub)204    %sub2 = sub i32 %n, 2205    %call2 = call i32 @fib_rec(i32 %sub2)206    %add = add i32 %call, %call2207    ret i32 %add208}209 210define i32 @fib_check(){211    %correct = alloca i32212    %i = alloca i32213    store i32 1, i32* %correct214    store i32 0, i32* %i215    br label %loop_cond216  loop_cond:217    %i_val = load i32, i32* %i218    %cmp = icmp slt i32 %i_val, 10219    br i1 %cmp, label %loop_body, label %loop_end220  loop_body:221    %i_val2 = load i32, i32* %i222    %call = call i32 @fib_loop(i32 %i_val2)223    %i_val3 = load i32, i32* %i224    %call2 = call i32 @fib_rec(i32 %i_val3)225    %cmp2 = icmp ne i32 %call, %call2226    br i1 %cmp2, label %if_true, label %if_false227  if_true:228    store i32 0, i32* %correct229    br label %if_end230  if_false:231    br label %if_end232  if_end:233    %i_val4 = load i32, i32* %i234    %add = add i32 %i_val4, 1235    store i32 %add, i32* %i236    br label %loop_cond237  loop_end:238    %correct_val = load i32, i32* %correct239    ret i32 %correct_val240}241  )"};242 243} // namespace244 245// check that loading a plugin works246// the plugin being loaded acts identically to the default inliner247TEST(PluginInlineAdvisorTest, PluginLoad) {248#if !defined(LLVM_ENABLE_PLUGINS)249  // Skip the test if plugins are disabled.250  GTEST_SKIP();251#endif252  CompilerInstance DefaultCI{};253 254  CompilerInstance PluginCI{};255  PluginCI.setupPlugin();256 257  for (StringRef IR : TestIRS) {258    DefaultCI.run(IR);259    std::string default_output = DefaultCI.output;260    PluginCI.run(IR);261    std::string dynamic_output = PluginCI.output;262    ASSERT_EQ(default_output, dynamic_output);263  }264}265 266// check that the behaviour of a custom inliner is correct267// the custom inliner inlines all functions that are not named "foo"268// this testdoes not require plugins to be enabled269TEST(PluginInlineAdvisorTest, CustomAdvisor) {270  CompilerInstance CI{};271  CI.setupFooOnly();272 273  for (StringRef IR : TestIRS) {274    CI.run(IR);275    CallGraph CGraph = CallGraph(*CI.outputM);276    for (auto &node : CGraph) {277      for (auto &edge : *node.second) {278        if (!edge.first)279          continue;280        ASSERT_NE(edge.second->getFunction()->getName(), "foo");281      }282    }283  }284}285 286} // namespace llvm287