1//===-- LlvmState.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 "LlvmState.h"
10#include "Target.h"
11#include "llvm/ADT/SmallVector.h"
12#include "llvm/MC/MCCodeEmitter.h"
13#include "llvm/MC/MCContext.h"
14#include "llvm/MC/MCFixup.h"
15#include "llvm/MC/MCObjectFileInfo.h"
16#include "llvm/MC/TargetRegistry.h"
17#include "llvm/Target/TargetMachine.h"
18#include "llvm/Target/TargetOptions.h"
19#include "llvm/TargetParser/Host.h"
20
21namespace llvm {
22namespace exegesis {
23
24Expected<LLVMState> LLVMState::Create(std::string TripleName,
25 std::string CpuName,
26 const StringRef Features,
27 bool UseDummyPerfCounters) {
28 if (TripleName.empty())
29 TripleName = Triple::normalize(Str: sys::getDefaultTargetTriple());
30
31 Triple TheTriple(TripleName);
32
33 // Get the target specific parser.
34 std::string Error;
35 const Target *TheTarget =
36 TargetRegistry::lookupTarget(/*MArch=*/ArchName: "", TheTriple, Error);
37 if (!TheTarget) {
38 return make_error<StringError>(Args: "no LLVM target for triple " + TripleName,
39 Args: inconvertibleErrorCode());
40 }
41
42 // Update Triple with the updated triple from the target lookup.
43 TripleName = TheTriple.str();
44
45 if (CpuName == "native") {
46 // case for cross generating, when native arch and target mismatch
47 if ((Triple(sys::getProcessTriple()).getArch() !=
48 Triple(TripleName).getArch()))
49 return make_error<StringError>(
50 Args: "A CPU must be explicitly specified when cross compiling. To see all "
51 "possible options for " +
52 TripleName + " triple use -mcpu=help",
53 Args: inconvertibleErrorCode());
54 CpuName = std::string(sys::getHostCPUName());
55 }
56
57 std::unique_ptr<MCSubtargetInfo> STI(
58 TheTarget->createMCSubtargetInfo(TheTriple, CPU: CpuName, Features: ""));
59 if (!STI) {
60 return make_error<StringError>(Args: "unable to create subtarget info",
61 Args: inconvertibleErrorCode());
62 }
63
64 assert(STI && "Unable to create subtarget info!");
65 if (!STI->isCPUStringValid(CPU: CpuName)) {
66 return make_error<StringError>(Args: Twine("invalid CPU name (")
67 .concat(Suffix: CpuName)
68 .concat(Suffix: ") for triple ")
69 .concat(Suffix: TripleName),
70 Args: inconvertibleErrorCode());
71 }
72 const TargetOptions Options;
73 std::unique_ptr<const TargetMachine> TM(TheTarget->createTargetMachine(
74 TT: TheTriple, CPU: CpuName, Features, Options, RM: Reloc::Model::Static));
75 if (!TM) {
76 return make_error<StringError>(Args: "unable to create target machine",
77 Args: inconvertibleErrorCode());
78 }
79
80 const ExegesisTarget *ET =
81 TripleName.empty() ? &ExegesisTarget::getDefault()
82 : ExegesisTarget::lookup(TT: TM->getTargetTriple());
83 if (!ET) {
84 return make_error<StringError>(Args: "no Exegesis target for triple " +
85 TripleName,
86 Args: inconvertibleErrorCode());
87 }
88 const PfmCountersInfo &PCI = UseDummyPerfCounters
89 ? ET->getDummyPfmCounters()
90 : ET->getPfmCounters(CpuName);
91 return LLVMState(std::move(TM), ET, &PCI);
92}
93
94LLVMState::LLVMState(std::unique_ptr<const TargetMachine> TM,
95 const ExegesisTarget *ET, const PfmCountersInfo *PCI)
96 : TheExegesisTarget(ET), TheTargetMachine(std::move(TM)), PfmCounters(PCI),
97 OpcodeNameToOpcodeIdxMapping(createOpcodeNameToOpcodeIdxMapping()),
98 RegNameToRegNoMapping(createRegNameToRegNoMapping()) {
99 BitVector ReservedRegs = getFunctionReservedRegs(TM: getTargetMachine());
100 for (const MCPhysReg Reg : TheExegesisTarget->getUnavailableRegisters())
101 ReservedRegs.set(Reg);
102 RATC.reset(
103 p: new RegisterAliasingTrackerCache(getRegInfo(), std::move(ReservedRegs)));
104 IC.reset(
105 p: new InstructionsCache(getInstrInfo(), getRATC(), &getSubtargetInfo()));
106}
107
108std::unique_ptr<TargetMachine> LLVMState::createTargetMachine() const {
109 return std::unique_ptr<TargetMachine>(
110 TheTargetMachine->getTarget().createTargetMachine(
111 TT: Triple(TheTargetMachine->getTargetTriple().normalize()),
112 CPU: TheTargetMachine->getTargetCPU(),
113 Features: TheTargetMachine->getTargetFeatureString(), Options: TheTargetMachine->Options,
114 RM: Reloc::Model::Static));
115}
116
117std::optional<MCRegister>
118LLVMState::getRegisterNumberFromName(StringRef RegisterName) const {
119 auto RegisterIt = RegNameToRegNoMapping->find(Val: RegisterName);
120 if (RegisterIt == RegNameToRegNoMapping->end())
121 return std::nullopt;
122 return RegisterIt->second;
123}
124
125std::unique_ptr<const DenseMap<StringRef, unsigned>>
126LLVMState::createOpcodeNameToOpcodeIdxMapping() const {
127 const MCInstrInfo &InstrInfo = getInstrInfo();
128 auto Map = std::make_unique<DenseMap<StringRef, unsigned>>(
129 args: InstrInfo.getNumOpcodes());
130 for (unsigned I = 0, E = InstrInfo.getNumOpcodes(); I < E; ++I)
131 (*Map)[InstrInfo.getName(Opcode: I)] = I;
132 assert(Map->size() == InstrInfo.getNumOpcodes() && "Size prediction failed");
133 return std::move(Map);
134}
135
136std::unique_ptr<const DenseMap<StringRef, MCRegister>>
137LLVMState::createRegNameToRegNoMapping() const {
138 const MCRegisterInfo &RegInfo = getRegInfo();
139 auto Map =
140 std::make_unique<DenseMap<StringRef, MCRegister>>(args: RegInfo.getNumRegs());
141 // Special-case RegNo 0, which would otherwise be spelled as ''.
142 (*Map)[kNoRegister] = 0;
143 for (unsigned I = 1, E = RegInfo.getNumRegs(); I < E; ++I)
144 (*Map)[RegInfo.getName(RegNo: I)] = I;
145 assert(Map->size() == RegInfo.getNumRegs() && "Size prediction failed");
146 return std::move(Map);
147}
148
149bool LLVMState::canAssemble(const MCInst &Inst) const {
150 MCContext Context(TheTargetMachine->getTargetTriple(),
151 TheTargetMachine->getMCAsmInfo(),
152 TheTargetMachine->getMCRegisterInfo(),
153 TheTargetMachine->getMCSubtargetInfo());
154 std::unique_ptr<const MCCodeEmitter> CodeEmitter(
155 TheTargetMachine->getTarget().createMCCodeEmitter(
156 II: *TheTargetMachine->getMCInstrInfo(), Ctx&: Context));
157 assert(CodeEmitter && "unable to create code emitter");
158 SmallVector<char, 16> Tmp;
159 SmallVector<MCFixup, 4> Fixups;
160 CodeEmitter->encodeInstruction(Inst, CB&: Tmp, Fixups,
161 STI: TheTargetMachine->getMCSubtargetInfo());
162 return Tmp.size() > 0;
163}
164
165} // namespace exegesis
166} // namespace llvm
167