Files
TheRock/compiler/spirv-llvm-translator/lib/SPIRV/libSPIRV/SPIRVEntry.h
T
derek.holloway 7502bf64a4
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
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

1141 lines
44 KiB
C++

//===- SPIRVEntry.h - Base Class for SPIR-V Entities ------------*- C++ -*-===//
//
// The LLVM/SPIRV Translator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
// Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal with the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimers in the documentation
// and/or other materials provided with the distribution.
// Neither the names of Advanced Micro Devices, Inc., nor the names of its
// contributors may be used to endorse or promote products derived from this
// Software without specific prior written permission.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
//
//===----------------------------------------------------------------------===//
/// \file
///
/// This file defines the base class for SPIRV entities.
///
//===----------------------------------------------------------------------===//
#ifndef SPIRV_LIBSPIRV_SPIRVENTRY_H
#define SPIRV_LIBSPIRV_SPIRVENTRY_H
#include "SPIRVEnum.h"
#include "SPIRVError.h"
#include "SPIRVIsValidEnum.h"
#include <cassert>
#include <iostream>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>
namespace SPIRV {
class SPIRVModule;
class SPIRVEncoder;
class SPIRVDecoder;
class SPIRVType;
class SPIRVValue;
class SPIRVDecorate;
class SPIRVDecorateId;
class SPIRVForward;
class SPIRVMemberDecorate;
class SPIRVLine;
class SPIRVString;
class SPIRVExtInst;
// Add declaration of encode/decode functions to a class.
// Used inside class definition.
#define _SPIRV_DCL_ENCDEC \
void encode(spv_ostream &O) const override; \
void decode(std::istream &I) override;
#define _REQ_SPIRV_VER(Version) \
VersionNumber getRequiredSPIRVVersion() const override { return Version; }
// Add implementation of encode/decode functions to a class.
// Used out side of class definition.
#define _SPIRV_IMP_ENCDEC0(Ty) \
void Ty::encode(spv_ostream &O) const {} \
void Ty::decode(std::istream &I) {}
#define _SPIRV_IMP_ENCDEC1(Ty, x) \
void Ty::encode(spv_ostream &O) const { getEncoder(O) << (x); } \
void Ty::decode(std::istream &I) { getDecoder(I) >> (x); }
#define _SPIRV_IMP_ENCDEC2(Ty, x, y) \
void Ty::encode(spv_ostream &O) const { getEncoder(O) << (x) << (y); } \
void Ty::decode(std::istream &I) { getDecoder(I) >> (x) >> (y); }
#define _SPIRV_IMP_ENCDEC3(Ty, x, y, z) \
void Ty::encode(spv_ostream &O) const { \
getEncoder(O) << (x) << (y) << (z); \
} \
void Ty::decode(std::istream &I) { getDecoder(I) >> (x) >> (y) >> (z); }
#define _SPIRV_IMP_ENCDEC4(Ty, x, y, z, u) \
void Ty::encode(spv_ostream &O) const { \
getEncoder(O) << (x) << (y) << (z) << (u); \
} \
void Ty::decode(std::istream &I) { \
getDecoder(I) >> (x) >> (y) >> (z) >> (u); \
}
#define _SPIRV_IMP_ENCDEC5(Ty, x, y, z, u, v) \
void Ty::encode(spv_ostream &O) const { \
getEncoder(O) << (x) << (y) << (z) << (u) << (v); \
} \
void Ty::decode(std::istream &I) { \
getDecoder(I) >> (x) >> (y) >> (z) >> (u) >> (v); \
}
#define _SPIRV_IMP_ENCDEC6(Ty, x, y, z, u, v, w) \
void Ty::encode(spv_ostream &O) const { \
getEncoder(O) << (x) << (y) << (z) << (u) << (v) << (w); \
} \
void Ty::decode(std::istream &I) { \
getDecoder(I) >> (x) >> (y) >> (z) >> (u) >> (v) >> (w); \
}
#define _SPIRV_IMP_ENCDEC7(Ty, x, y, z, u, v, w, r) \
void Ty::encode(spv_ostream &O) const { \
getEncoder(O) << (x) << (y) << (z) << (u) << (v) << (w) << (r); \
} \
void Ty::decode(std::istream &I) { \
getDecoder(I) >> (x) >> (y) >> (z) >> (u) >> (v) >> (w) >> (r); \
}
#define _SPIRV_IMP_ENCDEC8(Ty, x, y, z, u, v, w, r, s) \
void Ty::encode(spv_ostream &O) const { \
getEncoder(O) << (x) << (y) << (z) << (u) << (v) << (w) << (r) << (s); \
} \
void Ty::decode(std::istream &I) { \
getDecoder(I) >> (x) >> (y) >> (z) >> (u) >> (v) >> (w) >> (r) >> (s); \
}
#define _SPIRV_IMP_ENCDEC9(Ty, x, y, z, u, v, w, r, s, t) \
void Ty::encode(spv_ostream &O) const { \
getEncoder(O) << (x) << (y) << (z) << (u) << (v) << (w) << (r) << (s) \
<< (t); \
} \
void Ty::decode(std::istream &I) { \
getDecoder(I) >> (x) >> (y) >> (z) >> (u) >> (v) >> (w) >> (r) >> (s) >> \
(t); \
}
// Add definition of encode/decode functions to a class.
// Used inside class definition.
#define _SPIRV_DEF_ENCDEC0 \
void encode(spv_ostream &O) const override {} \
void decode(std::istream &I) override {}
#define _SPIRV_DEF_ENCDEC1(x) \
void encode(spv_ostream &O) const override { getEncoder(O) << (x); } \
void decode(std::istream &I) override { getDecoder(I) >> (x); }
#define _SPIRV_DEF_ENCDEC2(x, y) \
void encode(spv_ostream &O) const override { getEncoder(O) << (x) << (y); } \
void decode(std::istream &I) override { getDecoder(I) >> (x) >> (y); }
#define _SPIRV_DEF_ENCDEC3(x, y, z) \
void encode(spv_ostream &O) const override { \
getEncoder(O) << (x) << (y) << (z); \
} \
void decode(std::istream &I) override { getDecoder(I) >> (x) >> (y) >> (z); }
#define _SPIRV_DEF_ENCDEC4(x, y, z, u) \
void encode(spv_ostream &O) const override { \
getEncoder(O) << (x) << (y) << (z) << (u); \
} \
void decode(std::istream &I) override { \
getDecoder(I) >> (x) >> (y) >> (z) >> (u); \
}
#define _SPIRV_DEF_ENCDEC5(x, y, z, u, v) \
void encode(spv_ostream &O) const override { \
getEncoder(O) << (x) << (y) << (z) << (u) << (v); \
} \
void decode(std::istream &I) override { \
getDecoder(I) >> (x) >> (y) >> (z) >> (u) >> (v); \
}
#define _SPIRV_DEF_ENCDEC6(x, y, z, u, v, w) \
void encode(spv_ostream &O) const override { \
getEncoder(O) << (x) << (y) << (z) << (u) << (v) << (w); \
} \
void decode(std::istream &I) override { \
getDecoder(I) >> (x) >> (y) >> (z) >> (u) >> (v) >> (w); \
}
#define _SPIRV_DEF_ENCDEC7(x, y, z, u, v, w, r) \
void encode(spv_ostream &O) const override { \
getEncoder(O) << (x) << (y) << (z) << (u) << (v) << (w) << (r); \
} \
void decode(std::istream &I) override { \
getDecoder(I) >> (x) >> (y) >> (z) >> (u) >> (v) >> (w) >> (r); \
}
#define _SPIRV_DEF_ENCDEC8(x, y, z, u, v, w, r, s) \
void encode(spv_ostream &O) const override { \
getEncoder(O) << (x) << (y) << (z) << (u) << (v) << (w) << (r) << (s); \
} \
void decode(std::istream &I) override { \
getDecoder(I) >> (x) >> (y) >> (z) >> (u) >> (v) >> (w) >> (r) >> (s); \
}
#define _SPIRV_DEF_ENCDEC9(x, y, z, u, v, w, r, s, t) \
void encode(spv_ostream &O) const override { \
getEncoder(O) << (x) << (y) << (z) << (u) << (v) << (w) << (r) << (s) \
<< (t); \
} \
void decode(std::istream &I) override { \
getDecoder(I) >> (x) >> (y) >> (z) >> (u) >> (v) >> (w) >> (r) >> (s) >> \
(t); \
}
/// All SPIR-V in-memory-representation entities inherits from SPIRVEntry.
/// Usually there are two flavors of constructors of SPIRV objects:
///
/// 1. complete constructor: It requires all the parameters needed to create a
/// SPIRV entity with complete information which can be validated. It is
/// usually used by LLVM/SPIR-V translator to create SPIRV object
/// corresponding to LLVM object. Such constructor calls validate() at
/// the end of the construction.
///
/// 2. incomplete constructor: For leaf classes, it has no parameters.
/// It is usually called by SPIRVEntry::make(opcode) to create an incomplete
/// object which should not be validated. Then setWordCount(count) is
/// called to fix the size of the object if it is variable, and then the
/// information is filled by the virtual function decode(istream).
/// After that the object can be validated.
///
/// To add a new SPIRV class:
///
/// 1. It is recommended to name the class as SPIRVXXX if it has a fixed op code
/// OpXXX. Although it is not mandatory, doing this facilitates adding it to
/// the table of the factory function SPIRVEntry::create().
/// 2. Inherit from proper SPIRV class such as SPIRVType, SPIRVValue,
/// SPIRVInstruction, etc.
/// 3. Implement virtual function encode(), decode(), validate().
/// 4. If the object has variable size, implement virtual function
/// setWordCount().
/// 5. If the class has special attributes, e.g. having no id, or having no
/// type as a value, set them in the constructors.
/// 6. If the class may represent SPIRV entity which has been added in version
/// later than 1.0, implement virtual function getRequiredSPIRVVersion().
/// To automaticly update module's version you can also call protected
/// function updateModuleVersion() in the constructor.
/// 7. Add the class to the Table of SPIRVEntry::create().
/// 8. Add the class to SPIRVToLLVM and LLVMToSPIRV.
class SPIRVEntry {
public:
enum SPIRVEntryAttrib {
SPIRVEA_DEFAULT = 0,
SPIRVEA_NOID = 1, // Entry has no valid id
SPIRVEA_NOTYPE = 2, // Value has no type
};
// Complete constructor for objects with id
SPIRVEntry(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, SPIRVId TheId)
: Module(M), OpCode(TheOpCode), Id(TheId), Attrib(SPIRVEA_DEFAULT),
WordCount(TheWordCount), Line(nullptr) {
SPIRVEntry::validate();
}
// Complete constructor for objects without id
SPIRVEntry(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode)
: Module(M), OpCode(TheOpCode), Id(SPIRVID_INVALID), Attrib(SPIRVEA_NOID),
WordCount(TheWordCount), Line(nullptr) {
SPIRVEntry::validate();
}
// Incomplete constructor
SPIRVEntry(Op TheOpCode)
: Module(NULL), OpCode(TheOpCode), Id(SPIRVID_INVALID),
Attrib(SPIRVEA_DEFAULT), WordCount(0), Line(nullptr) {}
SPIRVEntry()
: Module(NULL), OpCode(OpNop), Id(SPIRVID_INVALID),
Attrib(SPIRVEA_DEFAULT), WordCount(0), Line(nullptr) {}
virtual ~SPIRVEntry() {}
bool exist(SPIRVId) const;
template <class T> T *get(SPIRVId TheId) const {
// NOLINTNEXTLINE
return static_cast<T *>(getEntry(TheId));
}
SPIRVEntry *getEntry(SPIRVId) const;
SPIRVEntry *getOrCreate(SPIRVId TheId) const;
SPIRVValue *getValue(SPIRVId TheId) const;
std::vector<SPIRVValue *> getValues(const std::vector<SPIRVId> &) const;
std::vector<SPIRVId> getIds(const std::vector<SPIRVValue *>) const;
SPIRVType *getValueType(SPIRVId TheId) const;
std::vector<SPIRVType *> getValueTypes(const std::vector<SPIRVId> &) const;
virtual SPIRVDecoder getDecoder(std::istream &);
virtual SPIRVEncoder getEncoder(spv_ostream &) const;
SPIRVErrorLog &getErrorLog() const;
SPIRVId getId() const {
assert(hasId());
return Id;
}
std::shared_ptr<const SPIRVLine> getLine() const { return Line; }
std::shared_ptr<const SPIRVExtInst> getDebugLine() const { return DebugLine; }
SPIRVLinkageTypeKind getLinkageType() const;
Op getOpCode() const { return OpCode; }
SPIRVModule *getModule() const { return Module; }
virtual SPIRVCapVec getRequiredCapability() const { return SPIRVCapVec(); }
virtual std::optional<ExtensionID> getRequiredExtension() const { return {}; }
const std::string &getName() const { return Name; }
size_t getNumDecorations() const { return Decorates.size(); }
bool hasDecorate(Decoration Kind, size_t Index = 0,
SPIRVWord *Result = 0) const;
bool hasDecorateId(Decoration Kind, size_t Index = 0,
SPIRVId *Result = 0) const;
bool hasMemberDecorate(Decoration Kind, size_t Index = 0,
SPIRVWord MemberNumber = 0,
SPIRVWord *Result = 0) const;
std::vector<SPIRVWord> getDecorationLiterals(Decoration Kind) const;
std::vector<SPIRVId> getDecorationIdLiterals(Decoration Kind) const;
std::vector<SPIRVWord>
getMemberDecorationLiterals(Decoration Kind, SPIRVWord MemberNumber) const;
std::vector<std::string> getDecorationStringLiteral(Decoration Kind) const;
std::vector<std::vector<std::string>>
getAllDecorationStringLiterals(Decoration Kind) const;
std::vector<std::vector<std::string>>
getAllMemberDecorationStringLiterals(Decoration Kind,
SPIRVWord MemberNumber) const;
std::vector<std::string>
getMemberDecorationStringLiteral(Decoration Kind,
SPIRVWord MemberNumber) const;
std::set<SPIRVWord> getDecorate(Decoration Kind, size_t Index = 0) const;
std::vector<SPIRVDecorate const *> getDecorations(Decoration Kind) const;
std::vector<SPIRVDecorate const *> getDecorations() const;
std::set<SPIRVId> getDecorateId(Decoration Kind, size_t Index = 0) const;
std::vector<SPIRVDecorateId const *> getDecorationIds(Decoration Kind) const;
bool hasId() const { return !(Attrib & SPIRVEA_NOID); }
bool hasLine() const { return Line != nullptr; }
bool hasLinkageType() const;
bool isAtomic() const { return isAtomicOpCode(OpCode); }
bool isBasicBlock() const { return isLabel(); }
bool isExtInst() const { return OpCode == OpExtInst; }
bool isExtInst(const SPIRVExtInstSetKind InstSet) const;
bool isExtInst(const SPIRVExtInstSetKind InstSet,
const SPIRVWord ExtOp) const;
bool isDecorate() const { return OpCode == OpDecorate; }
bool isDecorateId() const { return OpCode == OpDecorateId; }
bool isMemberDecorate() const { return OpCode == OpMemberDecorate; }
bool isForward() const { return OpCode == internal::OpForward; }
bool isLabel() const { return OpCode == OpLabel; }
bool isUndef() const { return OpCode == OpUndef; }
bool isControlBarrier() const { return OpCode == OpControlBarrier; }
bool isMemoryBarrier() const { return OpCode == OpMemoryBarrier; }
bool isVariable() const {
return OpCode == OpVariable || OpCode == OpUntypedVariableKHR;
}
bool isUntypedVariable() const { return OpCode == OpUntypedVariableKHR; }
bool isEndOfBlock() const;
virtual bool isInst() const { return false; }
virtual bool isOperandLiteral(unsigned Index) const {
assert(0 && "not implemented");
return false;
}
virtual bool isImplemented() const { return true; }
void addDecorate(SPIRVDecorate *);
void addDecorate(SPIRVDecorateId *);
void addDecorate(Decoration Kind);
void addDecorate(Decoration Kind, SPIRVWord Literal);
void eraseDecorate(Decoration);
void eraseDecorateId(Decoration);
void addMemberDecorate(SPIRVMemberDecorate *);
void addMemberDecorate(SPIRVWord MemberNumber, Decoration Kind);
void addMemberDecorate(SPIRVWord MemberNumber, Decoration Kind,
SPIRVWord Literal);
void eraseMemberDecorate(SPIRVWord MemberNumber, Decoration Kind);
void setHasNoId() { Attrib |= SPIRVEA_NOID; }
void setId(SPIRVId TheId) { Id = TheId; }
void setLine(const std::shared_ptr<const SPIRVLine> &L);
void setDebugLine(const std::shared_ptr<const SPIRVExtInst> &DL);
void setLinkageType(SPIRVLinkageTypeKind);
void setModule(SPIRVModule *TheModule);
void setName(const std::string &TheName);
virtual void setScope(SPIRVEntry *Scope) {}
void takeAnnotations(SPIRVForward *);
void takeDecorates(SPIRVEntry *);
void takeDecorateIds(SPIRVEntry *);
void takeMemberDecorates(SPIRVEntry *);
void replaceTargetIdInDecorates(SPIRVId);
/// After a SPIRV entry is created during reading SPIRV binary by default
/// constructor, this function is called to allow the SPIRV entry to resize
/// its variable sized member before decoding the remaining words.
virtual void setWordCount(SPIRVWord TheWordCount);
/// Create an empty SPIRV object by op code, e.g. OpTypeInt creates
/// SPIRVTypeInt.
static SPIRVEntry *create(Op);
static std::unique_ptr<SPIRVEntry> createUnique(Op);
/// Create an empty extended instruction.
static std::unique_ptr<SPIRVExtInst> createUnique(SPIRVExtInstSetKind Set,
unsigned ExtOp);
friend spv_ostream &operator<<(spv_ostream &O, const SPIRVEntry &E);
friend std::istream &operator>>(std::istream &I, SPIRVEntry &E);
virtual void encodeLine(spv_ostream &O) const;
virtual void encodeDebugLine(spv_ostream &O) const;
virtual void encodeAll(spv_ostream &O) const;
virtual void encodeName(spv_ostream &O) const;
virtual void encodeChildren(spv_ostream &O) const;
virtual void encodeDecorate(spv_ostream &O) const;
virtual void encodeWordCountOpCode(spv_ostream &O) const;
virtual void encode(spv_ostream &O) const;
virtual void decode(std::istream &I);
friend class SPIRVDecoder;
/// Checks the integrity of the object.
virtual void validate() const {
assert(Module && "Invalid module");
assert(OpCode != OpNop && "Invalid op code");
assert((!hasId() || isValidId(Id)) && "Invalid Id");
if (WordCount > 65535) {
std::stringstream SS;
SS << "Id: " << Id << ", OpCode: " << OpCodeNameMap::map(OpCode)
<< ", Name: \"" << Name << "\"\n";
getErrorLog().checkError(
false, SPIRVEC_InvalidWordCount,
"Can't encode instruction with word count greater than 65535:\n" +
SS.str());
}
}
void validateFunctionControlMask(SPIRVWord FCtlMask) const;
void validateValues(const std::vector<SPIRVId> &) const;
void validateBuiltin(SPIRVWord, SPIRVWord) const;
// By default assume SPIRV 1.0 as required version
virtual VersionNumber getRequiredSPIRVVersion() const {
return VersionNumber::SPIRV_1_0;
}
virtual std::vector<SPIRVEntry *> getNonLiteralOperands() const {
return std::vector<SPIRVEntry *>();
}
protected:
/// An entry may have multiple FuncParamAttr decorations.
typedef std::multimap<Decoration, const SPIRVDecorate *> DecorateMapType;
typedef std::multimap<Decoration, const SPIRVDecorateId *> DecorateIdMapType;
typedef std::multimap<std::pair<SPIRVWord, Decoration>,
const SPIRVMemberDecorate *>
MemberDecorateMapType;
bool canHaveMemberDecorates() const {
return OpCode == OpTypeStruct || OpCode == internal::OpForward;
}
MemberDecorateMapType &getMemberDecorates() {
assert(canHaveMemberDecorates());
return MemberDecorates;
}
void updateModuleVersion() const;
SPIRVModule *Module;
Op OpCode;
SPIRVId Id;
std::string Name;
unsigned Attrib;
SPIRVWord WordCount;
DecorateMapType Decorates;
DecorateIdMapType DecorateIds;
MemberDecorateMapType MemberDecorates;
std::shared_ptr<const SPIRVLine> Line;
std::shared_ptr<const SPIRVExtInst> DebugLine;
};
class SPIRVEntryNoIdGeneric : public SPIRVEntry {
public:
SPIRVEntryNoIdGeneric(SPIRVModule *M, unsigned TheWordCount, Op OC)
: SPIRVEntry(M, TheWordCount, OC) {
setAttr();
}
SPIRVEntryNoIdGeneric(Op OC) : SPIRVEntry(OC) { setAttr(); }
protected:
void setAttr() { setHasNoId(); }
};
template <Op OC> class SPIRVEntryNoId : public SPIRVEntryNoIdGeneric {
public:
SPIRVEntryNoId(SPIRVModule *M, unsigned TheWordCount)
: SPIRVEntryNoIdGeneric(M, TheWordCount, OC) {}
SPIRVEntryNoId() : SPIRVEntryNoIdGeneric(OC) {}
};
template <Op TheOpCode>
class SPIRVEntryOpCodeOnly : public SPIRVEntryNoId<TheOpCode> {
public:
SPIRVEntryOpCodeOnly() {
SPIRVEntry::WordCount = 1;
validate();
}
protected:
_SPIRV_DEF_ENCDEC0
void validate() const override { assert(isValidId(SPIRVEntry::OpCode)); }
};
template <Op TheOpCode>
class SPIRVEntryUnimplemented : public SPIRVEntryNoId<TheOpCode> {
public:
SPIRVEntryUnimplemented() {
SPIRVEntry::WordCount = 1;
validate();
}
bool isImplemented() const override { return false; }
protected:
_SPIRV_DEF_ENCDEC0
void validate() const override { assert(isValidId(SPIRVEntry::OpCode)); }
};
class SPIRVAnnotationGeneric : public SPIRVEntryNoIdGeneric {
public:
// Complete constructor
SPIRVAnnotationGeneric(SPIRVModule *TheModule, unsigned TheWordCount, Op OC,
SPIRVId TheTarget = SPIRVID_INVALID)
: SPIRVEntryNoIdGeneric(TheModule, TheWordCount, OC), Target(TheTarget) {}
// Incomplete constructor
SPIRVAnnotationGeneric(Op OC)
: SPIRVEntryNoIdGeneric(OC), Target(SPIRVID_INVALID) {}
SPIRVId getTargetId() const { return Target; }
SPIRVForward *getOrCreateTarget() const;
void setTargetId(SPIRVId T) { Target = T; }
protected:
SPIRVId Target;
};
class SPIRVAnnotation : public SPIRVAnnotationGeneric {
public:
// Complete constructor
SPIRVAnnotation(Op OC, const SPIRVEntry *TheTarget, unsigned TheWordCount)
: SPIRVAnnotationGeneric(TheTarget->getModule(), TheWordCount, OC,
TheTarget->getId()) {}
// Incomplete constructors
SPIRVAnnotation(Op OC) : SPIRVAnnotationGeneric(OC) {}
SPIRVAnnotation() : SPIRVAnnotationGeneric(OpNop) {}
};
class SPIRVEntryPoint : public SPIRVAnnotation {
public:
static const SPIRVWord FixedWC = 4;
SPIRVEntryPoint(SPIRVModule *TheModule, SPIRVExecutionModelKind,
SPIRVId TheId, const std::string &TheName,
std::vector<SPIRVId> Variables);
SPIRVEntryPoint() : SPIRVAnnotation(OpEntryPoint) {}
_SPIRV_DCL_ENCDEC
protected:
SPIRVExecutionModelKind ExecModel = ExecutionModelMax;
std::string Name;
private:
std::vector<SPIRVId> Variables;
};
class SPIRVName : public SPIRVAnnotation {
public:
// Complete constructor
SPIRVName(const SPIRVEntry *TheTarget, const std::string &TheStr);
// Incomplete constructor
SPIRVName() : SPIRVAnnotation(OpName) {}
protected:
_SPIRV_DCL_ENCDEC
void validate() const override;
std::string Str;
};
class SPIRVMemberName : public SPIRVAnnotation {
public:
static const SPIRVWord FixedWC = 3;
// Complete constructor
SPIRVMemberName(const SPIRVEntry *TheTarget, SPIRVWord TheMemberNumber,
const std::string &TheStr)
: SPIRVAnnotation(OpName, TheTarget, FixedWC + getSizeInWords(TheStr)),
MemberNumber(TheMemberNumber), Str(TheStr) {
validate();
}
// Incomplete constructor
SPIRVMemberName() : SPIRVAnnotation(OpName), MemberNumber(SPIRVWORD_MAX) {}
protected:
_SPIRV_DCL_ENCDEC
void validate() const override;
SPIRVWord MemberNumber;
std::string Str;
};
class SPIRVString : public SPIRVEntry {
static const Op OC = OpString;
static const SPIRVWord FixedWC = 2;
public:
SPIRVString(SPIRVModule *M, SPIRVId TheId, const std::string &TheStr)
: SPIRVEntry(M, FixedWC + getSizeInWords(TheStr), OC, TheId),
Str(TheStr) {}
SPIRVString() : SPIRVEntry(OC) {}
_SPIRV_DCL_ENCDEC
const std::string &getStr() const { return Str; }
protected:
std::string Str;
};
class SPIRVLine : public SPIRVEntry {
public:
static const SPIRVWord WC = 4;
// Complete constructor
SPIRVLine(SPIRVModule *M, SPIRVId TheFileName, SPIRVWord TheLine,
SPIRVWord TheColumn)
: SPIRVEntry(M, WC, OpLine), FileName(TheFileName), Line(TheLine),
Column(TheColumn) {
Attrib = SPIRVEA_NOID | SPIRVEA_NOTYPE;
validate();
}
// Incomplete constructor
SPIRVLine()
: SPIRVEntry(OpLine), FileName(SPIRVID_INVALID), Line(SPIRVWORD_MAX),
Column(SPIRVWORD_MAX) {
Attrib = SPIRVEA_NOID | SPIRVEA_NOTYPE;
}
SPIRVWord getColumn() const { return Column; }
void setColumn(const SPIRVWord Column) { this->Column = Column; }
SPIRVId getFileName() const { return FileName; }
const std::string &getFileNameStr() const {
return get<SPIRVString>(FileName)->getStr();
}
void setFileName(const SPIRVId FileName) { this->FileName = FileName; }
SPIRVWord getLine() const { return Line; }
void setLine(const SPIRVWord Line) { this->Line = Line; }
bool operator!=(const SPIRVLine &O) const {
return !equals(O.FileName, O.Line, O.Column);
}
bool equals(const SPIRVId TheFileName, const SPIRVWord TheLine,
const SPIRVWord TheColumn) const {
return FileName == TheFileName && Line == TheLine && Column == TheColumn;
}
protected:
_SPIRV_DCL_ENCDEC
void validate() const override;
SPIRVId FileName;
SPIRVWord Line;
SPIRVWord Column;
};
class SPIRVExecutionMode : public SPIRVAnnotation {
public:
// Complete constructor for LocalSize, LocalSizeHint
SPIRVExecutionMode(Op OC, SPIRVEntry *TheTarget,
SPIRVExecutionModeKind TheExecMode, SPIRVWord X,
SPIRVWord Y, SPIRVWord Z)
: SPIRVAnnotation(OC, TheTarget, 6), ExecMode(TheExecMode) {
WordLiterals.push_back(X);
WordLiterals.push_back(Y);
WordLiterals.push_back(Z);
updateModuleVersion();
}
// Complete constructor for FPFastMathDefault.
SPIRVExecutionMode(Op OC, SPIRVEntry *TheTarget,
SPIRVExecutionModeKind TheExecMode, SPIRVWord TargetType,
SPIRVWord FastMathMode)
: SPIRVAnnotation(OC, TheTarget, 5), ExecMode(TheExecMode) {
assert(OC == OpExecutionModeId);
assert(TheExecMode == ExecutionModeFPFastMathDefault);
WordLiterals.push_back(TargetType);
WordLiterals.push_back(FastMathMode);
updateModuleVersion();
}
// Complete constructor for VecTypeHint, SubgroupSize, SubgroupsPerWorkgroup
SPIRVExecutionMode(Op OC, SPIRVEntry *TheTarget,
SPIRVExecutionModeKind TheExecMode, SPIRVWord Code)
: SPIRVAnnotation(OC, TheTarget, 4), ExecMode(TheExecMode) {
WordLiterals.push_back(Code);
}
// Complete constructor for ContractionOff
SPIRVExecutionMode(Op OC, SPIRVEntry *TheTarget,
SPIRVExecutionModeKind TheExecMode)
: SPIRVAnnotation(OC, TheTarget, 3), ExecMode(TheExecMode) {
updateModuleVersion();
}
// Incomplete constructor
SPIRVExecutionMode()
: SPIRVAnnotation(OpExecutionMode), ExecMode(ExecutionModeInvocations) {}
SPIRVExecutionModeKind getExecutionMode() const { return ExecMode; }
const std::vector<SPIRVWord> &getLiterals() const { return WordLiterals; }
SPIRVCapVec getRequiredCapability() const override {
return getCapability(ExecMode);
}
VersionNumber getRequiredSPIRVVersion() const override {
switch (ExecMode) {
case ExecutionModeFinalizer:
case ExecutionModeInitializer:
case ExecutionModeSubgroupSize:
case ExecutionModeSubgroupsPerWorkgroup:
return VersionNumber::SPIRV_1_1;
default:
return VersionNumber::SPIRV_1_0;
}
}
std::optional<ExtensionID> getRequiredExtension() const override {
switch (static_cast<unsigned>(ExecMode)) {
case ExecutionModeMaximumRegistersINTEL:
case ExecutionModeMaximumRegistersIdINTEL:
case ExecutionModeNamedMaximumRegistersINTEL:
return ExtensionID::SPV_INTEL_maximum_registers;
case ExecutionModeArithmeticPoisonKHR:
return ExtensionID::SPV_KHR_poison_freeze;
default:
return {};
}
}
protected:
_SPIRV_DCL_ENCDEC
SPIRVExecutionModeKind ExecMode;
std::vector<SPIRVWord> WordLiterals;
};
class SPIRVExecutionModeId : public SPIRVExecutionMode {
public:
// Complete constructor for LocalSizeId, LocalSizeHintId
SPIRVExecutionModeId(SPIRVEntry *TheTarget,
SPIRVExecutionModeKind TheExecMode, SPIRVWord X,
SPIRVWord Y, SPIRVWord Z)
: SPIRVExecutionMode(OpExecutionModeId, TheTarget, TheExecMode, X, Y, Z) {
updateModuleVersion();
}
// Complete constructor for FPFastMathDefault.
SPIRVExecutionModeId(SPIRVEntry *TheTarget,
SPIRVExecutionModeKind TheExecMode, SPIRVWord TargetType,
SPIRVWord FastMathMode)
: SPIRVExecutionMode(OpExecutionModeId, TheTarget, TheExecMode,
TargetType, FastMathMode) {
assert(TheExecMode == ExecutionModeFPFastMathDefault);
updateModuleVersion();
}
// Complete constructor for SubgroupsPerWorkgroupId
SPIRVExecutionModeId(SPIRVEntry *TheTarget,
SPIRVExecutionModeKind TheExecMode, SPIRVWord Code)
: SPIRVExecutionMode(OpExecutionModeId, TheTarget, TheExecMode, Code) {
updateModuleVersion();
}
// Incomplete constructor
SPIRVExecutionModeId() : SPIRVExecutionMode() {}
VersionNumber getRequiredSPIRVVersion() const override {
return VersionNumber::SPIRV_1_2;
}
};
class SPIRVComponentExecutionModes {
typedef std::multimap<SPIRVExecutionModeKind, SPIRVExecutionMode *>
SPIRVExecutionModeMap;
typedef std::pair<SPIRVExecutionModeMap::const_iterator,
SPIRVExecutionModeMap::const_iterator>
SPIRVExecutionModeRange;
public:
void addExecutionMode(SPIRVExecutionMode *ExecMode) {
// There should not be more than 1 execution mode kind except the ones
// mentioned in SPV_KHR_float_controls and SPV_INTEL_float_controls2.
#ifndef NDEBUG
auto IsDenorm = [](auto EMK) {
return EMK == ExecutionModeDenormPreserve ||
EMK == ExecutionModeDenormFlushToZero;
};
auto IsRoundingMode = [](auto EMK) {
return EMK == ExecutionModeRoundingModeRTE ||
EMK == ExecutionModeRoundingModeRTZ ||
EMK == ExecutionModeRoundingModeRTPINTEL ||
EMK == ExecutionModeRoundingModeRTNINTEL;
};
auto IsFPMode = [](auto EMK) {
return EMK == ExecutionModeFloatingPointModeALTINTEL ||
EMK == ExecutionModeFloatingPointModeIEEEINTEL;
};
auto IsOtherFP = [](auto EMK) {
return EMK == ExecutionModeSignedZeroInfNanPreserve;
};
auto IsFastMathDefault = [](auto EMK) {
return EMK == ExecutionModeFPFastMathDefault;
};
auto IsFloatControl = [&](auto EMK) {
return IsDenorm(EMK) || IsRoundingMode(EMK) || IsFPMode(EMK) ||
IsOtherFP(EMK) || IsFastMathDefault(EMK);
};
auto IsMaxRegisters = [&](auto EMK) {
return EMK == ExecutionModeMaximumRegistersINTEL ||
EMK == ExecutionModeMaximumRegistersIdINTEL ||
EMK == ExecutionModeNamedMaximumRegistersINTEL;
};
auto IsCompatible = [&](SPIRVExecutionMode *EM0, SPIRVExecutionMode *EM1) {
if (EM0->getTargetId() != EM1->getTargetId())
return true;
auto EMK0 = EM0->getExecutionMode();
auto EMK1 = EM1->getExecutionMode();
if (!IsFloatControl(EMK0) || !IsFloatControl(EMK1))
return EMK0 != EMK1;
auto TW0 = EM0->getLiterals().at(0);
auto TW1 = EM1->getLiterals().at(0);
if (TW0 != TW1)
return true;
return !(IsDenorm(EMK0) && IsDenorm(EMK1)) &&
!(IsRoundingMode(EMK0) && IsRoundingMode(EMK1)) &&
!(IsFPMode(EMK0) && IsFPMode(EMK1)) &&
!(IsMaxRegisters(EMK0) && IsMaxRegisters(EMK1));
};
for (auto I = ExecModes.begin(); I != ExecModes.end(); ++I) {
assert(IsCompatible(ExecMode, (*I).second) &&
"Found incompatible execution modes");
}
#endif // !NDEBUG
SPIRVExecutionModeKind EMK = ExecMode->getExecutionMode();
ExecModes.emplace(EMK, ExecMode);
}
SPIRVExecutionMode *getExecutionMode(SPIRVExecutionModeKind EMK) const {
auto Loc = ExecModes.find(EMK);
if (Loc == ExecModes.end())
return nullptr;
return Loc->second;
}
SPIRVExecutionModeId *getExecutionModeId(SPIRVExecutionModeKind EMK) const {
auto Loc = ExecModes.find(EMK);
if (Loc == ExecModes.end())
return nullptr;
return static_cast<SPIRVExecutionModeId *>(Loc->second);
}
SPIRVExecutionModeRange
getExecutionModeRange(SPIRVExecutionModeKind EMK) const {
return ExecModes.equal_range(EMK);
}
protected:
SPIRVExecutionModeMap ExecModes;
};
class SPIRVExtInstImport : public SPIRVEntry {
public:
const static Op OC = OpExtInstImport;
// Complete constructor
SPIRVExtInstImport(SPIRVModule *TheModule, SPIRVId TheId,
const std::string &TheStr);
// Incomplete constructor
SPIRVExtInstImport() : SPIRVEntry(OC) {}
protected:
_SPIRV_DCL_ENCDEC
void validate() const override;
std::string Str;
};
class SPIRVMemoryModel : public SPIRVEntryNoId<OpMemoryModel> {
public:
SPIRVMemoryModel(SPIRVModule *M) : SPIRVEntryNoId(M, 3) {}
SPIRVMemoryModel() {}
_SPIRV_DCL_ENCDEC
void validate() const override;
};
class SPIRVSource : public SPIRVEntryNoId<OpSource> {
public:
SPIRVSource(SPIRVModule *M) : SPIRVEntryNoId(M, 3) {}
SPIRVSource() {}
_SPIRV_DCL_ENCDEC
};
class SPIRVSourceExtension : public SPIRVEntryNoId<OpSourceExtension> {
public:
SPIRVSourceExtension(SPIRVModule *M, const std::string &SS);
SPIRVSourceExtension() {}
_SPIRV_DCL_ENCDEC
private:
std::string S;
};
class SPIRVExtension : public SPIRVEntryNoId<OpExtension> {
public:
SPIRVExtension(SPIRVModule *M, const std::string &SS);
SPIRVExtension() {}
std::string getExtensionName() const { return S; }
_SPIRV_DCL_ENCDEC
private:
std::string S;
};
class SPIRVCapability : public SPIRVEntryNoId<OpCapability> {
public:
SPIRVCapability(SPIRVModule *M, SPIRVCapabilityKind K);
SPIRVCapability() : Kind(CapabilityMatrix) {}
_SPIRV_DCL_ENCDEC
VersionNumber getRequiredSPIRVVersion() const override {
switch (Kind) {
case CapabilityGroupNonUniform:
case CapabilityGroupNonUniformVote:
case CapabilityGroupNonUniformArithmetic:
case CapabilityGroupNonUniformBallot:
case CapabilityGroupNonUniformShuffle:
case CapabilityGroupNonUniformShuffleRelative:
case CapabilityGroupNonUniformClustered:
return VersionNumber::SPIRV_1_3;
case CapabilityFloatControls2:
return VersionNumber::SPIRV_1_2;
case CapabilityNamedBarrier:
case CapabilitySubgroupDispatch:
case CapabilityPipeStorage:
return VersionNumber::SPIRV_1_1;
default:
return VersionNumber::SPIRV_1_0;
}
}
std::optional<ExtensionID> getRequiredExtension() const override {
switch (static_cast<unsigned>(Kind)) {
case CapabilityRoundToInfinityINTEL:
case CapabilityFloatingPointModeINTEL:
case CapabilityFunctionFloatControlINTEL:
return ExtensionID::SPV_INTEL_float_controls2;
case CapabilityVectorComputeINTEL:
case CapabilityVectorAnyINTEL:
return ExtensionID::SPV_INTEL_vector_compute;
case internal::CapabilitySubgroupRequirementsINTEL:
return ExtensionID::SPV_INTEL_subgroup_requirements;
case CapabilityFPFastMathModeINTEL:
return ExtensionID::SPV_INTEL_fp_fast_math_mode;
case CapabilityFunctionVariantsINTEL:
case CapabilitySpecConditionalINTEL:
return ExtensionID::SPV_INTEL_function_variants;
case internal::CapabilityBFloat16ArithmeticINTEL:
return ExtensionID::SPV_INTEL_bfloat16_arithmetic;
case internal::CapabilityDeviceBarrierINTEL:
return ExtensionID::SPV_INTEL_device_barrier;
case CapabilityFloatControls2:
return ExtensionID::SPV_KHR_float_controls2;
default:
return {};
}
}
private:
SPIRVCapabilityKind Kind;
};
template <class T> T *bcast(SPIRVEntry *E) { return static_cast<T *>(E); }
template <spv::Op OC> bool isa(SPIRVEntry *E) {
return E ? E->getOpCode() == OC : false;
}
template <spv::Op OC>
class SPIRVContinuedInstINTELBase : public SPIRVEntryNoId<OC> {
public:
template <spv::Op _OC, class T = void>
using EnableIfCompositeConst =
typename std::enable_if_t<_OC == OpConstantCompositeContinuedINTEL ||
_OC ==
OpSpecConstantCompositeContinuedINTEL,
T>;
// Complete constructor
SPIRVContinuedInstINTELBase(SPIRVModule *M,
const std::vector<SPIRVValue *> &TheElements)
: SPIRVEntryNoId<OC>(M, TheElements.size() + 1) {
Elements = SPIRVEntry::getIds(TheElements);
validate();
}
SPIRVContinuedInstINTELBase(SPIRVModule *M, unsigned NumOfElements)
: SPIRVEntryNoId<OC>(M, NumOfElements + 1) {
Elements.resize(NumOfElements, SPIRVID_INVALID);
validate();
}
// Incomplete constructor
SPIRVContinuedInstINTELBase() : SPIRVEntryNoId<OC>() {}
template <spv::Op OPC = OC>
EnableIfCompositeConst<OPC, std::vector<SPIRVValue *>> getElements() const {
return SPIRVEntry::getValues(Elements);
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityLongCompositesINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_long_composites;
}
SPIRVWord getNumElements() const { return Elements.size(); }
protected:
void validate() const override;
void setWordCount(SPIRVWord WordCount) override {
SPIRVEntry::setWordCount(WordCount);
this->SPIRVCK(WordCount, InvalidWordCount, "");
Elements.resize(WordCount - 1);
}
_SPIRV_DCL_ENCDEC
std::vector<SPIRVId> Elements;
};
class SPIRVTypeStructContinuedINTEL
: public SPIRVContinuedInstINTELBase<OpTypeStructContinuedINTEL> {
public:
constexpr static Op OC = OpTypeStructContinuedINTEL;
// Complete constructor
SPIRVTypeStructContinuedINTEL(SPIRVModule *M, unsigned NumOfElements)
: SPIRVContinuedInstINTELBase<OC>(M, NumOfElements) {}
// Incomplete constructor
SPIRVTypeStructContinuedINTEL() : SPIRVContinuedInstINTELBase<OC>() {}
void setElementId(size_t I, SPIRVId Id) { Elements[I] = Id; }
SPIRVType *getMemberType(size_t I) const;
};
using SPIRVConstantCompositeContinuedINTEL =
SPIRVContinuedInstINTELBase<OpConstantCompositeContinuedINTEL>;
using SPIRVSpecConstantCompositeContinuedINTEL =
SPIRVContinuedInstINTELBase<OpSpecConstantCompositeContinuedINTEL>;
template <spv::Op OpCode> struct InstToContinued;
template <> struct InstToContinued<OpTypeStruct> {
using Type = SPIRVTypeStructContinuedINTEL *;
constexpr static spv::Op OpCode = OpTypeStructContinuedINTEL;
};
template <> struct InstToContinued<OpConstantComposite> {
using Type = SPIRVConstantCompositeContinuedINTEL *;
constexpr static spv::Op OpCode = OpConstantCompositeContinuedINTEL;
};
template <> struct InstToContinued<OpSpecConstantComposite> {
using Type = SPIRVSpecConstantCompositeContinuedINTEL *;
constexpr static spv::Op OpCode = OpSpecConstantCompositeContinuedINTEL;
};
class SPIRVModuleProcessed : public SPIRVEntryNoId<OpModuleProcessed> {
public:
SPIRVModuleProcessed(SPIRVModule *M, const std::string &Process)
: SPIRVEntryNoId(M, FixedWC + getSizeInWords(Process)),
ProcessStr(Process) {
updateModuleVersion();
}
SPIRVModuleProcessed() { updateModuleVersion(); }
_SPIRV_DCL_ENCDEC
void validate() const override;
VersionNumber getRequiredSPIRVVersion() const override {
return VersionNumber::SPIRV_1_1;
}
std::string getProcessStr();
private:
std::string ProcessStr;
static const SPIRVWord FixedWC = 1;
};
// ToDo: The following typedef's are place holders for SPIRV entity classes
// to be implemented.
// Each time a new class is implemented, remove the corresponding typedef.
// This is also an indication of how much work is left.
#define _SPIRV_OP(x) typedef SPIRVEntryUnimplemented<Op##x> SPIRV##x;
_SPIRV_OP(Nop)
_SPIRV_OP(SourceContinued)
_SPIRV_OP(TypeRuntimeArray)
_SPIRV_OP(ImageTexelPointer)
_SPIRV_OP(ImageSampleDrefImplicitLod)
_SPIRV_OP(ImageSampleDrefExplicitLod)
_SPIRV_OP(ImageSampleProjImplicitLod)
_SPIRV_OP(ImageSampleProjExplicitLod)
_SPIRV_OP(ImageSampleProjDrefImplicitLod)
_SPIRV_OP(ImageSampleProjDrefExplicitLod)
_SPIRV_OP(ImageFetch)
_SPIRV_OP(ImageGather)
_SPIRV_OP(ImageDrefGather)
_SPIRV_OP(QuantizeToF16)
_SPIRV_OP(ArrayLength)
_SPIRV_OP(OuterProduct)
_SPIRV_OP(DPdx)
_SPIRV_OP(DPdy)
_SPIRV_OP(Fwidth)
_SPIRV_OP(DPdxFine)
_SPIRV_OP(DPdyFine)
_SPIRV_OP(FwidthFine)
_SPIRV_OP(DPdxCoarse)
_SPIRV_OP(DPdyCoarse)
_SPIRV_OP(FwidthCoarse)
_SPIRV_OP(EmitVertex)
_SPIRV_OP(EndPrimitive)
_SPIRV_OP(EmitStreamVertex)
_SPIRV_OP(EndStreamPrimitive)
_SPIRV_OP(Kill)
_SPIRV_OP(ImageSparseSampleImplicitLod)
_SPIRV_OP(ImageSparseSampleExplicitLod)
_SPIRV_OP(ImageSparseSampleDrefImplicitLod)
_SPIRV_OP(ImageSparseSampleDrefExplicitLod)
_SPIRV_OP(ImageSparseSampleProjImplicitLod)
_SPIRV_OP(ImageSparseSampleProjExplicitLod)
_SPIRV_OP(ImageSparseSampleProjDrefImplicitLod)
_SPIRV_OP(ImageSparseSampleProjDrefExplicitLod)
_SPIRV_OP(ImageSparseFetch)
_SPIRV_OP(ImageSparseGather)
_SPIRV_OP(ImageSparseDrefGather)
_SPIRV_OP(ImageSparseTexelsResident)
_SPIRV_OP(NoLine)
_SPIRV_OP(TypeNamedBarrier)
_SPIRV_OP(NamedBarrierInitialize)
_SPIRV_OP(MemoryNamedBarrier)
_SPIRV_OP(GetKernelMaxNumSubgroups)
_SPIRV_OP(GetKernelLocalSizeForSubgroupCount)
#undef _SPIRV_OP
} // namespace SPIRV
#endif // SPIRV_LIBSPIRV_SPIRVENTRY_H