xref: /llvm-project/llvm/examples/HowToUseLLJIT/HowToUseLLJIT.cpp (revision 16dcbb53dc7968a3752661aac731172ebe0faf64)
17163aa99Sxgupta //===------- HowToUseLLJIT.cpp - An example use of ORC-based LLJIT --------===//
2843f198aSLang Hames //
3843f198aSLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4843f198aSLang Hames // See https://llvm.org/LICENSE.txt for license information.
5843f198aSLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6843f198aSLang Hames //
7843f198aSLang Hames //===----------------------------------------------------------------------===//
87163aa99Sxgupta //
97163aa99Sxgupta //  This small program provides an example of how to quickly build a small
107163aa99Sxgupta //  module with a 'add1' function and use of IRBuilder to create add & return
117163aa99Sxgupta //  instructions.
127163aa99Sxgupta //
137163aa99Sxgupta // Goal:
147163aa99Sxgupta //  The goal of this snippet is to create in the memory
157163aa99Sxgupta //  the LLVM module consisting of a function as follow:
167163aa99Sxgupta //
177163aa99Sxgupta // int add1(int x) {
187163aa99Sxgupta //   return x+1;
197163aa99Sxgupta // }
207163aa99Sxgupta //  add1(42);
217163aa99Sxgupta //
227163aa99Sxgupta // then compile the module via LLJIT, then execute the 'add1'
237163aa99Sxgupta // function and return result to a driver, i.e. to a "host program".
247163aa99Sxgupta //
257163aa99Sxgupta //===----------------------------------------------------------------------===//
26843f198aSLang Hames 
27e3748b5aSLang Hames #include "llvm/ExecutionEngine/Orc/LLJIT.h"
28e3748b5aSLang Hames #include "llvm/IR/Function.h"
29e3748b5aSLang Hames #include "llvm/IR/IRBuilder.h"
30e3748b5aSLang Hames #include "llvm/IR/Module.h"
3118b45339SSimon Pilgrim #include "llvm/Support/CommandLine.h"
32e3748b5aSLang Hames #include "llvm/Support/InitLLVM.h"
33e3748b5aSLang Hames #include "llvm/Support/TargetSelect.h"
34e3748b5aSLang Hames #include "llvm/Support/raw_ostream.h"
35e3748b5aSLang Hames 
36e3748b5aSLang Hames using namespace llvm;
37e3748b5aSLang Hames using namespace llvm::orc;
38e3748b5aSLang Hames 
39e3748b5aSLang Hames ExitOnError ExitOnErr;
40e3748b5aSLang Hames 
createDemoModule()41e3748b5aSLang Hames ThreadSafeModule createDemoModule() {
420eaee545SJonas Devlieghere   auto Context = std::make_unique<LLVMContext>();
430eaee545SJonas Devlieghere   auto M = std::make_unique<Module>("test", *Context);
44e3748b5aSLang Hames 
45e3748b5aSLang Hames   // Create the add1 function entry and insert this entry into module M.  The
46e3748b5aSLang Hames   // function will have a return type of "int" and take an argument of "int".
47e3748b5aSLang Hames   Function *Add1F =
48e3748b5aSLang Hames       Function::Create(FunctionType::get(Type::getInt32Ty(*Context),
49e3748b5aSLang Hames                                          {Type::getInt32Ty(*Context)}, false),
50e3748b5aSLang Hames                        Function::ExternalLinkage, "add1", M.get());
51e3748b5aSLang Hames 
52e3748b5aSLang Hames   // Add a basic block to the function. As before, it automatically inserts
53e3748b5aSLang Hames   // because of the last argument.
54e3748b5aSLang Hames   BasicBlock *BB = BasicBlock::Create(*Context, "EntryBlock", Add1F);
55e3748b5aSLang Hames 
56e3748b5aSLang Hames   // Create a basic block builder with default parameters.  The builder will
57e3748b5aSLang Hames   // automatically append instructions to the basic block `BB'.
58e3748b5aSLang Hames   IRBuilder<> builder(BB);
59e3748b5aSLang Hames 
60e3748b5aSLang Hames   // Get pointers to the constant `1'.
61e3748b5aSLang Hames   Value *One = builder.getInt32(1);
62e3748b5aSLang Hames 
63e3748b5aSLang Hames   // Get pointers to the integer argument of the add1 function...
64e3748b5aSLang Hames   assert(Add1F->arg_begin() != Add1F->arg_end()); // Make sure there's an arg
65e3748b5aSLang Hames   Argument *ArgX = &*Add1F->arg_begin();          // Get the arg
66e3748b5aSLang Hames   ArgX->setName("AnArg"); // Give it a nice symbolic name for fun.
67e3748b5aSLang Hames 
68e3748b5aSLang Hames   // Create the add instruction, inserting it into the end of BB.
69e3748b5aSLang Hames   Value *Add = builder.CreateAdd(One, ArgX);
70e3748b5aSLang Hames 
71e3748b5aSLang Hames   // Create the return instruction and add it to the basic block
72e3748b5aSLang Hames   builder.CreateRet(Add);
73e3748b5aSLang Hames 
74e3748b5aSLang Hames   return ThreadSafeModule(std::move(M), std::move(Context));
75e3748b5aSLang Hames }
76e3748b5aSLang Hames 
main(int argc,char * argv[])77e3748b5aSLang Hames int main(int argc, char *argv[]) {
78e3748b5aSLang Hames   // Initialize LLVM.
79e3748b5aSLang Hames   InitLLVM X(argc, argv);
80e3748b5aSLang Hames 
81e3748b5aSLang Hames   InitializeNativeTarget();
82e3748b5aSLang Hames   InitializeNativeTargetAsmPrinter();
83e3748b5aSLang Hames 
84e3748b5aSLang Hames   cl::ParseCommandLineOptions(argc, argv, "HowToUseLLJIT");
85e3748b5aSLang Hames   ExitOnErr.setBanner(std::string(argv[0]) + ": ");
86e3748b5aSLang Hames 
87e3748b5aSLang Hames   // Create an LLJIT instance.
88e3748b5aSLang Hames   auto J = ExitOnErr(LLJITBuilder().create());
89e3748b5aSLang Hames   auto M = createDemoModule();
90e3748b5aSLang Hames 
91e3748b5aSLang Hames   ExitOnErr(J->addIRModule(std::move(M)));
92e3748b5aSLang Hames 
93e3748b5aSLang Hames   // Look up the JIT'd function, cast it to a function pointer, then call it.
94*16dcbb53SLang Hames   auto Add1Addr = ExitOnErr(J->lookup("add1"));
95*16dcbb53SLang Hames   int (*Add1)(int) = Add1Addr.toPtr<int(int)>();
96e3748b5aSLang Hames 
97e3748b5aSLang Hames   int Result = Add1(42);
98e3748b5aSLang Hames   outs() << "add1(42) = " << Result << "\n";
99e3748b5aSLang Hames 
100e3748b5aSLang Hames   return 0;
101e3748b5aSLang Hames }
102