summaryrefslogtreecommitdiffstats
path: root/llvm/tools/llvm-exegesis/lib/Assembler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-exegesis/lib/Assembler.cpp')
-rw-r--r--llvm/tools/llvm-exegesis/lib/Assembler.cpp249
1 files changed, 249 insertions, 0 deletions
diff --git a/llvm/tools/llvm-exegesis/lib/Assembler.cpp b/llvm/tools/llvm-exegesis/lib/Assembler.cpp
new file mode 100644
index 00000000000..81185064eef
--- /dev/null
+++ b/llvm/tools/llvm-exegesis/lib/Assembler.cpp
@@ -0,0 +1,249 @@
+//===-- Assembler.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Assembler.h"
+
+#include "llvm/CodeGen/GlobalISel/CallLowering.h"
+#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetInstrInfo.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
+#include "llvm/ExecutionEngine/SectionMemoryManager.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+namespace exegesis {
+
+static constexpr const char ModuleID[] = "ExegesisInfoTest";
+static constexpr const char FunctionID[] = "foo";
+
+// Small utility function to add named passes.
+static bool addPass(llvm::PassManagerBase &PM, llvm::StringRef PassName,
+ llvm::TargetPassConfig &TPC) {
+ const llvm::PassRegistry *PR = llvm::PassRegistry::getPassRegistry();
+ const llvm::PassInfo *PI = PR->getPassInfo(PassName);
+ if (!PI) {
+ llvm::errs() << " run-pass " << PassName << " is not registered.\n";
+ return true;
+ }
+
+ if (!PI->getNormalCtor()) {
+ llvm::errs() << " cannot create pass: " << PI->getPassName() << "\n";
+ return true;
+ }
+ llvm::Pass *P = PI->getNormalCtor()();
+ std::string Banner = std::string("After ") + std::string(P->getPassName());
+ PM.add(P);
+ TPC.printAndVerify(Banner);
+
+ return false;
+}
+
+// Creates a void MachineFunction with no argument.
+static llvm::MachineFunction &
+createVoidVoidMachineFunction(llvm::StringRef FunctionID, llvm::Module *Module,
+ llvm::MachineModuleInfo *MMI) {
+ llvm::Type *const ReturnType = llvm::Type::getInt32Ty(Module->getContext());
+ llvm::FunctionType *FunctionType = llvm::FunctionType::get(ReturnType, false);
+ llvm::Function *const F = llvm::Function::Create(
+ FunctionType, llvm::GlobalValue::InternalLinkage, FunctionID, Module);
+ // Making sure we can create a MachineFunction out of this Function even if it
+ // contains no IR.
+ F->setIsMaterializable(true);
+ return MMI->getOrCreateMachineFunction(*F);
+}
+
+static void fillMachineFunction(llvm::MachineFunction &MF,
+ llvm::ArrayRef<llvm::MCInst> Instructions) {
+ llvm::MachineBasicBlock *MBB = MF.CreateMachineBasicBlock();
+ MF.push_back(MBB);
+ const llvm::MCInstrInfo *MCII = MF.getTarget().getMCInstrInfo();
+ llvm::DebugLoc DL;
+ for (const llvm::MCInst &Inst : Instructions) {
+ const unsigned Opcode = Inst.getOpcode();
+ const llvm::MCInstrDesc &MCID = MCII->get(Opcode);
+ llvm::MachineInstrBuilder Builder = llvm::BuildMI(MBB, DL, MCID);
+ for (unsigned OpIndex = 0, E = Inst.getNumOperands(); OpIndex < E;
+ ++OpIndex) {
+ const llvm::MCOperand &Op = Inst.getOperand(OpIndex);
+ if (Op.isReg()) {
+ const bool IsDef = OpIndex < MCID.getNumDefs();
+ unsigned Flags = 0;
+ const llvm::MCOperandInfo &OpInfo = MCID.operands().begin()[OpIndex];
+ if (IsDef && !OpInfo.isOptionalDef())
+ Flags |= llvm::RegState::Define;
+ Builder.addReg(Op.getReg(), Flags);
+ } else if (Op.isImm()) {
+ Builder.addImm(Op.getImm());
+ } else {
+ llvm_unreachable("Not yet implemented");
+ }
+ }
+ }
+ // Insert the return code.
+ const llvm::TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+ if (TII->getReturnOpcode() < TII->getNumOpcodes()) {
+ llvm::BuildMI(MBB, DL, TII->get(TII->getReturnOpcode()));
+ } else {
+ llvm::MachineIRBuilder MIB(MF);
+ MIB.setMBB(*MBB);
+ MF.getSubtarget().getCallLowering()->lowerReturn(MIB, nullptr, 0);
+ }
+}
+
+static std::unique_ptr<llvm::Module>
+createModule(const std::unique_ptr<llvm::LLVMContext> &Context,
+ const llvm::DataLayout DL) {
+ auto Module = llvm::make_unique<llvm::Module>(ModuleID, *Context);
+ Module->setDataLayout(DL);
+ return Module;
+}
+
+llvm::BitVector getFunctionReservedRegs(const llvm::TargetMachine &TM) {
+ std::unique_ptr<llvm::LLVMContext> Context =
+ llvm::make_unique<llvm::LLVMContext>();
+ std::unique_ptr<llvm::Module> Module =
+ createModule(Context, TM.createDataLayout());
+ std::unique_ptr<llvm::MachineModuleInfo> MMI =
+ llvm::make_unique<llvm::MachineModuleInfo>(&TM);
+ llvm::MachineFunction &MF =
+ createVoidVoidMachineFunction(FunctionID, Module.get(), MMI.get());
+ // Saving reserved registers for client.
+ return MF.getSubtarget().getRegisterInfo()->getReservedRegs(MF);
+}
+
+void assembleToStream(std::unique_ptr<llvm::LLVMTargetMachine> TM,
+ llvm::ArrayRef<llvm::MCInst> Instructions,
+ llvm::raw_pwrite_stream &AsmStream) {
+ std::unique_ptr<llvm::LLVMContext> Context =
+ llvm::make_unique<llvm::LLVMContext>();
+ std::unique_ptr<llvm::Module> Module =
+ createModule(Context, TM->createDataLayout());
+ std::unique_ptr<llvm::MachineModuleInfo> MMI =
+ llvm::make_unique<llvm::MachineModuleInfo>(TM.get());
+ llvm::MachineFunction &MF =
+ createVoidVoidMachineFunction(FunctionID, Module.get(), MMI.get());
+
+ // We need to instruct the passes that we're done with SSA and virtual
+ // registers.
+ auto &Properties = MF.getProperties();
+ Properties.set(llvm::MachineFunctionProperties::Property::NoVRegs);
+ Properties.reset(llvm::MachineFunctionProperties::Property::IsSSA);
+ Properties.reset(llvm::MachineFunctionProperties::Property::TracksLiveness);
+ // prologue/epilogue pass needs the reserved registers to be frozen, this
+ // is usually done by the SelectionDAGISel pass.
+ MF.getRegInfo().freezeReservedRegs(MF);
+
+ // Fill the MachineFunction from the instructions.
+ fillMachineFunction(MF, Instructions);
+
+ // We create the pass manager, run the passes to populate AsmBuffer.
+ llvm::MCContext &MCContext = MMI->getContext();
+ llvm::legacy::PassManager PM;
+
+ llvm::TargetLibraryInfoImpl TLII(llvm::Triple(Module->getTargetTriple()));
+ PM.add(new llvm::TargetLibraryInfoWrapperPass(TLII));
+
+ llvm::TargetPassConfig *TPC = TM->createPassConfig(PM);
+ PM.add(TPC);
+ PM.add(MMI.release());
+ TPC->printAndVerify("MachineFunctionGenerator::assemble");
+ // Adding the following passes:
+ // - machineverifier: checks that the MachineFunction is well formed.
+ // - prologepilog: saves and restore callee saved registers.
+ for (const char *PassName : {"machineverifier", "prologepilog"})
+ if (addPass(PM, PassName, *TPC))
+ llvm::report_fatal_error("Unable to add a mandatory pass");
+ TPC->setInitialized();
+
+ // AsmPrinter is responsible for generating the assembly into AsmBuffer.
+ if (TM->addAsmPrinter(PM, AsmStream, llvm::TargetMachine::CGFT_ObjectFile,
+ MCContext))
+ llvm::report_fatal_error("Cannot add AsmPrinter passes");
+
+ PM.run(*Module); // Run all the passes
+}
+
+llvm::object::OwningBinary<llvm::object::ObjectFile>
+getObjectFromBuffer(llvm::StringRef InputData) {
+ // Storing the generated assembly into a MemoryBuffer that owns the memory.
+ std::unique_ptr<llvm::MemoryBuffer> Buffer =
+ llvm::MemoryBuffer::getMemBufferCopy(InputData);
+ // Create the ObjectFile from the MemoryBuffer.
+ std::unique_ptr<llvm::object::ObjectFile> Obj = llvm::cantFail(
+ llvm::object::ObjectFile::createObjectFile(Buffer->getMemBufferRef()));
+ // Returning both the MemoryBuffer and the ObjectFile.
+ return llvm::object::OwningBinary<llvm::object::ObjectFile>(
+ std::move(Obj), std::move(Buffer));
+}
+
+llvm::object::OwningBinary<llvm::object::ObjectFile>
+getObjectFromFile(llvm::StringRef Filename) {
+ return llvm::cantFail(llvm::object::ObjectFile::createObjectFile(Filename));
+}
+
+namespace {
+
+// Implementation of this class relies on the fact that a single object with a
+// single function will be loaded into memory.
+class TrackingSectionMemoryManager : public llvm::SectionMemoryManager {
+public:
+ explicit TrackingSectionMemoryManager(uintptr_t *CodeSize)
+ : CodeSize(CodeSize) {}
+
+ uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
+ unsigned SectionID,
+ llvm::StringRef SectionName) override {
+ *CodeSize = Size;
+ return llvm::SectionMemoryManager::allocateCodeSection(
+ Size, Alignment, SectionID, SectionName);
+ }
+
+private:
+ uintptr_t *const CodeSize = nullptr;
+};
+
+} // namespace
+
+ExecutableFunction::ExecutableFunction(
+ std::unique_ptr<llvm::LLVMTargetMachine> TM,
+ llvm::object::OwningBinary<llvm::object::ObjectFile> &&ObjectFileHolder)
+ : Context(llvm::make_unique<llvm::LLVMContext>()) {
+ assert(ObjectFileHolder.getBinary() && "cannot create object file");
+ // Initializing the execution engine.
+ // We need to use the JIT EngineKind to be able to add an object file.
+ LLVMLinkInMCJIT();
+ uintptr_t CodeSize = 0;
+ std::string Error;
+ ExecEngine.reset(
+ llvm::EngineBuilder(createModule(Context, TM->createDataLayout()))
+ .setErrorStr(&Error)
+ .setMCPU(TM->getTargetCPU())
+ .setEngineKind(llvm::EngineKind::JIT)
+ .setMCJITMemoryManager(
+ llvm::make_unique<TrackingSectionMemoryManager>(&CodeSize))
+ .create(TM.release()));
+ if (!ExecEngine)
+ llvm::report_fatal_error(Error);
+ // Adding the generated object file containing the assembled function.
+ // The ExecutionEngine makes sure the object file is copied into an
+ // executable page.
+ ExecEngine->addObjectFile(std::move(ObjectFileHolder));
+ // Fetching function bytes.
+ FunctionBytes =
+ llvm::StringRef(reinterpret_cast<const char *>(
+ ExecEngine->getFunctionAddress(FunctionID)),
+ CodeSize);
+}
+
+} // namespace exegesis
OpenPOWER on IntegriCloud