263 lines · c
1//===- SPIRVModuleAnalysis.h - analysis of global instrs & regs -*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// The analysis collects instructions that should be output at the module level10// and performs the global register numbering.11//12//===----------------------------------------------------------------------===//13 14#ifndef LLVM_LIB_TARGET_SPIRV_SPIRVMODULEANALYSIS_H15#define LLVM_LIB_TARGET_SPIRV_SPIRVMODULEANALYSIS_H16 17#include "MCTargetDesc/SPIRVBaseInfo.h"18#include "SPIRVGlobalRegistry.h"19#include "SPIRVUtils.h"20#include "llvm/ADT/DenseMap.h"21#include "llvm/ADT/SmallSet.h"22#include "llvm/ADT/SmallVector.h"23 24namespace llvm {25class SPIRVSubtarget;26class MachineFunction;27class MachineModuleInfo;28 29namespace SPIRV {30// The enum contains logical module sections for the instruction collection.31enum ModuleSectionType {32 // MB_Capabilities, MB_Extensions, MB_ExtInstImports, MB_MemoryModel,33 MB_EntryPoints, // All OpEntryPoint instructions (if any).34 // MB_ExecutionModes, MB_DebugSourceAndStrings,35 MB_DebugNames, // All OpName and OpMemberName intrs.36 MB_DebugStrings, // All OpString intrs.37 MB_DebugModuleProcessed, // All OpModuleProcessed instructions.38 MB_AliasingInsts, // SPV_INTEL_memory_access_aliasing instructions.39 MB_Annotations, // OpDecorate, OpMemberDecorate etc.40 MB_TypeConstVars, // OpTypeXXX, OpConstantXXX, and global OpVariables.41 MB_NonSemanticGlobalDI, // OpExtInst with e.g. DebugSource, DebugTypeBasic.42 MB_ExtFuncDecls, // OpFunction etc. to declare for external funcs.43 NUM_MODULE_SECTIONS // Total number of sections requiring basic blocks.44};45 46struct Requirements {47 const bool IsSatisfiable;48 const std::optional<Capability::Capability> Cap;49 const ExtensionList Exts;50 const VersionTuple MinVer; // 0 if no min version is required.51 const VersionTuple MaxVer; // 0 if no max version is required.52 53 Requirements(bool IsSatisfiable = false,54 std::optional<Capability::Capability> Cap = {},55 ExtensionList Exts = {}, VersionTuple MinVer = VersionTuple(),56 VersionTuple MaxVer = VersionTuple())57 : IsSatisfiable(IsSatisfiable), Cap(Cap), Exts(std::move(Exts)),58 MinVer(MinVer), MaxVer(MaxVer) {}59 Requirements(Capability::Capability Cap) : Requirements(true, {Cap}) {}60};61 62struct RequirementHandler {63private:64 CapabilityList MinimalCaps;65 66 // AllCaps and AvailableCaps are related but different. AllCaps is a subset of67 // AvailableCaps. AvailableCaps is the complete set of capabilities that are68 // available to the current target. AllCaps is the set of capabilities that69 // are required by the current module.70 SmallSet<Capability::Capability, 8> AllCaps;71 DenseSet<unsigned> AvailableCaps;72 73 SmallSet<Extension::Extension, 4> AllExtensions;74 VersionTuple MinVersion; // 0 if no min version is defined.75 VersionTuple MaxVersion; // 0 if no max version is defined.76 // Add capabilities to AllCaps, recursing through their implicitly declared77 // capabilities too.78 void recursiveAddCapabilities(const CapabilityList &ToPrune);79 80 void initAvailableCapabilitiesForOpenCL(const SPIRVSubtarget &ST);81 void initAvailableCapabilitiesForVulkan(const SPIRVSubtarget &ST);82 83public:84 RequirementHandler() = default;85 void clear() {86 MinimalCaps.clear();87 AllCaps.clear();88 AvailableCaps.clear();89 AllExtensions.clear();90 MinVersion = VersionTuple();91 MaxVersion = VersionTuple();92 }93 const CapabilityList &getMinimalCapabilities() const { return MinimalCaps; }94 const SmallSet<Extension::Extension, 4> &getExtensions() const {95 return AllExtensions;96 }97 // Add a list of capabilities, ensuring AllCaps captures all the implicitly98 // declared capabilities, and MinimalCaps has the minimal set of required99 // capabilities (so all implicitly declared ones are removed).100 void addCapabilities(const CapabilityList &ToAdd);101 void addCapability(Capability::Capability ToAdd) { addCapabilities({ToAdd}); }102 void addExtensions(const ExtensionList &ToAdd) {103 AllExtensions.insert_range(ToAdd);104 }105 void addExtension(Extension::Extension ToAdd) { AllExtensions.insert(ToAdd); }106 // Add the given requirements to the lists. If constraints conflict, or these107 // requirements cannot be satisfied, then abort the compilation.108 void addRequirements(const Requirements &Req);109 // Get requirement and add it to the list.110 void getAndAddRequirements(SPIRV::OperandCategory::OperandCategory Category,111 uint32_t i, const SPIRVSubtarget &ST);112 // Check if all the requirements can be satisfied for the given subtarget, and113 // if not abort compilation.114 void checkSatisfiable(const SPIRVSubtarget &ST) const;115 void initAvailableCapabilities(const SPIRVSubtarget &ST);116 // Add the given capabilities to available and all their implicitly defined117 // capabilities too.118 void addAvailableCaps(const CapabilityList &ToAdd);119 bool isCapabilityAvailable(Capability::Capability Cap) const {120 return AvailableCaps.contains(Cap);121 }122 123 // Remove capability ToRemove, but only if IfPresent is present.124 void removeCapabilityIf(const Capability::Capability ToRemove,125 const Capability::Capability IfPresent);126};127 128using InstrList = SmallVector<const MachineInstr *>;129// Maps a local register to the corresponding global alias.130using LocalToGlobalRegTable = std::map<Register, MCRegister>;131using RegisterAliasMapTy =132 std::map<const MachineFunction *, LocalToGlobalRegTable>;133 134// The struct contains results of the module analysis and methods135// to access them.136struct ModuleAnalysisInfo {137 RequirementHandler Reqs;138 MemoryModel::MemoryModel Mem;139 AddressingModel::AddressingModel Addr;140 SourceLanguage::SourceLanguage SrcLang;141 unsigned SrcLangVersion;142 StringSet<> SrcExt;143 // Maps ExtInstSet to corresponding ID register.144 DenseMap<unsigned, MCRegister> ExtInstSetMap;145 // Contains the list of all global OpVariables in the module.146 SmallVector<const MachineInstr *, 4> GlobalVarList;147 // Maps functions to corresponding function ID registers.148 DenseMap<const Function *, MCRegister> FuncMap;149 // The set contains machine instructions which are necessary150 // for correct MIR but will not be emitted in function bodies.151 DenseSet<const MachineInstr *> InstrsToDelete;152 // The table contains global aliases of local registers for each machine153 // function. The aliases are used to substitute local registers during154 // code emission.155 RegisterAliasMapTy RegisterAliasTable;156 // The counter holds the maximum ID we have in the module.157 unsigned MaxID;158 // The array contains lists of MIs for each module section.159 InstrList MS[NUM_MODULE_SECTIONS];160 // The table maps MBB number to SPIR-V unique ID register.161 DenseMap<std::pair<const MachineFunction *, int>, MCRegister> BBNumToRegMap;162 // The table maps function pointers to their default FP fast math info. It can163 // be assumed that the SmallVector is sorted by the bit width of the type. The164 // first element is the smallest bit width, and the last element is the165 // largest bit width, therefore, we will have {half, float, double} in166 // the order of their bit widths.167 DenseMap<const Function *, SPIRV::FPFastMathDefaultInfoVector>168 FPFastMathDefaultInfoMap;169 170 MCRegister getFuncReg(const Function *F) {171 assert(F && "Function is null");172 return FuncMap.lookup(F);173 }174 MCRegister getExtInstSetReg(unsigned SetNum) { return ExtInstSetMap[SetNum]; }175 InstrList &getMSInstrs(unsigned MSType) { return MS[MSType]; }176 void setSkipEmission(const MachineInstr *MI) { InstrsToDelete.insert(MI); }177 bool getSkipEmission(const MachineInstr *MI) {178 return InstrsToDelete.contains(MI);179 }180 void setRegisterAlias(const MachineFunction *MF, Register Reg,181 MCRegister AliasReg) {182 RegisterAliasTable[MF][Reg] = AliasReg;183 }184 MCRegister getRegisterAlias(const MachineFunction *MF, Register Reg) {185 auto &RegTable = RegisterAliasTable[MF];186 auto RI = RegTable.find(Reg);187 if (RI == RegTable.end()) {188 return MCRegister();189 }190 return RI->second;191 }192 bool hasRegisterAlias(const MachineFunction *MF, Register Reg) {193 auto RI = RegisterAliasTable.find(MF);194 if (RI == RegisterAliasTable.end())195 return false;196 return RI->second.find(Reg) != RI->second.end();197 }198 unsigned getNextID() { return MaxID++; }199 MCRegister getNextIDRegister() {200 return MCRegister((1U << 31) | getNextID());201 }202 bool hasMBBRegister(const MachineBasicBlock &MBB) {203 auto Key = std::make_pair(MBB.getParent(), MBB.getNumber());204 return BBNumToRegMap.contains(Key);205 }206 // Convert MBB's number to corresponding ID register.207 MCRegister getOrCreateMBBRegister(const MachineBasicBlock &MBB) {208 auto Key = std::make_pair(MBB.getParent(), MBB.getNumber());209 auto [It, Inserted] = BBNumToRegMap.try_emplace(Key);210 if (Inserted)211 It->second = getNextIDRegister();212 return It->second;213 }214};215} // namespace SPIRV216 217using InstrSignature = SmallVector<size_t>;218using InstrTraces = std::set<InstrSignature>;219using InstrGRegsMap = std::map<SmallVector<size_t>, unsigned>;220 221struct SPIRVModuleAnalysis : public ModulePass {222 static char ID;223 224public:225 SPIRVModuleAnalysis()226 : ModulePass(ID), ST(nullptr), GR(nullptr), TII(nullptr), MMI(nullptr) {}227 228 bool runOnModule(Module &M) override;229 void getAnalysisUsage(AnalysisUsage &AU) const override;230 static struct SPIRV::ModuleAnalysisInfo MAI;231 232private:233 void setBaseInfo(const Module &M);234 void collectFuncNames(MachineInstr &MI, const Function *F);235 void processOtherInstrs(const Module &M);236 void numberRegistersGlobally(const Module &M);237 238 // analyze dependencies to collect module scope definitions239 void collectDeclarations(const Module &M);240 void visitDecl(const MachineRegisterInfo &MRI, InstrGRegsMap &SignatureToGReg,241 std::map<const Value *, unsigned> &GlobalToGReg,242 const MachineFunction *MF, const MachineInstr &MI);243 MCRegister handleVariable(const MachineFunction *MF, const MachineInstr &MI,244 std::map<const Value *, unsigned> &GlobalToGReg);245 MCRegister handleTypeDeclOrConstant(const MachineInstr &MI,246 InstrGRegsMap &SignatureToGReg);247 MCRegister248 handleFunctionOrParameter(const MachineFunction *MF, const MachineInstr &MI,249 std::map<const Value *, unsigned> &GlobalToGReg,250 bool &IsFunDef);251 void visitFunPtrUse(Register OpReg, InstrGRegsMap &SignatureToGReg,252 std::map<const Value *, unsigned> &GlobalToGReg,253 const MachineFunction *MF, const MachineInstr &MI);254 bool isDeclSection(const MachineRegisterInfo &MRI, const MachineInstr &MI);255 256 const SPIRVSubtarget *ST;257 SPIRVGlobalRegistry *GR;258 const SPIRVInstrInfo *TII;259 MachineModuleInfo *MMI;260};261} // namespace llvm262#endif // LLVM_LIB_TARGET_SPIRV_SPIRVMODULEANALYSIS_H263