//===-- LLJITWithOptimizingIRTransform.cpp -- LLJIT with IR optimization --===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // In this example we will use an IR transform to optimize a module as it // passes through LLJIT's IRTransformLayer. // //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/LLJIT.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Scalar.h" #include "../ExampleModules.h" using namespace llvm; using namespace llvm::orc; ExitOnError ExitOnErr; // Example IR module. // // This IR contains a recursive definition of the factorial function: // // fac(n) | n == 0 = 1 // | otherwise = n * fac(n - 1) // // It also contains an entry function which calls the factorial function with // an input value of 5. // // We expect the IR optimization transform that we build below to transform // this into a non-recursive factorial function and an entry function that // returns a constant value of 5!, or 120. const llvm::StringRef MainMod = R"( define i32 @fac(i32 %n) { entry: %tobool = icmp eq i32 %n, 0 br i1 %tobool, label %return, label %if.then if.then: ; preds = %entry %arg = add nsw i32 %n, -1 %call_result = call i32 @fac(i32 %arg) %result = mul nsw i32 %n, %call_result br label %return return: ; preds = %entry, %if.then %final_result = phi i32 [ %result, %if.then ], [ 1, %entry ] ret i32 %final_result } define i32 @entry() { entry: %result = call i32 @fac(i32 5) ret i32 %result } )"; // A function object that creates a simple pass pipeline to apply to each // module as it passes through the IRTransformLayer. class MyOptimizationTransform { public: MyOptimizationTransform() : PM(std::make_unique()) { PM->add(createTailCallEliminationPass()); PM->add(createFunctionInliningPass()); PM->add(createIndVarSimplifyPass()); PM->add(createCFGSimplificationPass()); } Expected operator()(ThreadSafeModule TSM, MaterializationResponsibility &R) { TSM.withModuleDo([this](Module &M) { dbgs() << "--- BEFORE OPTIMIZATION ---\n" << M << "\n"; PM->run(M); dbgs() << "--- AFTER OPTIMIZATION ---\n" << M << "\n"; }); return std::move(TSM); } private: std::unique_ptr PM; }; int main(int argc, char *argv[]) { // Initialize LLVM. InitLLVM X(argc, argv); InitializeNativeTarget(); InitializeNativeTargetAsmPrinter(); ExitOnErr.setBanner(std::string(argv[0]) + ": "); // (1) Create LLJIT instance. auto J = ExitOnErr(LLJITBuilder().create()); // (2) Install transform to optimize modules when they're materialized. J->getIRTransformLayer().setTransform(MyOptimizationTransform()); // (3) Add modules. ExitOnErr(J->addIRModule(ExitOnErr(parseExampleModule(MainMod, "MainMod")))); // (4) Look up the JIT'd function and call it. auto EntrySym = ExitOnErr(J->lookup("entry")); auto *Entry = (int (*)())EntrySym.getAddress(); int Result = Entry(); outs() << "--- Result ---\n" << "entry() = " << Result << "\n"; return 0; }