xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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;
48*0fca6ea1SDimitry Andric   const VersionTuple MinVer; // 0 if no min version is required.
49*0fca6ea1SDimitry Andric   const VersionTuple MaxVer; // 0 if no max version is required.
50bdd1243dSDimitry Andric 
51bdd1243dSDimitry Andric   Requirements(bool IsSatisfiable = false,
52bdd1243dSDimitry Andric                std::optional<Capability::Capability> Cap = {},
53*0fca6ea1SDimitry Andric                ExtensionList Exts = {}, VersionTuple MinVer = VersionTuple(),
54*0fca6ea1SDimitry Andric                VersionTuple MaxVer = VersionTuple())
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;
72*0fca6ea1SDimitry Andric   VersionTuple MinVersion; // 0 if no min version is defined.
73*0fca6ea1SDimitry Andric   VersionTuple MaxVersion; // 0 if no max version is defined.
74*0fca6ea1SDimitry Andric   // Add capabilities to AllCaps, recursing through their implicitly declared
75*0fca6ea1SDimitry Andric   // capabilities too.
76*0fca6ea1SDimitry Andric   void recursiveAddCapabilities(const CapabilityList &ToPrune);
77bdd1243dSDimitry Andric 
785f757f3fSDimitry Andric   void initAvailableCapabilitiesForOpenCL(const SPIRVSubtarget &ST);
795f757f3fSDimitry Andric   void initAvailableCapabilitiesForVulkan(const SPIRVSubtarget &ST);
805f757f3fSDimitry Andric 
81bdd1243dSDimitry Andric public:
82*0fca6ea1SDimitry Andric   RequirementHandler() {}
83bdd1243dSDimitry Andric   void clear() {
84bdd1243dSDimitry Andric     MinimalCaps.clear();
85bdd1243dSDimitry Andric     AllCaps.clear();
86bdd1243dSDimitry Andric     AvailableCaps.clear();
87bdd1243dSDimitry Andric     AllExtensions.clear();
88*0fca6ea1SDimitry Andric     MinVersion = VersionTuple();
89*0fca6ea1SDimitry Andric     MaxVersion = VersionTuple();
90bdd1243dSDimitry Andric   }
91bdd1243dSDimitry Andric   const CapabilityList &getMinimalCapabilities() const { return MinimalCaps; }
92bdd1243dSDimitry Andric   const SmallSet<Extension::Extension, 4> &getExtensions() const {
93bdd1243dSDimitry Andric     return AllExtensions;
94bdd1243dSDimitry Andric   }
95bdd1243dSDimitry Andric   // Add a list of capabilities, ensuring AllCaps captures all the implicitly
96bdd1243dSDimitry Andric   // declared capabilities, and MinimalCaps has the minimal set of required
97bdd1243dSDimitry Andric   // capabilities (so all implicitly declared ones are removed).
98bdd1243dSDimitry Andric   void addCapabilities(const CapabilityList &ToAdd);
99bdd1243dSDimitry Andric   void addCapability(Capability::Capability ToAdd) { addCapabilities({ToAdd}); }
100bdd1243dSDimitry Andric   void addExtensions(const ExtensionList &ToAdd) {
101bdd1243dSDimitry Andric     AllExtensions.insert(ToAdd.begin(), ToAdd.end());
102bdd1243dSDimitry Andric   }
103bdd1243dSDimitry Andric   void addExtension(Extension::Extension ToAdd) { AllExtensions.insert(ToAdd); }
104bdd1243dSDimitry Andric   // Add the given requirements to the lists. If constraints conflict, or these
105bdd1243dSDimitry Andric   // requirements cannot be satisfied, then abort the compilation.
106bdd1243dSDimitry Andric   void addRequirements(const Requirements &Req);
107bdd1243dSDimitry Andric   // Get requirement and add it to the list.
108bdd1243dSDimitry Andric   void getAndAddRequirements(SPIRV::OperandCategory::OperandCategory Category,
109bdd1243dSDimitry Andric                              uint32_t i, const SPIRVSubtarget &ST);
110bdd1243dSDimitry Andric   // Check if all the requirements can be satisfied for the given subtarget, and
111bdd1243dSDimitry Andric   // if not abort compilation.
112bdd1243dSDimitry Andric   void checkSatisfiable(const SPIRVSubtarget &ST) const;
113bdd1243dSDimitry Andric   void initAvailableCapabilities(const SPIRVSubtarget &ST);
114bdd1243dSDimitry Andric   // Add the given capabilities to available and all their implicitly defined
115bdd1243dSDimitry Andric   // capabilities too.
116bdd1243dSDimitry Andric   void addAvailableCaps(const CapabilityList &ToAdd);
117bdd1243dSDimitry Andric   bool isCapabilityAvailable(Capability::Capability Cap) const {
118bdd1243dSDimitry Andric     return AvailableCaps.contains(Cap);
119bdd1243dSDimitry Andric   }
1205f757f3fSDimitry Andric 
1215f757f3fSDimitry Andric   // Remove capability ToRemove, but only if IfPresent is present.
1225f757f3fSDimitry Andric   void removeCapabilityIf(const Capability::Capability ToRemove,
1235f757f3fSDimitry Andric                           const Capability::Capability IfPresent);
124bdd1243dSDimitry Andric };
125bdd1243dSDimitry Andric 
12681ad6265SDimitry Andric using InstrList = SmallVector<MachineInstr *>;
12781ad6265SDimitry Andric // Maps a local register to the corresponding global alias.
12881ad6265SDimitry Andric using LocalToGlobalRegTable = std::map<Register, Register>;
12981ad6265SDimitry Andric using RegisterAliasMapTy =
13081ad6265SDimitry Andric     std::map<const MachineFunction *, LocalToGlobalRegTable>;
13181ad6265SDimitry Andric 
13281ad6265SDimitry Andric // The struct contains results of the module analysis and methods
13381ad6265SDimitry Andric // to access them.
13481ad6265SDimitry Andric struct ModuleAnalysisInfo {
135bdd1243dSDimitry Andric   RequirementHandler Reqs;
136bdd1243dSDimitry Andric   MemoryModel::MemoryModel Mem;
137bdd1243dSDimitry Andric   AddressingModel::AddressingModel Addr;
138bdd1243dSDimitry Andric   SourceLanguage::SourceLanguage SrcLang;
13981ad6265SDimitry Andric   unsigned SrcLangVersion;
140fcaf7f86SDimitry Andric   StringSet<> SrcExt;
141fcaf7f86SDimitry Andric   // Maps ExtInstSet to corresponding ID register.
142fcaf7f86SDimitry Andric   DenseMap<unsigned, Register> ExtInstSetMap;
14381ad6265SDimitry Andric   // Contains the list of all global OpVariables in the module.
14481ad6265SDimitry Andric   SmallVector<MachineInstr *, 4> GlobalVarList;
145bdd1243dSDimitry Andric   // Maps functions to corresponding function ID registers.
146bdd1243dSDimitry Andric   DenseMap<const Function *, Register> FuncMap;
14781ad6265SDimitry Andric   // The set contains machine instructions which are necessary
14881ad6265SDimitry Andric   // for correct MIR but will not be emitted in function bodies.
14981ad6265SDimitry Andric   DenseSet<MachineInstr *> InstrsToDelete;
15081ad6265SDimitry Andric   // The table contains global aliases of local registers for each machine
15181ad6265SDimitry Andric   // function. The aliases are used to substitute local registers during
15281ad6265SDimitry Andric   // code emission.
15381ad6265SDimitry Andric   RegisterAliasMapTy RegisterAliasTable;
15481ad6265SDimitry Andric   // The counter holds the maximum ID we have in the module.
15581ad6265SDimitry Andric   unsigned MaxID;
15681ad6265SDimitry Andric   // The array contains lists of MIs for each module section.
15781ad6265SDimitry Andric   InstrList MS[NUM_MODULE_SECTIONS];
15881ad6265SDimitry Andric   // The table maps MBB number to SPIR-V unique ID register.
15981ad6265SDimitry Andric   DenseMap<int, Register> BBNumToRegMap;
16081ad6265SDimitry Andric 
161bdd1243dSDimitry Andric   Register getFuncReg(const Function *F) {
162bdd1243dSDimitry Andric     assert(F && "Function is null");
163bdd1243dSDimitry Andric     auto FuncPtrRegPair = FuncMap.find(F);
164*0fca6ea1SDimitry Andric     return FuncPtrRegPair == FuncMap.end() ? Register(0)
165*0fca6ea1SDimitry Andric                                            : FuncPtrRegPair->second;
16681ad6265SDimitry Andric   }
167fcaf7f86SDimitry Andric   Register getExtInstSetReg(unsigned SetNum) { return ExtInstSetMap[SetNum]; }
16881ad6265SDimitry Andric   InstrList &getMSInstrs(unsigned MSType) { return MS[MSType]; }
16981ad6265SDimitry Andric   void setSkipEmission(MachineInstr *MI) { InstrsToDelete.insert(MI); }
17081ad6265SDimitry Andric   bool getSkipEmission(const MachineInstr *MI) {
17181ad6265SDimitry Andric     return InstrsToDelete.contains(MI);
17281ad6265SDimitry Andric   }
17381ad6265SDimitry Andric   void setRegisterAlias(const MachineFunction *MF, Register Reg,
17481ad6265SDimitry Andric                         Register AliasReg) {
17581ad6265SDimitry Andric     RegisterAliasTable[MF][Reg] = AliasReg;
17681ad6265SDimitry Andric   }
17781ad6265SDimitry Andric   Register getRegisterAlias(const MachineFunction *MF, Register Reg) {
17881ad6265SDimitry Andric     auto RI = RegisterAliasTable[MF].find(Reg);
17981ad6265SDimitry Andric     if (RI == RegisterAliasTable[MF].end()) {
18081ad6265SDimitry Andric       return Register(0);
18181ad6265SDimitry Andric     }
18281ad6265SDimitry Andric     return RegisterAliasTable[MF][Reg];
18381ad6265SDimitry Andric   }
18481ad6265SDimitry Andric   bool hasRegisterAlias(const MachineFunction *MF, Register Reg) {
18581ad6265SDimitry Andric     return RegisterAliasTable.find(MF) != RegisterAliasTable.end() &&
18681ad6265SDimitry Andric            RegisterAliasTable[MF].find(Reg) != RegisterAliasTable[MF].end();
18781ad6265SDimitry Andric   }
18881ad6265SDimitry Andric   unsigned getNextID() { return MaxID++; }
18981ad6265SDimitry Andric   bool hasMBBRegister(const MachineBasicBlock &MBB) {
190cb14a3feSDimitry Andric     return BBNumToRegMap.contains(MBB.getNumber());
19181ad6265SDimitry Andric   }
19281ad6265SDimitry Andric   // Convert MBB's number to corresponding ID register.
19381ad6265SDimitry Andric   Register getOrCreateMBBRegister(const MachineBasicBlock &MBB) {
19481ad6265SDimitry Andric     auto f = BBNumToRegMap.find(MBB.getNumber());
19581ad6265SDimitry Andric     if (f != BBNumToRegMap.end())
19681ad6265SDimitry Andric       return f->second;
19781ad6265SDimitry Andric     Register NewReg = Register::index2VirtReg(getNextID());
19881ad6265SDimitry Andric     BBNumToRegMap[MBB.getNumber()] = NewReg;
19981ad6265SDimitry Andric     return NewReg;
20081ad6265SDimitry Andric   }
20181ad6265SDimitry Andric };
20281ad6265SDimitry Andric } // namespace SPIRV
20381ad6265SDimitry Andric 
20481ad6265SDimitry Andric struct SPIRVModuleAnalysis : public ModulePass {
20581ad6265SDimitry Andric   static char ID;
20681ad6265SDimitry Andric 
20781ad6265SDimitry Andric public:
20881ad6265SDimitry Andric   SPIRVModuleAnalysis() : ModulePass(ID) {}
20981ad6265SDimitry Andric 
21081ad6265SDimitry Andric   bool runOnModule(Module &M) override;
21181ad6265SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
21281ad6265SDimitry Andric   static struct SPIRV::ModuleAnalysisInfo MAI;
21381ad6265SDimitry Andric 
21481ad6265SDimitry Andric private:
21581ad6265SDimitry Andric   void setBaseInfo(const Module &M);
216753f127fSDimitry Andric   void collectGlobalEntities(
217753f127fSDimitry Andric       const std::vector<SPIRV::DTSortableEntry *> &DepsGraph,
218753f127fSDimitry Andric       SPIRV::ModuleSectionType MSType,
219753f127fSDimitry Andric       std::function<bool(const SPIRV::DTSortableEntry *)> Pred,
220753f127fSDimitry Andric       bool UsePreOrder);
22181ad6265SDimitry Andric   void processDefInstrs(const Module &M);
222bdd1243dSDimitry Andric   void collectFuncNames(MachineInstr &MI, const Function *F);
22381ad6265SDimitry Andric   void processOtherInstrs(const Module &M);
22481ad6265SDimitry Andric   void numberRegistersGlobally(const Module &M);
225*0fca6ea1SDimitry Andric   void collectFuncPtrs();
226*0fca6ea1SDimitry Andric   void collectFuncPtrs(MachineInstr *MI);
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