Path: blob/main/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVIRMapping.h
213799 views
//===------------ SPIRVMapping.h - SPIR-V Duplicates Tracker ----*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// General infrastructure for keeping track of the values that according to9// the SPIR-V binary layout should be global to the whole module.10//11//===----------------------------------------------------------------------===//1213#ifndef LLVM_LIB_TARGET_SPIRV_SPIRVIRMAPPING_H14#define LLVM_LIB_TARGET_SPIRV_SPIRVIRMAPPING_H1516#include "MCTargetDesc/SPIRVBaseInfo.h"17#include "MCTargetDesc/SPIRVMCTargetDesc.h"18#include "SPIRVUtils.h"19#include "llvm/ADT/DenseMap.h"20#include "llvm/ADT/Hashing.h"21#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"22#include "llvm/CodeGen/MachineModuleInfo.h"2324#include <type_traits>2526namespace llvm {27namespace SPIRV {2829inline size_t to_hash(const MachineInstr *MI) {30hash_code H = llvm::hash_combine(MI->getOpcode(), MI->getNumOperands());31for (unsigned I = MI->getNumDefs(); I < MI->getNumOperands(); ++I) {32const MachineOperand &MO = MI->getOperand(I);33if (MO.getType() == MachineOperand::MO_CImmediate)34H = llvm::hash_combine(H, MO.getType(), MO.getCImm());35else if (MO.getType() == MachineOperand::MO_FPImmediate)36H = llvm::hash_combine(H, MO.getType(), MO.getFPImm());37else38H = llvm::hash_combine(H, MO.getType());39}40return H;41}4243using MIHandle = std::tuple<const MachineInstr *, Register, size_t>;4445inline MIHandle getMIKey(const MachineInstr *MI) {46return std::make_tuple(MI, MI->getOperand(0).getReg(), SPIRV::to_hash(MI));47}4849using IRHandle = std::tuple<const void *, unsigned, unsigned>;50using IRHandleMF = std::pair<IRHandle, const MachineFunction *>;5152inline IRHandleMF getIRHandleMF(IRHandle Handle, const MachineFunction *MF) {53return std::make_pair(Handle, MF);54}5556enum SpecialTypeKind {57STK_Empty = 0,58STK_Image,59STK_SampledImage,60STK_Sampler,61STK_Pipe,62STK_DeviceEvent,63STK_ElementPointer,64STK_Type,65STK_Value,66STK_MachineInstr,67STK_VkBuffer,68STK_ExplictLayoutType,69STK_Last = -170};7172union ImageAttrs {73struct BitFlags {74unsigned Dim : 3;75unsigned Depth : 2;76unsigned Arrayed : 1;77unsigned MS : 1;78unsigned Sampled : 2;79unsigned ImageFormat : 6;80unsigned AQ : 2;81} Flags;82unsigned Val;8384ImageAttrs(unsigned Dim, unsigned Depth, unsigned Arrayed, unsigned MS,85unsigned Sampled, unsigned ImageFormat, unsigned AQ = 0) {86Val = 0;87Flags.Dim = Dim;88Flags.Depth = Depth;89Flags.Arrayed = Arrayed;90Flags.MS = MS;91Flags.Sampled = Sampled;92Flags.ImageFormat = ImageFormat;93Flags.AQ = AQ;94}95};9697inline IRHandle irhandle_image(const Type *SampledTy, unsigned Dim,98unsigned Depth, unsigned Arrayed, unsigned MS,99unsigned Sampled, unsigned ImageFormat,100unsigned AQ = 0) {101return std::make_tuple(102SampledTy,103ImageAttrs(Dim, Depth, Arrayed, MS, Sampled, ImageFormat, AQ).Val,104SpecialTypeKind::STK_Image);105}106107inline IRHandle irhandle_sampled_image(const Type *SampledTy,108const MachineInstr *ImageTy) {109assert(ImageTy->getOpcode() == SPIRV::OpTypeImage);110unsigned AC = AccessQualifier::AccessQualifier::None;111if (ImageTy->getNumOperands() > 8)112AC = ImageTy->getOperand(8).getImm();113return std::make_tuple(114SampledTy,115ImageAttrs(116ImageTy->getOperand(2).getImm(), ImageTy->getOperand(3).getImm(),117ImageTy->getOperand(4).getImm(), ImageTy->getOperand(5).getImm(),118ImageTy->getOperand(6).getImm(), ImageTy->getOperand(7).getImm(), AC)119.Val,120SpecialTypeKind::STK_SampledImage);121}122123inline IRHandle irhandle_sampler() {124return std::make_tuple(nullptr, 0U, SpecialTypeKind::STK_Sampler);125}126127inline IRHandle irhandle_pipe(uint8_t AQ) {128return std::make_tuple(nullptr, AQ, SpecialTypeKind::STK_Pipe);129}130131inline IRHandle irhandle_event() {132return std::make_tuple(nullptr, 0U, SpecialTypeKind::STK_DeviceEvent);133}134135inline IRHandle irhandle_pointee(const Type *ElementType,136unsigned AddressSpace) {137return std::make_tuple(unifyPtrType(ElementType), AddressSpace,138SpecialTypeKind::STK_ElementPointer);139}140141inline IRHandle irhandle_ptr(const void *Ptr, unsigned Arg,142enum SpecialTypeKind STK) {143return std::make_tuple(Ptr, Arg, STK);144}145146inline IRHandle irhandle_vkbuffer(const Type *ElementType,147StorageClass::StorageClass SC,148bool IsWriteable) {149return std::make_tuple(ElementType, (SC << 1) | IsWriteable,150SpecialTypeKind::STK_VkBuffer);151}152153inline IRHandle irhandle_explict_layout_type(const Type *Ty) {154const Type *WrpTy = unifyPtrType(Ty);155return irhandle_ptr(WrpTy, Ty->getTypeID(), STK_ExplictLayoutType);156}157158inline IRHandle handle(const Type *Ty) {159const Type *WrpTy = unifyPtrType(Ty);160return irhandle_ptr(WrpTy, Ty->getTypeID(), STK_Type);161}162163inline IRHandle handle(const Value *V) {164return irhandle_ptr(V, V->getValueID(), STK_Value);165}166167inline IRHandle handle(const MachineInstr *KeyMI) {168return irhandle_ptr(KeyMI, SPIRV::to_hash(KeyMI), STK_MachineInstr);169}170171inline bool type_has_layout_decoration(const Type *T) {172return (isa<StructType>(T) || isa<ArrayType>(T));173}174175} // namespace SPIRV176177// Bi-directional mappings between LLVM entities and (v-reg, machine function)178// pairs support management of unique SPIR-V definitions per machine function179// per an LLVM/GlobalISel entity (e.g., Type, Constant, Machine Instruction).180class SPIRVIRMapping {181DenseMap<SPIRV::IRHandleMF, SPIRV::MIHandle> Vregs;182DenseMap<const MachineInstr *, SPIRV::IRHandleMF> Defs;183184public:185bool add(SPIRV::IRHandle Handle, const MachineInstr *MI) {186if (auto DefIt = Defs.find(MI); DefIt != Defs.end()) {187auto [ExistHandle, ExistMF] = DefIt->second;188if (Handle == ExistHandle && MI->getMF() == ExistMF)189return false; // already exists190// invalidate the record191Vregs.erase(DefIt->second);192Defs.erase(DefIt);193}194SPIRV::IRHandleMF HandleMF = SPIRV::getIRHandleMF(Handle, MI->getMF());195SPIRV::MIHandle MIKey = SPIRV::getMIKey(MI);196auto It1 = Vregs.try_emplace(HandleMF, MIKey);197if (!It1.second) {198// there is an expired record that we need to invalidate199Defs.erase(std::get<0>(It1.first->second));200// update the record201It1.first->second = MIKey;202}203[[maybe_unused]] auto It2 = Defs.try_emplace(MI, HandleMF);204assert(It2.second);205return true;206}207bool erase(const MachineInstr *MI) {208bool Res = false;209if (auto It = Defs.find(MI); It != Defs.end()) {210Res = Vregs.erase(It->second);211Defs.erase(It);212}213return Res;214}215const MachineInstr *findMI(SPIRV::IRHandle Handle,216const MachineFunction *MF) {217SPIRV::IRHandleMF HandleMF = SPIRV::getIRHandleMF(Handle, MF);218auto It = Vregs.find(HandleMF);219if (It == Vregs.end())220return nullptr;221auto [MI, Reg, Hash] = It->second;222const MachineInstr *Def = MF->getRegInfo().getVRegDef(Reg);223if (!Def || Def != MI || SPIRV::to_hash(MI) != Hash) {224// there is an expired record that we need to invalidate225erase(MI);226return nullptr;227}228assert(Defs.contains(MI) && Defs.find(MI)->second == HandleMF);229return MI;230}231Register find(SPIRV::IRHandle Handle, const MachineFunction *MF) {232const MachineInstr *MI = findMI(Handle, MF);233return MI ? MI->getOperand(0).getReg() : Register();234}235236// helpers237bool add(const Type *PointeeTy, unsigned AddressSpace,238const MachineInstr *MI) {239return add(SPIRV::irhandle_pointee(PointeeTy, AddressSpace), MI);240}241Register find(const Type *PointeeTy, unsigned AddressSpace,242const MachineFunction *MF) {243return find(SPIRV::irhandle_pointee(PointeeTy, AddressSpace), MF);244}245const MachineInstr *findMI(const Type *PointeeTy, unsigned AddressSpace,246const MachineFunction *MF) {247return findMI(SPIRV::irhandle_pointee(PointeeTy, AddressSpace), MF);248}249250bool add(const Value *V, const MachineInstr *MI) {251return add(SPIRV::handle(V), MI);252}253254bool add(const Type *T, bool RequiresExplicitLayout, const MachineInstr *MI) {255if (RequiresExplicitLayout && SPIRV::type_has_layout_decoration(T)) {256return add(SPIRV::irhandle_explict_layout_type(T), MI);257}258return add(SPIRV::handle(T), MI);259}260261bool add(const MachineInstr *Obj, const MachineInstr *MI) {262return add(SPIRV::handle(Obj), MI);263}264265Register find(const Value *V, const MachineFunction *MF) {266return find(SPIRV::handle(V), MF);267}268269Register find(const Type *T, bool RequiresExplicitLayout,270const MachineFunction *MF) {271if (RequiresExplicitLayout && SPIRV::type_has_layout_decoration(T))272return find(SPIRV::irhandle_explict_layout_type(T), MF);273return find(SPIRV::handle(T), MF);274}275276Register find(const MachineInstr *MI, const MachineFunction *MF) {277return find(SPIRV::handle(MI), MF);278}279280const MachineInstr *findMI(const Value *Obj, const MachineFunction *MF) {281return findMI(SPIRV::handle(Obj), MF);282}283284const MachineInstr *findMI(const Type *T, bool RequiresExplicitLayout,285const MachineFunction *MF) {286if (RequiresExplicitLayout && SPIRV::type_has_layout_decoration(T))287return findMI(SPIRV::irhandle_explict_layout_type(T), MF);288return findMI(SPIRV::handle(T), MF);289}290291const MachineInstr *findMI(const MachineInstr *Obj,292const MachineFunction *MF) {293return findMI(SPIRV::handle(Obj), MF);294}295};296} // namespace llvm297#endif // LLVM_LIB_TARGET_SPIRV_SPIRVIRMAPPING_H298299300