1 | //===-- Assembler.cpp -------------------------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "Assembler.h" |
10 | |
11 | #include "SnippetRepetitor.h" |
12 | #include "SubprocessMemory.h" |
13 | #include "Target.h" |
14 | #include "llvm/Analysis/TargetLibraryInfo.h" |
15 | #include "llvm/CodeGen/FunctionLoweringInfo.h" |
16 | #include "llvm/CodeGen/GlobalISel/CallLowering.h" |
17 | #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" |
18 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
19 | #include "llvm/CodeGen/MachineModuleInfo.h" |
20 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
21 | #include "llvm/CodeGen/TargetInstrInfo.h" |
22 | #include "llvm/CodeGen/TargetLowering.h" |
23 | #include "llvm/CodeGen/TargetPassConfig.h" |
24 | #include "llvm/CodeGen/TargetSubtargetInfo.h" |
25 | #include "llvm/ExecutionEngine/Orc/LLJIT.h" |
26 | #include "llvm/IR/BasicBlock.h" |
27 | #include "llvm/IR/Instructions.h" |
28 | #include "llvm/IR/LegacyPassManager.h" |
29 | #include "llvm/MC/MCInstrInfo.h" |
30 | #include "llvm/Object/SymbolSize.h" |
31 | #include "llvm/Support/Alignment.h" |
32 | #include "llvm/Support/Error.h" |
33 | #include "llvm/Support/MemoryBuffer.h" |
34 | #include "llvm/Support/raw_ostream.h" |
35 | |
36 | #ifdef HAVE_LIBPFM |
37 | #include "perfmon/perf_event.h" |
38 | #endif // HAVE_LIBPFM |
39 | |
40 | #ifdef __linux__ |
41 | #include <unistd.h> |
42 | #endif |
43 | |
44 | namespace llvm { |
45 | namespace exegesis { |
46 | |
47 | static constexpr const char ModuleID[] = "ExegesisInfoTest" ; |
48 | static constexpr const char FunctionID[] = "foo" ; |
49 | static const Align kFunctionAlignment(4096); |
50 | |
51 | // Fills the given basic block with register setup code, and returns true if |
52 | // all registers could be setup correctly. |
53 | static bool generateSnippetSetupCode(const ExegesisTarget &ET, |
54 | const MCSubtargetInfo *const MSI, |
55 | BasicBlockFiller &BBF, |
56 | const BenchmarkKey &Key, |
57 | bool GenerateMemoryInstructions) { |
58 | bool IsSnippetSetupComplete = true; |
59 | if (GenerateMemoryInstructions) { |
60 | BBF.addInstructions(Insts: ET.generateMemoryInitialSetup()); |
61 | for (const MemoryMapping &MM : Key.MemoryMappings) { |
62 | #ifdef __linux__ |
63 | // The frontend that generates that parses the memory mapping information |
64 | // from the user should validate that the requested address is a multiple |
65 | // of the page size. Assert that this is true here. |
66 | assert(MM.Address % getpagesize() == 0 && |
67 | "Memory mappings need to be aligned to page boundaries." ); |
68 | #endif |
69 | const MemoryValue &MemVal = Key.MemoryValues.at(k: MM.MemoryValueName); |
70 | BBF.addInstructions(Insts: ET.generateMmap( |
71 | Address: MM.Address, Length: MemVal.SizeBytes, |
72 | FileDescriptorAddress: ET.getAuxiliaryMemoryStartAddress() + |
73 | sizeof(int) * |
74 | (MemVal.Index + SubprocessMemory::AuxiliaryMemoryOffset))); |
75 | } |
76 | BBF.addInstructions(Insts: ET.setStackRegisterToAuxMem()); |
77 | } |
78 | Register StackPointerRegister = BBF.MF.getSubtarget() |
79 | .getTargetLowering() |
80 | ->getStackPointerRegisterToSaveRestore(); |
81 | for (const RegisterValue &RV : Key.RegisterInitialValues) { |
82 | if (GenerateMemoryInstructions) { |
83 | // If we're generating memory instructions, don't load in the value for |
84 | // the register with the stack pointer as it will be used later to finish |
85 | // the setup. |
86 | if (Register(RV.Register) == StackPointerRegister) |
87 | continue; |
88 | } |
89 | // Load a constant in the register. |
90 | const auto SetRegisterCode = ET.setRegTo(STI: *MSI, Reg: RV.Register, Value: RV.Value); |
91 | if (SetRegisterCode.empty()) |
92 | IsSnippetSetupComplete = false; |
93 | BBF.addInstructions(Insts: SetRegisterCode); |
94 | } |
95 | if (GenerateMemoryInstructions) { |
96 | #ifdef HAVE_LIBPFM |
97 | BBF.addInstructions(ET.configurePerfCounter(PERF_EVENT_IOC_RESET, true)); |
98 | #endif // HAVE_LIBPFM |
99 | for (const RegisterValue &RV : Key.RegisterInitialValues) { |
100 | // Load in the stack register now as we're done using it elsewhere |
101 | // and need to set the value in preparation for executing the |
102 | // snippet. |
103 | if (Register(RV.Register) != StackPointerRegister) |
104 | continue; |
105 | const auto SetRegisterCode = ET.setRegTo(STI: *MSI, Reg: RV.Register, Value: RV.Value); |
106 | if (SetRegisterCode.empty()) |
107 | IsSnippetSetupComplete = false; |
108 | BBF.addInstructions(Insts: SetRegisterCode); |
109 | break; |
110 | } |
111 | } |
112 | return IsSnippetSetupComplete; |
113 | } |
114 | |
115 | // Small utility function to add named passes. |
116 | static bool addPass(PassManagerBase &PM, StringRef PassName, |
117 | TargetPassConfig &TPC) { |
118 | const PassRegistry *PR = PassRegistry::getPassRegistry(); |
119 | const PassInfo *PI = PR->getPassInfo(Arg: PassName); |
120 | if (!PI) { |
121 | errs() << " run-pass " << PassName << " is not registered.\n" ; |
122 | return true; |
123 | } |
124 | |
125 | if (!PI->getNormalCtor()) { |
126 | errs() << " cannot create pass: " << PI->getPassName() << "\n" ; |
127 | return true; |
128 | } |
129 | Pass *P = PI->getNormalCtor()(); |
130 | std::string Banner = std::string("After " ) + std::string(P->getPassName()); |
131 | PM.add(P); |
132 | TPC.printAndVerify(Banner); |
133 | |
134 | return false; |
135 | } |
136 | |
137 | MachineFunction &createVoidVoidPtrMachineFunction(StringRef FunctionName, |
138 | Module *Module, |
139 | MachineModuleInfo *MMI) { |
140 | Type *const ReturnType = Type::getInt32Ty(C&: Module->getContext()); |
141 | Type *const MemParamType = |
142 | PointerType::get(C&: Module->getContext(), AddressSpace: 0 /*default address space*/); |
143 | FunctionType *FunctionType = |
144 | FunctionType::get(Result: ReturnType, Params: {MemParamType}, isVarArg: false); |
145 | Function *const F = Function::Create( |
146 | Ty: FunctionType, Linkage: GlobalValue::ExternalLinkage, N: FunctionName, M: Module); |
147 | BasicBlock *BB = BasicBlock::Create(Context&: Module->getContext(), Name: "" , Parent: F); |
148 | new UnreachableInst(Module->getContext(), BB); |
149 | return MMI->getOrCreateMachineFunction(F&: *F); |
150 | } |
151 | |
152 | BasicBlockFiller::BasicBlockFiller(MachineFunction &MF, MachineBasicBlock *MBB, |
153 | const MCInstrInfo *MCII) |
154 | : MF(MF), MBB(MBB), MCII(MCII) {} |
155 | |
156 | void BasicBlockFiller::addInstruction(const MCInst &Inst, const DebugLoc &DL) { |
157 | const unsigned Opcode = Inst.getOpcode(); |
158 | const MCInstrDesc &MCID = MCII->get(Opcode); |
159 | MachineInstrBuilder Builder = BuildMI(BB: MBB, MIMD: DL, MCID); |
160 | for (unsigned OpIndex = 0, E = Inst.getNumOperands(); OpIndex < E; |
161 | ++OpIndex) { |
162 | const MCOperand &Op = Inst.getOperand(i: OpIndex); |
163 | if (Op.isReg()) { |
164 | const bool IsDef = OpIndex < MCID.getNumDefs(); |
165 | unsigned Flags = 0; |
166 | const MCOperandInfo &OpInfo = MCID.operands().begin()[OpIndex]; |
167 | if (IsDef && !OpInfo.isOptionalDef()) |
168 | Flags |= RegState::Define; |
169 | Builder.addReg(RegNo: Op.getReg(), flags: Flags); |
170 | } else if (Op.isImm()) { |
171 | Builder.addImm(Val: Op.getImm()); |
172 | } else if (!Op.isValid()) { |
173 | llvm_unreachable("Operand is not set" ); |
174 | } else { |
175 | llvm_unreachable("Not yet implemented" ); |
176 | } |
177 | } |
178 | } |
179 | |
180 | void BasicBlockFiller::addInstructions(ArrayRef<MCInst> Insts, |
181 | const DebugLoc &DL) { |
182 | for (const MCInst &Inst : Insts) |
183 | addInstruction(Inst, DL); |
184 | } |
185 | |
186 | void BasicBlockFiller::addReturn(const ExegesisTarget &ET, |
187 | bool SubprocessCleanup, const DebugLoc &DL) { |
188 | // Insert cleanup code |
189 | if (SubprocessCleanup) { |
190 | #ifdef HAVE_LIBPFM |
191 | addInstructions(ET.configurePerfCounter(PERF_EVENT_IOC_DISABLE, false)); |
192 | #endif // HAVE_LIBPFM |
193 | #ifdef __linux__ |
194 | addInstructions(Insts: ET.generateExitSyscall(ExitCode: 0)); |
195 | #endif // __linux__ |
196 | } |
197 | // Insert the return code. |
198 | const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); |
199 | if (TII->getReturnOpcode() < TII->getNumOpcodes()) { |
200 | BuildMI(BB: MBB, MIMD: DL, MCID: TII->get(Opcode: TII->getReturnOpcode())); |
201 | } else { |
202 | MachineIRBuilder MIB(MF); |
203 | MIB.setMBB(*MBB); |
204 | |
205 | FunctionLoweringInfo FuncInfo; |
206 | FuncInfo.CanLowerReturn = true; |
207 | MF.getSubtarget().getCallLowering()->lowerReturn(MIRBuilder&: MIB, Val: nullptr, VRegs: {}, FLI&: FuncInfo, |
208 | SwiftErrorVReg: 0); |
209 | } |
210 | } |
211 | |
212 | FunctionFiller::FunctionFiller(MachineFunction &MF, |
213 | std::vector<MCRegister> ) |
214 | : MF(MF), MCII(MF.getTarget().getMCInstrInfo()), Entry(addBasicBlock()), |
215 | RegistersSetUp(std::move(RegistersSetUp)) {} |
216 | |
217 | BasicBlockFiller FunctionFiller::addBasicBlock() { |
218 | MachineBasicBlock *MBB = MF.CreateMachineBasicBlock(); |
219 | MF.push_back(MBB); |
220 | return BasicBlockFiller(MF, MBB, MCII); |
221 | } |
222 | |
223 | ArrayRef<MCRegister> FunctionFiller::() const { |
224 | return RegistersSetUp; |
225 | } |
226 | |
227 | static std::unique_ptr<Module> |
228 | createModule(const std::unique_ptr<LLVMContext> &Context, const DataLayout &DL) { |
229 | auto Mod = std::make_unique<Module>(args: ModuleID, args&: *Context); |
230 | Mod->setDataLayout(DL); |
231 | return Mod; |
232 | } |
233 | |
234 | BitVector getFunctionReservedRegs(const TargetMachine &TM) { |
235 | std::unique_ptr<LLVMContext> Context = std::make_unique<LLVMContext>(); |
236 | std::unique_ptr<Module> Module = createModule(Context, DL: TM.createDataLayout()); |
237 | auto MMIWP = std::make_unique<MachineModuleInfoWrapperPass>(args: &TM); |
238 | MachineFunction &MF = createVoidVoidPtrMachineFunction( |
239 | FunctionName: FunctionID, Module: Module.get(), MMI: &MMIWP->getMMI()); |
240 | // Saving reserved registers for client. |
241 | return MF.getSubtarget().getRegisterInfo()->getReservedRegs(MF); |
242 | } |
243 | |
244 | Error assembleToStream(const ExegesisTarget &ET, |
245 | std::unique_ptr<TargetMachine> TM, |
246 | ArrayRef<MCRegister> LiveIns, const FillFunction &Fill, |
247 | raw_pwrite_stream &AsmStream, const BenchmarkKey &Key, |
248 | bool GenerateMemoryInstructions) { |
249 | auto Context = std::make_unique<LLVMContext>(); |
250 | std::unique_ptr<Module> Module = |
251 | createModule(Context, DL: TM->createDataLayout()); |
252 | auto MMIWP = std::make_unique<MachineModuleInfoWrapperPass>(args: TM.get()); |
253 | MachineFunction &MF = createVoidVoidPtrMachineFunction( |
254 | FunctionName: FunctionID, Module: Module.get(), MMI: &MMIWP.get()->getMMI()); |
255 | MF.ensureAlignment(A: kFunctionAlignment); |
256 | |
257 | // We need to instruct the passes that we're done with SSA and virtual |
258 | // registers. |
259 | auto &Properties = MF.getProperties(); |
260 | Properties.setNoVRegs().resetIsSSA().setNoPHIs(); |
261 | |
262 | for (const MCRegister Reg : LiveIns) |
263 | MF.getRegInfo().addLiveIn(Reg); |
264 | |
265 | if (GenerateMemoryInstructions) { |
266 | for (const MCRegister Reg : ET.getArgumentRegisters()) |
267 | MF.getRegInfo().addLiveIn(Reg); |
268 | // Add a live in for registers that need saving so that the machine verifier |
269 | // doesn't fail if the register is never defined. |
270 | for (const MCRegister Reg : ET.getRegistersNeedSaving()) |
271 | MF.getRegInfo().addLiveIn(Reg); |
272 | } |
273 | |
274 | std::vector<MCRegister> ; |
275 | RegistersSetUp.reserve(n: Key.RegisterInitialValues.size()); |
276 | for (const auto &InitValue : Key.RegisterInitialValues) { |
277 | RegistersSetUp.push_back(x: InitValue.Register); |
278 | } |
279 | FunctionFiller Sink(MF, std::move(RegistersSetUp)); |
280 | auto Entry = Sink.getEntry(); |
281 | |
282 | for (const MCRegister Reg : LiveIns) |
283 | Entry.MBB->addLiveIn(PhysReg: Reg); |
284 | |
285 | if (GenerateMemoryInstructions) { |
286 | for (const MCRegister Reg : ET.getArgumentRegisters()) |
287 | Entry.MBB->addLiveIn(PhysReg: Reg); |
288 | // Add a live in for registers that need saving so that the machine verifier |
289 | // doesn't fail if the register is never defined. |
290 | for (const MCRegister Reg : ET.getRegistersNeedSaving()) |
291 | Entry.MBB->addLiveIn(PhysReg: Reg); |
292 | } |
293 | |
294 | const bool IsSnippetSetupComplete = generateSnippetSetupCode( |
295 | ET, MSI: TM->getMCSubtargetInfo(), BBF&: Entry, Key, GenerateMemoryInstructions); |
296 | |
297 | // If the snippet setup is not complete, we disable liveliness tracking. This |
298 | // means that we won't know what values are in the registers. |
299 | // FIXME: this should probably be an assertion. |
300 | if (!IsSnippetSetupComplete) |
301 | Properties.resetTracksLiveness(); |
302 | |
303 | Fill(Sink); |
304 | |
305 | // prologue/epilogue pass needs the reserved registers to be frozen, this |
306 | // is usually done by the SelectionDAGISel pass. |
307 | MF.getRegInfo().freezeReservedRegs(); |
308 | |
309 | // We create the pass manager, run the passes to populate AsmBuffer. |
310 | MCContext &MCContext = MMIWP->getMMI().getContext(); |
311 | legacy::PassManager PM; |
312 | |
313 | TargetLibraryInfoImpl TLII(Module->getTargetTriple()); |
314 | PM.add(P: new TargetLibraryInfoWrapperPass(TLII)); |
315 | |
316 | TargetPassConfig *TPC = TM->createPassConfig(PM); |
317 | PM.add(P: TPC); |
318 | PM.add(P: MMIWP.release()); |
319 | TPC->printAndVerify(Banner: "MachineFunctionGenerator::assemble" ); |
320 | // Add target-specific passes. |
321 | ET.addTargetSpecificPasses(PM); |
322 | TPC->printAndVerify(Banner: "After ExegesisTarget::addTargetSpecificPasses" ); |
323 | // Adding the following passes: |
324 | // - postrapseudos: expands pseudo return instructions used on some targets. |
325 | // - prologepilog: saves and restore callee saved registers. |
326 | for (const char *PassName : {"postrapseudos" , "prologepilog" }) |
327 | if (addPass(PM, PassName, TPC&: *TPC)) |
328 | return make_error<Failure>(Args: "Unable to add a mandatory pass" ); |
329 | TPC->setInitialized(); |
330 | |
331 | // AsmPrinter is responsible for generating the assembly into AsmBuffer. |
332 | if (TM->addAsmPrinter(PM, Out&: AsmStream, DwoOut: nullptr, FileType: CodeGenFileType::ObjectFile, |
333 | Context&: MCContext)) |
334 | return make_error<Failure>(Args: "Cannot add AsmPrinter passes" ); |
335 | |
336 | PM.run(M&: *Module); // Run all the passes |
337 | bool MFWellFormed = |
338 | MF.verify(p: nullptr, Banner: "llvm-exegesis Assembly" , OS: &outs(), AbortOnError: false); |
339 | if (!MFWellFormed) |
340 | return make_error<Failure>(Args: "The machine function failed verification." ); |
341 | return Error::success(); |
342 | } |
343 | |
344 | object::OwningBinary<object::ObjectFile> |
345 | getObjectFromBuffer(StringRef InputData) { |
346 | // Storing the generated assembly into a MemoryBuffer that owns the memory. |
347 | std::unique_ptr<MemoryBuffer> Buffer = |
348 | MemoryBuffer::getMemBufferCopy(InputData); |
349 | // Create the ObjectFile from the MemoryBuffer. |
350 | std::unique_ptr<object::ObjectFile> Obj = |
351 | cantFail(ValOrErr: object::ObjectFile::createObjectFile(Object: Buffer->getMemBufferRef())); |
352 | // Returning both the MemoryBuffer and the ObjectFile. |
353 | return object::OwningBinary<object::ObjectFile>(std::move(Obj), |
354 | std::move(Buffer)); |
355 | } |
356 | |
357 | object::OwningBinary<object::ObjectFile> getObjectFromFile(StringRef Filename) { |
358 | return cantFail(ValOrErr: object::ObjectFile::createObjectFile(ObjectPath: Filename)); |
359 | } |
360 | |
361 | Expected<ExecutableFunction> ExecutableFunction::create( |
362 | std::unique_ptr<TargetMachine> TM, |
363 | object::OwningBinary<object::ObjectFile> &&ObjectFileHolder) { |
364 | assert(ObjectFileHolder.getBinary() && "cannot create object file" ); |
365 | std::unique_ptr<LLVMContext> Ctx = std::make_unique<LLVMContext>(); |
366 | |
367 | auto SymbolSizes = object::computeSymbolSizes(O: *ObjectFileHolder.getBinary()); |
368 | // Get the size of the function that we want to call into (with the name of |
369 | // FunctionID). |
370 | auto SymbolIt = find_if(Range&: SymbolSizes, P: [&](const auto &Pair) { |
371 | auto SymbolName = Pair.first.getName(); |
372 | if (SymbolName) |
373 | return *SymbolName == FunctionID; |
374 | // We should always succeed in finding the FunctionID, hence we suppress |
375 | // the error here and assert later on the search result, rather than |
376 | // propagating the Expected<> error back to the caller. |
377 | consumeError(SymbolName.takeError()); |
378 | return false; |
379 | }); |
380 | assert(SymbolIt != SymbolSizes.end() && |
381 | "Cannot find the symbol for FunctionID" ); |
382 | uintptr_t CodeSize = SymbolIt->second; |
383 | |
384 | auto EJITOrErr = orc::LLJITBuilder().create(); |
385 | if (!EJITOrErr) |
386 | return EJITOrErr.takeError(); |
387 | |
388 | auto EJIT = std::move(*EJITOrErr); |
389 | |
390 | if (auto ObjErr = |
391 | EJIT->addObjectFile(Obj: std::get<1>(in: ObjectFileHolder.takeBinary()))) |
392 | return std::move(ObjErr); |
393 | |
394 | auto FunctionAddressOrErr = EJIT->lookup(UnmangledName: FunctionID); |
395 | if (!FunctionAddressOrErr) |
396 | return FunctionAddressOrErr.takeError(); |
397 | |
398 | const uint64_t FunctionAddress = FunctionAddressOrErr->getValue(); |
399 | |
400 | assert(isAligned(kFunctionAlignment, FunctionAddress) && |
401 | "function is not properly aligned" ); |
402 | |
403 | StringRef FBytes = |
404 | StringRef(reinterpret_cast<const char *>(FunctionAddress), CodeSize); |
405 | return ExecutableFunction(std::move(Ctx), std::move(EJIT), FBytes); |
406 | } |
407 | |
408 | ExecutableFunction::ExecutableFunction(std::unique_ptr<LLVMContext> Ctx, |
409 | std::unique_ptr<orc::LLJIT> EJIT, |
410 | StringRef FB) |
411 | : FunctionBytes(FB), Context(std::move(Ctx)), ExecJIT(std::move(EJIT)) {} |
412 | |
413 | Error getBenchmarkFunctionBytes(const StringRef InputData, |
414 | std::vector<uint8_t> &Bytes) { |
415 | const auto Holder = getObjectFromBuffer(InputData); |
416 | const auto *Obj = Holder.getBinary(); |
417 | // See RuntimeDyldImpl::loadObjectImpl(Obj) for much more complete |
418 | // implementation. |
419 | |
420 | // Find the only function in the object file. |
421 | SmallVector<object::SymbolRef, 1> Functions; |
422 | for (auto &Sym : Obj->symbols()) { |
423 | auto SymType = Sym.getType(); |
424 | if (SymType && *SymType == object::SymbolRef::Type::ST_Function) |
425 | Functions.push_back(Elt: Sym); |
426 | } |
427 | if (Functions.size() != 1) |
428 | return make_error<Failure>(Args: "Exactly one function expected" ); |
429 | |
430 | // Find the containing section - it is assumed to contain only this function. |
431 | auto SectionOrErr = Functions.front().getSection(); |
432 | if (!SectionOrErr || *SectionOrErr == Obj->section_end()) |
433 | return make_error<Failure>(Args: "Section not found" ); |
434 | |
435 | auto Address = Functions.front().getAddress(); |
436 | if (!Address || *Address != SectionOrErr.get()->getAddress()) |
437 | return make_error<Failure>(Args: "Unexpected layout" ); |
438 | |
439 | auto ContentsOrErr = SectionOrErr.get()->getContents(); |
440 | if (!ContentsOrErr) |
441 | return ContentsOrErr.takeError(); |
442 | Bytes.assign(first: ContentsOrErr->begin(), last: ContentsOrErr->end()); |
443 | return Error::success(); |
444 | } |
445 | |
446 | } // namespace exegesis |
447 | } // namespace llvm |
448 | |