blob: f110d00451e5f7ec64da95695df71cc705c8fa13 [file] [log] [blame]
Clement Courbetac74acd2018-04-04 11:37:06 +00001//===-- InMemoryAssembler.cpp -----------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "InMemoryAssembler.h"
11#include "llvm/ADT/SmallVector.h"
12#include "llvm/ADT/StringRef.h"
13#include "llvm/CodeGen/MachineInstrBuilder.h"
14#include "llvm/CodeGen/MachineModuleInfo.h"
15#include "llvm/CodeGen/MachineRegisterInfo.h"
16#include "llvm/CodeGen/TargetInstrInfo.h"
17#include "llvm/CodeGen/TargetPassConfig.h"
18#include "llvm/ExecutionEngine/ExecutionEngine.h"
19#include "llvm/ExecutionEngine/MCJIT.h"
20#include "llvm/ExecutionEngine/SectionMemoryManager.h"
21#include "llvm/IR/LLVMContext.h"
22#include "llvm/IR/LegacyPassManager.h"
23#include "llvm/MC/MCFixup.h"
24#include "llvm/MC/MCInstrDesc.h"
25#include "llvm/Object/Binary.h"
26#include "llvm/Object/ObjectFile.h"
27#include "llvm/PassInfo.h"
28#include "llvm/PassRegistry.h"
29#include "llvm/Support/raw_ostream.h"
30#include "llvm/Target/TargetMachine.h"
31#include "llvm/Target/TargetOptions.h"
32
33namespace exegesis {
34
35static constexpr const char ModuleID[] = "ExegesisInfoTest";
36static constexpr const char FunctionID[] = "foo";
37
38// Small utility function to add named passes.
39static bool addPass(llvm::PassManagerBase &PM, llvm::StringRef PassName,
40 llvm::TargetPassConfig &TPC) {
41 const llvm::PassRegistry *PR = llvm::PassRegistry::getPassRegistry();
42 const llvm::PassInfo *PI = PR->getPassInfo(PassName);
43 if (!PI) {
44 llvm::errs() << " run-pass " << PassName << " is not registered.\n";
45 return true;
46 }
47
48 if (!PI->getNormalCtor()) {
49 llvm::errs() << " cannot create pass: " << PI->getPassName() << "\n";
50 return true;
51 }
52 llvm::Pass *P = PI->getNormalCtor()();
53 std::string Banner = std::string("After ") + std::string(P->getPassName());
54 PM.add(P);
55 TPC.printAndVerify(Banner);
56
57 return false;
58}
59
60// Creates a void MachineFunction with no argument.
61static llvm::MachineFunction &
62createVoidVoidMachineFunction(llvm::StringRef FunctionID, llvm::Module *Module,
63 llvm::MachineModuleInfo *MMI) {
64 llvm::Type *const ReturnType = llvm::Type::getInt32Ty(Module->getContext());
65 llvm::FunctionType *FunctionType = llvm::FunctionType::get(ReturnType, false);
66 llvm::Function *const F = llvm::Function::Create(
67 FunctionType, llvm::GlobalValue::InternalLinkage, FunctionID, Module);
68 // Making sure we can create a MachineFunction out of this Function even if it
69 // contains no IR.
70 F->setIsMaterializable(true);
71 return MMI->getOrCreateMachineFunction(*F);
72}
73
74static llvm::object::OwningBinary<llvm::object::ObjectFile>
75assemble(llvm::Module *Module, std::unique_ptr<llvm::MachineModuleInfo> MMI,
76 llvm::LLVMTargetMachine *LLVMTM) {
77 llvm::legacy::PassManager PM;
78 llvm::MCContext &Context = MMI->getContext();
79
80 llvm::TargetLibraryInfoImpl TLII(llvm::Triple(Module->getTargetTriple()));
81 PM.add(new llvm::TargetLibraryInfoWrapperPass(TLII));
82
83 llvm::TargetPassConfig *TPC = LLVMTM->createPassConfig(PM);
84 PM.add(TPC);
85 PM.add(MMI.release());
86 TPC->printAndVerify("MachineFunctionGenerator::assemble");
87 // Adding the following passes:
88 // - machineverifier: checks that the MachineFunction is well formed.
89 // - prologepilog: saves and restore callee saved registers.
90 for (const char *PassName : {"machineverifier", "prologepilog"})
91 if (addPass(PM, PassName, *TPC))
92 llvm::report_fatal_error("Unable to add a mandatory pass");
93 TPC->setInitialized();
94
95 llvm::SmallVector<char, 4096> AsmBuffer;
96 llvm::raw_svector_ostream AsmStream(AsmBuffer);
97 // AsmPrinter is responsible for generating the assembly into AsmBuffer.
98 if (LLVMTM->addAsmPrinter(PM, AsmStream, llvm::TargetMachine::CGFT_ObjectFile,
99 Context))
100 llvm::report_fatal_error("Cannot add AsmPrinter passes");
101
102 PM.run(*Module); // Run all the passes
103
104 // Storing the generated assembly into a MemoryBuffer that owns the memory.
105 std::unique_ptr<llvm::MemoryBuffer> Buffer =
106 llvm::MemoryBuffer::getMemBufferCopy(AsmStream.str());
107 // Create the ObjectFile from the MemoryBuffer.
108 std::unique_ptr<llvm::object::ObjectFile> Obj = llvm::cantFail(
109 llvm::object::ObjectFile::createObjectFile(Buffer->getMemBufferRef()));
110 // Returning both the MemoryBuffer and the ObjectFile.
111 return llvm::object::OwningBinary<llvm::object::ObjectFile>(
112 std::move(Obj), std::move(Buffer));
113}
114
115static void fillMachineFunction(llvm::MachineFunction &MF,
116 llvm::ArrayRef<llvm::MCInst> Instructions) {
117 llvm::MachineBasicBlock *MBB = MF.CreateMachineBasicBlock();
118 MF.push_back(MBB);
119 const llvm::MCInstrInfo *MCII = MF.getTarget().getMCInstrInfo();
Clement Courbet615b31d2018-04-04 11:45:53 +0000120 llvm::DebugLoc DL;
Clement Courbetac74acd2018-04-04 11:37:06 +0000121 for (const llvm::MCInst &Inst : Instructions) {
122 const unsigned Opcode = Inst.getOpcode();
123 const llvm::MCInstrDesc &MCID = MCII->get(Opcode);
124 llvm::MachineInstrBuilder Builder = llvm::BuildMI(MBB, DL, MCID);
125 for (unsigned OpIndex = 0, E = Inst.getNumOperands(); OpIndex < E;
126 ++OpIndex) {
127 const llvm::MCOperand &Op = Inst.getOperand(OpIndex);
128 if (Op.isReg()) {
129 const bool IsDef = OpIndex < MCID.getNumDefs();
130 unsigned Flags = 0;
131 const llvm::MCOperandInfo &OpInfo = MCID.operands().begin()[OpIndex];
132 if (IsDef && !OpInfo.isOptionalDef())
133 Flags |= llvm::RegState::Define;
134 Builder.addReg(Op.getReg(), Flags);
135 } else if (Op.isImm()) {
136 Builder.addImm(Op.getImm());
137 } else {
138 llvm_unreachable("Not yet implemented");
139 }
140 }
141 }
142 // Adding the Return Opcode.
143 const llvm::TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
144 llvm::BuildMI(MBB, DL, TII->get(TII->getReturnOpcode()));
145}
146
147namespace {
148
149// Implementation of this class relies on the fact that a single object with a
150// single function will be loaded into memory.
151class TrackingSectionMemoryManager : public llvm::SectionMemoryManager {
152public:
153 explicit TrackingSectionMemoryManager(uintptr_t *CodeSize)
154 : CodeSize(CodeSize) {}
155
156 uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
157 unsigned SectionID,
158 llvm::StringRef SectionName) override {
159 *CodeSize = Size;
160 return llvm::SectionMemoryManager::allocateCodeSection(
161 Size, Alignment, SectionID, SectionName);
162 }
163
164private:
165 uintptr_t *const CodeSize = nullptr;
166};
167
168} // namespace
169
170JitFunctionContext::JitFunctionContext(
171 std::unique_ptr<llvm::LLVMTargetMachine> TheTM)
172 : Context(llvm::make_unique<llvm::LLVMContext>()), TM(std::move(TheTM)),
173 MMI(llvm::make_unique<llvm::MachineModuleInfo>(TM.get())),
174 Module(llvm::make_unique<llvm::Module>(ModuleID, *Context)) {
175 Module->setDataLayout(TM->createDataLayout());
176 MF = &createVoidVoidMachineFunction(FunctionID, Module.get(), MMI.get());
177 // We need to instruct the passes that we're done with SSA and virtual
178 // registers.
179 auto &Properties = MF->getProperties();
180 Properties.set(llvm::MachineFunctionProperties::Property::NoVRegs);
181 Properties.reset(llvm::MachineFunctionProperties::Property::IsSSA);
182 Properties.reset(llvm::MachineFunctionProperties::Property::TracksLiveness);
183 // prologue/epilogue pass needs the reserved registers to be frozen, this is
184 // usually done by the SelectionDAGISel pass.
185 MF->getRegInfo().freezeReservedRegs(*MF);
186 // Saving reserved registers for client.
187 ReservedRegs = MF->getSubtarget().getRegisterInfo()->getReservedRegs(*MF);
188}
189
190JitFunction::JitFunction(JitFunctionContext &&Context,
191 llvm::ArrayRef<llvm::MCInst> Instructions)
192 : FunctionContext(std::move(Context)) {
193 fillMachineFunction(*FunctionContext.MF, Instructions);
194 // We create the pass manager, run the passes and returns the produced
195 // ObjectFile.
196 llvm::object::OwningBinary<llvm::object::ObjectFile> ObjHolder =
197 assemble(FunctionContext.Module.get(), std::move(FunctionContext.MMI),
198 FunctionContext.TM.get());
199 assert(ObjHolder.getBinary() && "cannot create object file");
200 // Initializing the execution engine.
201 // We need to use the JIT EngineKind to be able to add an object file.
202 LLVMLinkInMCJIT();
203 uintptr_t CodeSize = 0;
204 std::string Error;
Simon Pilgrim715596d2018-04-18 13:39:03 +0000205 llvm::LLVMTargetMachine *TM = FunctionContext.TM.release();
Clement Courbetac74acd2018-04-04 11:37:06 +0000206 ExecEngine.reset(
207 llvm::EngineBuilder(std::move(FunctionContext.Module))
208 .setErrorStr(&Error)
209 .setMCPU(FunctionContext.TM->getTargetCPU())
210 .setEngineKind(llvm::EngineKind::JIT)
211 .setMCJITMemoryManager(
212 llvm::make_unique<TrackingSectionMemoryManager>(&CodeSize))
Simon Pilgrim715596d2018-04-18 13:39:03 +0000213 .create(TM));
Clement Courbetac74acd2018-04-04 11:37:06 +0000214 if (!ExecEngine)
215 llvm::report_fatal_error(Error);
216 // Adding the generated object file containing the assembled function.
217 // The ExecutionEngine makes sure the object file is copied into an
218 // executable page.
Clement Courbet19249932018-04-13 14:46:48 +0000219 ExecEngine->addObjectFile(std::move(ObjHolder));
Clement Courbetac74acd2018-04-04 11:37:06 +0000220 // Setting function
221 FunctionBytes =
222 llvm::StringRef(reinterpret_cast<const char *>(
223 ExecEngine->getFunctionAddress(FunctionID)),
224 CodeSize);
225}
226
227} // namespace exegesis