xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
181ad6265SDimitry Andric //===- SPIRVModuleAnalysis.h - analysis of global instrs & regs -*- C++ -*-===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // The analysis collects instructions that should be output at the module level
1081ad6265SDimitry Andric // and performs the global register numbering.
1181ad6265SDimitry Andric //
1281ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1381ad6265SDimitry Andric 
1481ad6265SDimitry Andric #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVMODULEANALYSIS_H
1581ad6265SDimitry Andric #define LLVM_LIB_TARGET_SPIRV_SPIRVMODULEANALYSIS_H
1681ad6265SDimitry Andric 
1781ad6265SDimitry Andric #include "MCTargetDesc/SPIRVBaseInfo.h"
18*bdd1243dSDimitry Andric #include "SPIRVGlobalRegistry.h"
19*bdd1243dSDimitry Andric #include "SPIRVUtils.h"
2081ad6265SDimitry Andric #include "llvm/ADT/DenseMap.h"
21*bdd1243dSDimitry Andric #include "llvm/ADT/SmallSet.h"
2281ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h"
2381ad6265SDimitry Andric #include "llvm/ADT/StringMap.h"
2481ad6265SDimitry Andric 
2581ad6265SDimitry Andric namespace llvm {
26*bdd1243dSDimitry Andric class SPIRVSubtarget;
2781ad6265SDimitry Andric class MachineFunction;
2881ad6265SDimitry Andric class MachineModuleInfo;
2981ad6265SDimitry Andric 
3081ad6265SDimitry Andric namespace SPIRV {
3181ad6265SDimitry Andric // The enum contains logical module sections for the instruction collection.
3281ad6265SDimitry Andric enum ModuleSectionType {
3381ad6265SDimitry Andric   //  MB_Capabilities, MB_Extensions, MB_ExtInstImports, MB_MemoryModel,
3481ad6265SDimitry Andric   MB_EntryPoints, // All OpEntryPoint instructions (if any).
3581ad6265SDimitry Andric   //  MB_ExecutionModes, MB_DebugSourceAndStrings,
3681ad6265SDimitry Andric   MB_DebugNames,           // All OpName and OpMemberName intrs.
3781ad6265SDimitry Andric   MB_DebugModuleProcessed, // All OpModuleProcessed instructions.
3881ad6265SDimitry Andric   MB_Annotations,          // OpDecorate, OpMemberDecorate etc.
3981ad6265SDimitry Andric   MB_TypeConstVars,        // OpTypeXXX, OpConstantXXX, and global OpVariables.
4081ad6265SDimitry Andric   MB_ExtFuncDecls,         // OpFunction etc. to declare for external funcs.
4181ad6265SDimitry Andric   NUM_MODULE_SECTIONS      // Total number of sections requiring basic blocks.
4281ad6265SDimitry Andric };
4381ad6265SDimitry Andric 
44*bdd1243dSDimitry Andric struct Requirements {
45*bdd1243dSDimitry Andric   const bool IsSatisfiable;
46*bdd1243dSDimitry Andric   const std::optional<Capability::Capability> Cap;
47*bdd1243dSDimitry Andric   const ExtensionList Exts;
48*bdd1243dSDimitry Andric   const unsigned MinVer; // 0 if no min version is required.
49*bdd1243dSDimitry Andric   const unsigned MaxVer; // 0 if no max version is required.
50*bdd1243dSDimitry Andric 
51*bdd1243dSDimitry Andric   Requirements(bool IsSatisfiable = false,
52*bdd1243dSDimitry Andric                std::optional<Capability::Capability> Cap = {},
53*bdd1243dSDimitry Andric                ExtensionList Exts = {}, unsigned MinVer = 0,
54*bdd1243dSDimitry Andric                unsigned MaxVer = 0)
55*bdd1243dSDimitry Andric       : IsSatisfiable(IsSatisfiable), Cap(Cap), Exts(Exts), MinVer(MinVer),
56*bdd1243dSDimitry Andric         MaxVer(MaxVer) {}
57*bdd1243dSDimitry Andric   Requirements(Capability::Capability Cap) : Requirements(true, {Cap}) {}
58*bdd1243dSDimitry Andric };
59*bdd1243dSDimitry Andric 
60*bdd1243dSDimitry Andric struct RequirementHandler {
61*bdd1243dSDimitry Andric private:
62*bdd1243dSDimitry Andric   CapabilityList MinimalCaps;
63*bdd1243dSDimitry Andric   SmallSet<Capability::Capability, 8> AllCaps;
64*bdd1243dSDimitry Andric   SmallSet<Extension::Extension, 4> AllExtensions;
65*bdd1243dSDimitry Andric   unsigned MinVersion; // 0 if no min version is defined.
66*bdd1243dSDimitry Andric   unsigned MaxVersion; // 0 if no max version is defined.
67*bdd1243dSDimitry Andric   DenseSet<unsigned> AvailableCaps;
68*bdd1243dSDimitry Andric   // Remove a list of capabilities from dedupedCaps and add them to AllCaps,
69*bdd1243dSDimitry Andric   // recursing through their implicitly declared capabilities too.
70*bdd1243dSDimitry Andric   void pruneCapabilities(const CapabilityList &ToPrune);
71*bdd1243dSDimitry Andric 
72*bdd1243dSDimitry Andric public:
73*bdd1243dSDimitry Andric   RequirementHandler() : MinVersion(0), MaxVersion(0) {}
74*bdd1243dSDimitry Andric   void clear() {
75*bdd1243dSDimitry Andric     MinimalCaps.clear();
76*bdd1243dSDimitry Andric     AllCaps.clear();
77*bdd1243dSDimitry Andric     AvailableCaps.clear();
78*bdd1243dSDimitry Andric     AllExtensions.clear();
79*bdd1243dSDimitry Andric     MinVersion = 0;
80*bdd1243dSDimitry Andric     MaxVersion = 0;
81*bdd1243dSDimitry Andric   }
82*bdd1243dSDimitry Andric   unsigned getMinVersion() const { return MinVersion; }
83*bdd1243dSDimitry Andric   unsigned getMaxVersion() const { return MaxVersion; }
84*bdd1243dSDimitry Andric   const CapabilityList &getMinimalCapabilities() const { return MinimalCaps; }
85*bdd1243dSDimitry Andric   const SmallSet<Extension::Extension, 4> &getExtensions() const {
86*bdd1243dSDimitry Andric     return AllExtensions;
87*bdd1243dSDimitry Andric   }
88*bdd1243dSDimitry Andric   // Add a list of capabilities, ensuring AllCaps captures all the implicitly
89*bdd1243dSDimitry Andric   // declared capabilities, and MinimalCaps has the minimal set of required
90*bdd1243dSDimitry Andric   // capabilities (so all implicitly declared ones are removed).
91*bdd1243dSDimitry Andric   void addCapabilities(const CapabilityList &ToAdd);
92*bdd1243dSDimitry Andric   void addCapability(Capability::Capability ToAdd) { addCapabilities({ToAdd}); }
93*bdd1243dSDimitry Andric   void addExtensions(const ExtensionList &ToAdd) {
94*bdd1243dSDimitry Andric     AllExtensions.insert(ToAdd.begin(), ToAdd.end());
95*bdd1243dSDimitry Andric   }
96*bdd1243dSDimitry Andric   void addExtension(Extension::Extension ToAdd) { AllExtensions.insert(ToAdd); }
97*bdd1243dSDimitry Andric   // Add the given requirements to the lists. If constraints conflict, or these
98*bdd1243dSDimitry Andric   // requirements cannot be satisfied, then abort the compilation.
99*bdd1243dSDimitry Andric   void addRequirements(const Requirements &Req);
100*bdd1243dSDimitry Andric   // Get requirement and add it to the list.
101*bdd1243dSDimitry Andric   void getAndAddRequirements(SPIRV::OperandCategory::OperandCategory Category,
102*bdd1243dSDimitry Andric                              uint32_t i, const SPIRVSubtarget &ST);
103*bdd1243dSDimitry Andric   // Check if all the requirements can be satisfied for the given subtarget, and
104*bdd1243dSDimitry Andric   // if not abort compilation.
105*bdd1243dSDimitry Andric   void checkSatisfiable(const SPIRVSubtarget &ST) const;
106*bdd1243dSDimitry Andric   void initAvailableCapabilities(const SPIRVSubtarget &ST);
107*bdd1243dSDimitry Andric   // Add the given capabilities to available and all their implicitly defined
108*bdd1243dSDimitry Andric   // capabilities too.
109*bdd1243dSDimitry Andric   void addAvailableCaps(const CapabilityList &ToAdd);
110*bdd1243dSDimitry Andric   bool isCapabilityAvailable(Capability::Capability Cap) const {
111*bdd1243dSDimitry Andric     return AvailableCaps.contains(Cap);
112*bdd1243dSDimitry Andric   }
113*bdd1243dSDimitry Andric };
114*bdd1243dSDimitry Andric 
11581ad6265SDimitry Andric using InstrList = SmallVector<MachineInstr *>;
11681ad6265SDimitry Andric // Maps a local register to the corresponding global alias.
11781ad6265SDimitry Andric using LocalToGlobalRegTable = std::map<Register, Register>;
11881ad6265SDimitry Andric using RegisterAliasMapTy =
11981ad6265SDimitry Andric     std::map<const MachineFunction *, LocalToGlobalRegTable>;
12081ad6265SDimitry Andric 
12181ad6265SDimitry Andric // The struct contains results of the module analysis and methods
12281ad6265SDimitry Andric // to access them.
12381ad6265SDimitry Andric struct ModuleAnalysisInfo {
124*bdd1243dSDimitry Andric   RequirementHandler Reqs;
125*bdd1243dSDimitry Andric   MemoryModel::MemoryModel Mem;
126*bdd1243dSDimitry Andric   AddressingModel::AddressingModel Addr;
127*bdd1243dSDimitry Andric   SourceLanguage::SourceLanguage SrcLang;
12881ad6265SDimitry Andric   unsigned SrcLangVersion;
129fcaf7f86SDimitry Andric   StringSet<> SrcExt;
130fcaf7f86SDimitry Andric   // Maps ExtInstSet to corresponding ID register.
131fcaf7f86SDimitry Andric   DenseMap<unsigned, Register> ExtInstSetMap;
13281ad6265SDimitry Andric   // Contains the list of all global OpVariables in the module.
13381ad6265SDimitry Andric   SmallVector<MachineInstr *, 4> GlobalVarList;
134*bdd1243dSDimitry Andric   // Maps functions to corresponding function ID registers.
135*bdd1243dSDimitry Andric   DenseMap<const Function *, Register> FuncMap;
13681ad6265SDimitry Andric   // The set contains machine instructions which are necessary
13781ad6265SDimitry Andric   // for correct MIR but will not be emitted in function bodies.
13881ad6265SDimitry Andric   DenseSet<MachineInstr *> InstrsToDelete;
139fcaf7f86SDimitry Andric   // The set contains machine basic blocks which are necessary
140fcaf7f86SDimitry Andric   // for correct MIR but will not be emitted.
141fcaf7f86SDimitry Andric   DenseSet<MachineBasicBlock *> MBBsToSkip;
14281ad6265SDimitry Andric   // The table contains global aliases of local registers for each machine
14381ad6265SDimitry Andric   // function. The aliases are used to substitute local registers during
14481ad6265SDimitry Andric   // code emission.
14581ad6265SDimitry Andric   RegisterAliasMapTy RegisterAliasTable;
14681ad6265SDimitry Andric   // The counter holds the maximum ID we have in the module.
14781ad6265SDimitry Andric   unsigned MaxID;
14881ad6265SDimitry Andric   // The array contains lists of MIs for each module section.
14981ad6265SDimitry Andric   InstrList MS[NUM_MODULE_SECTIONS];
15081ad6265SDimitry Andric   // The table maps MBB number to SPIR-V unique ID register.
15181ad6265SDimitry Andric   DenseMap<int, Register> BBNumToRegMap;
15281ad6265SDimitry Andric 
153*bdd1243dSDimitry Andric   Register getFuncReg(const Function *F) {
154*bdd1243dSDimitry Andric     assert(F && "Function is null");
155*bdd1243dSDimitry Andric     auto FuncPtrRegPair = FuncMap.find(F);
156*bdd1243dSDimitry Andric     assert(FuncPtrRegPair != FuncMap.end() && "Cannot find function ID");
157*bdd1243dSDimitry Andric     return FuncPtrRegPair->second;
15881ad6265SDimitry Andric   }
159fcaf7f86SDimitry Andric   Register getExtInstSetReg(unsigned SetNum) { return ExtInstSetMap[SetNum]; }
16081ad6265SDimitry Andric   InstrList &getMSInstrs(unsigned MSType) { return MS[MSType]; }
16181ad6265SDimitry Andric   void setSkipEmission(MachineInstr *MI) { InstrsToDelete.insert(MI); }
16281ad6265SDimitry Andric   bool getSkipEmission(const MachineInstr *MI) {
16381ad6265SDimitry Andric     return InstrsToDelete.contains(MI);
16481ad6265SDimitry Andric   }
16581ad6265SDimitry Andric   void setRegisterAlias(const MachineFunction *MF, Register Reg,
16681ad6265SDimitry Andric                         Register AliasReg) {
16781ad6265SDimitry Andric     RegisterAliasTable[MF][Reg] = AliasReg;
16881ad6265SDimitry Andric   }
16981ad6265SDimitry Andric   Register getRegisterAlias(const MachineFunction *MF, Register Reg) {
17081ad6265SDimitry Andric     auto RI = RegisterAliasTable[MF].find(Reg);
17181ad6265SDimitry Andric     if (RI == RegisterAliasTable[MF].end()) {
17281ad6265SDimitry Andric       return Register(0);
17381ad6265SDimitry Andric     }
17481ad6265SDimitry Andric     return RegisterAliasTable[MF][Reg];
17581ad6265SDimitry Andric   }
17681ad6265SDimitry Andric   bool hasRegisterAlias(const MachineFunction *MF, Register Reg) {
17781ad6265SDimitry Andric     return RegisterAliasTable.find(MF) != RegisterAliasTable.end() &&
17881ad6265SDimitry Andric            RegisterAliasTable[MF].find(Reg) != RegisterAliasTable[MF].end();
17981ad6265SDimitry Andric   }
18081ad6265SDimitry Andric   unsigned getNextID() { return MaxID++; }
18181ad6265SDimitry Andric   bool hasMBBRegister(const MachineBasicBlock &MBB) {
18281ad6265SDimitry Andric     return BBNumToRegMap.find(MBB.getNumber()) != BBNumToRegMap.end();
18381ad6265SDimitry Andric   }
18481ad6265SDimitry Andric   // Convert MBB's number to corresponding ID register.
18581ad6265SDimitry Andric   Register getOrCreateMBBRegister(const MachineBasicBlock &MBB) {
18681ad6265SDimitry Andric     auto f = BBNumToRegMap.find(MBB.getNumber());
18781ad6265SDimitry Andric     if (f != BBNumToRegMap.end())
18881ad6265SDimitry Andric       return f->second;
18981ad6265SDimitry Andric     Register NewReg = Register::index2VirtReg(getNextID());
19081ad6265SDimitry Andric     BBNumToRegMap[MBB.getNumber()] = NewReg;
19181ad6265SDimitry Andric     return NewReg;
19281ad6265SDimitry Andric   }
19381ad6265SDimitry Andric };
19481ad6265SDimitry Andric } // namespace SPIRV
19581ad6265SDimitry Andric 
19681ad6265SDimitry Andric struct SPIRVModuleAnalysis : public ModulePass {
19781ad6265SDimitry Andric   static char ID;
19881ad6265SDimitry Andric 
19981ad6265SDimitry Andric public:
20081ad6265SDimitry Andric   SPIRVModuleAnalysis() : ModulePass(ID) {}
20181ad6265SDimitry Andric 
20281ad6265SDimitry Andric   bool runOnModule(Module &M) override;
20381ad6265SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
20481ad6265SDimitry Andric   static struct SPIRV::ModuleAnalysisInfo MAI;
20581ad6265SDimitry Andric 
20681ad6265SDimitry Andric private:
20781ad6265SDimitry Andric   void setBaseInfo(const Module &M);
208753f127fSDimitry Andric   void collectGlobalEntities(
209753f127fSDimitry Andric       const std::vector<SPIRV::DTSortableEntry *> &DepsGraph,
210753f127fSDimitry Andric       SPIRV::ModuleSectionType MSType,
211753f127fSDimitry Andric       std::function<bool(const SPIRV::DTSortableEntry *)> Pred,
212753f127fSDimitry Andric       bool UsePreOrder);
21381ad6265SDimitry Andric   void processDefInstrs(const Module &M);
214*bdd1243dSDimitry Andric   void collectFuncNames(MachineInstr &MI, const Function *F);
21581ad6265SDimitry Andric   void processOtherInstrs(const Module &M);
21681ad6265SDimitry Andric   void numberRegistersGlobally(const Module &M);
21781ad6265SDimitry Andric 
21881ad6265SDimitry Andric   const SPIRVSubtarget *ST;
21981ad6265SDimitry Andric   SPIRVGlobalRegistry *GR;
22081ad6265SDimitry Andric   const SPIRVInstrInfo *TII;
22181ad6265SDimitry Andric   MachineModuleInfo *MMI;
22281ad6265SDimitry Andric };
22381ad6265SDimitry Andric } // namespace llvm
22481ad6265SDimitry Andric #endif // LLVM_LIB_TARGET_SPIRV_SPIRVMODULEANALYSIS_H
225