316 lines
15 KiB
C++
316 lines
15 KiB
C++
//===-- SPIRVGlobalRegistry.h - SPIR-V Global Registry ----------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// SPIRVGlobalRegistry is used to maintain rich type information required for
|
|
// SPIR-V even after lowering from LLVM IR to GMIR. It can convert an llvm::Type
|
|
// into an OpTypeXXX instruction, and map it to a virtual register. Also it
|
|
// builds and supports consistency of constants and global variables.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H
|
|
#define LLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H
|
|
|
|
#include "MCTargetDesc/SPIRVBaseInfo.h"
|
|
#include "SPIRVDuplicatesTracker.h"
|
|
#include "SPIRVInstrInfo.h"
|
|
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
|
|
|
namespace llvm {
|
|
using SPIRVType = const MachineInstr;
|
|
|
|
class SPIRVGlobalRegistry {
|
|
// Registers holding values which have types associated with them.
|
|
// Initialized upon VReg definition in IRTranslator.
|
|
// Do not confuse this with DuplicatesTracker as DT maps Type* to <MF, Reg>
|
|
// where Reg = OpType...
|
|
// while VRegToTypeMap tracks SPIR-V type assigned to other regs (i.e. not
|
|
// type-declaring ones).
|
|
DenseMap<const MachineFunction *, DenseMap<Register, SPIRVType *>>
|
|
VRegToTypeMap;
|
|
|
|
SPIRVGeneralDuplicatesTracker DT;
|
|
|
|
DenseMap<SPIRVType *, const Type *> SPIRVToLLVMType;
|
|
|
|
// Look for an equivalent of the newType in the map. Return the equivalent
|
|
// if it's found, otherwise insert newType to the map and return the type.
|
|
const MachineInstr *checkSpecialInstr(const SPIRV::SpecialTypeDescriptor &TD,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
SmallPtrSet<const Type *, 4> TypesInProcessing;
|
|
DenseMap<const Type *, SPIRVType *> ForwardPointerTypes;
|
|
|
|
// Number of bits pointers and size_t integers require.
|
|
const unsigned PointerSize;
|
|
|
|
// Add a new OpTypeXXX instruction without checking for duplicates.
|
|
SPIRVType *createSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder,
|
|
SPIRV::AccessQualifier::AccessQualifier AQ =
|
|
SPIRV::AccessQualifier::ReadWrite,
|
|
bool EmitIR = true);
|
|
SPIRVType *findSPIRVType(const Type *Ty, MachineIRBuilder &MIRBuilder,
|
|
SPIRV::AccessQualifier::AccessQualifier accessQual =
|
|
SPIRV::AccessQualifier::ReadWrite,
|
|
bool EmitIR = true);
|
|
SPIRVType *
|
|
restOfCreateSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder,
|
|
SPIRV::AccessQualifier::AccessQualifier AccessQual,
|
|
bool EmitIR);
|
|
|
|
public:
|
|
SPIRVGlobalRegistry(unsigned PointerSize);
|
|
|
|
MachineFunction *CurMF;
|
|
|
|
void add(const Constant *C, MachineFunction *MF, Register R) {
|
|
DT.add(C, MF, R);
|
|
}
|
|
|
|
void add(const GlobalVariable *GV, MachineFunction *MF, Register R) {
|
|
DT.add(GV, MF, R);
|
|
}
|
|
|
|
void add(const Function *F, MachineFunction *MF, Register R) {
|
|
DT.add(F, MF, R);
|
|
}
|
|
|
|
void add(const Argument *Arg, MachineFunction *MF, Register R) {
|
|
DT.add(Arg, MF, R);
|
|
}
|
|
|
|
Register find(const Constant *C, MachineFunction *MF) {
|
|
return DT.find(C, MF);
|
|
}
|
|
|
|
Register find(const GlobalVariable *GV, MachineFunction *MF) {
|
|
return DT.find(GV, MF);
|
|
}
|
|
|
|
Register find(const Function *F, MachineFunction *MF) {
|
|
return DT.find(F, MF);
|
|
}
|
|
|
|
void buildDepsGraph(std::vector<SPIRV::DTSortableEntry *> &Graph,
|
|
MachineModuleInfo *MMI = nullptr) {
|
|
DT.buildDepsGraph(Graph, MMI);
|
|
}
|
|
|
|
// Get or create a SPIR-V type corresponding the given LLVM IR type,
|
|
// and map it to the given VReg by creating an ASSIGN_TYPE instruction.
|
|
SPIRVType *assignTypeToVReg(const Type *Type, Register VReg,
|
|
MachineIRBuilder &MIRBuilder,
|
|
SPIRV::AccessQualifier::AccessQualifier AQ =
|
|
SPIRV::AccessQualifier::ReadWrite,
|
|
bool EmitIR = true);
|
|
SPIRVType *assignIntTypeToVReg(unsigned BitWidth, Register VReg,
|
|
MachineInstr &I, const SPIRVInstrInfo &TII);
|
|
SPIRVType *assignVectTypeToVReg(SPIRVType *BaseType, unsigned NumElements,
|
|
Register VReg, MachineInstr &I,
|
|
const SPIRVInstrInfo &TII);
|
|
|
|
// In cases where the SPIR-V type is already known, this function can be
|
|
// used to map it to the given VReg via an ASSIGN_TYPE instruction.
|
|
void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg,
|
|
MachineFunction &MF);
|
|
|
|
// Either generate a new OpTypeXXX instruction or return an existing one
|
|
// corresponding to the given LLVM IR type.
|
|
// EmitIR controls if we emit GMIR or SPV constants (e.g. for array sizes)
|
|
// because this method may be called from InstructionSelector and we don't
|
|
// want to emit extra IR instructions there.
|
|
SPIRVType *getOrCreateSPIRVType(const Type *Type,
|
|
MachineIRBuilder &MIRBuilder,
|
|
SPIRV::AccessQualifier::AccessQualifier AQ =
|
|
SPIRV::AccessQualifier::ReadWrite,
|
|
bool EmitIR = true);
|
|
|
|
const Type *getTypeForSPIRVType(const SPIRVType *Ty) const {
|
|
auto Res = SPIRVToLLVMType.find(Ty);
|
|
assert(Res != SPIRVToLLVMType.end());
|
|
return Res->second;
|
|
}
|
|
|
|
// Either generate a new OpTypeXXX instruction or return an existing one
|
|
// corresponding to the given string containing the name of the builtin type.
|
|
SPIRVType *getOrCreateSPIRVTypeByName(StringRef TypeStr,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
// Return the SPIR-V type instruction corresponding to the given VReg, or
|
|
// nullptr if no such type instruction exists.
|
|
SPIRVType *getSPIRVTypeForVReg(Register VReg) const;
|
|
|
|
// Whether the given VReg has a SPIR-V type mapped to it yet.
|
|
bool hasSPIRVTypeForVReg(Register VReg) const {
|
|
return getSPIRVTypeForVReg(VReg) != nullptr;
|
|
}
|
|
|
|
// Return the VReg holding the result of the given OpTypeXXX instruction.
|
|
Register getSPIRVTypeID(const SPIRVType *SpirvType) const;
|
|
|
|
void setCurrentFunc(MachineFunction &MF) { CurMF = &MF; }
|
|
|
|
// Whether the given VReg has an OpTypeXXX instruction mapped to it with the
|
|
// given opcode (e.g. OpTypeFloat).
|
|
bool isScalarOfType(Register VReg, unsigned TypeOpcode) const;
|
|
|
|
// Return true if the given VReg's assigned SPIR-V type is either a scalar
|
|
// matching the given opcode, or a vector with an element type matching that
|
|
// opcode (e.g. OpTypeBool, or OpTypeVector %x 4, where %x is OpTypeBool).
|
|
bool isScalarOrVectorOfType(Register VReg, unsigned TypeOpcode) const;
|
|
|
|
// For vectors or scalars of ints/floats, return the scalar type's bitwidth.
|
|
unsigned getScalarOrVectorBitWidth(const SPIRVType *Type) const;
|
|
|
|
// For integer vectors or scalars, return whether the integers are signed.
|
|
bool isScalarOrVectorSigned(const SPIRVType *Type) const;
|
|
|
|
// Gets the storage class of the pointer type assigned to this vreg.
|
|
SPIRV::StorageClass::StorageClass getPointerStorageClass(Register VReg) const;
|
|
|
|
// Return the number of bits SPIR-V pointers and size_t variables require.
|
|
unsigned getPointerSize() const { return PointerSize; }
|
|
|
|
private:
|
|
SPIRVType *getOpTypeBool(MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVType *getOpTypeInt(uint32_t Width, MachineIRBuilder &MIRBuilder,
|
|
bool IsSigned = false);
|
|
|
|
SPIRVType *getOpTypeFloat(uint32_t Width, MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVType *getOpTypeVoid(MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVType *getOpTypeVector(uint32_t NumElems, SPIRVType *ElemType,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVType *getOpTypeArray(uint32_t NumElems, SPIRVType *ElemType,
|
|
MachineIRBuilder &MIRBuilder, bool EmitIR = true);
|
|
|
|
SPIRVType *getOpTypeOpaque(const StructType *Ty,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVType *getOpTypeStruct(const StructType *Ty, MachineIRBuilder &MIRBuilder,
|
|
bool EmitIR = true);
|
|
|
|
SPIRVType *getOpTypePointer(SPIRV::StorageClass::StorageClass SC,
|
|
SPIRVType *ElemType, MachineIRBuilder &MIRBuilder,
|
|
Register Reg);
|
|
|
|
SPIRVType *getOpTypeForwardPointer(SPIRV::StorageClass::StorageClass SC,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVType *getOpTypeFunction(SPIRVType *RetType,
|
|
const SmallVectorImpl<SPIRVType *> &ArgTypes,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVType *
|
|
getOrCreateSpecialType(const Type *Ty, MachineIRBuilder &MIRBuilder,
|
|
SPIRV::AccessQualifier::AccessQualifier AccQual);
|
|
|
|
std::tuple<Register, ConstantInt *, bool> getOrCreateConstIntReg(
|
|
uint64_t Val, SPIRVType *SpvType, MachineIRBuilder *MIRBuilder,
|
|
MachineInstr *I = nullptr, const SPIRVInstrInfo *TII = nullptr);
|
|
SPIRVType *finishCreatingSPIRVType(const Type *LLVMTy, SPIRVType *SpirvType);
|
|
Register getOrCreateIntCompositeOrNull(uint64_t Val, MachineInstr &I,
|
|
SPIRVType *SpvType,
|
|
const SPIRVInstrInfo &TII,
|
|
Constant *CA, unsigned BitWidth,
|
|
unsigned ElemCnt);
|
|
Register getOrCreateIntCompositeOrNull(uint64_t Val,
|
|
MachineIRBuilder &MIRBuilder,
|
|
SPIRVType *SpvType, bool EmitIR,
|
|
Constant *CA, unsigned BitWidth,
|
|
unsigned ElemCnt);
|
|
|
|
public:
|
|
Register buildConstantInt(uint64_t Val, MachineIRBuilder &MIRBuilder,
|
|
SPIRVType *SpvType = nullptr, bool EmitIR = true);
|
|
Register getOrCreateConstInt(uint64_t Val, MachineInstr &I,
|
|
SPIRVType *SpvType, const SPIRVInstrInfo &TII);
|
|
Register buildConstantFP(APFloat Val, MachineIRBuilder &MIRBuilder,
|
|
SPIRVType *SpvType = nullptr);
|
|
Register getOrCreateConsIntVector(uint64_t Val, MachineInstr &I,
|
|
SPIRVType *SpvType,
|
|
const SPIRVInstrInfo &TII);
|
|
Register getOrCreateConsIntArray(uint64_t Val, MachineInstr &I,
|
|
SPIRVType *SpvType,
|
|
const SPIRVInstrInfo &TII);
|
|
Register getOrCreateConsIntVector(uint64_t Val, MachineIRBuilder &MIRBuilder,
|
|
SPIRVType *SpvType, bool EmitIR = true);
|
|
Register getOrCreateConsIntArray(uint64_t Val, MachineIRBuilder &MIRBuilder,
|
|
SPIRVType *SpvType, bool EmitIR = true);
|
|
Register getOrCreateConstNullPtr(MachineIRBuilder &MIRBuilder,
|
|
SPIRVType *SpvType);
|
|
Register buildConstantSampler(Register Res, unsigned AddrMode, unsigned Param,
|
|
unsigned FilerMode,
|
|
MachineIRBuilder &MIRBuilder,
|
|
SPIRVType *SpvType);
|
|
Register getOrCreateUndef(MachineInstr &I, SPIRVType *SpvType,
|
|
const SPIRVInstrInfo &TII);
|
|
Register buildGlobalVariable(Register Reg, SPIRVType *BaseType,
|
|
StringRef Name, const GlobalValue *GV,
|
|
SPIRV::StorageClass::StorageClass Storage,
|
|
const MachineInstr *Init, bool IsConst,
|
|
bool HasLinkageTy,
|
|
SPIRV::LinkageType::LinkageType LinkageType,
|
|
MachineIRBuilder &MIRBuilder,
|
|
bool IsInstSelector);
|
|
|
|
// Convenient helpers for getting types with check for duplicates.
|
|
SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth,
|
|
MachineIRBuilder &MIRBuilder);
|
|
SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineInstr &I,
|
|
const SPIRVInstrInfo &TII);
|
|
SPIRVType *getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder);
|
|
SPIRVType *getOrCreateSPIRVBoolType(MachineInstr &I,
|
|
const SPIRVInstrInfo &TII);
|
|
SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType,
|
|
unsigned NumElements,
|
|
MachineIRBuilder &MIRBuilder);
|
|
SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType,
|
|
unsigned NumElements, MachineInstr &I,
|
|
const SPIRVInstrInfo &TII);
|
|
SPIRVType *getOrCreateSPIRVArrayType(SPIRVType *BaseType,
|
|
unsigned NumElements, MachineInstr &I,
|
|
const SPIRVInstrInfo &TII);
|
|
|
|
SPIRVType *getOrCreateSPIRVPointerType(
|
|
SPIRVType *BaseType, MachineIRBuilder &MIRBuilder,
|
|
SPIRV::StorageClass::StorageClass SClass = SPIRV::StorageClass::Function);
|
|
SPIRVType *getOrCreateSPIRVPointerType(
|
|
SPIRVType *BaseType, MachineInstr &I, const SPIRVInstrInfo &TII,
|
|
SPIRV::StorageClass::StorageClass SClass = SPIRV::StorageClass::Function);
|
|
|
|
SPIRVType *
|
|
getOrCreateOpTypeImage(MachineIRBuilder &MIRBuilder, SPIRVType *SampledType,
|
|
SPIRV::Dim::Dim Dim, uint32_t Depth, uint32_t Arrayed,
|
|
uint32_t Multisampled, uint32_t Sampled,
|
|
SPIRV::ImageFormat::ImageFormat ImageFormat,
|
|
SPIRV::AccessQualifier::AccessQualifier AccQual);
|
|
|
|
SPIRVType *getOrCreateOpTypeSampler(MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVType *getOrCreateOpTypeSampledImage(SPIRVType *ImageType,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVType *
|
|
getOrCreateOpTypePipe(MachineIRBuilder &MIRBuilder,
|
|
SPIRV::AccessQualifier::AccessQualifier AccQual);
|
|
SPIRVType *getOrCreateOpTypeDeviceEvent(MachineIRBuilder &MIRBuilder);
|
|
SPIRVType *getOrCreateOpTypeFunctionWithArgs(
|
|
const Type *Ty, SPIRVType *RetType,
|
|
const SmallVectorImpl<SPIRVType *> &ArgTypes,
|
|
MachineIRBuilder &MIRBuilder);
|
|
SPIRVType *getOrCreateOpTypeByOpcode(const Type *Ty,
|
|
MachineIRBuilder &MIRBuilder,
|
|
unsigned Opcode);
|
|
};
|
|
} // end namespace llvm
|
|
#endif // LLLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H
|