Chandler Carruth 2946cd7010 Update the file headers across all of the LLVM projects in the monorepo
to reflect the new license.

We understand that people may be surprised that we're moving the header
entirely to discuss the new license. We checked this carefully with the
Foundation's lawyer and we believe this is the correct approach.

Essentially, all code in the project is now made available by the LLVM
project under our new license, so you will see that the license headers
include that license only. Some of our contributors have contributed
code under our old license, and accordingly, we have retained a copy of
our old license notice in the top-level files in each project and
repository.

llvm-svn: 351636
2019-01-19 08:50:56 +00:00

301 lines
12 KiB
C++

//===-- Assembler.cpp -------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Assembler.h"
#include "Target.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 llvm {
namespace exegesis {
static constexpr const char ModuleID[] = "ExegesisInfoTest";
static constexpr const char FunctionID[] = "foo";
static std::vector<llvm::MCInst>
generateSnippetSetupCode(const ExegesisTarget &ET,
const llvm::MCSubtargetInfo *const MSI,
llvm::ArrayRef<RegisterValue> RegisterInitialValues,
bool &IsSnippetSetupComplete) {
IsSnippetSetupComplete = true;
std::vector<llvm::MCInst> Result;
for (const RegisterValue &RV : RegisterInitialValues) {
// Load a constant in the register.
const auto SetRegisterCode = ET.setRegTo(*MSI, RV.Register, RV.Value);
if (SetRegisterCode.empty())
IsSnippetSetupComplete = false;
Result.insert(Result.end(), SetRegisterCode.begin(), SetRegisterCode.end());
}
return Result;
}
// 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(int8*) MachineFunction.
static llvm::MachineFunction &
createVoidVoidPtrMachineFunction(llvm::StringRef FunctionID,
llvm::Module *Module,
llvm::MachineModuleInfo *MMI) {
llvm::Type *const ReturnType = llvm::Type::getInt32Ty(Module->getContext());
llvm::Type *const MemParamType = llvm::PointerType::get(
llvm::Type::getInt8Ty(Module->getContext()), 0 /*default address space*/);
llvm::FunctionType *FunctionType =
llvm::FunctionType::get(ReturnType, {MemParamType}, 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<unsigned> LiveIns,
llvm::ArrayRef<llvm::MCInst> Instructions) {
llvm::MachineBasicBlock *MBB = MF.CreateMachineBasicBlock();
MF.push_back(MBB);
for (const unsigned Reg : LiveIns)
MBB->addLiveIn(Reg);
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 if (!Op.isValid()) {
llvm_unreachable("Operand is not set");
} 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, {});
}
}
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());
// TODO: This only works for targets implementing LLVMTargetMachine.
const LLVMTargetMachine &LLVMTM = static_cast<const LLVMTargetMachine&>(TM);
std::unique_ptr<llvm::MachineModuleInfo> MMI =
llvm::make_unique<llvm::MachineModuleInfo>(&LLVMTM);
llvm::MachineFunction &MF =
createVoidVoidPtrMachineFunction(FunctionID, Module.get(), MMI.get());
// Saving reserved registers for client.
return MF.getSubtarget().getRegisterInfo()->getReservedRegs(MF);
}
void assembleToStream(const ExegesisTarget &ET,
std::unique_ptr<llvm::LLVMTargetMachine> TM,
llvm::ArrayRef<unsigned> LiveIns,
llvm::ArrayRef<RegisterValue> RegisterInitialValues,
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 =
createVoidVoidPtrMachineFunction(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);
for (const unsigned Reg : LiveIns)
MF.getRegInfo().addLiveIn(Reg);
bool IsSnippetSetupComplete;
std::vector<llvm::MCInst> Code =
generateSnippetSetupCode(ET, TM->getMCSubtargetInfo(),
RegisterInitialValues, IsSnippetSetupComplete);
Code.insert(Code.end(), Instructions.begin(), Instructions.end());
// If the snippet setup is not complete, we disable liveliness tracking. This
// means that we won't know what values are in the registers.
if (!IsSnippetSetupComplete)
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, LiveIns, Code);
// 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");
// Add target-specific passes.
ET.addTargetSpecificPasses(PM);
TPC->printAndVerify("After ExegesisTarget::addTargetSpecificPasses");
// 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, nullptr,
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
} // namespace llvm