28#define DEBUG_TYPE "mir2vec"
31 "Number of lookups to MIR entities not present in the vocabulary");
33 "Number of register operands with no register class");
45 cl::desc(
"Weight for machine opcode embeddings"),
49 cl::desc(
"Weight for common operand embeddings"),
53 cl::desc(
"Weight for register operand embeddings"),
58 "Generate symbolic embeddings for MIR")),
63 "mir2vec-print-all-vocab-entries",
cl::init(
false),
64 cl::desc(
"Print all vocabulary entries including zero embeddings"),
75 VocabMap &&PhysicalRegisterMap,
76 VocabMap &&VirtualRegisterMap,
81 buildCanonicalOpcodeMapping();
82 unsigned CanonicalOpcodeCount = UniqueBaseOpcodeNames.size();
83 assert(CanonicalOpcodeCount > 0 &&
84 "No canonical opcodes found for target - invalid vocabulary");
86 buildRegisterOperandMapping();
89 Layout.OpcodeBase = 0;
90 Layout.CommonOperandBase = CanonicalOpcodeCount;
92 Layout.PhyRegBase = Layout.CommonOperandBase + std::size(CommonOperandNames);
93 Layout.VirtRegBase = Layout.PhyRegBase + RegisterOperandNames.size();
95 generateStorage(OpcodeMap, CommonOperandMap, PhysicalRegisterMap,
97 Layout.TotalEntries = Storage.size();
105 if (OpcodeMap.empty() || CommonOperandMap.empty() || PhyRegMap.empty() ||
108 "Empty vocabulary entries provided");
110 MIRVocabulary Vocab(std::move(OpcodeMap), std::move(CommonOperandMap),
111 std::move(PhyRegMap), std::move(
VirtRegMap), TII, TRI,
117 "Failed to create valid vocabulary storage");
119 return std::move(Vocab);
134 assert(!InstrName.
empty() &&
"Instruction name should not be empty");
137 static const Regex BaseOpcodeRegex(
"([a-zA-Z_]+)");
140 if (BaseOpcodeRegex.
match(InstrName, &Matches) && Matches.
size() > 1) {
143 while (!Match.
empty() && Match.
back() ==
'_')
149 return InstrName.
str();
153 assert(!UniqueBaseOpcodeNames.empty() &&
"Canonical mapping not built");
154 auto It = std::find(UniqueBaseOpcodeNames.begin(),
155 UniqueBaseOpcodeNames.end(), BaseName.
str());
156 assert(It != UniqueBaseOpcodeNames.end() &&
157 "Base name not found in unique opcodes");
158 return std::distance(UniqueBaseOpcodeNames.begin(), It);
161unsigned MIRVocabulary::getCanonicalOpcodeIndex(
unsigned Opcode)
const {
162 auto BaseOpcode = extractBaseOpcodeName(
TII.getName(Opcode));
163 return getCanonicalIndexForBaseName(BaseOpcode);
168 auto It = std::find(std::begin(CommonOperandNames),
169 std::end(CommonOperandNames), OperandName);
170 assert(It != std::end(CommonOperandNames) &&
171 "Operand name not found in common operands");
172 return Layout.CommonOperandBase +
173 std::distance(std::begin(CommonOperandNames), It);
178 bool IsPhysical)
const {
179 auto It = std::find(RegisterOperandNames.begin(), RegisterOperandNames.end(),
181 assert(It != RegisterOperandNames.end() &&
182 "Register name not found in register operands");
183 unsigned LocalIndex = std::distance(RegisterOperandNames.begin(), It);
184 return (IsPhysical ? Layout.PhyRegBase : Layout.VirtRegBase) + LocalIndex;
188 assert(Pos < Layout.TotalEntries &&
"Position out of bounds in vocabulary");
191 if (Pos < Layout.CommonOperandBase) {
193 auto It = UniqueBaseOpcodeNames.begin();
194 std::advance(It, Pos);
195 assert(It != UniqueBaseOpcodeNames.end() &&
196 "Canonical index out of bounds in opcode section");
200 auto getLocalIndex = [](
unsigned Pos,
size_t BaseOffset,
size_t Bound,
202 unsigned LocalIndex = Pos - BaseOffset;
208 if (Pos < Layout.PhyRegBase) {
209 unsigned LocalIndex = getLocalIndex(
210 Pos, Layout.CommonOperandBase, std::size(CommonOperandNames),
211 "Local index out of bounds in common operands");
212 return CommonOperandNames[LocalIndex].str();
216 if (Pos < Layout.VirtRegBase) {
217 unsigned LocalIndex =
218 getLocalIndex(Pos, Layout.PhyRegBase, RegisterOperandNames.size(),
219 "Local index out of bounds in physical registers");
220 return "PhyReg_" + RegisterOperandNames[LocalIndex];
224 unsigned LocalIndex =
225 getLocalIndex(Pos, Layout.VirtRegBase, RegisterOperandNames.size(),
226 "Local index out of bounds in virtual registers");
227 return "VirtReg_" + RegisterOperandNames[LocalIndex];
230void MIRVocabulary::generateStorage(
const VocabMap &OpcodeMap,
231 const VocabMap &CommonOperandsMap,
232 const VocabMap &PhyRegMap,
240 <<
"; using zero vector. This will result in an error "
242 ++MIRVocabMissCounter;
246 unsigned EmbeddingDim = OpcodeMap.begin()->second.size();
247 std::vector<Embedding> OpcodeEmbeddings(Layout.CommonOperandBase,
251 for (
auto COpcodeName : UniqueBaseOpcodeNames) {
252 if (
auto It = OpcodeMap.find(COpcodeName); It != OpcodeMap.end()) {
253 auto COpcodeIndex = getCanonicalIndexForBaseName(COpcodeName);
254 assert(COpcodeIndex < Layout.CommonOperandBase &&
255 "Canonical index out of bounds");
256 OpcodeEmbeddings[COpcodeIndex] = It->second;
258 handleMissingEntity(COpcodeName);
263 std::vector<Embedding> CommonOperandEmbeddings(std::size(CommonOperandNames),
265 unsigned OperandIndex = 0;
266 for (
const auto &CommonOperandName : CommonOperandNames) {
267 if (
auto It = CommonOperandsMap.find(CommonOperandName.str());
268 It != CommonOperandsMap.end()) {
269 CommonOperandEmbeddings[OperandIndex] = It->second;
271 handleMissingEntity(CommonOperandName);
277 auto createRegisterEmbeddings = [&](
const VocabMap &RegMap) {
278 std::vector<Embedding> RegEmbeddings(
TRI.getNumRegClasses(),
280 unsigned RegOperandIndex = 0;
281 for (
const auto &RegOperandName : RegisterOperandNames) {
282 if (
auto It = RegMap.find(RegOperandName); It != RegMap.end())
283 RegEmbeddings[RegOperandIndex] = It->second;
285 handleMissingEntity(RegOperandName);
288 return RegEmbeddings;
292 std::vector<Embedding> PhyRegEmbeddings = createRegisterEmbeddings(PhyRegMap);
293 std::vector<Embedding> VirtRegEmbeddings =
297 auto scaleVocabSection = [](std::vector<Embedding> &Embeddings,
302 scaleVocabSection(OpcodeEmbeddings,
OpcWeight);
307 std::vector<std::vector<Embedding>> Sections(
308 static_cast<unsigned>(Section::MaxSections));
309 Sections[
static_cast<unsigned>(Section::Opcodes)] =
310 std::move(OpcodeEmbeddings);
311 Sections[
static_cast<unsigned>(Section::CommonOperands)] =
312 std::move(CommonOperandEmbeddings);
313 Sections[
static_cast<unsigned>(Section::PhyRegisters)] =
314 std::move(PhyRegEmbeddings);
315 Sections[
static_cast<unsigned>(Section::VirtRegisters)] =
316 std::move(VirtRegEmbeddings);
321void MIRVocabulary::buildCanonicalOpcodeMapping() {
323 if (!UniqueBaseOpcodeNames.empty())
327 for (
unsigned Opcode = 0; Opcode <
TII.getNumOpcodes(); ++Opcode) {
328 std::string BaseOpcode = extractBaseOpcodeName(
TII.getName(Opcode));
329 UniqueBaseOpcodeNames.insert(BaseOpcode);
332 LLVM_DEBUG(
dbgs() <<
"MIR2Vec: Built canonical mapping for target with "
333 << UniqueBaseOpcodeNames.size()
334 <<
" unique base opcodes\n");
337void MIRVocabulary::buildRegisterOperandMapping() {
339 if (!RegisterOperandNames.empty())
342 for (
unsigned RC = 0; RC <
TRI.getNumRegClasses(); ++RC) {
349 RegisterOperandNames.push_back(ClassName.
str());
353unsigned MIRVocabulary::getCommonOperandIndex(
356 "Expected non-register operand type");
362std::optional<unsigned>
363MIRVocabulary::getRegisterOperandIndex(
Register Reg)
const {
364 assert(!RegisterOperandNames.empty() &&
"Register operand mapping not built");
367 "Expected a physical or virtual register");
375 RegClass =
TRI.getMinimalPhysRegClass(
Reg);
395 <<
"; using zero vector.\n");
396 ++MIRClasslessRegCounter;
400 return RegClass->
getID();
406 assert(Dim > 0 &&
"Dimension must be greater than zero");
408 float DummyVal = 0.1f;
410 VocabMap DummyOpcMap, DummyOperandMap, DummyPhyRegMap, DummyVirtRegMap;
413 for (
unsigned Opcode = 0; Opcode < TII.getNumOpcodes(); ++Opcode) {
415 if (DummyOpcMap.count(BaseOpcode) == 0) {
416 DummyOpcMap[BaseOpcode] =
Embedding(Dim, DummyVal);
422 for (
const auto &CommonOperandName : CommonOperandNames) {
423 DummyOperandMap[CommonOperandName.str()] =
Embedding(Dim, DummyVal);
428 for (
unsigned RC = 0; RC < TRI.getNumRegClasses(); ++RC) {
433 std::string ClassName = TRI.getRegClassName(RegClass);
434 DummyPhyRegMap[ClassName] =
Embedding(Dim, DummyVal);
435 DummyVirtRegMap[ClassName] =
Embedding(Dim, DummyVal);
441 std::move(DummyOpcMap), std::move(DummyOperandMap),
442 std::move(DummyPhyRegMap), std::move(DummyVirtRegMap), TII, TRI, MRI);
451 VocabMap OpcVocab, CommonOperandVocab, PhyRegVocabMap, VirtRegVocabMap;
453 if (
Error Err = readVocabulary(OpcVocab, CommonOperandVocab, PhyRegVocabMap,
455 return std::move(Err);
457 for (
const auto &
F : M) {
458 if (
F.isDeclaration())
461 if (
auto *MF = MMI.getMachineFunction(
F)) {
462 auto &Subtarget = MF->getSubtarget();
463 if (
const auto *
TII = Subtarget.getInstrInfo())
464 if (
const auto *
TRI = Subtarget.getRegisterInfo())
466 std::move(OpcVocab), std::move(CommonOperandVocab),
467 std::move(PhyRegVocabMap), std::move(VirtRegVocabMap), *
TII, *
TRI,
472 "No machine functions found in module");
475Error MIR2VecVocabProvider::readVocabulary(VocabMap &OpcodeVocab,
476 VocabMap &CommonOperandVocab,
477 VocabMap &PhyRegVocabMap,
478 VocabMap &VirtRegVocabMap) {
482 "MIR2Vec vocabulary file path not specified; set it "
483 "using --mir2vec-vocab-path");
489 auto Content = BufOrError.get()->getBuffer();
492 if (!ParsedVocabValue)
495 unsigned OpcodeDim = 0, CommonOperandDim = 0, PhyRegOperandDim = 0,
496 VirtRegOperandDim = 0;
498 "Opcodes", *ParsedVocabValue, OpcodeVocab, OpcodeDim))
502 "CommonOperands", *ParsedVocabValue, CommonOperandVocab,
507 "PhysicalRegisters", *ParsedVocabValue, PhyRegVocabMap,
512 "VirtualRegisters", *ParsedVocabValue, VirtRegVocabMap,
517 if (!(OpcodeDim == CommonOperandDim && CommonOperandDim == PhyRegOperandDim &&
518 PhyRegOperandDim == VirtRegOperandDim)) {
521 "MIR2Vec vocabulary sections have different dimensions");
529 "MIR2Vec Vocabulary Analysis",
false,
true)
535 return "MIR2Vec Vocabulary Analysis";
547 return std::make_unique<SymbolicMIREmbedder>(
MF,
Vocab);
556 const auto &Subtarget =
MF.getSubtarget();
557 const auto *
TII = Subtarget.getInstrInfo();
559 MF.getFunction().getContext().emitError(
560 "MIR2Vec: No TargetInstrInfo available; cannot compute embeddings");
565 for (
const auto &
MI :
MBB) {
567 if (
MI.isDebugInstr())
591std::unique_ptr<SymbolicMIREmbedder>
594 return std::make_unique<SymbolicMIREmbedder>(
MF,
Vocab);
599 if (
MI.isDebugInstr())
607 InstructionEmbedding +=
Vocab[MO];
609 return InstructionEmbedding;
618 "MIR2Vec Vocabulary Printer Pass",
false,
true)
630 auto MIR2VecVocabOrErr =
Analysis.getMIR2VecVocabulary(M);
632 if (!MIR2VecVocabOrErr) {
633 OS <<
"MIR2Vec Vocabulary Printer: Failed to get vocabulary - "
634 <<
toString(MIR2VecVocabOrErr.takeError()) <<
"\n";
638 auto &MIR2VecVocab = *MIR2VecVocabOrErr;
640 for (
const auto &Entry : MIR2VecVocab) {
644 OS <<
"Key: " << MIR2VecVocab.getStringKey(Pos) <<
": ";
660 "MIR2Vec Embedder Printer Pass",
false,
true)
664 "MIR2Vec Embedder Printer Pass",
false,
true)
669 Analysis.getMIR2VecVocabulary(*MF.getFunction().getParent());
670 assert(VocabOrErr &&
"Failed to get MIR2Vec vocabulary");
671 auto &MIRVocab = *VocabOrErr;
675 OS <<
"Error creating MIR2Vec embeddings for function " << MF.getName()
680 OS <<
"MIR2Vec embeddings for machine function " << MF.getName() <<
":\n";
681 OS <<
"Machine Function vector: ";
682 Emb->getMFunctionVector().print(OS);
684 OS <<
"Machine basic block vectors:\n";
686 OS <<
"Machine basic block: " <<
MBB.getFullName() <<
":\n";
687 Emb->getMBBVector(
MBB).print(OS);
690 OS <<
"Machine instruction vectors:\n";
695 if (
MI.isDebugInstr())
698 OS <<
"Machine instruction: ";
700 Emb->getMInstVector(
MI).print(OS);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
block Block Frequency Analysis
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
const HexagonInstrInfo * TII
Module.h This file contains the declarations for the Module class.
This file defines the MIR2Vec framework for generating Machine IR embeddings.
Register const TargetRegisterInfo * TRI
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
SmallVector< MachineBasicBlock *, 4 > MBBVector
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
unsigned getID() const
getID() - Return the register class ID number.
This pass prints the MIR2Vec embeddings for machine functions, basic blocks, and instructions.
MIR2VecPrinterLegacyPass(raw_ostream &OS)
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
Pass to analyze and populate MIR2Vec vocabulary from a module.
This pass prints the embeddings in the MIR2Vec vocabulary.
bool doFinalization(Module &M) override
doFinalization - Virtual method overriden by subclasses to do any necessary clean up after all passes...
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
MIR2VecVocabPrinterLegacyPass(raw_ostream &OS)
LLVM_ABI Expected< mir2vec::MIRVocabulary > getVocabulary(const Module &M)
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
Representation of each machine instruction.
MachineOperand class - Representation of each machine instruction operand.
@ MO_Register
Register operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
A Module instance is used to store all the information related to an LLVM module.
AnalysisType & getAnalysis() const
getAnalysis<AnalysisType>() - This function is used by subclasses to get to the analysis information ...
LLVM_ABI bool match(StringRef String, SmallVectorImpl< StringRef > *Matches=nullptr, std::string *Error=nullptr) const
matches - Match the regex against a given String.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr unsigned id() const
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
std::string str() const
Get the contents as an std::string.
constexpr bool empty() const
Check if the string is empty.
char back() const
Get the last character in the string.
StringRef drop_back(size_t N=1) const
Return a StringRef equal to 'this' but with the last N elements dropped.
TargetInstrInfo - Interface to description of machine instruction set.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
Generic storage class for section-based vocabularies.
static LLVM_ABI Error parseVocabSection(StringRef Key, const json::Value &ParsedVocabValue, VocabMap &TargetVocab, unsigned &Dim)
Parse a vocabulary section from JSON and populate the target vocabulary map.
unsigned getDimension() const
Get vocabulary dimension.
bool isValid() const
Check if vocabulary is valid (has data)
const unsigned Dimension
Dimension of the embeddings; Captured from the vocabulary.
const MIRVocabulary & Vocab
MIREmbedder(const MachineFunction &MF, const MIRVocabulary &Vocab)
LLVM_ABI Embedding computeEmbeddings() const
Function to compute embeddings.
const MachineFunction & MF
static LLVM_ABI std::unique_ptr< MIREmbedder > create(MIR2VecKind Mode, const MachineFunction &MF, const MIRVocabulary &Vocab)
Factory method to create an Embedder object of the specified kind Returns nullptr if the requested ki...
Class for storing and accessing the MIR2Vec vocabulary.
LLVM_ABI unsigned getCanonicalIndexForOperandName(StringRef OperandName) const
LLVM_ABI unsigned getCanonicalIndexForRegisterClass(StringRef RegName, bool IsPhysical=true) const
static LLVM_ABI Expected< MIRVocabulary > create(VocabMap &&OpcMap, VocabMap &&CommonOperandsMap, VocabMap &&PhyRegMap, VocabMap &&VirtRegMap, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const MachineRegisterInfo &MRI)
Factory method to create MIRVocabulary from vocabulary map.
static LLVM_ABI std::string extractBaseOpcodeName(StringRef InstrName)
Static method for extracting base opcode names (public for testing)
static LLVM_ABI Expected< MIRVocabulary > createDummyVocabForTest(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const MachineRegisterInfo &MRI, unsigned Dim=1)
Create a dummy vocabulary for testing purposes.
LLVM_ABI std::string getStringKey(unsigned Pos) const
Get the string key for a vocabulary entry at the given position.
LLVM_ABI unsigned getCanonicalIndexForBaseName(StringRef BaseName) const
Get indices from opcode or operand names.
static std::unique_ptr< SymbolicMIREmbedder > create(const MachineFunction &MF, const MIRVocabulary &Vocab)
SymbolicMIREmbedder(const MachineFunction &F, const MIRVocabulary &Vocab)
This class implements an extremely fast bulk output stream that can only output to a stream.
OperandType
Operands are tagged with one of the values of this enum.
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
LLVM_ABI llvm::Expected< Value > parse(llvm::StringRef JSON)
Parses the provided JSON source, or returns a ParseError.
LLVM_ABI llvm::cl::OptionCategory MIR2VecCategory
static cl::opt< bool > PrintAllVocabEntries("mir2vec-print-all-vocab-entries", cl::init(false), cl::desc("Print all vocabulary entries including zero embeddings"), cl::cat(MIR2VecCategory))
LLVM_ABI cl::opt< float > RegOperandWeight
ir2vec::Embedding Embedding
LLVM_ABI cl::opt< float > OpcWeight
cl::opt< MIR2VecKind > MIR2VecEmbeddingKind("mir2vec-kind", cl::values(clEnumValN(MIR2VecKind::Symbolic, "symbolic", "Generate symbolic embeddings for MIR")), cl::init(MIR2VecKind::Symbolic), cl::desc("MIR2Vec embedding kind"), cl::cat(MIR2VecCategory))
static cl::opt< std::string > VocabFile("mir2vec-vocab-path", cl::desc("Path to the vocabulary file for MIR2Vec"), cl::init(""), cl::cat(MIR2VecCategory))
LLVM_ABI cl::opt< float > CommonOperandWeight
This is an optimization pass for GlobalISel generic memory operations.
Error createFileError(const Twine &F, Error E)
Concatenate a source file path and/or name with an Error.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
LLVM_ABI MachineFunctionPass * createMIR2VecPrinterLegacyPass(raw_ostream &OS)
Create a machine pass that prints MIR2Vec embeddings.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
LLVM_ABI MachineFunctionPass * createMIR2VecVocabPrinterLegacyPass(raw_ostream &OS)
MIR2VecVocabPrinter pass - This pass prints out the MIR2Vec vocabulary contents to the given stream a...
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
iterator_range< df_iterator< T > > depth_first(const T &G)
MCRegisterClass TargetRegisterClass