xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
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"
18bdd1243dSDimitry Andric #include "SPIRVGlobalRegistry.h"
19bdd1243dSDimitry Andric #include "SPIRVUtils.h"
2081ad6265SDimitry Andric #include "llvm/ADT/DenseMap.h"
21bdd1243dSDimitry 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 {
26bdd1243dSDimitry 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 
44bdd1243dSDimitry Andric struct Requirements {
45bdd1243dSDimitry Andric   const bool IsSatisfiable;
46bdd1243dSDimitry Andric   const std::optional<Capability::Capability> Cap;
47bdd1243dSDimitry Andric   const ExtensionList Exts;
48bdd1243dSDimitry Andric   const unsigned MinVer; // 0 if no min version is required.
49bdd1243dSDimitry Andric   const unsigned MaxVer; // 0 if no max version is required.
50bdd1243dSDimitry Andric 
51bdd1243dSDimitry Andric   Requirements(bool IsSatisfiable = false,
52bdd1243dSDimitry Andric                std::optional<Capability::Capability> Cap = {},
53bdd1243dSDimitry Andric                ExtensionList Exts = {}, unsigned MinVer = 0,
54bdd1243dSDimitry Andric                unsigned MaxVer = 0)
55bdd1243dSDimitry Andric       : IsSatisfiable(IsSatisfiable), Cap(Cap), Exts(Exts), MinVer(MinVer),
56bdd1243dSDimitry Andric         MaxVer(MaxVer) {}
57bdd1243dSDimitry Andric   Requirements(Capability::Capability Cap) : Requirements(true, {Cap}) {}
58bdd1243dSDimitry Andric };
59bdd1243dSDimitry Andric 
60bdd1243dSDimitry Andric struct RequirementHandler {
61bdd1243dSDimitry Andric private:
62bdd1243dSDimitry Andric   CapabilityList MinimalCaps;
635f757f3fSDimitry Andric 
645f757f3fSDimitry Andric   // AllCaps and AvailableCaps are related but different. AllCaps is a subset of
655f757f3fSDimitry Andric   // AvailableCaps. AvailableCaps is the complete set of capabilities that are
665f757f3fSDimitry Andric   // available to the current target. AllCaps is the set of capabilities that
675f757f3fSDimitry Andric   // are required by the current module.
68bdd1243dSDimitry Andric   SmallSet<Capability::Capability, 8> AllCaps;
695f757f3fSDimitry Andric   DenseSet<unsigned> AvailableCaps;
705f757f3fSDimitry Andric 
71bdd1243dSDimitry Andric   SmallSet<Extension::Extension, 4> AllExtensions;
72bdd1243dSDimitry Andric   unsigned MinVersion; // 0 if no min version is defined.
73bdd1243dSDimitry Andric   unsigned MaxVersion; // 0 if no max version is defined.
74bdd1243dSDimitry Andric   // Remove a list of capabilities from dedupedCaps and add them to AllCaps,
75bdd1243dSDimitry Andric   // recursing through their implicitly declared capabilities too.
76bdd1243dSDimitry Andric   void pruneCapabilities(const CapabilityList &ToPrune);
77bdd1243dSDimitry Andric 
785f757f3fSDimitry Andric   void initAvailableCapabilitiesForOpenCL(const SPIRVSubtarget &ST);
795f757f3fSDimitry Andric   void initAvailableCapabilitiesForVulkan(const SPIRVSubtarget &ST);
805f757f3fSDimitry Andric 
81bdd1243dSDimitry Andric public:
82bdd1243dSDimitry Andric   RequirementHandler() : MinVersion(0), MaxVersion(0) {}
83bdd1243dSDimitry Andric   void clear() {
84bdd1243dSDimitry Andric     MinimalCaps.clear();
85bdd1243dSDimitry Andric     AllCaps.clear();
86bdd1243dSDimitry Andric     AvailableCaps.clear();
87bdd1243dSDimitry Andric     AllExtensions.clear();
88bdd1243dSDimitry Andric     MinVersion = 0;
89bdd1243dSDimitry Andric     MaxVersion = 0;
90bdd1243dSDimitry Andric   }
91bdd1243dSDimitry Andric   unsigned getMinVersion() const { return MinVersion; }
92bdd1243dSDimitry Andric   unsigned getMaxVersion() const { return MaxVersion; }
93bdd1243dSDimitry Andric   const CapabilityList &getMinimalCapabilities() const { return MinimalCaps; }
94bdd1243dSDimitry Andric   const SmallSet<Extension::Extension, 4> &getExtensions() const {
95bdd1243dSDimitry Andric     return AllExtensions;
96bdd1243dSDimitry Andric   }
97bdd1243dSDimitry Andric   // Add a list of capabilities, ensuring AllCaps captures all the implicitly
98bdd1243dSDimitry Andric   // declared capabilities, and MinimalCaps has the minimal set of required
99bdd1243dSDimitry Andric   // capabilities (so all implicitly declared ones are removed).
100bdd1243dSDimitry Andric   void addCapabilities(const CapabilityList &ToAdd);
101bdd1243dSDimitry Andric   void addCapability(Capability::Capability ToAdd) { addCapabilities({ToAdd}); }
102bdd1243dSDimitry Andric   void addExtensions(const ExtensionList &ToAdd) {
103bdd1243dSDimitry Andric     AllExtensions.insert(ToAdd.begin(), ToAdd.end());
104bdd1243dSDimitry Andric   }
105bdd1243dSDimitry Andric   void addExtension(Extension::Extension ToAdd) { AllExtensions.insert(ToAdd); }
106bdd1243dSDimitry Andric   // Add the given requirements to the lists. If constraints conflict, or these
107bdd1243dSDimitry Andric   // requirements cannot be satisfied, then abort the compilation.
108bdd1243dSDimitry Andric   void addRequirements(const Requirements &Req);
109bdd1243dSDimitry Andric   // Get requirement and add it to the list.
110bdd1243dSDimitry Andric   void getAndAddRequirements(SPIRV::OperandCategory::OperandCategory Category,
111bdd1243dSDimitry Andric                              uint32_t i, const SPIRVSubtarget &ST);
112bdd1243dSDimitry Andric   // Check if all the requirements can be satisfied for the given subtarget, and
113bdd1243dSDimitry Andric   // if not abort compilation.
114bdd1243dSDimitry Andric   void checkSatisfiable(const SPIRVSubtarget &ST) const;
115bdd1243dSDimitry Andric   void initAvailableCapabilities(const SPIRVSubtarget &ST);
116bdd1243dSDimitry Andric   // Add the given capabilities to available and all their implicitly defined
117bdd1243dSDimitry Andric   // capabilities too.
118bdd1243dSDimitry Andric   void addAvailableCaps(const CapabilityList &ToAdd);
119bdd1243dSDimitry Andric   bool isCapabilityAvailable(Capability::Capability Cap) const {
120bdd1243dSDimitry Andric     return AvailableCaps.contains(Cap);
121bdd1243dSDimitry Andric   }
1225f757f3fSDimitry Andric 
1235f757f3fSDimitry Andric   // Remove capability ToRemove, but only if IfPresent is present.
1245f757f3fSDimitry Andric   void removeCapabilityIf(const Capability::Capability ToRemove,
1255f757f3fSDimitry Andric                           const Capability::Capability IfPresent);
126bdd1243dSDimitry Andric };
127bdd1243dSDimitry Andric 
12881ad6265SDimitry Andric using InstrList = SmallVector<MachineInstr *>;
12981ad6265SDimitry Andric // Maps a local register to the corresponding global alias.
13081ad6265SDimitry Andric using LocalToGlobalRegTable = std::map<Register, Register>;
13181ad6265SDimitry Andric using RegisterAliasMapTy =
13281ad6265SDimitry Andric     std::map<const MachineFunction *, LocalToGlobalRegTable>;
13381ad6265SDimitry Andric 
13481ad6265SDimitry Andric // The struct contains results of the module analysis and methods
13581ad6265SDimitry Andric // to access them.
13681ad6265SDimitry Andric struct ModuleAnalysisInfo {
137bdd1243dSDimitry Andric   RequirementHandler Reqs;
138bdd1243dSDimitry Andric   MemoryModel::MemoryModel Mem;
139bdd1243dSDimitry Andric   AddressingModel::AddressingModel Addr;
140bdd1243dSDimitry Andric   SourceLanguage::SourceLanguage SrcLang;
14181ad6265SDimitry Andric   unsigned SrcLangVersion;
142fcaf7f86SDimitry Andric   StringSet<> SrcExt;
143fcaf7f86SDimitry Andric   // Maps ExtInstSet to corresponding ID register.
144fcaf7f86SDimitry Andric   DenseMap<unsigned, Register> ExtInstSetMap;
14581ad6265SDimitry Andric   // Contains the list of all global OpVariables in the module.
14681ad6265SDimitry Andric   SmallVector<MachineInstr *, 4> GlobalVarList;
147bdd1243dSDimitry Andric   // Maps functions to corresponding function ID registers.
148bdd1243dSDimitry Andric   DenseMap<const Function *, Register> FuncMap;
14981ad6265SDimitry Andric   // The set contains machine instructions which are necessary
15081ad6265SDimitry Andric   // for correct MIR but will not be emitted in function bodies.
15181ad6265SDimitry Andric   DenseSet<MachineInstr *> InstrsToDelete;
15281ad6265SDimitry Andric   // The table contains global aliases of local registers for each machine
15381ad6265SDimitry Andric   // function. The aliases are used to substitute local registers during
15481ad6265SDimitry Andric   // code emission.
15581ad6265SDimitry Andric   RegisterAliasMapTy RegisterAliasTable;
15681ad6265SDimitry Andric   // The counter holds the maximum ID we have in the module.
15781ad6265SDimitry Andric   unsigned MaxID;
15881ad6265SDimitry Andric   // The array contains lists of MIs for each module section.
15981ad6265SDimitry Andric   InstrList MS[NUM_MODULE_SECTIONS];
16081ad6265SDimitry Andric   // The table maps MBB number to SPIR-V unique ID register.
16181ad6265SDimitry Andric   DenseMap<int, Register> BBNumToRegMap;
16281ad6265SDimitry Andric 
163bdd1243dSDimitry Andric   Register getFuncReg(const Function *F) {
164bdd1243dSDimitry Andric     assert(F && "Function is null");
165bdd1243dSDimitry Andric     auto FuncPtrRegPair = FuncMap.find(F);
166bdd1243dSDimitry Andric     assert(FuncPtrRegPair != FuncMap.end() && "Cannot find function ID");
167bdd1243dSDimitry Andric     return FuncPtrRegPair->second;
16881ad6265SDimitry Andric   }
169fcaf7f86SDimitry Andric   Register getExtInstSetReg(unsigned SetNum) { return ExtInstSetMap[SetNum]; }
17081ad6265SDimitry Andric   InstrList &getMSInstrs(unsigned MSType) { return MS[MSType]; }
17181ad6265SDimitry Andric   void setSkipEmission(MachineInstr *MI) { InstrsToDelete.insert(MI); }
17281ad6265SDimitry Andric   bool getSkipEmission(const MachineInstr *MI) {
17381ad6265SDimitry Andric     return InstrsToDelete.contains(MI);
17481ad6265SDimitry Andric   }
17581ad6265SDimitry Andric   void setRegisterAlias(const MachineFunction *MF, Register Reg,
17681ad6265SDimitry Andric                         Register AliasReg) {
17781ad6265SDimitry Andric     RegisterAliasTable[MF][Reg] = AliasReg;
17881ad6265SDimitry Andric   }
17981ad6265SDimitry Andric   Register getRegisterAlias(const MachineFunction *MF, Register Reg) {
18081ad6265SDimitry Andric     auto RI = RegisterAliasTable[MF].find(Reg);
18181ad6265SDimitry Andric     if (RI == RegisterAliasTable[MF].end()) {
18281ad6265SDimitry Andric       return Register(0);
18381ad6265SDimitry Andric     }
18481ad6265SDimitry Andric     return RegisterAliasTable[MF][Reg];
18581ad6265SDimitry Andric   }
18681ad6265SDimitry Andric   bool hasRegisterAlias(const MachineFunction *MF, Register Reg) {
18781ad6265SDimitry Andric     return RegisterAliasTable.find(MF) != RegisterAliasTable.end() &&
18881ad6265SDimitry Andric            RegisterAliasTable[MF].find(Reg) != RegisterAliasTable[MF].end();
18981ad6265SDimitry Andric   }
19081ad6265SDimitry Andric   unsigned getNextID() { return MaxID++; }
19181ad6265SDimitry Andric   bool hasMBBRegister(const MachineBasicBlock &MBB) {
192*cb14a3feSDimitry Andric     return BBNumToRegMap.contains(MBB.getNumber());
19381ad6265SDimitry Andric   }
19481ad6265SDimitry Andric   // Convert MBB's number to corresponding ID register.
19581ad6265SDimitry Andric   Register getOrCreateMBBRegister(const MachineBasicBlock &MBB) {
19681ad6265SDimitry Andric     auto f = BBNumToRegMap.find(MBB.getNumber());
19781ad6265SDimitry Andric     if (f != BBNumToRegMap.end())
19881ad6265SDimitry Andric       return f->second;
19981ad6265SDimitry Andric     Register NewReg = Register::index2VirtReg(getNextID());
20081ad6265SDimitry Andric     BBNumToRegMap[MBB.getNumber()] = NewReg;
20181ad6265SDimitry Andric     return NewReg;
20281ad6265SDimitry Andric   }
20381ad6265SDimitry Andric };
20481ad6265SDimitry Andric } // namespace SPIRV
20581ad6265SDimitry Andric 
20681ad6265SDimitry Andric struct SPIRVModuleAnalysis : public ModulePass {
20781ad6265SDimitry Andric   static char ID;
20881ad6265SDimitry Andric 
20981ad6265SDimitry Andric public:
21081ad6265SDimitry Andric   SPIRVModuleAnalysis() : ModulePass(ID) {}
21181ad6265SDimitry Andric 
21281ad6265SDimitry Andric   bool runOnModule(Module &M) override;
21381ad6265SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
21481ad6265SDimitry Andric   static struct SPIRV::ModuleAnalysisInfo MAI;
21581ad6265SDimitry Andric 
21681ad6265SDimitry Andric private:
21781ad6265SDimitry Andric   void setBaseInfo(const Module &M);
218753f127fSDimitry Andric   void collectGlobalEntities(
219753f127fSDimitry Andric       const std::vector<SPIRV::DTSortableEntry *> &DepsGraph,
220753f127fSDimitry Andric       SPIRV::ModuleSectionType MSType,
221753f127fSDimitry Andric       std::function<bool(const SPIRV::DTSortableEntry *)> Pred,
222753f127fSDimitry Andric       bool UsePreOrder);
22381ad6265SDimitry Andric   void processDefInstrs(const Module &M);
224bdd1243dSDimitry Andric   void collectFuncNames(MachineInstr &MI, const Function *F);
22581ad6265SDimitry Andric   void processOtherInstrs(const Module &M);
22681ad6265SDimitry Andric   void numberRegistersGlobally(const Module &M);
22781ad6265SDimitry Andric 
22881ad6265SDimitry Andric   const SPIRVSubtarget *ST;
22981ad6265SDimitry Andric   SPIRVGlobalRegistry *GR;
23081ad6265SDimitry Andric   const SPIRVInstrInfo *TII;
23181ad6265SDimitry Andric   MachineModuleInfo *MMI;
23281ad6265SDimitry Andric };
23381ad6265SDimitry Andric } // namespace llvm
23481ad6265SDimitry Andric #endif // LLVM_LIB_TARGET_SPIRV_SPIRVMODULEANALYSIS_H
235