CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
697 lines
33 KiB
C++
697 lines
33 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_SPIRVGLOBALREGISTRY_H
|
|
#define LLVM_LIB_TARGET_SPIRV_SPIRVGLOBALREGISTRY_H
|
|
|
|
#include "MCTargetDesc/SPIRVBaseInfo.h"
|
|
#include "SPIRVIRMapping.h"
|
|
#include "SPIRVInstrInfo.h"
|
|
#include "SPIRVTypeInst.h"
|
|
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
|
#include "llvm/IR/Constant.h"
|
|
#include "llvm/IR/TypedPointerType.h"
|
|
|
|
namespace llvm {
|
|
class SPIRVSubtarget;
|
|
|
|
using StructOffsetDecorator = std::function<void(Register)>;
|
|
|
|
class SPIRVGlobalRegistry : public SPIRVIRMapping {
|
|
// 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, SPIRVTypeInst>>
|
|
VRegToTypeMap;
|
|
|
|
DenseMap<SPIRVTypeInst, const Type *> SPIRVToLLVMType;
|
|
|
|
// map a Function to its definition (as a machine instruction operand)
|
|
DenseMap<const Function *, const MachineOperand *> FunctionToInstr;
|
|
DenseMap<const MachineInstr *, const Function *> FunctionToInstrRev;
|
|
// map function pointer (as a machine instruction operand) to the used
|
|
// Function
|
|
DenseMap<const MachineOperand *, const Function *> InstrToFunction;
|
|
// Maps Functions to their calls (in a form of the machine instruction,
|
|
// OpFunctionCall) that happened before the definition is available
|
|
DenseMap<const Function *, SmallPtrSet<MachineInstr *, 8>> ForwardCalls;
|
|
// map a Function to its original return type before the clone function was
|
|
// created during substitution of aggregate arguments
|
|
// (see `SPIRVPrepareFunctions::removeAggregateTypesFromSignature()`)
|
|
DenseMap<Value *, Type *> MutatedAggRet;
|
|
// map an instruction to its value's attributes (type, name)
|
|
DenseMap<MachineInstr *, std::pair<Type *, std::string>> ValueAttrs;
|
|
|
|
SmallPtrSet<const Type *, 4> TypesInProcessing;
|
|
DenseMap<const Type *, SPIRVTypeInst> ForwardPointerTypes;
|
|
|
|
// Stores for each function the last inserted SPIR-V Type.
|
|
// See: SPIRVGlobalRegistry::createOpType.
|
|
DenseMap<const MachineFunction *, MachineInstr *> LastInsertedTypeMap;
|
|
|
|
// if a function returns a pointer, this is to map it into TypedPointerType
|
|
DenseMap<const Function *, TypedPointerType *> FunResPointerTypes;
|
|
|
|
// Current target's datalayout.
|
|
DataLayout DL;
|
|
|
|
// Holds the maximum ID we have in the module.
|
|
unsigned Bound;
|
|
|
|
// Maps values associated with untyped pointers into deduced element types of
|
|
// untyped pointers.
|
|
DenseMap<Value *, Type *> DeducedElTys;
|
|
// Maps composite values to deduced types where untyped pointers are replaced
|
|
// with typed ones.
|
|
DenseMap<Value *, Type *> DeducedNestedTys;
|
|
// Maps values to "assign type" calls, thus being a registry of created
|
|
// Intrinsic::spv_assign_ptr_type instructions.
|
|
DenseMap<Value *, CallInst *> AssignPtrTypeInstr;
|
|
|
|
// Maps OpVariable and OpFunction-related v-regs to its LLVM IR definition.
|
|
DenseMap<std::pair<const MachineFunction *, Register>, const Value *> Reg2GO;
|
|
|
|
// map of aliasing decorations to aliasing metadata
|
|
std::unordered_map<const MDNode *, MachineInstr *> AliasInstMDMap;
|
|
|
|
// Add a new OpTypeXXX instruction without checking for duplicates.
|
|
SPIRVTypeInst createSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder,
|
|
SPIRV::AccessQualifier::AccessQualifier AQ,
|
|
bool ExplicitLayoutRequired, bool EmitIR);
|
|
SPIRVTypeInst
|
|
findSPIRVType(const Type *Ty, MachineIRBuilder &MIRBuilder,
|
|
SPIRV::AccessQualifier::AccessQualifier accessQual,
|
|
bool ExplicitLayoutRequired, bool EmitIR);
|
|
SPIRVTypeInst
|
|
restOfCreateSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder,
|
|
SPIRV::AccessQualifier::AccessQualifier AccessQual,
|
|
bool ExplicitLayoutRequired, bool EmitIR);
|
|
|
|
// Internal function creating the Types/Constants at the correct position
|
|
// in the function by tweaking the passed "MIRBuilder" insertion point and
|
|
// restoring it to the correct position. "Op" should be the function creating
|
|
// the specific operation you need, and should return the newly created
|
|
// instruction.
|
|
const MachineInstr *createConstOrTypeAtFunctionEntry(
|
|
MachineIRBuilder &MIRBuilder,
|
|
std::function<MachineInstr *(MachineIRBuilder &)> Op);
|
|
|
|
public:
|
|
SPIRVGlobalRegistry(DataLayout DL);
|
|
|
|
MachineFunction *CurMF;
|
|
|
|
void setBound(unsigned V) { Bound = V; }
|
|
unsigned getBound() { return Bound; }
|
|
|
|
void addGlobalObject(const Value *V, const MachineFunction *MF, Register R) {
|
|
Reg2GO[std::make_pair(MF, R)] = V;
|
|
}
|
|
const Value *getGlobalObject(const MachineFunction *MF, Register R) {
|
|
auto It = Reg2GO.find(std::make_pair(MF, R));
|
|
return It == Reg2GO.end() ? nullptr : It->second;
|
|
}
|
|
|
|
// Add a record to the map of function return pointer types.
|
|
void addReturnType(const Function *ArgF, TypedPointerType *DerivedTy) {
|
|
FunResPointerTypes[ArgF] = DerivedTy;
|
|
}
|
|
// Find a record in the map of function return pointer types.
|
|
const TypedPointerType *findReturnType(const Function *ArgF) {
|
|
auto It = FunResPointerTypes.find(ArgF);
|
|
return It == FunResPointerTypes.end() ? nullptr : It->second;
|
|
}
|
|
|
|
// A registry of "assign type" records:
|
|
// - Add a record.
|
|
void addAssignPtrTypeInstr(Value *Val, CallInst *AssignPtrTyCI) {
|
|
AssignPtrTypeInstr[Val] = AssignPtrTyCI;
|
|
}
|
|
// - Find a record.
|
|
CallInst *findAssignPtrTypeInstr(const Value *Val) {
|
|
auto It = AssignPtrTypeInstr.find(Val);
|
|
return It == AssignPtrTypeInstr.end() ? nullptr : It->second;
|
|
}
|
|
// - Find a record and update its key or add a new record, if found.
|
|
void updateIfExistAssignPtrTypeInstr(Value *OldVal, Value *NewVal,
|
|
bool DeleteOld) {
|
|
if (CallInst *CI = findAssignPtrTypeInstr(OldVal)) {
|
|
if (DeleteOld)
|
|
AssignPtrTypeInstr.erase(OldVal);
|
|
AssignPtrTypeInstr[NewVal] = CI;
|
|
}
|
|
}
|
|
|
|
// A registry of mutated values
|
|
// (see `SPIRVPrepareFunctions::removeAggregateTypesFromSignature()`):
|
|
// - Add a record.
|
|
void addMutated(Value *Val, Type *Ty) { MutatedAggRet[Val] = Ty; }
|
|
// - Find a record.
|
|
Type *findMutated(const Value *Val) {
|
|
auto It = MutatedAggRet.find(Val);
|
|
return It == MutatedAggRet.end() ? nullptr : It->second;
|
|
}
|
|
|
|
// A registry of value's attributes (type, name)
|
|
// - Add a record.
|
|
void addValueAttrs(MachineInstr *Key, std::pair<Type *, std::string> Val) {
|
|
ValueAttrs[Key] = Val;
|
|
}
|
|
// - Find a record.
|
|
bool findValueAttrs(const MachineInstr *Key, Type *&Ty, StringRef &Name) {
|
|
auto It = ValueAttrs.find(Key);
|
|
if (It == ValueAttrs.end())
|
|
return false;
|
|
Ty = It->second.first;
|
|
Name = It->second.second;
|
|
return true;
|
|
}
|
|
|
|
// Deduced element types of untyped pointers and composites:
|
|
// - Add a record to the map of deduced element types.
|
|
void addDeducedElementType(Value *Val, Type *Ty) { DeducedElTys[Val] = Ty; }
|
|
// - Find a record in the map of deduced element types.
|
|
Type *findDeducedElementType(const Value *Val) {
|
|
auto It = DeducedElTys.find(Val);
|
|
return It == DeducedElTys.end() ? nullptr : It->second;
|
|
}
|
|
// - Find a record and update its key or add a new record, if found.
|
|
void updateIfExistDeducedElementType(Value *OldVal, Value *NewVal,
|
|
bool DeleteOld) {
|
|
if (Type *Ty = findDeducedElementType(OldVal)) {
|
|
if (DeleteOld)
|
|
DeducedElTys.erase(OldVal);
|
|
DeducedElTys[NewVal] = Ty;
|
|
}
|
|
}
|
|
// - Add a record to the map of deduced composite types.
|
|
void addDeducedCompositeType(Value *Val, Type *Ty) {
|
|
DeducedNestedTys[Val] = Ty;
|
|
}
|
|
// - Find a record in the map of deduced composite types.
|
|
Type *findDeducedCompositeType(const Value *Val) {
|
|
auto It = DeducedNestedTys.find(Val);
|
|
return It == DeducedNestedTys.end() ? nullptr : It->second;
|
|
}
|
|
// - Find a type of the given Global value
|
|
Type *getDeducedGlobalValueType(const GlobalValue *Global) {
|
|
// we may know element type if it was deduced earlier
|
|
Type *ElementTy = findDeducedElementType(Global);
|
|
if (!ElementTy) {
|
|
// or we may know element type if it's associated with a composite
|
|
// value
|
|
if (Value *GlobalElem =
|
|
Global->getNumOperands() > 0 ? Global->getOperand(0) : nullptr)
|
|
ElementTy = findDeducedCompositeType(GlobalElem);
|
|
else if (const Function *Fn = dyn_cast<Function>(Global))
|
|
ElementTy = SPIRV::getOriginalFunctionType(*Fn);
|
|
}
|
|
return ElementTy ? ElementTy : Global->getValueType();
|
|
}
|
|
|
|
// Map a machine operand that represents a use of a function via function
|
|
// pointer to a machine operand that represents the function definition.
|
|
// Return either the register or invalid value, because we have no context for
|
|
// a good diagnostic message in case of unexpectedly missing references.
|
|
const MachineOperand *getFunctionDefinitionByUse(const MachineOperand *Use) {
|
|
auto ResF = InstrToFunction.find(Use);
|
|
if (ResF == InstrToFunction.end())
|
|
return nullptr;
|
|
auto ResReg = FunctionToInstr.find(ResF->second);
|
|
return ResReg == FunctionToInstr.end() ? nullptr : ResReg->second;
|
|
}
|
|
|
|
// Map a Function to a machine instruction that represents the function
|
|
// definition.
|
|
const MachineInstr *getFunctionDefinition(const Function *F) {
|
|
if (!F)
|
|
return nullptr;
|
|
auto MOIt = FunctionToInstr.find(F);
|
|
return MOIt == FunctionToInstr.end() ? nullptr : MOIt->second->getParent();
|
|
}
|
|
|
|
// Map a Function to a machine instruction that represents the function
|
|
// definition.
|
|
const Function *getFunctionByDefinition(const MachineInstr *MI) {
|
|
if (!MI)
|
|
return nullptr;
|
|
auto FIt = FunctionToInstrRev.find(MI);
|
|
return FIt == FunctionToInstrRev.end() ? nullptr : FIt->second;
|
|
}
|
|
|
|
// map function pointer (as a machine instruction operand) to the used
|
|
// Function
|
|
void recordFunctionPointer(const MachineOperand *MO, const Function *F) {
|
|
InstrToFunction[MO] = F;
|
|
}
|
|
|
|
// map a Function to its definition (as a machine instruction)
|
|
void recordFunctionDefinition(const Function *F, const MachineOperand *MO) {
|
|
FunctionToInstr[F] = MO;
|
|
FunctionToInstrRev[MO->getParent()] = F;
|
|
}
|
|
|
|
// Return true if any OpConstantFunctionPointerINTEL were generated
|
|
bool hasConstFunPtr() { return !InstrToFunction.empty(); }
|
|
|
|
// Add a record about forward function call.
|
|
void addForwardCall(const Function *F, MachineInstr *MI) {
|
|
ForwardCalls[F].insert(MI);
|
|
}
|
|
|
|
// Map a Function to the vector of machine instructions that represents
|
|
// forward function calls or to nullptr if not found.
|
|
SmallPtrSet<MachineInstr *, 8> *getForwardCalls(const Function *F) {
|
|
auto It = ForwardCalls.find(F);
|
|
return It == ForwardCalls.end() ? nullptr : &It->second;
|
|
}
|
|
|
|
// Get or create a SPIR-V type corresponding the given LLVM IR type,
|
|
// and map it to the given VReg.
|
|
SPIRVTypeInst assignTypeToVReg(const Type *Type, Register VReg,
|
|
MachineIRBuilder &MIRBuilder,
|
|
SPIRV::AccessQualifier::AccessQualifier AQ,
|
|
bool EmitIR);
|
|
SPIRVTypeInst assignIntTypeToVReg(unsigned BitWidth, Register VReg,
|
|
MachineInstr &I, const SPIRVInstrInfo &TII);
|
|
SPIRVTypeInst assignFloatTypeToVReg(unsigned BitWidth, Register VReg,
|
|
MachineInstr &I,
|
|
const SPIRVInstrInfo &TII);
|
|
SPIRVTypeInst assignVectTypeToVReg(SPIRVTypeInst 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.
|
|
void assignSPIRVTypeToVReg(SPIRVTypeInst Type, Register VReg,
|
|
const 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.
|
|
SPIRVTypeInst getOrCreateSPIRVType(const Type *Type, MachineInstr &I,
|
|
SPIRV::AccessQualifier::AccessQualifier AQ,
|
|
bool EmitIR) {
|
|
MachineIRBuilder MIRBuilder(I);
|
|
return getOrCreateSPIRVType(Type, MIRBuilder, AQ, EmitIR);
|
|
}
|
|
|
|
SPIRVTypeInst getOrCreateSPIRVType(const Type *Type,
|
|
MachineIRBuilder &MIRBuilder,
|
|
SPIRV::AccessQualifier::AccessQualifier AQ,
|
|
bool EmitIR) {
|
|
return getOrCreateSPIRVType(Type, MIRBuilder, AQ, false, EmitIR);
|
|
}
|
|
|
|
const Type *getTypeForSPIRVType(SPIRVTypeInst Ty) const {
|
|
auto Res = SPIRVToLLVMType.find(Ty);
|
|
assert(Res != SPIRVToLLVMType.end());
|
|
return Res->second;
|
|
}
|
|
|
|
// Return a pointee's type, or nullptr otherwise.
|
|
SPIRVTypeInst getPointeeType(SPIRVTypeInst PtrType);
|
|
// Return a pointee's type op code, or 0 otherwise.
|
|
unsigned getPointeeTypeOp(Register PtrReg);
|
|
|
|
// Either generate a new OpTypeXXX instruction or return an existing one
|
|
// corresponding to the given string containing the name of the builtin type.
|
|
// Return nullptr if unable to recognize SPIRV type name from `TypeStr`.
|
|
SPIRVTypeInst getOrCreateSPIRVTypeByName(
|
|
StringRef TypeStr, MachineIRBuilder &MIRBuilder, bool EmitIR,
|
|
SPIRV::StorageClass::StorageClass SC = SPIRV::StorageClass::Function,
|
|
SPIRV::AccessQualifier::AccessQualifier AQ =
|
|
SPIRV::AccessQualifier::ReadWrite);
|
|
|
|
// Return the SPIR-V type instruction corresponding to the given VReg, or
|
|
// nullptr if no such type instruction exists. The second argument MF
|
|
// allows to search for the association in a context of the machine functions
|
|
// than the current one, without switching between different "current" machine
|
|
// functions.
|
|
SPIRVTypeInst getSPIRVTypeForVReg(Register VReg,
|
|
const MachineFunction *MF = nullptr) const;
|
|
|
|
// Return the result type of the instruction defining the register.
|
|
SPIRVTypeInst getResultType(Register VReg, MachineFunction *MF = nullptr);
|
|
|
|
// 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(SPIRVTypeInst SpirvType) const;
|
|
|
|
// Return previous value of the current machine function
|
|
MachineFunction *setCurrentFunc(MachineFunction &MF) {
|
|
MachineFunction *Ret = CurMF;
|
|
CurMF = &MF;
|
|
return Ret;
|
|
}
|
|
|
|
// Return true if the type is an aggregate type.
|
|
bool isAggregateType(SPIRVTypeInst Type) const {
|
|
return Type && (Type->getOpcode() == SPIRV::OpTypeStruct ||
|
|
Type->getOpcode() == SPIRV::OpTypeArray);
|
|
}
|
|
|
|
// 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;
|
|
|
|
// Returns true if `Type` is a resource type. This could be an image type
|
|
// or a struct for a buffer decorated with the block decoration.
|
|
bool isResourceType(SPIRVTypeInst Type) const;
|
|
|
|
// Return number of elements in a vector if the argument is associated with
|
|
// a vector type. Return 1 for a scalar type, and 0 for a missing type.
|
|
unsigned getScalarOrVectorComponentCount(Register VReg) const;
|
|
unsigned getScalarOrVectorComponentCount(SPIRVTypeInst Type) const;
|
|
|
|
// Return the component type in a vector if the argument is associated with
|
|
// a vector type. Returns the argument itself for other types, and nullptr
|
|
// for a missing type.
|
|
SPIRVTypeInst getScalarOrVectorComponentType(SPIRVTypeInst Type) const;
|
|
|
|
// For vectors or scalars of booleans, integers and floats, return the scalar
|
|
// type's bitwidth. Otherwise calls llvm_unreachable().
|
|
unsigned getScalarOrVectorBitWidth(SPIRVTypeInst Type) const;
|
|
|
|
// For vectors or scalars of integers and floats, return total bitwidth of the
|
|
// argument. Otherwise returns 0.
|
|
unsigned getNumScalarOrVectorTotalBitWidth(SPIRVTypeInst Type) const;
|
|
|
|
// Returns either pointer to integer type, that may be a type of vector
|
|
// elements or an original type, or nullptr if the argument is niether
|
|
// an integer scalar, nor an integer vector
|
|
SPIRVTypeInst retrieveScalarOrVectorIntType(SPIRVTypeInst Type) const;
|
|
|
|
// For integer vectors or scalars, return whether the integers are signed.
|
|
bool isScalarOrVectorSigned(SPIRVTypeInst Type) const;
|
|
|
|
// Gets the storage class of the pointer type assigned to this vreg.
|
|
SPIRV::StorageClass::StorageClass getPointerStorageClass(Register VReg) const;
|
|
SPIRV::StorageClass::StorageClass
|
|
getPointerStorageClass(SPIRVTypeInst Type) const;
|
|
|
|
// Return the number of bits SPIR-V pointers and size_t variables require.
|
|
unsigned getPointerSize() const {
|
|
return DL.getPointerSizeInBits(/* AS = */ 0);
|
|
}
|
|
|
|
// Returns true if two types are defined and are compatible in a sense of
|
|
// OpBitcast instruction
|
|
bool isBitcastCompatible(SPIRVTypeInst Type1, SPIRVTypeInst Type2) const;
|
|
|
|
// Informs about removal of the machine instruction and invalidates data
|
|
// structures referring this instruction.
|
|
void invalidateMachineInstr(MachineInstr *MI);
|
|
|
|
private:
|
|
SPIRVTypeInst getOpTypeBool(MachineIRBuilder &MIRBuilder);
|
|
|
|
const Type *adjustIntTypeByWidth(const Type *Ty) const;
|
|
unsigned adjustOpTypeIntWidth(unsigned Width) const;
|
|
|
|
SPIRVTypeInst getOrCreateSPIRVType(const Type *Type,
|
|
MachineIRBuilder &MIRBuilder,
|
|
SPIRV::AccessQualifier::AccessQualifier AQ,
|
|
bool ExplicitLayoutRequired, bool EmitIR);
|
|
|
|
SPIRVTypeInst getOpTypeInt(unsigned Width, MachineIRBuilder &MIRBuilder,
|
|
bool IsSigned = false);
|
|
|
|
SPIRVTypeInst getOpTypeFloat(uint32_t Width, MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVTypeInst getOpTypeFloat(uint32_t Width, MachineIRBuilder &MIRBuilder,
|
|
SPIRV::FPEncoding::FPEncoding FPEncode);
|
|
|
|
SPIRVTypeInst getOpTypeVoid(MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVTypeInst getOpTypeVector(uint32_t NumElems, SPIRVTypeInst ElemType,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVTypeInst getOpTypeArray(uint32_t NumElems, SPIRVTypeInst ElemType,
|
|
MachineIRBuilder &MIRBuilder,
|
|
bool ExplicitLayoutRequired, bool EmitIR);
|
|
|
|
SPIRVTypeInst getOpTypeOpaque(const StructType *Ty,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVTypeInst getOpTypeStruct(const StructType *Ty,
|
|
MachineIRBuilder &MIRBuilder,
|
|
SPIRV::AccessQualifier::AccessQualifier AccQual,
|
|
StructOffsetDecorator Decorator, bool EmitIR);
|
|
|
|
SPIRVTypeInst getOpTypePointer(SPIRV::StorageClass::StorageClass SC,
|
|
SPIRVTypeInst ElemType,
|
|
MachineIRBuilder &MIRBuilder, Register Reg);
|
|
|
|
SPIRVTypeInst getOpTypeForwardPointer(SPIRV::StorageClass::StorageClass SC,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVTypeInst
|
|
getOpTypeFunction(const FunctionType *Ty, SPIRVTypeInst RetType,
|
|
const SmallVectorImpl<SPIRVTypeInst> &ArgTypes,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVTypeInst
|
|
getOrCreateSpecialType(const Type *Ty, MachineIRBuilder &MIRBuilder,
|
|
SPIRV::AccessQualifier::AccessQualifier AccQual);
|
|
|
|
SPIRVTypeInst finishCreatingSPIRVType(const Type *LLVMTy,
|
|
SPIRVTypeInst SpirvType);
|
|
Register getOrCreateBaseRegister(Constant *Val, MachineInstr &I,
|
|
SPIRVTypeInst SpvType,
|
|
const SPIRVInstrInfo &TII, unsigned BitWidth,
|
|
bool ZeroAsNull);
|
|
Register getOrCreateCompositeOrNull(Constant *Val, MachineInstr &I,
|
|
SPIRVTypeInst SpvType,
|
|
const SPIRVInstrInfo &TII, Constant *CA,
|
|
unsigned BitWidth, unsigned ElemCnt,
|
|
bool ZeroAsNull = true);
|
|
|
|
Register getOrCreateIntCompositeOrNull(uint64_t Val,
|
|
MachineIRBuilder &MIRBuilder,
|
|
SPIRVTypeInst SpvType, bool EmitIR,
|
|
Constant *CA, unsigned BitWidth,
|
|
unsigned ElemCnt);
|
|
|
|
// Returns a pointer to a SPIR-V pointer type with the given base type and
|
|
// storage class. It is the responsibility of the caller to make sure the
|
|
// decorations on the base type are valid for the given storage class. For
|
|
// example, it has the correct offset and stride decorations.
|
|
SPIRVTypeInst
|
|
getOrCreateSPIRVPointerTypeInternal(SPIRVTypeInst BaseType,
|
|
MachineIRBuilder &MIRBuilder,
|
|
SPIRV::StorageClass::StorageClass SC);
|
|
|
|
void addStructOffsetDecorations(Register Reg, StructType *Ty,
|
|
MachineIRBuilder &MIRBuilder);
|
|
void addArrayStrideDecorations(Register Reg, Type *ElementType,
|
|
MachineIRBuilder &MIRBuilder);
|
|
bool hasBlockDecoration(SPIRVTypeInst Type) const;
|
|
|
|
SPIRVTypeInst
|
|
getOrCreateOpTypeImage(MachineIRBuilder &MIRBuilder,
|
|
SPIRVTypeInst 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);
|
|
|
|
public:
|
|
Register buildConstantInt(uint64_t Val, MachineIRBuilder &MIRBuilder,
|
|
SPIRVTypeInst SpvType, bool EmitIR,
|
|
bool ZeroAsNull = true);
|
|
Register getOrCreateConstInt(uint64_t Val, MachineInstr &I,
|
|
SPIRVTypeInst SpvType, const SPIRVInstrInfo &TII,
|
|
bool ZeroAsNull = true);
|
|
Register getOrCreateConstInt(const APInt &Val, MachineInstr &I,
|
|
SPIRVTypeInst SpvType, const SPIRVInstrInfo &TII,
|
|
bool ZeroAsNull = true);
|
|
Register createConstInt(const ConstantInt *CI, MachineInstr &I,
|
|
SPIRVTypeInst SpvType, const SPIRVInstrInfo &TII,
|
|
bool ZeroAsNull);
|
|
Register getOrCreateConstFP(APFloat Val, MachineInstr &I,
|
|
SPIRVTypeInst SpvType, const SPIRVInstrInfo &TII,
|
|
bool ZeroAsNull = true);
|
|
Register createConstFP(const ConstantFP *CF, MachineInstr &I,
|
|
SPIRVTypeInst SpvType, const SPIRVInstrInfo &TII,
|
|
bool ZeroAsNull);
|
|
Register buildConstantFP(APFloat Val, MachineIRBuilder &MIRBuilder,
|
|
SPIRVTypeInst SpvType = nullptr);
|
|
|
|
Register getOrCreateConstVector(uint64_t Val, MachineInstr &I,
|
|
SPIRVTypeInst SpvType,
|
|
const SPIRVInstrInfo &TII,
|
|
bool ZeroAsNull = true);
|
|
Register getOrCreateConstVector(const APInt &Val, MachineInstr &I,
|
|
SPIRVTypeInst SpvType,
|
|
const SPIRVInstrInfo &TII,
|
|
bool ZeroAsNull = true);
|
|
Register getOrCreateConstVector(APFloat Val, MachineInstr &I,
|
|
SPIRVTypeInst SpvType,
|
|
const SPIRVInstrInfo &TII,
|
|
bool ZeroAsNull = true);
|
|
Register getOrCreateConstIntArray(uint64_t Val, size_t Num, MachineInstr &I,
|
|
SPIRVTypeInst SpvType,
|
|
const SPIRVInstrInfo &TII);
|
|
Register getOrCreateConsIntVector(uint64_t Val, MachineIRBuilder &MIRBuilder,
|
|
SPIRVTypeInst SpvType, bool EmitIR);
|
|
Register getOrCreateConstNullPtr(MachineIRBuilder &MIRBuilder,
|
|
SPIRVTypeInst SpvType);
|
|
Register buildConstantSampler(Register Res, unsigned AddrMode, unsigned Param,
|
|
unsigned FilerMode,
|
|
MachineIRBuilder &MIRBuilder);
|
|
Register getOrCreateUndef(MachineInstr &I, SPIRVTypeInst SpvType,
|
|
const SPIRVInstrInfo &TII);
|
|
Register buildGlobalVariable(
|
|
Register Reg, SPIRVTypeInst BaseType, StringRef Name,
|
|
const GlobalValue *GV, SPIRV::StorageClass::StorageClass Storage,
|
|
const MachineInstr *Init, bool IsConst,
|
|
const std::optional<SPIRV::LinkageType::LinkageType> &LinkageType,
|
|
MachineIRBuilder &MIRBuilder, bool IsInstSelector);
|
|
Register getOrCreateGlobalVariableWithBinding(SPIRVTypeInst VarType,
|
|
uint32_t Set, uint32_t Binding,
|
|
StringRef Name,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
// Convenient helpers for getting types with check for duplicates.
|
|
SPIRVTypeInst getOrCreateSPIRVIntegerType(unsigned BitWidth,
|
|
MachineIRBuilder &MIRBuilder);
|
|
SPIRVTypeInst getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineInstr &I,
|
|
const SPIRVInstrInfo &TII);
|
|
SPIRVTypeInst getOrCreateSPIRVType(unsigned BitWidth, MachineInstr &I,
|
|
const SPIRVInstrInfo &TII,
|
|
unsigned SPIRVOPcode, Type *LLVMTy);
|
|
SPIRVTypeInst getOrCreateSPIRVFloatType(unsigned BitWidth, MachineInstr &I,
|
|
const SPIRVInstrInfo &TII);
|
|
SPIRVTypeInst getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder,
|
|
bool EmitIR);
|
|
SPIRVTypeInst getOrCreateSPIRVBoolType(MachineInstr &I,
|
|
const SPIRVInstrInfo &TII);
|
|
SPIRVTypeInst getOrCreateSPIRVVectorType(SPIRVTypeInst BaseType,
|
|
unsigned NumElements,
|
|
MachineIRBuilder &MIRBuilder,
|
|
bool EmitIR);
|
|
SPIRVTypeInst getOrCreateSPIRVVectorType(SPIRVTypeInst BaseType,
|
|
unsigned NumElements,
|
|
MachineInstr &I,
|
|
const SPIRVInstrInfo &TII);
|
|
|
|
// Returns a pointer to a SPIR-V pointer type with the given base type and
|
|
// storage class. The base type will be translated to a SPIR-V type, and the
|
|
// appropriate layout decorations will be added to the base type.
|
|
SPIRVTypeInst
|
|
getOrCreateSPIRVPointerType(const Type *BaseType,
|
|
MachineIRBuilder &MIRBuilder,
|
|
SPIRV::StorageClass::StorageClass SC);
|
|
SPIRVTypeInst
|
|
getOrCreateSPIRVPointerType(const Type *BaseType, MachineInstr &I,
|
|
SPIRV::StorageClass::StorageClass SC);
|
|
|
|
// Returns a pointer to a SPIR-V pointer type with the given base type and
|
|
// storage class. It is the responsibility of the caller to make sure the
|
|
// decorations on the base type are valid for the given storage class. For
|
|
// example, it has the correct offset and stride decorations.
|
|
SPIRVTypeInst
|
|
getOrCreateSPIRVPointerType(SPIRVTypeInst BaseType,
|
|
MachineIRBuilder &MIRBuilder,
|
|
SPIRV::StorageClass::StorageClass SC);
|
|
|
|
// Returns a pointer to a SPIR-V pointer type that is the same as `PtrType`
|
|
// except the stroage class has been changed to `SC`. It is the responsibility
|
|
// of the caller to be sure that the original and new storage class have the
|
|
// same layout requirements.
|
|
SPIRVTypeInst changePointerStorageClass(SPIRVTypeInst PtrType,
|
|
SPIRV::StorageClass::StorageClass SC,
|
|
MachineInstr &I);
|
|
|
|
SPIRVTypeInst
|
|
getOrCreateVulkanBufferType(MachineIRBuilder &MIRBuilder, Type *ElemType,
|
|
SPIRV::StorageClass::StorageClass SC,
|
|
bool IsWritable, bool EmitIr = false);
|
|
|
|
SPIRVTypeInst getOrCreatePaddingType(MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVTypeInst getOrCreateVulkanPushConstantType(MachineIRBuilder &MIRBuilder,
|
|
Type *ElemType);
|
|
|
|
SPIRVTypeInst getOrCreateLayoutType(MachineIRBuilder &MIRBuilder,
|
|
const TargetExtType *T,
|
|
bool EmitIr = false);
|
|
|
|
SPIRVTypeInst
|
|
getImageType(const TargetExtType *ExtensionType,
|
|
const SPIRV::AccessQualifier::AccessQualifier Qualifier,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVTypeInst getOrCreateOpTypeSampler(MachineIRBuilder &MIRBuilder);
|
|
|
|
SPIRVTypeInst getOrCreateOpTypeSampledImage(SPIRVTypeInst ImageType,
|
|
MachineIRBuilder &MIRBuilder);
|
|
SPIRVTypeInst getOrCreateOpTypeCoopMatr(MachineIRBuilder &MIRBuilder,
|
|
const TargetExtType *ExtensionType,
|
|
SPIRVTypeInst ElemType,
|
|
uint32_t Scope, uint32_t Rows,
|
|
uint32_t Columns, uint32_t Use,
|
|
bool EmitIR);
|
|
SPIRVTypeInst
|
|
getOrCreateOpTypePipe(MachineIRBuilder &MIRBuilder,
|
|
SPIRV::AccessQualifier::AccessQualifier AccQual);
|
|
SPIRVTypeInst getOrCreateOpTypeDeviceEvent(MachineIRBuilder &MIRBuilder);
|
|
SPIRVTypeInst getOrCreateOpTypeFunctionWithArgs(
|
|
const Type *Ty, SPIRVTypeInst RetType,
|
|
const SmallVectorImpl<SPIRVTypeInst> &ArgTypes,
|
|
MachineIRBuilder &MIRBuilder);
|
|
SPIRVTypeInst getOrCreateOpTypeByOpcode(const Type *Ty,
|
|
MachineIRBuilder &MIRBuilder,
|
|
unsigned Opcode);
|
|
|
|
SPIRVTypeInst getOrCreateUnknownType(const Type *Ty,
|
|
MachineIRBuilder &MIRBuilder,
|
|
unsigned Opcode,
|
|
const ArrayRef<MCOperand> Operands);
|
|
|
|
const TargetRegisterClass *getRegClass(SPIRVTypeInst SpvType) const;
|
|
LLT getRegType(SPIRVTypeInst SpvType) const;
|
|
|
|
MachineInstr *getOrAddMemAliasingINTELInst(MachineIRBuilder &MIRBuilder,
|
|
const MDNode *AliasingListMD);
|
|
void buildMemAliasingOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder,
|
|
uint32_t Dec, const MDNode *GVarMD);
|
|
// Replace all uses of a |Old| with |New| updates the global registry type
|
|
// mappings.
|
|
void replaceAllUsesWith(Value *Old, Value *New, bool DeleteOld = true);
|
|
|
|
void buildAssignType(IRBuilder<> &B, Type *Ty, Value *Arg);
|
|
void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg);
|
|
void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType);
|
|
};
|
|
} // end namespace llvm
|
|
#endif // LLVM_LIB_TARGET_SPIRV_SPIRVGLOBALREGISTRY_H
|