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