//===-- LlvmState.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 "LlvmState.h" #include "Target.h" #include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "llvm/TargetParser/Host.h" namespace llvm { namespace exegesis { Expected LLVMState::Create(std::string TripleName, std::string CpuName, const StringRef Features, bool UseDummyPerfCounters) { if (TripleName.empty()) TripleName = Triple::normalize(sys::getDefaultTargetTriple()); Triple TheTriple(TripleName); // Get the target specific parser. std::string Error; const Target *TheTarget = TargetRegistry::lookupTarget(/*MArch=*/"", TheTriple, Error); if (!TheTarget) { return make_error("no LLVM target for triple " + TripleName, inconvertibleErrorCode()); } // Update Triple with the updated triple from the target lookup. TripleName = TheTriple.str(); if (CpuName == "native") { // case for cross generating, when native arch and target mismatch if ((Triple(sys::getProcessTriple()).getArch() != Triple(TripleName).getArch())) return make_error( "A CPU must be explicitly specified when cross compiling. To see all " "possible options for " + TripleName + " triple use -mcpu=help", inconvertibleErrorCode()); CpuName = std::string(sys::getHostCPUName()); } std::unique_ptr STI( TheTarget->createMCSubtargetInfo(TripleName, CpuName, "")); assert(STI && "Unable to create subtarget info!"); if (!STI->isCPUStringValid(CpuName)) { return make_error(Twine("invalid CPU name (") .concat(CpuName) .concat(") for triple ") .concat(TripleName), inconvertibleErrorCode()); } const TargetOptions Options; std::unique_ptr TM(TheTarget->createTargetMachine( TheTriple, CpuName, Features, Options, Reloc::Model::Static)); if (!TM) { return make_error("unable to create target machine", inconvertibleErrorCode()); } const ExegesisTarget *ET = TripleName.empty() ? &ExegesisTarget::getDefault() : ExegesisTarget::lookup(TM->getTargetTriple()); if (!ET) { return make_error("no Exegesis target for triple " + TripleName, inconvertibleErrorCode()); } const PfmCountersInfo &PCI = UseDummyPerfCounters ? ET->getDummyPfmCounters() : ET->getPfmCounters(CpuName); return LLVMState(std::move(TM), ET, &PCI); } LLVMState::LLVMState(std::unique_ptr TM, const ExegesisTarget *ET, const PfmCountersInfo *PCI) : TheExegesisTarget(ET), TheTargetMachine(std::move(TM)), PfmCounters(PCI), OpcodeNameToOpcodeIdxMapping(createOpcodeNameToOpcodeIdxMapping()), RegNameToRegNoMapping(createRegNameToRegNoMapping()) { BitVector ReservedRegs = getFunctionReservedRegs(getTargetMachine()); for (const MCPhysReg Reg : TheExegesisTarget->getUnavailableRegisters()) ReservedRegs.set(Reg); RATC.reset( new RegisterAliasingTrackerCache(getRegInfo(), std::move(ReservedRegs))); IC.reset(new InstructionsCache(getInstrInfo(), getRATC())); } std::unique_ptr LLVMState::createTargetMachine() const { return std::unique_ptr( TheTargetMachine->getTarget().createTargetMachine( Triple(TheTargetMachine->getTargetTriple().normalize()), TheTargetMachine->getTargetCPU(), TheTargetMachine->getTargetFeatureString(), TheTargetMachine->Options, Reloc::Model::Static)); } std::optional LLVMState::getRegisterNumberFromName(StringRef RegisterName) const { auto RegisterIt = RegNameToRegNoMapping->find(RegisterName); if (RegisterIt == RegNameToRegNoMapping->end()) return std::nullopt; return RegisterIt->second; } std::unique_ptr> LLVMState::createOpcodeNameToOpcodeIdxMapping() const { const MCInstrInfo &InstrInfo = getInstrInfo(); auto Map = std::make_unique>( InstrInfo.getNumOpcodes()); for (unsigned I = 0, E = InstrInfo.getNumOpcodes(); I < E; ++I) (*Map)[InstrInfo.getName(I)] = I; assert(Map->size() == InstrInfo.getNumOpcodes() && "Size prediction failed"); return std::move(Map); } std::unique_ptr> LLVMState::createRegNameToRegNoMapping() const { const MCRegisterInfo &RegInfo = getRegInfo(); auto Map = std::make_unique>(RegInfo.getNumRegs()); // Special-case RegNo 0, which would otherwise be spelled as ''. (*Map)[kNoRegister] = 0; for (unsigned I = 1, E = RegInfo.getNumRegs(); I < E; ++I) (*Map)[RegInfo.getName(I)] = I; assert(Map->size() == RegInfo.getNumRegs() && "Size prediction failed"); return std::move(Map); } bool LLVMState::canAssemble(const MCInst &Inst) const { MCContext Context(TheTargetMachine->getTargetTriple(), TheTargetMachine->getMCAsmInfo(), TheTargetMachine->getMCRegisterInfo(), TheTargetMachine->getMCSubtargetInfo()); std::unique_ptr CodeEmitter( TheTargetMachine->getTarget().createMCCodeEmitter( *TheTargetMachine->getMCInstrInfo(), Context)); assert(CodeEmitter && "unable to create code emitter"); SmallVector Tmp; SmallVector Fixups; CodeEmitter->encodeInstruction(Inst, Tmp, Fixups, *TheTargetMachine->getMCSubtargetInfo()); return Tmp.size() > 0; } } // namespace exegesis } // namespace llvm