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"),
52 cl::desc(
"Weight for register operand embeddings"),
57 "Generate symbolic embeddings for MIR")),
63 cl::desc(
"Print all vocabulary entries including zero embeddings"),
74 VocabMap &&PhysicalRegisterMap,
75 VocabMap &&VirtualRegisterMap,
80 buildCanonicalOpcodeMapping();
81 unsigned CanonicalOpcodeCount = UniqueBaseOpcodeNames.size();
82 assert(CanonicalOpcodeCount > 0 &&
83 "No canonical opcodes found for target - invalid vocabulary");
85 buildRegisterOperandMapping();
88 Layout.OpcodeBase = 0;
89 Layout.CommonOperandBase = CanonicalOpcodeCount;
91 Layout.PhyRegBase = Layout.CommonOperandBase + std::size(CommonOperandNames);
92 Layout.VirtRegBase = Layout.PhyRegBase + RegisterOperandNames.size();
94 generateStorage(OpcodeMap, CommonOperandMap, PhysicalRegisterMap,
96 Layout.TotalEntries = Storage.size();
104 if (OpcodeMap.empty() || CommonOperandMap.empty() || PhyRegMap.empty() ||
107 "Empty vocabulary entries provided");
109 MIRVocabulary Vocab(std::move(OpcodeMap), std::move(CommonOperandMap),
110 std::move(PhyRegMap), std::move(
VirtRegMap), TII, TRI,
116 "Failed to create valid vocabulary storage");
118 return std::move(Vocab);
133 assert(!InstrName.
empty() &&
"Instruction name should not be empty");
136 static const Regex BaseOpcodeRegex(
"([a-zA-Z_]+)");
139 if (BaseOpcodeRegex.
match(InstrName, &Matches) && Matches.
size() > 1) {
142 while (!Match.
empty() && Match.
back() ==
'_')
148 return InstrName.
str();
152 assert(!UniqueBaseOpcodeNames.empty() &&
"Canonical mapping not built");
153 auto It = std::find(UniqueBaseOpcodeNames.begin(),
154 UniqueBaseOpcodeNames.end(), BaseName.
str());
155 assert(It != UniqueBaseOpcodeNames.end() &&
156 "Base name not found in unique opcodes");
157 return std::distance(UniqueBaseOpcodeNames.begin(), It);
160unsigned MIRVocabulary::getCanonicalOpcodeIndex(
unsigned Opcode)
const {
161 auto BaseOpcode = extractBaseOpcodeName(
TII.getName(Opcode));
162 return getCanonicalIndexForBaseName(BaseOpcode);
167 auto It = std::find(std::begin(CommonOperandNames),
168 std::end(CommonOperandNames), OperandName);
169 assert(It != std::end(CommonOperandNames) &&
170 "Operand name not found in common operands");
171 return Layout.CommonOperandBase +
172 std::distance(std::begin(CommonOperandNames), It);
177 bool IsPhysical)
const {
178 auto It = std::find(RegisterOperandNames.begin(), RegisterOperandNames.end(),
180 assert(It != RegisterOperandNames.end() &&
181 "Register name not found in register operands");
182 unsigned LocalIndex = std::distance(RegisterOperandNames.begin(), It);
183 return (IsPhysical ? Layout.PhyRegBase : Layout.VirtRegBase) + LocalIndex;
187 assert(Pos < Layout.TotalEntries &&
"Position out of bounds in vocabulary");
190 if (Pos < Layout.CommonOperandBase) {
192 auto It = UniqueBaseOpcodeNames.begin();
193 std::advance(It, Pos);
194 assert(It != UniqueBaseOpcodeNames.end() &&
195 "Canonical index out of bounds in opcode section");
199 auto getLocalIndex = [](
unsigned Pos,
size_t BaseOffset,
size_t Bound,
201 unsigned LocalIndex = Pos - BaseOffset;
207 if (Pos < Layout.PhyRegBase) {
208 unsigned LocalIndex = getLocalIndex(
209 Pos, Layout.CommonOperandBase, std::size(CommonOperandNames),
210 "Local index out of bounds in common operands");
211 return CommonOperandNames[LocalIndex].str();
215 if (Pos < Layout.VirtRegBase) {
216 unsigned LocalIndex =
217 getLocalIndex(Pos, Layout.PhyRegBase, RegisterOperandNames.size(),
218 "Local index out of bounds in physical registers");
219 return "PhyReg_" + RegisterOperandNames[LocalIndex];
223 unsigned LocalIndex =
224 getLocalIndex(Pos, Layout.VirtRegBase, RegisterOperandNames.size(),
225 "Local index out of bounds in virtual registers");
226 return "VirtReg_" + RegisterOperandNames[LocalIndex];
229void MIRVocabulary::generateStorage(
const VocabMap &OpcodeMap,
230 const VocabMap &CommonOperandsMap,
231 const VocabMap &PhyRegMap,
239 <<
"; using zero vector. This will result in an error "
241 ++MIRVocabMissCounter;
245 unsigned EmbeddingDim = OpcodeMap.begin()->second.size();
246 std::vector<Embedding> OpcodeEmbeddings(Layout.CommonOperandBase,
250 for (
auto COpcodeName : UniqueBaseOpcodeNames) {
251 if (
auto It = OpcodeMap.find(COpcodeName); It != OpcodeMap.end()) {
252 auto COpcodeIndex = getCanonicalIndexForBaseName(COpcodeName);
253 assert(COpcodeIndex < Layout.CommonOperandBase &&
254 "Canonical index out of bounds");
255 OpcodeEmbeddings[COpcodeIndex] = It->second;
257 handleMissingEntity(COpcodeName);
262 std::vector<Embedding> CommonOperandEmbeddings(std::size(CommonOperandNames),
264 unsigned OperandIndex = 0;
265 for (
const auto &CommonOperandName : CommonOperandNames) {
266 if (
auto It = CommonOperandsMap.find(CommonOperandName.str());
267 It != CommonOperandsMap.end()) {
268 CommonOperandEmbeddings[OperandIndex] = It->second;
270 handleMissingEntity(CommonOperandName);
276 auto createRegisterEmbeddings = [&](
const VocabMap &RegMap) {
277 std::vector<Embedding> RegEmbeddings(
TRI.getNumRegClasses(),
279 unsigned RegOperandIndex = 0;
280 for (
const auto &RegOperandName : RegisterOperandNames) {
281 if (
auto It = RegMap.find(RegOperandName); It != RegMap.end())
282 RegEmbeddings[RegOperandIndex] = It->second;
284 handleMissingEntity(RegOperandName);
287 return RegEmbeddings;
291 std::vector<Embedding> PhyRegEmbeddings = createRegisterEmbeddings(PhyRegMap);
292 std::vector<Embedding> VirtRegEmbeddings =
296 auto scaleVocabSection = [](std::vector<Embedding> &Embeddings,
301 scaleVocabSection(OpcodeEmbeddings,
OpcWeight);
306 std::vector<std::vector<Embedding>> Sections(
307 static_cast<unsigned>(Section::MaxSections));
308 Sections[
static_cast<unsigned>(Section::Opcodes)] =
309 std::move(OpcodeEmbeddings);
310 Sections[
static_cast<unsigned>(Section::CommonOperands)] =
311 std::move(CommonOperandEmbeddings);
312 Sections[
static_cast<unsigned>(Section::PhyRegisters)] =
313 std::move(PhyRegEmbeddings);
314 Sections[
static_cast<unsigned>(Section::VirtRegisters)] =
315 std::move(VirtRegEmbeddings);
320void MIRVocabulary::buildCanonicalOpcodeMapping() {
322 if (!UniqueBaseOpcodeNames.empty())
326 for (
unsigned Opcode = 0; Opcode <
TII.getNumOpcodes(); ++Opcode) {
327 std::string BaseOpcode = extractBaseOpcodeName(
TII.getName(Opcode));
328 UniqueBaseOpcodeNames.insert(BaseOpcode);
331 LLVM_DEBUG(
dbgs() <<
"MIR2Vec: Built canonical mapping for target with "
332 << UniqueBaseOpcodeNames.size()
333 <<
" unique base opcodes\n");
336void MIRVocabulary::buildRegisterOperandMapping() {
338 if (!RegisterOperandNames.empty())
341 for (
unsigned RC = 0; RC <
TRI.getNumRegClasses(); ++RC) {
348 RegisterOperandNames.push_back(ClassName.
str());
352unsigned MIRVocabulary::getCommonOperandIndex(
355 "Expected non-register operand type");
361std::optional<unsigned>
362MIRVocabulary::getRegisterOperandIndex(
Register Reg)
const {
363 assert(!RegisterOperandNames.empty() &&
"Register operand mapping not built");
366 "Expected a physical or virtual register");
374 RegClass =
TRI.getMinimalPhysRegClass(
Reg);
394 <<
"; using zero vector.\n");
395 ++MIRClasslessRegCounter;
399 return RegClass->
getID();
405 assert(Dim > 0 &&
"Dimension must be greater than zero");
407 float DummyVal = 0.1f;
409 VocabMap DummyOpcMap, DummyOperandMap, DummyPhyRegMap, DummyVirtRegMap;
412 for (
unsigned Opcode = 0; Opcode < TII.getNumOpcodes(); ++Opcode) {
414 if (DummyOpcMap.count(BaseOpcode) == 0) {
415 DummyOpcMap[BaseOpcode] =
Embedding(Dim, DummyVal);
421 for (
const auto &CommonOperandName : CommonOperandNames) {
422 DummyOperandMap[CommonOperandName.str()] =
Embedding(Dim, DummyVal);
427 for (
unsigned RC = 0; RC < TRI.getNumRegClasses(); ++RC) {
432 std::string ClassName = TRI.getRegClassName(RegClass);
433 DummyPhyRegMap[ClassName] =
Embedding(Dim, DummyVal);
434 DummyVirtRegMap[ClassName] =
Embedding(Dim, DummyVal);
440 std::move(DummyOpcMap), std::move(DummyOperandMap),
441 std::move(DummyPhyRegMap), std::move(DummyVirtRegMap), TII, TRI, MRI);
450 VocabMap OpcVocab, CommonOperandVocab, PhyRegVocabMap, VirtRegVocabMap;
452 if (
Error Err = readVocabulary(OpcVocab, CommonOperandVocab, PhyRegVocabMap,
454 return std::move(Err);
456 for (
const auto &
F : M) {
457 if (
F.isDeclaration())
460 if (
auto *MF = MMI.getMachineFunction(
F)) {
461 auto &Subtarget = MF->getSubtarget();
462 if (
const auto *
TII = Subtarget.getInstrInfo())
463 if (
const auto *
TRI = Subtarget.getRegisterInfo())
465 std::move(OpcVocab), std::move(CommonOperandVocab),
466 std::move(PhyRegVocabMap), std::move(VirtRegVocabMap), *
TII, *
TRI,
471 "No machine functions found in module");
474Error MIR2VecVocabProvider::readVocabulary(VocabMap &OpcodeVocab,
475 VocabMap &CommonOperandVocab,
476 VocabMap &PhyRegVocabMap,
477 VocabMap &VirtRegVocabMap) {
481 "MIR2Vec vocabulary file path not specified; set it "
482 "using --mir2vec-vocab-path");
488 auto Content = BufOrError.get()->getBuffer();
491 if (!ParsedVocabValue)
494 unsigned OpcodeDim = 0, CommonOperandDim = 0, PhyRegOperandDim = 0,
495 VirtRegOperandDim = 0;
497 "Opcodes", *ParsedVocabValue, OpcodeVocab, OpcodeDim))
501 "CommonOperands", *ParsedVocabValue, CommonOperandVocab,
506 "PhysicalRegisters", *ParsedVocabValue, PhyRegVocabMap,
511 "VirtualRegisters", *ParsedVocabValue, VirtRegVocabMap,
516 if (!(OpcodeDim == CommonOperandDim && CommonOperandDim == PhyRegOperandDim &&
517 PhyRegOperandDim == VirtRegOperandDim)) {
520 "MIR2Vec vocabulary sections have different dimensions");
528 "MIR2Vec Vocabulary Analysis",
false,
true)
534 return "MIR2Vec Vocabulary Analysis";
546 return std::make_unique<SymbolicMIREmbedder>(
MF,
Vocab);
555 const auto &Subtarget =
MF.getSubtarget();
556 const auto *
TII = Subtarget.getInstrInfo();
558 MF.getFunction().getContext().emitError(
559 "MIR2Vec: No TargetInstrInfo available; cannot compute embeddings");
564 for (
const auto &
MI :
MBB) {
566 if (
MI.isDebugInstr())
590std::unique_ptr<SymbolicMIREmbedder>
593 return std::make_unique<SymbolicMIREmbedder>(
MF,
Vocab);
598 if (
MI.isDebugInstr())
606 InstructionEmbedding +=
Vocab[MO];
608 return InstructionEmbedding;
617 "MIR2Vec Vocabulary Printer Pass",
false,
true)
629 auto MIR2VecVocabOrErr =
Analysis.getMIR2VecVocabulary(M);
631 if (!MIR2VecVocabOrErr) {
632 OS <<
"MIR2Vec Vocabulary Printer: Failed to get vocabulary - "
633 <<
toString(MIR2VecVocabOrErr.takeError()) <<
"\n";
637 auto &MIR2VecVocab = *MIR2VecVocabOrErr;
639 for (
const auto &Entry : MIR2VecVocab) {
643 OS <<
"Key: " << MIR2VecVocab.getStringKey(Pos) <<
": ";
659 "MIR2Vec Embedder Printer Pass",
false,
true)
663 "MIR2Vec Embedder Printer Pass",
false,
true)
668 Analysis.getMIR2VecVocabulary(*MF.getFunction().getParent());
669 assert(VocabOrErr &&
"Failed to get MIR2Vec vocabulary");
670 auto &MIRVocab = *VocabOrErr;
674 OS <<
"Error creating MIR2Vec embeddings for function " << MF.getName()
679 OS <<
"MIR2Vec embeddings for machine function " << MF.getName() <<
":\n";
680 OS <<
"Machine Function vector: ";
681 Emb->getMFunctionVector().print(OS);
683 OS <<
"Machine basic block vectors:\n";
685 OS <<
"Machine basic block: " <<
MBB.getFullName() <<
":\n";
686 Emb->getMBBVector(
MBB).print(OS);
689 OS <<
"Machine instruction vectors:\n";
694 if (
MI.isDebugInstr())
697 OS <<
"Machine instruction: ";
699 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
LLVM_ABI cl::opt< float > OpcWeight
static cl::opt< std::string > VocabFile("mir2vec-vocab-path", cl::Optional, cl::desc("Path to the vocabulary file for MIR2Vec"), cl::init(""), cl::cat(MIR2VecCategory))
LLVM_ABI cl::opt< float > RegOperandWeight
static cl::opt< bool > PrintAllVocabEntries("mir2vec-print-all-vocab-entries", cl::Optional, cl::init(false), cl::desc("Print all vocabulary entries including zero embeddings"), cl::cat(MIR2VecCategory))
ir2vec::Embedding Embedding
LLVM_ABI cl::opt< float > CommonOperandWeight
cl::opt< MIR2VecKind > MIR2VecEmbeddingKind("mir2vec-kind", cl::Optional, cl::values(clEnumValN(MIR2VecKind::Symbolic, "symbolic", "Generate symbolic embeddings for MIR")), cl::init(MIR2VecKind::Symbolic), cl::desc("MIR2Vec embedding kind"), cl::cat(MIR2VecCategory))
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