Files
TheRock/compiler/spirv-llvm-translator/lib/SPIRV/libSPIRV/SPIRVInstruction.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

4825 lines
171 KiB
C++

//===- SPIRVInstruction.h - Class to represent SPIRV instruction -- 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 Instruction class for SPIR-V.
///
//===----------------------------------------------------------------------===//
#ifndef SPIRV_LIBSPIRV_SPIRVINSTRUCTION_H
#define SPIRV_LIBSPIRV_SPIRVINSTRUCTION_H
#include "SPIRVBasicBlock.h"
#include "SPIRVEnum.h"
#include "SPIRVFunction.h"
#include "SPIRVIsValidEnum.h"
#include "SPIRVOpCode.h"
#include "SPIRVStream.h"
#include "SPIRVValue.h"
#include <cassert>
#include <functional>
#include <iostream>
#include <unordered_set>
#include <utility>
#include <vector>
namespace SPIRV {
typedef std::vector<SPIRVValue *> ValueVec;
typedef std::pair<ValueVec::iterator, ValueVec::iterator> ValueRange;
class SPIRVBasicBlock;
class SPIRVFunction;
bool isSpecConstantOpAllowedOp(Op OC);
class SPIRVComponentExecutionScope {
public:
SPIRVComponentExecutionScope(Scope TheScope = ScopeInvocation)
: ExecScope(TheScope) {}
Scope ExecScope;
};
class SPIRVComponentMemorySemanticsMask {
public:
SPIRVComponentMemorySemanticsMask(SPIRVWord TheSema = SPIRVWORD_MAX)
: MemSema(TheSema) {}
SPIRVWord MemSema;
};
class SPIRVComponentOperands {
public:
SPIRVComponentOperands() {}
SPIRVComponentOperands(const std::vector<SPIRVValue *> &TheOperands)
: Operands(TheOperands) {}
SPIRVComponentOperands(std::vector<SPIRVValue *> &&TheOperands)
: Operands(std::move(TheOperands)) {}
std::vector<SPIRVValue *> getCompOperands() { return Operands; }
std::vector<SPIRVType *> getCompOperandTypes() {
std::vector<SPIRVType *> Tys;
for (auto &I : getCompOperands())
Tys.push_back(I->getType());
return Tys;
}
protected:
std::vector<SPIRVValue *> Operands;
};
class SPIRVInstruction : public SPIRVValue {
public:
// Complete constructor for instruction with type and id
SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType,
SPIRVId TheId, SPIRVBasicBlock *TheBB);
// Complete constructor for instruction with module, type and id
SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType,
SPIRVId TheId, SPIRVBasicBlock *TheBB, SPIRVModule *TheBM);
// Complete constructor for instruction with id but no type
SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVId TheId,
SPIRVBasicBlock *TheBB);
// Complete constructor for instruction without type and id
SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVBasicBlock *TheBB);
// Complete constructor for instruction with type but no id
SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType,
SPIRVBasicBlock *TheBB);
// Special constructor for debug instruction
SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType,
SPIRVId TheId, SPIRVModule *TheBM,
SPIRVBasicBlock *TheBB = nullptr);
// Incomplete constructor
SPIRVInstruction(Op TheOC = OpNop)
: SPIRVValue(TheOC), BB(NULL), DebugScope(nullptr) {}
bool isInst() const override { return true; }
SPIRVBasicBlock *getParent() const { return BB; }
SPIRVInstruction *getPrevious() const { return BB->getPrevious(this); }
SPIRVInstruction *getNext() const { return BB->getNext(this); }
virtual std::vector<SPIRVValue *> getOperands();
static std::vector<SPIRVType *>
getOperandTypes(const std::vector<SPIRVValue *> &Ops);
void setParent(SPIRVBasicBlock *);
void setScope(SPIRVEntry *) override;
void addFPRoundingMode(SPIRVFPRoundingModeKind Kind) {
addDecorate(DecorationFPRoundingMode, Kind);
}
void eraseFPRoundingMode() { eraseDecorate(DecorationFPRoundingMode); }
void setSaturatedConversion(bool Enable) {
if (Enable)
addDecorate(DecorationSaturatedConversion);
else
eraseDecorate(DecorationSaturatedConversion);
}
bool hasFPRoundingMode(SPIRVFPRoundingModeKind *Kind = nullptr) {
SPIRVWord V;
auto Found = hasDecorate(DecorationFPRoundingMode, 0, &V);
if (Found && Kind)
*Kind = static_cast<SPIRVFPRoundingModeKind>(V);
return Found;
}
bool isSaturatedConversion() {
return hasDecorate(DecorationSaturatedConversion) ||
OpCode == OpSatConvertSToU || OpCode == OpSatConvertUToS;
}
SPIRVBasicBlock *getBasicBlock() const { return BB; }
void setBasicBlock(SPIRVBasicBlock *TheBB) {
BB = TheBB;
if (TheBB)
setModule(TheBB->getModule());
}
void setDebugScope(SPIRVEntry *Scope) { DebugScope = Scope; }
SPIRVEntry *getDebugScope() const { return DebugScope; }
protected:
void validate() const override { SPIRVValue::validate(); }
private:
SPIRVBasicBlock *BB;
SPIRVEntry *DebugScope;
};
class SPIRVInstTemplateBase : public SPIRVInstruction {
public:
/// Create an empty instruction. Mainly for getting format information,
/// e.g. whether an operand is literal.
static SPIRVInstTemplateBase *create(Op TheOC) {
auto Inst = static_cast<SPIRVInstTemplateBase *>(SPIRVEntry::create(TheOC));
assert(Inst);
Inst->init();
return Inst;
}
/// Create a instruction without operands.
static SPIRVInstTemplateBase *create(Op TheOC, SPIRVType *TheType,
SPIRVId TheId, SPIRVBasicBlock *TheBB,
SPIRVModule *TheModule) {
auto Inst = create(TheOC);
Inst->init(TheType, TheId, TheBB, TheModule);
return Inst;
}
/// Create a complete and valid instruction.
static SPIRVInstTemplateBase *create(Op TheOC, SPIRVType *TheType,
SPIRVId TheId,
const std::vector<SPIRVWord> &TheOps,
SPIRVBasicBlock *TheBB,
SPIRVModule *TheModule) {
auto Inst = create(TheOC);
Inst->init(TheType, TheId, TheBB, TheModule);
Inst->setOpWords(TheOps);
Inst->validate();
return Inst;
}
SPIRVInstTemplateBase(Op OC = OpNop)
: SPIRVInstruction(OC), HasVariWC(false) {
init();
}
~SPIRVInstTemplateBase() override {}
SPIRVInstTemplateBase *init(SPIRVType *TheType, SPIRVId TheId,
SPIRVBasicBlock *TheBB, SPIRVModule *TheModule) {
assert((TheBB || TheModule) && "Invalid BB or Module");
if (TheBB)
setBasicBlock(TheBB);
else {
setModule(TheModule);
}
setId(hasId() ? TheId : SPIRVID_INVALID);
setType(hasType() ? TheType : nullptr);
return this;
}
virtual void init() {}
virtual void initImpl(Op OC, bool HasId = true, SPIRVWord WC = 0,
bool VariWC = false, unsigned Lit1 = ~0U,
unsigned Lit2 = ~0U, unsigned Lit3 = ~0U,
unsigned Lit4 = ~0U) {
OpCode = OC;
if (!HasId) {
setHasNoId();
setHasNoType();
}
if (WC)
SPIRVEntry::setWordCount(WC);
setHasVariableWordCount(VariWC);
addLit(Lit1);
addLit(Lit2);
addLit(Lit3);
addLit(Lit4);
}
bool isOperandLiteral(unsigned I) const override { return Lit.count(I); }
void addLit(unsigned L) {
if (L != ~0U)
Lit.insert(L);
}
/// \return Expected number of operands. If the instruction has variable
/// number of words, return the minimum.
SPIRVWord getExpectedNumOperands() const {
assert(WordCount > 0 && "Word count not initialized");
auto Exp = WordCount - 1;
if (hasId())
--Exp;
if (hasType())
--Exp;
return Exp;
}
virtual void setOpWordsAndValidate(const std::vector<SPIRVWord> &TheOps) {
setOpWords(TheOps);
validate();
}
virtual void setOpWords(const std::vector<SPIRVWord> &TheOps) {
SPIRVWord WC = TheOps.size() + 1;
if (hasId())
++WC;
if (hasType())
++WC;
if (WordCount) {
if (WordCount == WC) {
// do nothing
} else {
assert(HasVariWC && WC >= WordCount && "Invalid word count");
SPIRVEntry::setWordCount(WC);
}
} else
SPIRVEntry::setWordCount(WC);
Ops = TheOps;
// The required SPIR-V version depends on the operands for some
// instructions.
updateModuleVersion();
}
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
auto NumOps = WordCount - 1;
if (hasId())
--NumOps;
if (hasType())
--NumOps;
Ops.resize(NumOps);
}
std::vector<SPIRVWord> &getOpWords() { return Ops; }
const std::vector<SPIRVWord> &getOpWords() const { return Ops; }
SPIRVWord getOpWord(int I) const { return Ops[I]; }
/// Get operand as value.
/// If the operand is a literal, return it as a uint32 constant.
const SPIRVValue *getOpValue(int I) const {
return isOperandLiteral(I) ? Module->getLiteralAsConstant(Ops[I])
: getValue(Ops[I]);
}
SPIRVValue *getOpValue(int I) {
return isOperandLiteral(I) ? Module->getLiteralAsConstant(Ops[I])
: getValue(Ops[I]);
}
std::vector<SPIRVValue *> getOperands() override {
std::vector<SPIRVValue *> VOps;
for (size_t I = 0, E = Ops.size(); I != E; ++I)
VOps.push_back(getOperand(I));
return VOps;
}
std::vector<SPIRVEntry *> getNonLiteralOperands() const override {
std::vector<SPIRVEntry *> Operands;
for (size_t I = 0, E = Ops.size(); I < E; ++I)
if (!isOperandLiteral(I))
Operands.push_back(getEntry(Ops[I]));
return Operands;
}
virtual const SPIRVValue *getOperand(unsigned I) const {
return getOpValue(I);
}
virtual SPIRVValue *getOperand(unsigned I) { return getOpValue(I); }
bool hasExecScope() const { return SPIRV::hasExecScope(OpCode); }
bool hasGroupOperation() const { return SPIRV::hasGroupOperation(OpCode); }
bool getSPIRVGroupOperation(SPIRVGroupOperationKind &GroupOp) const {
if (!hasGroupOperation())
return false;
GroupOp = static_cast<SPIRVGroupOperationKind>(Ops[1]);
return true;
}
Scope getExecutionScope() const {
if (!hasExecScope())
return ScopeInvocation;
return static_cast<Scope>(
static_cast<SPIRVConstant *>(getValue(Ops[0]))->getZExtIntValue());
}
bool hasVariableWordCount() const { return HasVariWC; }
void setHasVariableWordCount(bool VariWC) { HasVariWC = VariWC; }
protected:
void encode(spv_ostream &O) const override {
auto E = getEncoder(O);
if (hasType())
E << Type;
if (hasId())
E << Id;
E << Ops;
}
void decode(std::istream &I) override {
auto D = getDecoder(I);
if (hasType())
D >> Type;
if (hasId())
D >> Id;
D >> Ops;
}
std::vector<SPIRVWord> Ops;
bool HasVariWC;
std::unordered_set<unsigned> Lit; // Literal operand index
};
template <typename BT = SPIRVInstTemplateBase, Op OC = OpNop, bool HasId = true,
SPIRVWord WC = 0, bool HasVariableWC = false, unsigned Literal1 = ~0U,
unsigned Literal2 = ~0U, unsigned Literal3 = ~0U,
unsigned Literal4 = ~0U>
class SPIRVInstTemplate : public BT {
public:
typedef BT BaseTy;
SPIRVInstTemplate() { init(); }
~SPIRVInstTemplate() override {}
void init() override {
this->initImpl(OC, HasId, WC, HasVariableWC, Literal1, Literal2, Literal3,
Literal4);
}
};
class SPIRVMemoryAccess {
public:
SPIRVMemoryAccess(const std::vector<SPIRVWord> &TheMemoryAccess)
: TheMemoryAccessMask(0), Alignment(0), SrcAlignment(0),
AliasScopeInstID(0), NoAliasInstID(0) {
memoryAccessUpdate(TheMemoryAccess);
}
SPIRVMemoryAccess()
: TheMemoryAccessMask(0), Alignment(0), SrcAlignment(0),
AliasScopeInstID(0), NoAliasInstID(0) {}
void memoryAccessUpdate(const std::vector<SPIRVWord> &MemoryAccess) {
if (!MemoryAccess.size())
return;
assert(MemoryAccess.size() > 0 && "Invalid memory access operand size");
assert(MemoryAccess.size() < 5 && "Invalid memory access operand size");
TheMemoryAccessMask = MemoryAccess[0];
size_t MemAccessNumParam = 1;
if (MemoryAccess[0] & MemoryAccessAlignedMask) {
assert(MemoryAccess.size() > 1 && "Alignment operand is missing");
Alignment = MemoryAccess[MemAccessNumParam++];
}
if (MemoryAccess[0] & MemoryAccessAliasScopeINTELMaskMask) {
assert(MemoryAccess.size() > MemAccessNumParam &&
"Aliasing operand is missing");
AliasScopeInstID = MemoryAccess[MemAccessNumParam++];
}
if (MemoryAccess[0] & MemoryAccessNoAliasINTELMaskMask) {
assert(MemoryAccess.size() > MemAccessNumParam &&
"Aliasing operand is missing");
NoAliasInstID = MemoryAccess[MemAccessNumParam++];
}
// Exit if there is no second memory operand mask
if (MemoryAccess.size() == MemAccessNumParam)
return;
size_t SecondMaskId = MemAccessNumParam++;
if (MemoryAccess[SecondMaskId] & MemoryAccessAlignedMask) {
assert(MemoryAccess.size() > MemAccessNumParam &&
"Alignment operand is missing");
SrcAlignment = MemoryAccess[MemAccessNumParam];
}
}
SPIRVWord isVolatile() const {
return getMemoryAccessMask() & MemoryAccessVolatileMask;
}
SPIRVWord isNonTemporal() const {
return getMemoryAccessMask() & MemoryAccessNontemporalMask;
}
SPIRVWord isAliasScope() const {
return getMemoryAccessMask() & MemoryAccessAliasScopeINTELMaskMask;
}
SPIRVWord isNoAlias() const {
return getMemoryAccessMask() & MemoryAccessNoAliasINTELMaskMask;
}
SPIRVWord getMemoryAccessMask() const { return TheMemoryAccessMask; }
SPIRVWord getAlignment() const { return Alignment; }
SPIRVWord getSrcAlignment() const { return SrcAlignment; }
SPIRVWord getAliasScopeInstID() const { return AliasScopeInstID; }
SPIRVWord getNoAliasInstID() const { return NoAliasInstID; }
protected:
SPIRVWord TheMemoryAccessMask;
SPIRVWord Alignment;
SPIRVWord SrcAlignment;
SPIRVId AliasScopeInstID;
SPIRVId NoAliasInstID;
};
class SPIRVVariableBase : public SPIRVInstruction {
public:
static const SPIRVWord FixedWC = 4;
// Complete constructor for integer constant
SPIRVVariableBase(Op OC, SPIRVType *TheType, SPIRVId TheId,
SPIRVValue *TheInitializer, const std::string &TheName,
SPIRVStorageClassKind TheStorageClass,
SPIRVBasicBlock *TheBB, SPIRVModule *TheM, SPIRVWord WC)
: SPIRVInstruction(WC, OC, TheType, TheId, TheBB, TheM),
StorageClass(TheStorageClass) {
if (TheInitializer && !TheInitializer->isUndef())
Initializer.push_back(TheInitializer->getId());
Name = TheName;
validate();
}
// Incomplete constructors
SPIRVVariableBase(Op OC)
: SPIRVInstruction(OC), StorageClass(StorageClassFunction) {}
SPIRVVariableBase()
: SPIRVInstruction(OpNop), StorageClass(StorageClassFunction) {}
SPIRVStorageClassKind getStorageClass() const { return StorageClass; }
SPIRVValue *getInitializer() const {
if (Initializer.empty())
return nullptr;
assert(Initializer.size() == 1);
return getValue(Initializer[0]);
}
bool isConstant() const { return hasDecorate(DecorationConstant); }
bool isBuiltin(SPIRVBuiltinVariableKind *BuiltinKind = nullptr) const {
SPIRVWord Kind;
bool Found = hasDecorate(DecorationBuiltIn, 0, &Kind);
if (!Found)
return false;
if (BuiltinKind)
*BuiltinKind = static_cast<SPIRVBuiltinVariableKind>(Kind);
return true;
}
void setBuiltin(SPIRVBuiltinVariableKind Kind) {
assert(isValid(Kind));
addDecorate(new SPIRVDecorate(DecorationBuiltIn, this, Kind));
}
void setIsConstant(bool Is) {
if (Is)
addDecorate(new SPIRVDecorate(DecorationConstant, this));
else
eraseDecorate(DecorationConstant);
}
std::vector<SPIRVEntry *> getNonLiteralOperands() const override {
if (SPIRVValue *V = getInitializer())
return std::vector<SPIRVEntry *>(1, V);
return std::vector<SPIRVEntry *>();
}
protected:
void validate() const override {
SPIRVValue::validate();
assert(isValid(StorageClass));
assert(Initializer.size() == 1 || Initializer.empty());
assert(getType()->isTypePointer());
}
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
SPIRVCK(WordCount >= FixedWC, InvalidWordCount, "");
Initializer.resize(WordCount - FixedWC);
}
_SPIRV_DEF_ENCDEC4(Type, Id, StorageClass, Initializer)
SPIRVStorageClassKind StorageClass;
std::vector<SPIRVId> Initializer;
};
class SPIRVVariable : public SPIRVVariableBase {
public:
// Complete constructor for integer constant
SPIRVVariable(SPIRVType *TheType, SPIRVId TheId, SPIRVValue *TheInitializer,
const std::string &TheName,
SPIRVStorageClassKind TheStorageClass, SPIRVBasicBlock *TheBB,
SPIRVModule *TheM)
: SPIRVVariableBase(OpVariable, TheType, TheId, TheInitializer, TheName,
TheStorageClass, TheBB, TheM,
TheInitializer && !TheInitializer->isUndef() ? 5
: 4) {}
// Incomplete constructor
SPIRVVariable() : SPIRVVariableBase(OpVariable) {}
};
class SPIRVUntypedVariableKHR : public SPIRVVariableBase {
public:
SPIRVUntypedVariableKHR(SPIRVType *TheType, SPIRVId TheId,
SPIRVType *TheDataType, SPIRVValue *TheInitializer,
const std::string &TheName,
SPIRVStorageClassKind TheStorageClass,
SPIRVBasicBlock *TheBB, SPIRVModule *TheM)
: SPIRVVariableBase(
OpUntypedVariableKHR, TheType, TheId, TheInitializer, TheName,
TheStorageClass, TheBB, TheM,
TheDataType && !TheDataType->isUndef()
? (TheInitializer && !TheInitializer->isUndef() ? 6 : 5)
: 4) {
if (TheDataType && !TheDataType->isUndef())
DataType.push_back(TheDataType->getId());
validate();
}
SPIRVUntypedVariableKHR() : SPIRVVariableBase(OpUntypedVariableKHR) {}
SPIRVType *getDataType() const {
if (DataType.empty())
return nullptr;
assert(DataType.size() == 1);
return get<SPIRVType>(DataType[0]);
}
std::vector<SPIRVEntry *> getNonLiteralOperands() const override {
std::vector<SPIRVEntry *> Vec;
if (SPIRVType *T = getDataType())
Vec.push_back(T);
if (SPIRVValue *V = getInitializer())
Vec.push_back(V);
return Vec;
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_KHR_untyped_pointers;
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityUntypedPointersKHR);
}
protected:
void validate() const override {
SPIRVVariableBase::validate();
assert(DataType.size() == 1 || DataType.empty());
}
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
if (TheWordCount > FixedWC)
DataType.resize(1);
if (TheWordCount > FixedWC + 1)
Initializer.resize(1);
}
_SPIRV_DEF_ENCDEC5(Type, Id, StorageClass, DataType, Initializer)
std::vector<SPIRVId> DataType;
};
class SPIRVStore : public SPIRVInstruction, public SPIRVMemoryAccess {
public:
const static SPIRVWord FixedWords = 3;
// Complete constructor
SPIRVStore(SPIRVId PointerId, SPIRVId ValueId,
const std::vector<SPIRVWord> &TheMemoryAccess,
SPIRVBasicBlock *TheBB)
: SPIRVInstruction(FixedWords + TheMemoryAccess.size(), OpStore, TheBB),
SPIRVMemoryAccess(TheMemoryAccess), MemoryAccess(TheMemoryAccess),
PtrId(PointerId), ValId(ValueId) {
setAttr();
validate();
assert(TheBB && "Invalid BB");
}
// Incomplete constructor
SPIRVStore()
: SPIRVInstruction(OpStore), SPIRVMemoryAccess(), PtrId(SPIRVID_INVALID),
ValId(SPIRVID_INVALID) {
setAttr();
}
SPIRVValue *getSrc() const { return getValue(ValId); }
SPIRVValue *getDst() const { return getValue(PtrId); }
protected:
void setAttr() {
setHasNoType();
setHasNoId();
}
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
SPIRVCK(TheWordCount >= FixedWords, InvalidWordCount, "");
MemoryAccess.resize(TheWordCount - FixedWords);
}
void encode(spv_ostream &O) const override {
getEncoder(O) << PtrId << ValId << MemoryAccess;
}
void decode(std::istream &I) override {
getDecoder(I) >> PtrId >> ValId >> MemoryAccess;
memoryAccessUpdate(MemoryAccess);
}
void validate() const override {
SPIRVInstruction::validate();
if (getSrc()->isForward() || getDst()->isForward())
return;
assert(
(getValueType(PtrId)
->getPointerElementType()
->isTypeUntypedPointerKHR() ||
(getValueType(PtrId)->getPointerElementType()->isTypePointer() &&
getValueType(ValId)->isTypeUntypedPointerKHR()) ||
getValueType(PtrId)->getPointerElementType() == getValueType(ValId)) &&
"Inconsistent operand types");
}
private:
std::vector<SPIRVWord> MemoryAccess;
SPIRVId PtrId;
SPIRVId ValId;
};
class SPIRVLoad : public SPIRVInstruction, public SPIRVMemoryAccess {
public:
const static SPIRVWord FixedWords = 4;
// Complete constructor
SPIRVLoad(SPIRVId TheId, SPIRVId PointerId,
const std::vector<SPIRVWord> &TheMemoryAccess,
SPIRVBasicBlock *TheBB, SPIRVType *TheType = nullptr)
: SPIRVInstruction(
FixedWords + TheMemoryAccess.size(), OpLoad,
TheType ? TheType
: TheBB->getValueType(PointerId)->getPointerElementType(),
TheId, TheBB),
SPIRVMemoryAccess(TheMemoryAccess), PtrId(PointerId),
MemoryAccess(TheMemoryAccess) {
validate();
assert(TheBB && "Invalid BB");
}
// Incomplete constructor
SPIRVLoad()
: SPIRVInstruction(OpLoad), SPIRVMemoryAccess(), PtrId(SPIRVID_INVALID) {}
SPIRVValue *getSrc() const { return Module->get<SPIRVValue>(PtrId); }
protected:
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
SPIRVCK(TheWordCount >= FixedWords, InvalidWordCount, "");
MemoryAccess.resize(TheWordCount - FixedWords);
}
void encode(spv_ostream &O) const override {
getEncoder(O) << Type << Id << PtrId << MemoryAccess;
}
void decode(std::istream &I) override {
getDecoder(I) >> Type >> Id >> PtrId >> MemoryAccess;
memoryAccessUpdate(MemoryAccess);
}
void validate() const override {
SPIRVInstruction::validate();
assert((getValue(PtrId)->isForward() ||
getValueType(PtrId)
->getPointerElementType()
->isTypeUntypedPointerKHR() ||
Type->isTypeUntypedPointerKHR() ||
Type == getValueType(PtrId)->getPointerElementType()) &&
"Inconsistent types");
}
private:
SPIRVId PtrId;
std::vector<SPIRVWord> MemoryAccess;
};
class SPIRVBinary : public SPIRVInstTemplateBase {
protected:
void validate() const override {
SPIRVId Op1 = Ops[0];
SPIRVId Op2 = Ops[1];
SPIRVType *Op1Ty, *Op2Ty;
SPIRVInstruction::validate();
if (getValue(Op1)->isForward() || getValue(Op2)->isForward())
return;
if (getValueType(Op1)->isTypeVector()) {
Op1Ty = getValueType(Op1)->getVectorComponentType();
Op2Ty = getValueType(Op2)->getVectorComponentType();
assert(getValueType(Op1)->getVectorComponentCount() ==
getValueType(Op2)->getVectorComponentCount() &&
"Inconsistent Vector component width");
} else if (getValueType(Op1)->isTypeCooperativeMatrixKHR()) {
Op1Ty = getValueType(Op1)->getVectorComponentType();
Op2Ty = getValueType(Op2)->getVectorComponentType();
assert(Op1Ty == Op2Ty && "Inconsistent Cooperative matrix types");
} else {
Op1Ty = getValueType(Op1);
Op2Ty = getValueType(Op2);
}
(void)Op1Ty;
(void)Op2Ty;
if (isBinaryOpCode(OpCode)) {
assert(getValueType(Op1) == getValueType(Op2) &&
"Invalid type for binary instruction");
assert((Op1Ty->isTypeInt() || Op2Ty->isTypeFloat()) &&
"Invalid type for Binary instruction");
assert((Op1Ty->getBitWidth() == Op2Ty->getBitWidth()) &&
"Inconsistent BitWidth");
} else if (isShiftOpCode(OpCode)) {
assert((Op1Ty->isTypeInt() || Op2Ty->isTypeInt()) &&
"Invalid type for shift instruction");
} else if (isLogicalOpCode(OpCode)) {
assert((Op1Ty->isTypeBool() || Op2Ty->isTypeBool()) &&
"Invalid type for logical instruction");
} else if (isBitwiseOpCode(OpCode)) {
assert((Op1Ty->isTypeInt() || Op2Ty->isTypeInt()) &&
"Invalid type for bitwise instruction");
assert((Op1Ty->getIntegerBitWidth() == Op2Ty->getIntegerBitWidth()) &&
"Inconsistent BitWidth");
} else if (isBinaryPtrOpCode(OpCode)) {
assert((Op1Ty->isTypePointer() && Op2Ty->isTypePointer()) &&
"Invalid types for PtrEqual, PtrNotEqual, or PtrDiff instruction");
if (!Op1Ty->isTypeUntypedPointerKHR() &&
!Op2Ty->isTypeUntypedPointerKHR())
assert(
static_cast<SPIRVTypePointer *>(Op1Ty)->getElementType() ==
static_cast<SPIRVTypePointer *>(Op2Ty)->getElementType() &&
"Invalid types for PtrEqual, PtrNotEqual, or PtrDiff instruction");
else if (OpCode == OpPtrDiff)
assert(Op1Ty == Op2Ty && "Invalid types for PtrDiff instruction");
} else {
assert(0 && "Invalid op code!");
}
}
VersionNumber getRequiredSPIRVVersion() const override {
if (isBinaryPtrOpCode(OpCode))
return VersionNumber::SPIRV_1_4;
return VersionNumber::SPIRV_1_0;
}
SPIRVCapVec getRequiredCapability() const override {
if (OpCode == OpDot) {
const SPIRVType *OpTy = getValueType(Ops[0]);
if (OpTy && OpTy->isTypeVector()) {
OpTy = OpTy->getVectorComponentType();
if (OpTy && OpTy->isTypeFloat(16, FPEncodingBFloat16KHR)) {
return getVec(CapabilityBFloat16DotProductKHR);
}
}
}
return SPIRVInstruction::getRequiredCapability();
}
};
template <Op OC>
class SPIRVBinaryInst
: public SPIRVInstTemplate<SPIRVBinary, OC, true, 5, false> {};
#define _SPIRV_OP(x) typedef SPIRVBinaryInst<Op##x> SPIRV##x;
_SPIRV_OP(IAdd)
_SPIRV_OP(IAddCarry)
_SPIRV_OP(FAdd)
_SPIRV_OP(ISub)
_SPIRV_OP(ISubBorrow)
_SPIRV_OP(FSub)
_SPIRV_OP(IMul)
_SPIRV_OP(FMul)
_SPIRV_OP(SMulExtended)
_SPIRV_OP(UMulExtended)
_SPIRV_OP(UDiv)
_SPIRV_OP(SDiv)
_SPIRV_OP(FDiv)
_SPIRV_OP(SRem)
_SPIRV_OP(SMod)
_SPIRV_OP(FRem)
_SPIRV_OP(FMod)
_SPIRV_OP(UMod)
_SPIRV_OP(ShiftLeftLogical)
_SPIRV_OP(ShiftRightLogical)
_SPIRV_OP(ShiftRightArithmetic)
_SPIRV_OP(LogicalAnd)
_SPIRV_OP(LogicalOr)
_SPIRV_OP(LogicalEqual)
_SPIRV_OP(LogicalNotEqual)
_SPIRV_OP(BitwiseAnd)
_SPIRV_OP(BitwiseOr)
_SPIRV_OP(BitwiseXor)
_SPIRV_OP(Dot)
_SPIRV_OP(PtrEqual)
_SPIRV_OP(PtrNotEqual)
_SPIRV_OP(PtrDiff)
#undef _SPIRV_OP
template <Op TheOpCode> class SPIRVInstNoOperand : public SPIRVInstruction {
public:
// Complete constructor
SPIRVInstNoOperand(SPIRVBasicBlock *TheBB)
: SPIRVInstruction(1, TheOpCode, TheBB) {
setAttr();
validate();
}
// Incomplete constructor
SPIRVInstNoOperand() : SPIRVInstruction(TheOpCode) { setAttr(); }
protected:
void setAttr() {
setHasNoId();
setHasNoType();
}
_SPIRV_DEF_ENCDEC0
};
typedef SPIRVInstNoOperand<OpReturn> SPIRVReturn;
typedef SPIRVInstNoOperand<OpUnreachable> SPIRVUnreachable;
class SPIRVAbortKHR : public SPIRVInstruction {
public:
static const Op OC = OpAbortKHR;
static const SPIRVWord FixedWordCount = 3;
// Complete constructor.
SPIRVAbortKHR(SPIRVValue *TheMessage, SPIRVBasicBlock *TheBB)
: SPIRVInstruction(FixedWordCount, OC, TheBB),
MessageTypeId(TheMessage->getType()->getId()),
MessageId(TheMessage->getId()) {
setAttr();
validate();
assert(TheBB && "Invalid BB");
}
// Incomplete constructor.
SPIRVAbortKHR()
: SPIRVInstruction(OC), MessageTypeId(SPIRVID_INVALID),
MessageId(SPIRVID_INVALID) {
setAttr();
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityAbortKHR);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_KHR_abort;
}
std::vector<SPIRVValue *> getOperands() override {
return std::vector<SPIRVValue *>(1, getValue(MessageId));
}
_SPIRV_DEF_ENCDEC2(MessageTypeId, MessageId)
protected:
void setAttr() {
setHasNoId();
setHasNoType();
}
void validate() const override { SPIRVInstruction::validate(); }
SPIRVId MessageTypeId;
SPIRVId MessageId;
};
class SPIRVReturnValue : public SPIRVInstruction {
public:
static const Op OC = OpReturnValue;
// Complete constructor
SPIRVReturnValue(SPIRVValue *TheReturnValue, SPIRVBasicBlock *TheBB)
: SPIRVInstruction(2, OC, TheBB), ReturnValueId(TheReturnValue->getId()) {
setAttr();
validate();
assert(TheBB && "Invalid BB");
}
// Incomplete constructor
SPIRVReturnValue() : SPIRVInstruction(OC), ReturnValueId(SPIRVID_INVALID) {
setAttr();
}
SPIRVValue *getReturnValue() const { return getValue(ReturnValueId); }
protected:
void setAttr() {
setHasNoId();
setHasNoType();
}
_SPIRV_DEF_ENCDEC1(ReturnValueId)
void validate() const override { SPIRVInstruction::validate(); }
SPIRVId ReturnValueId;
};
class SPIRVBranch : public SPIRVInstruction {
public:
static const Op OC = OpBranch;
// Complete constructor
SPIRVBranch(SPIRVLabel *TheTargetLabel, SPIRVBasicBlock *TheBB)
: SPIRVInstruction(2, OC, TheBB), TargetLabelId(TheTargetLabel->getId()) {
validate();
assert(TheBB && "Invalid BB");
}
// Incomplete constructor
SPIRVBranch() : SPIRVInstruction(OC), TargetLabelId(SPIRVID_INVALID) {
setHasNoId();
setHasNoType();
}
SPIRVValue *getTargetLabel() const { return getValue(TargetLabelId); }
protected:
_SPIRV_DEF_ENCDEC1(TargetLabelId)
void validate() const override {
SPIRVInstruction::validate();
assert(WordCount == 2);
assert(OpCode == OC);
assert(getTargetLabel()->isLabel() || getTargetLabel()->isForward());
}
SPIRVId TargetLabelId;
};
class SPIRVBranchConditional : public SPIRVInstruction {
public:
static const Op OC = OpBranchConditional;
constexpr static SPIRVWord FixedWC = 4;
// Complete constructor
SPIRVBranchConditional(SPIRVValue *TheCondition, SPIRVLabel *TheTrueLabel,
SPIRVLabel *TheFalseLabel, SPIRVBasicBlock *TheBB)
: SPIRVInstruction(FixedWC, OC, TheBB),
ConditionId(TheCondition->getId()), TrueLabelId(TheTrueLabel->getId()),
FalseLabelId(TheFalseLabel->getId()) {
validate();
}
SPIRVBranchConditional(SPIRVValue *TheCondition, SPIRVLabel *TheTrueLabel,
SPIRVLabel *TheFalseLabel, SPIRVBasicBlock *TheBB,
SPIRVWord TrueWeight, SPIRVWord FalseWeight)
: SPIRVInstruction(6, OC, TheBB), ConditionId(TheCondition->getId()),
TrueLabelId(TheTrueLabel->getId()),
FalseLabelId(TheFalseLabel->getId()) {
BranchWeights.push_back(TrueWeight);
BranchWeights.push_back(FalseWeight);
validate();
assert(TheBB && "Invalid BB");
}
// Incomplete constructor
SPIRVBranchConditional()
: SPIRVInstruction(OC), ConditionId(SPIRVID_INVALID),
TrueLabelId(SPIRVID_INVALID), FalseLabelId(SPIRVID_INVALID) {
setHasNoId();
setHasNoType();
}
SPIRVValue *getCondition() const { return getValue(ConditionId); }
SPIRVLabel *getTrueLabel() const { return get<SPIRVLabel>(TrueLabelId); }
SPIRVLabel *getFalseLabel() const { return get<SPIRVLabel>(FalseLabelId); }
protected:
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
SPIRVCK(TheWordCount >= FixedWC, InvalidWordCount, "");
BranchWeights.resize(TheWordCount - FixedWC);
}
_SPIRV_DEF_ENCDEC4(ConditionId, TrueLabelId, FalseLabelId, BranchWeights)
void validate() const override {
SPIRVInstruction::validate();
assert(WordCount == FixedWC || WordCount == FixedWC + 2);
assert(WordCount == BranchWeights.size() + FixedWC);
assert(OpCode == OC);
assert(getCondition()->isForward() ||
getCondition()->getType()->isTypeBool());
assert(getTrueLabel()->isForward() || getTrueLabel()->isLabel());
assert(getFalseLabel()->isForward() || getFalseLabel()->isLabel());
if (Module->isAllowedToUseVersion(VersionNumber::SPIRV_1_6))
assert(TrueLabelId != FalseLabelId);
}
SPIRVId ConditionId;
SPIRVId TrueLabelId;
SPIRVId FalseLabelId;
std::vector<SPIRVWord> BranchWeights;
};
class SPIRVPhi : public SPIRVInstruction {
public:
static const Op OC = OpPhi;
static const SPIRVWord FixedWordCount = 3;
SPIRVPhi(SPIRVType *TheType, SPIRVId TheId,
const std::vector<SPIRVValue *> &ThePairs, SPIRVBasicBlock *BB)
: SPIRVInstruction(ThePairs.size() + FixedWordCount, OC, TheType, TheId,
BB) {
Pairs = getIds(ThePairs);
validate();
assert(BB && "Invalid BB");
}
SPIRVPhi() : SPIRVInstruction(OC) {}
std::vector<SPIRVValue *> getPairs() { return getValues(Pairs); }
void addPair(SPIRVValue *Value, SPIRVBasicBlock *BB) {
Pairs.push_back(Value->getId());
Pairs.push_back(BB->getId());
WordCount = Pairs.size() + FixedWordCount;
validate();
}
void setPairs(const std::vector<SPIRVValue *> &ThePairs) {
Pairs = getIds(ThePairs);
WordCount = Pairs.size() + FixedWordCount;
validate();
}
void foreachPair(
std::function<void(SPIRVValue *, SPIRVBasicBlock *, size_t)> Func) {
for (size_t I = 0, E = Pairs.size() / 2; I != E; ++I) {
SPIRVEntry *Value, *BB;
if (!Module->exist(Pairs[2 * I], &Value) ||
!Module->exist(Pairs[2 * I + 1], &BB))
continue;
Func(static_cast<SPIRVValue *>(Value), static_cast<SPIRVBasicBlock *>(BB),
I);
}
}
void
foreachPair(std::function<void(SPIRVValue *, SPIRVBasicBlock *)> Func) const {
for (size_t I = 0, E = Pairs.size() / 2; I != E; ++I) {
SPIRVEntry *Value, *BB;
if (!Module->exist(Pairs[2 * I], &Value) ||
!Module->exist(Pairs[2 * I + 1], &BB))
continue;
Func(static_cast<SPIRVValue *>(Value),
static_cast<SPIRVBasicBlock *>(BB));
}
}
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
SPIRVCK(TheWordCount >= FixedWordCount, InvalidWordCount, "");
Pairs.resize(TheWordCount - FixedWordCount);
}
_SPIRV_DEF_ENCDEC3(Type, Id, Pairs)
void validate() const override {
assert(WordCount == Pairs.size() + FixedWordCount);
assert(OpCode == OC);
assert(Pairs.size() % 2 == 0);
foreachPair([this](SPIRVValue *IncomingV, SPIRVBasicBlock *IncomingBB) {
assert(IncomingV->isForward() || IncomingV->getType() == Type ||
(IncomingV->getType()->isTypePointer() &&
Type->isTypeUntypedPointerKHR()) ||
(IncomingV->getType()->isTypeUntypedPointerKHR() &&
Type->isTypePointer()));
assert(IncomingBB->isBasicBlock() || IncomingBB->isForward());
});
SPIRVInstruction::validate();
}
protected:
std::vector<SPIRVId> Pairs;
};
class SPIRVFPGARegINTELInstBase : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityFPGARegINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_fpga_reg;
}
protected:
void validate() const override {
SPIRVInstruction::validate();
assert(OpCode == OpFPGARegINTEL &&
"Invalid op code for FPGARegINTEL instruction");
assert(getType() == getValueType(Ops[0]) && "Inconsistent type");
}
};
typedef SPIRVInstTemplate<SPIRVFPGARegINTELInstBase, OpFPGARegINTEL, true, 4>
SPIRVFPGARegINTEL;
class SPIRVCompare : public SPIRVInstTemplateBase {
protected:
void validate() const override {
auto Op1 = Ops[0];
auto Op2 = Ops[1];
SPIRVType *Op1Ty, *Op2Ty, *ResTy;
SPIRVInstruction::validate();
if (getValue(Op1)->isForward() || getValue(Op2)->isForward())
return;
(void)Op1Ty;
(void)Op2Ty;
(void)ResTy;
if (getValueType(Op1)->isTypeVector()) {
Op1Ty = getValueType(Op1)->getVectorComponentType();
Op2Ty = getValueType(Op2)->getVectorComponentType();
ResTy = Type->getVectorComponentType();
assert(getValueType(Op1)->getVectorComponentCount() ==
getValueType(Op2)->getVectorComponentCount() &&
"Inconsistent Vector component width");
} else {
Op1Ty = getValueType(Op1);
Op2Ty = getValueType(Op2);
ResTy = Type;
}
assert(isCmpOpCode(OpCode) && "Invalid op code for cmp inst");
if (OpCode == OpLessOrGreater)
assert(this->getModule()->getSPIRVVersion() <= VersionNumber::SPIRV_1_5 &&
"OpLessOrGreater is removed starting from SPIR-V 1.6");
assert((ResTy->isTypeBool() || ResTy->isTypeInt()) &&
"Invalid type for compare instruction");
assert(Op1Ty == Op2Ty && "Inconsistent types");
}
};
template <Op OC>
class SPIRVCmpInst
: public SPIRVInstTemplate<SPIRVCompare, OC, true, 5, false> {};
#define _SPIRV_OP(x) typedef SPIRVCmpInst<Op##x> SPIRV##x;
_SPIRV_OP(IEqual)
_SPIRV_OP(FOrdEqual)
_SPIRV_OP(FUnordEqual)
_SPIRV_OP(INotEqual)
_SPIRV_OP(FOrdNotEqual)
_SPIRV_OP(FUnordNotEqual)
_SPIRV_OP(ULessThan)
_SPIRV_OP(SLessThan)
_SPIRV_OP(FOrdLessThan)
_SPIRV_OP(FUnordLessThan)
_SPIRV_OP(UGreaterThan)
_SPIRV_OP(SGreaterThan)
_SPIRV_OP(FOrdGreaterThan)
_SPIRV_OP(FUnordGreaterThan)
_SPIRV_OP(ULessThanEqual)
_SPIRV_OP(SLessThanEqual)
_SPIRV_OP(FOrdLessThanEqual)
_SPIRV_OP(FUnordLessThanEqual)
_SPIRV_OP(UGreaterThanEqual)
_SPIRV_OP(SGreaterThanEqual)
_SPIRV_OP(FOrdGreaterThanEqual)
_SPIRV_OP(FUnordGreaterThanEqual)
_SPIRV_OP(LessOrGreater)
_SPIRV_OP(Ordered)
_SPIRV_OP(Unordered)
#undef _SPIRV_OP
class SPIRVSelectBase : public SPIRVInstTemplateBase {
public:
SPIRVValue *getCondition() { return getValue(Ops[0]); }
SPIRVValue *getTrueValue() { return getValue(Ops[1]); }
SPIRVValue *getFalseValue() { return getValue(Ops[2]); }
protected:
void validate() const override {
SPIRVId Condition = Ops[0];
SPIRVId Op1 = Ops[1];
SPIRVId Op2 = Ops[2];
SPIRVInstruction::validate();
if (getValue(Condition)->isForward() || getValue(Op1)->isForward() ||
getValue(Op2)->isForward())
return;
SPIRVType *ConTy = getValueType(Condition)->isTypeVector()
? getValueType(Condition)->getVectorComponentType()
: getValueType(Condition);
(void)ConTy;
assert(ConTy->isTypeBool() && "Invalid type");
if (getType()->getOpCode() != OpTypeUntypedPointerKHR &&
getValueType(Op1)->getOpCode() != OpTypeUntypedPointerKHR &&
getValueType(Op2)->getOpCode() != OpTypeUntypedPointerKHR)
assert(getType() == getValueType(Op1) && getType() == getValueType(Op2) &&
"Inconsistent type");
}
};
typedef SPIRVInstTemplate<SPIRVSelectBase, OpSelect, true, 6> SPIRVSelect;
class SPIRVSelectionMerge : public SPIRVInstruction {
public:
static const Op OC = OpSelectionMerge;
static const SPIRVWord FixedWordCount = 3;
SPIRVSelectionMerge(SPIRVId TheMergeBlock, SPIRVWord TheSelectionControl,
SPIRVBasicBlock *BB)
: SPIRVInstruction(3, OC, BB), MergeBlock(TheMergeBlock),
SelectionControl(TheSelectionControl) {
validate();
assert(BB && "Invalid BB");
}
SPIRVSelectionMerge()
: SPIRVInstruction(OC), MergeBlock(SPIRVID_INVALID),
SelectionControl(SPIRVWORD_MAX) {
setHasNoId();
setHasNoType();
}
SPIRVId getMergeBlock() { return MergeBlock; }
SPIRVWord getSelectionControl() { return SelectionControl; }
_SPIRV_DEF_ENCDEC2(MergeBlock, SelectionControl)
protected:
SPIRVId MergeBlock;
SPIRVWord SelectionControl;
};
class SPIRVLoopMerge : public SPIRVInstruction {
public:
static const Op OC = OpLoopMerge;
static const SPIRVWord FixedWordCount = 4;
SPIRVLoopMerge(SPIRVId TheMergeBlock, SPIRVId TheContinueTarget,
SPIRVWord TheLoopControl,
std::vector<SPIRVWord> TheLoopControlParameters,
SPIRVBasicBlock *BB)
: SPIRVInstruction(FixedWordCount + TheLoopControlParameters.size(), OC,
BB),
MergeBlock(TheMergeBlock), ContinueTarget(TheContinueTarget),
LoopControl(TheLoopControl),
LoopControlParameters(TheLoopControlParameters) {
validate();
assert(BB && "Invalid BB");
}
SPIRVLoopMerge()
: SPIRVInstruction(OC), MergeBlock(SPIRVID_MAX),
ContinueTarget(SPIRVID_MAX), LoopControl(SPIRVWORD_MAX) {
setHasNoId();
setHasNoType();
}
SPIRVId getMergeBlock() { return MergeBlock; }
SPIRVId getContinueTarget() { return ContinueTarget; }
SPIRVWord getLoopControl() const { return LoopControl; }
std::vector<SPIRVWord> getLoopControlParameters() const {
return LoopControlParameters;
}
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
SPIRVCK(TheWordCount >= FixedWordCount, InvalidWordCount, "");
LoopControlParameters.resize(TheWordCount - FixedWordCount);
}
_SPIRV_DEF_ENCDEC4(MergeBlock, ContinueTarget, LoopControl,
LoopControlParameters)
protected:
SPIRVId MergeBlock;
SPIRVId ContinueTarget;
SPIRVWord LoopControl;
std::vector<SPIRVWord> LoopControlParameters;
};
class SPIRVSwitch : public SPIRVInstruction {
public:
static const Op OC = OpSwitch;
static const SPIRVWord FixedWordCount = 3;
typedef std::vector<SPIRVWord> LiteralTy;
typedef std::pair<LiteralTy, SPIRVBasicBlock *> PairTy;
SPIRVSwitch(SPIRVValue *TheSelect, SPIRVBasicBlock *TheDefault,
const std::vector<PairTy> &ThePairs, SPIRVBasicBlock *BB)
: SPIRVInstruction(FixedWordCount, OC, BB), Select(TheSelect->getId()),
Default(TheDefault->getId()) {
if (!ThePairs.empty())
SPIRVEntry::setWordCount(
ThePairs.size() * (ThePairs.at(0).first.size() + 1) + FixedWordCount);
for (auto &I : ThePairs) {
for (auto &U : I.first)
Pairs.push_back(U);
Pairs.push_back(I.second->getId());
}
validate();
assert(BB && "Invalid BB");
}
SPIRVSwitch()
: SPIRVInstruction(OC), Select(SPIRVWORD_MAX), Default(SPIRVWORD_MAX) {
setHasNoId();
setHasNoType();
}
std::vector<SPIRVValue *> getPairs() const { return getValues(Pairs); }
SPIRVValue *getSelect() const { return getValue(Select); }
SPIRVBasicBlock *getDefault() const {
return static_cast<SPIRVBasicBlock *>(getValue(Default));
}
size_t getLiteralSize() const {
unsigned ByteWidth =
std::max(getSelect()->getType()->getBitWidth() / 8, 1u);
unsigned Remainder = (ByteWidth % sizeof(SPIRVWord)) != 0;
return (ByteWidth / sizeof(SPIRVWord)) + Remainder;
}
size_t getPairSize() const { return getLiteralSize() + 1; }
size_t getNumPairs() const { return Pairs.size() / getPairSize(); }
void
foreachPair(std::function<void(LiteralTy, SPIRVBasicBlock *)> Func) const {
unsigned PairSize = getPairSize();
for (size_t I = 0, E = getNumPairs(); I != E; ++I) {
SPIRVEntry *BB;
LiteralTy Literals;
if (!Module->exist(Pairs[PairSize * I + getLiteralSize()], &BB))
continue;
for (size_t J = 0; J < getLiteralSize(); ++J) {
Literals.push_back(Pairs.at(PairSize * I + J));
}
Func(Literals, static_cast<SPIRVBasicBlock *>(BB));
}
}
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
SPIRVCK(TheWordCount >= FixedWordCount, InvalidWordCount, "");
Pairs.resize(TheWordCount - FixedWordCount);
}
_SPIRV_DEF_ENCDEC3(Select, Default, Pairs)
void validate() const override {
assert(WordCount == Pairs.size() + FixedWordCount);
assert(OpCode == OC);
assert(Pairs.size() % getPairSize() == 0);
foreachPair([=](LiteralTy Literals, SPIRVBasicBlock *BB) {
assert(BB->isBasicBlock() || BB->isForward());
});
SPIRVInstruction::validate();
}
protected:
SPIRVId Select;
SPIRVId Default;
std::vector<SPIRVWord> Pairs;
};
class SPIRVVectorTimesScalar : public SPIRVInstruction {
public:
static const Op OC = OpVectorTimesScalar;
static const SPIRVWord FixedWordCount = 4;
// Complete constructor
SPIRVVectorTimesScalar(SPIRVType *TheType, SPIRVId TheId, SPIRVId TheVector,
SPIRVId TheScalar, SPIRVBasicBlock *BB)
: SPIRVInstruction(5, OC, TheType, TheId, BB), Vector(TheVector),
Scalar(TheScalar) {
validate();
assert(BB && "Invalid BB");
}
// Incomplete constructor
SPIRVVectorTimesScalar()
: SPIRVInstruction(OC), Vector(SPIRVID_INVALID), Scalar(SPIRVID_INVALID) {
}
SPIRVValue *getVector() const { return getValue(Vector); }
SPIRVValue *getScalar() const { return getValue(Scalar); }
std::vector<SPIRVValue *> getOperands() override {
std::vector<SPIRVId> Operands;
Operands.push_back(Vector);
Operands.push_back(Scalar);
return getValues(Operands);
}
void setWordCount(SPIRVWord FixedWordCount) override {
SPIRVEntry::setWordCount(FixedWordCount);
}
_SPIRV_DEF_ENCDEC4(Type, Id, Vector, Scalar)
void validate() const override {
SPIRVInstruction::validate();
if (getValue(Vector)->isForward() || getValue(Scalar)->isForward())
return;
assert(getValueType(Vector)->isTypeVector() &&
getValueType(Vector)->getVectorComponentType()->isTypeFloat() &&
"First operand must be a vector of floating-point type");
assert(getValueType(getId())->isTypeVector() &&
getValueType(getId())->getVectorComponentType()->isTypeFloat() &&
"Result type must be a vector of floating-point type");
assert(
getValueType(Vector)->getVectorComponentType() ==
getValueType(getId())->getVectorComponentType() &&
"Scalar must have the same type as the Component Type in Result Type");
SPIRVInstruction::validate();
}
protected:
SPIRVId Vector;
SPIRVId Scalar;
};
class SPIRVVectorTimesMatrix : public SPIRVInstruction {
public:
static const Op OC = OpVectorTimesMatrix;
static const SPIRVWord FixedWordCount = 4;
// Complete constructor
SPIRVVectorTimesMatrix(SPIRVType *TheType, SPIRVId TheId, SPIRVId TheVector,
SPIRVId TheMatrix, SPIRVBasicBlock *BB)
: SPIRVInstruction(5, OC, TheType, TheId, BB), Vector(TheVector),
Matrix(TheMatrix) {
validate();
assert(BB && "Invalid BB");
}
// Incomplete constructor
SPIRVVectorTimesMatrix()
: SPIRVInstruction(OC), Vector(SPIRVID_INVALID), Matrix(SPIRVID_INVALID) {
}
SPIRVValue *getVector() const { return getValue(Vector); }
SPIRVValue *getMatrix() const { return getValue(Matrix); }
std::vector<SPIRVValue *> getOperands() override {
std::vector<SPIRVId> Operands;
Operands.push_back(Vector);
Operands.push_back(Matrix);
return getValues(Operands);
}
void setWordCount(SPIRVWord FixedWordCount) override {
SPIRVEntry::setWordCount(FixedWordCount);
}
_SPIRV_DEF_ENCDEC4(Type, Id, Vector, Matrix)
void validate() const override {
SPIRVInstruction::validate();
if (getValue(Vector)->isForward() || getValue(Matrix)->isForward())
return;
SPIRVType *Ty = getType()->getScalarType();
SPIRVType *MTy = getValueType(Matrix)->getScalarType();
SPIRVType *VTy = getValueType(Vector)->getScalarType();
(void)Ty;
(void)MTy;
(void)VTy;
assert(Ty->isTypeFloat() && "Invalid result type for OpVectorTimesMatrix");
assert(VTy->isTypeFloat() && "Invalid Vector type for OpVectorTimesMatrix");
assert(MTy->isTypeFloat() && "Invalid Matrix type for OpVectorTimesMatrix");
assert(Ty == MTy && Ty == VTy && "Mismatch float type");
}
private:
SPIRVId Vector;
SPIRVId Matrix;
};
class SPIRVMatrixTimesScalar : public SPIRVInstruction {
public:
static const Op OC = OpMatrixTimesScalar;
static const SPIRVWord FixedWordCount = 4;
// Complete constructor
SPIRVMatrixTimesScalar(SPIRVType *TheType, SPIRVId TheId, SPIRVId TheMatrix,
SPIRVId TheScalar, SPIRVBasicBlock *BB)
: SPIRVInstruction(5, OC, TheType, TheId, BB), Matrix(TheMatrix),
Scalar(TheScalar) {
validate();
assert(BB && "Invalid BB");
}
// Incomplete constructor
SPIRVMatrixTimesScalar()
: SPIRVInstruction(OC), Matrix(SPIRVID_INVALID), Scalar(SPIRVID_INVALID) {
}
SPIRVValue *getMatrix() const { return getValue(Matrix); }
SPIRVValue *getScalar() const { return getValue(Scalar); }
std::vector<SPIRVValue *> getOperands() override {
std::vector<SPIRVId> Operands;
Operands.push_back(Matrix);
Operands.push_back(Scalar);
return getValues(Operands);
}
void setWordCount(SPIRVWord FixedWordCount) override {
SPIRVEntry::setWordCount(FixedWordCount);
}
_SPIRV_DEF_ENCDEC4(Type, Id, Matrix, Scalar)
void validate() const override {
SPIRVInstruction::validate();
if (getValue(Matrix)->isForward() || getValue(Scalar)->isForward())
return;
SPIRVType *Ty = getType()->getScalarType();
SPIRVType *MTy = getValueType(Matrix)->getScalarType();
SPIRVType *STy = getValueType(Scalar);
(void)Ty;
(void)MTy;
(void)STy;
assert(Ty && Ty->isTypeFloat() &&
"Invalid result type for OpMatrixTimesScalar");
assert(MTy && MTy->isTypeFloat() &&
"Invalid Matrix type for OpMatrixTimesScalar");
assert(STy->isTypeFloat() && "Invalid Scalar type for OpMatrixTimesScalar");
assert(Ty == MTy && Ty == STy && "Mismatch float type");
}
private:
SPIRVId Matrix;
SPIRVId Scalar;
};
class SPIRVMatrixTimesVector : public SPIRVInstruction {
public:
static const Op OC = OpMatrixTimesVector;
static const SPIRVWord FixedWordCount = 4;
// Complete constructor
SPIRVMatrixTimesVector(SPIRVType *TheType, SPIRVId TheId, SPIRVId TheMatrix,
SPIRVId TheVector, SPIRVBasicBlock *BB)
: SPIRVInstruction(5, OC, TheType, TheId, BB), Matrix(TheMatrix),
Vector(TheVector) {
validate();
assert(BB && "Invalid BB");
}
// Incomplete constructor
SPIRVMatrixTimesVector()
: SPIRVInstruction(OC), Matrix(SPIRVID_INVALID), Vector(SPIRVID_INVALID) {
}
SPIRVValue *getMatrix() const { return getValue(Matrix); }
SPIRVValue *getVector() const { return getValue(Vector); }
std::vector<SPIRVValue *> getOperands() override {
std::vector<SPIRVId> Operands;
Operands.push_back(Matrix);
Operands.push_back(Vector);
return getValues(Operands);
}
void setWordCount(SPIRVWord FixedWordCount) override {
SPIRVEntry::setWordCount(FixedWordCount);
}
_SPIRV_DEF_ENCDEC4(Type, Id, Matrix, Vector)
void validate() const override {
SPIRVInstruction::validate();
if (getValue(Matrix)->isForward() || getValue(Vector)->isForward())
return;
SPIRVType *Ty = getType()->getScalarType();
SPIRVType *MTy = getValueType(Matrix)->getScalarType();
SPIRVType *VTy = getValueType(Vector)->getScalarType();
(void)Ty;
(void)MTy;
(void)VTy;
assert(Ty->isTypeFloat() && "Invalid result type for OpMatrixTimesVector");
assert(MTy->isTypeFloat() && "Invalid Matrix type for OpMatrixTimesVector");
assert(VTy->isTypeFloat() && "Invalid Vector type for OpMatrixTimesVector");
assert(Ty == MTy && Ty == VTy && "Mismatch float type");
}
private:
SPIRVId Matrix;
SPIRVId Vector;
};
class SPIRVMatrixTimesMatrix : public SPIRVInstruction {
public:
static const Op OC = OpMatrixTimesMatrix;
static const SPIRVWord FixedWordCount = 4;
// Complete constructor
SPIRVMatrixTimesMatrix(SPIRVType *TheType, SPIRVId TheId, SPIRVId M1,
SPIRVId M2, SPIRVBasicBlock *BB)
: SPIRVInstruction(5, OC, TheType, TheId, BB), LeftMatrix(M1),
RightMatrix(M2) {
validate();
assert(BB && "Invalid BB");
}
// Incomplete constructor
SPIRVMatrixTimesMatrix()
: SPIRVInstruction(OC), LeftMatrix(SPIRVID_INVALID),
RightMatrix(SPIRVID_INVALID) {}
SPIRVValue *getLeftMatrix() const { return getValue(LeftMatrix); }
SPIRVValue *getRightMatrix() const { return getValue(RightMatrix); }
std::vector<SPIRVValue *> getOperands() override {
std::vector<SPIRVId> Operands;
Operands.push_back(LeftMatrix);
Operands.push_back(RightMatrix);
return getValues(Operands);
}
void setWordCount(SPIRVWord FixedWordCount) override {
SPIRVEntry::setWordCount(FixedWordCount);
}
_SPIRV_DEF_ENCDEC4(Type, Id, LeftMatrix, RightMatrix)
void validate() const override {
SPIRVInstruction::validate();
if (getValue(LeftMatrix)->isForward() || getValue(RightMatrix)->isForward())
return;
SPIRVType *Ty = getType()->getScalarType();
SPIRVType *LMTy = getValueType(LeftMatrix)->getScalarType();
SPIRVType *RMTy = getValueType(RightMatrix)->getScalarType();
(void)Ty;
(void)LMTy;
(void)RMTy;
assert(Ty->isTypeFloat() && "Invalid result type for OpMatrixTimesMatrix");
assert(LMTy->isTypeFloat() &&
"Invalid Matrix type for OpMatrixTimesMatrix");
assert(RMTy->isTypeFloat() &&
"Invalid Matrix type for OpMatrixTimesMatrix");
assert(Ty == LMTy && Ty == RMTy && "Mismatch float type");
}
private:
SPIRVId LeftMatrix;
SPIRVId RightMatrix;
};
class SPIRVTranspose : public SPIRVInstruction {
public:
static const Op OC = OpTranspose;
static const SPIRVWord FixedWordCount = 3;
// Complete constructor
SPIRVTranspose(SPIRVType *TheType, SPIRVId TheId, SPIRVId TheMatrix,
SPIRVBasicBlock *BB)
: SPIRVInstruction(4, OC, TheType, TheId, BB), Matrix(TheMatrix) {
validate();
assert(BB && "Invalid BB");
}
// Incomplete constructor
SPIRVTranspose() : SPIRVInstruction(OC), Matrix(SPIRVID_INVALID) {}
SPIRVValue *getMatrix() const { return getValue(Matrix); }
std::vector<SPIRVValue *> getOperands() override {
std::vector<SPIRVId> Operands;
Operands.push_back(Matrix);
return getValues(Operands);
}
void setWordCount(SPIRVWord FixedWordCount) override {
SPIRVEntry::setWordCount(FixedWordCount);
}
_SPIRV_DEF_ENCDEC3(Type, Id, Matrix)
void validate() const override {
SPIRVInstruction::validate();
if (getValue(Matrix)->isForward())
return;
SPIRVType *Ty = getType()->getScalarType();
SPIRVType *MTy = getValueType(Matrix)->getScalarType();
(void)Ty;
(void)MTy;
assert(Ty->isTypeFloat() && "Invalid result type for OpTranspose");
assert(Ty == MTy && "Mismatch float type");
}
private:
SPIRVId Matrix;
};
class SPIRVSizeOfInstBase : public SPIRVInstTemplateBase {
protected:
VersionNumber getRequiredSPIRVVersion() const override {
return VersionNumber::SPIRV_1_1;
}
};
typedef SPIRVInstTemplate<SPIRVSizeOfInstBase, OpSizeOf, true, 4, false>
SPIRVSizeOf;
class SPIRVUnary : public SPIRVInstTemplateBase {
protected:
void validate() const override {
auto Op = Ops[0];
SPIRVInstruction::validate();
if (getValue(Op)->isForward())
return;
if (isGenericNegateOpCode(OpCode)) {
SPIRVType *ResTy =
Type->isTypeVector() || Type->isTypeCooperativeMatrixKHR()
? Type->getVectorComponentType()
: Type;
SPIRVType *OpTy =
Type->isTypeVector() || Type->isTypeCooperativeMatrixKHR()
? getValueType(Op)->getVectorComponentType()
: getValueType(Op);
(void)ResTy;
(void)OpTy;
assert(getType() == getValueType(Op) && "Inconsistent type");
assert((ResTy->isTypeInt() || ResTy->isTypeFloat()) &&
"Invalid type for Generic Negate instruction");
assert((ResTy->getBitWidth() == OpTy->getBitWidth()) &&
"Invalid bitwidth for Generic Negate instruction");
assert((Type->isTypeVector()
? (Type->getVectorComponentCount() ==
getValueType(Op)->getVectorComponentCount())
: 1) &&
"Invalid vector component Width for Generic Negate instruction");
}
}
};
template <Op OC>
class SPIRVUnaryInst
: public SPIRVInstTemplate<SPIRVUnary, OC, true, 4, false> {};
#define _SPIRV_OP(x) typedef SPIRVUnaryInst<Op##x> SPIRV##x;
_SPIRV_OP(ConvertFToU)
_SPIRV_OP(ConvertFToS)
_SPIRV_OP(ConvertSToF)
_SPIRV_OP(ConvertUToF)
_SPIRV_OP(UConvert)
_SPIRV_OP(SConvert)
_SPIRV_OP(FConvert)
_SPIRV_OP(SatConvertSToU)
_SPIRV_OP(SatConvertUToS)
_SPIRV_OP(ConvertPtrToU)
_SPIRV_OP(ConvertUToPtr)
_SPIRV_OP(PtrCastToGeneric)
_SPIRV_OP(GenericCastToPtr)
_SPIRV_OP(CrossWorkgroupCastToPtrINTEL)
_SPIRV_OP(PtrCastToCrossWorkgroupINTEL)
_SPIRV_OP(Bitcast)
_SPIRV_OP(SNegate)
_SPIRV_OP(FNegate)
_SPIRV_OP(Not)
_SPIRV_OP(LogicalNot)
_SPIRV_OP(IsNan)
_SPIRV_OP(IsInf)
_SPIRV_OP(IsFinite)
_SPIRV_OP(IsNormal)
_SPIRV_OP(SignBitSet)
_SPIRV_OP(Any)
_SPIRV_OP(All)
_SPIRV_OP(BitCount)
_SPIRV_OP(ArithmeticFenceEXT)
#undef _SPIRV_OP
class SPIRVAccessChainBase : public SPIRVInstTemplateBase {
public:
SPIRVValue *getBase() {
if (this->isUntyped())
return this->getValue(this->Ops[1]);
return this->getValue(this->Ops[0]);
}
SPIRVType *getBaseType() {
if (this->isUntyped())
return get<SPIRVType>(this->Ops[0]);
return this->getValue(this->Ops[0])->getType();
}
std::vector<SPIRVValue *> getIndices() const {
unsigned IdxShift = this->isUntyped() ? 2 : 1;
std::vector<SPIRVWord> IndexWords(this->Ops.begin() + IdxShift,
this->Ops.end());
return this->getValues(IndexWords);
}
bool isInBounds() {
return OpCode == OpInBoundsAccessChain ||
OpCode == OpInBoundsPtrAccessChain ||
OpCode == OpUntypedInBoundsAccessChainKHR ||
OpCode == OpUntypedInBoundsPtrAccessChainKHR;
}
bool hasPtrIndex() {
return OpCode == OpPtrAccessChain || OpCode == OpInBoundsPtrAccessChain ||
OpCode == OpUntypedPtrAccessChainKHR ||
OpCode == OpUntypedInBoundsPtrAccessChainKHR;
}
bool isUntyped() const {
return OpCode == OpUntypedAccessChainKHR ||
OpCode == OpUntypedInBoundsAccessChainKHR ||
OpCode == OpUntypedPtrAccessChainKHR ||
OpCode == OpUntypedInBoundsPtrAccessChainKHR;
}
SPIRVCapVec getRequiredCapability() const override {
if (isUntyped())
return getVec(CapabilityUntypedPointersKHR);
return {};
}
std::optional<ExtensionID> getRequiredExtension() const override {
if (isUntyped())
return ExtensionID::SPV_KHR_untyped_pointers;
return {};
}
};
template <Op OC, unsigned FixedWC>
class SPIRVAccessChainGeneric
: public SPIRVInstTemplate<SPIRVAccessChainBase, OC, true, FixedWC, true> {
};
typedef SPIRVAccessChainGeneric<OpAccessChain, 4> SPIRVAccessChain;
typedef SPIRVAccessChainGeneric<OpInBoundsAccessChain, 4>
SPIRVInBoundsAccessChain;
typedef SPIRVAccessChainGeneric<OpPtrAccessChain, 5> SPIRVPtrAccessChain;
typedef SPIRVAccessChainGeneric<OpInBoundsPtrAccessChain, 5>
SPIRVInBoundsPtrAccessChain;
typedef SPIRVAccessChainGeneric<OpUntypedAccessChainKHR, 5>
SPIRVUntypedAccessChainKHR;
typedef SPIRVAccessChainGeneric<OpUntypedInBoundsAccessChainKHR, 5>
SPIRVUntypedInBoundsAccessChainKHR;
typedef SPIRVAccessChainGeneric<OpUntypedPtrAccessChainKHR, 6>
SPIRVUntypedPtrAccessChainKHR;
typedef SPIRVAccessChainGeneric<OpUntypedInBoundsPtrAccessChainKHR, 6>
SPIRVUntypedInBoundsPtrAccessChainKHR;
class SPIRVLoopControlINTEL : public SPIRVInstruction {
public:
static const Op OC = OpLoopControlINTEL;
static const SPIRVWord FixedWordCount = 2;
SPIRVLoopControlINTEL(SPIRVWord TheLoopControl,
std::vector<SPIRVWord> TheLoopControlParameters,
SPIRVBasicBlock *BB)
: SPIRVInstruction(FixedWordCount + TheLoopControlParameters.size(), OC,
BB),
LoopControl(TheLoopControl),
LoopControlParameters(TheLoopControlParameters) {
validate();
assert(BB && "Invalid BB");
}
SPIRVLoopControlINTEL() : SPIRVInstruction(OC), LoopControl(SPIRVWORD_MAX) {
setHasNoId();
setHasNoType();
}
SPIRVWord getLoopControl() const { return LoopControl; }
std::vector<SPIRVWord> getLoopControlParameters() const {
return LoopControlParameters;
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityUnstructuredLoopControlsINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_unstructured_loop_controls;
}
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
SPIRVCK(TheWordCount >= FixedWordCount, InvalidWordCount, "");
LoopControlParameters.resize(TheWordCount - FixedWordCount);
}
_SPIRV_DEF_ENCDEC2(LoopControl, LoopControlParameters)
protected:
SPIRVWord LoopControl;
std::vector<SPIRVWord> LoopControlParameters;
};
template <Op OC, SPIRVWord FixedWordCount>
class SPIRVFunctionCallGeneric : public SPIRVInstruction {
public:
SPIRVFunctionCallGeneric(SPIRVType *TheType, SPIRVId TheId,
const std::vector<SPIRVWord> &TheArgs,
SPIRVBasicBlock *BB)
: SPIRVInstruction(TheArgs.size() + FixedWordCount, OC, TheType, TheId,
BB),
Args(TheArgs) {
SPIRVFunctionCallGeneric::validate();
assert(BB && "Invalid BB");
}
SPIRVFunctionCallGeneric(SPIRVType *TheType, SPIRVId TheId,
const std::vector<SPIRVValue *> &TheArgs,
SPIRVBasicBlock *BB)
: SPIRVInstruction(TheArgs.size() + FixedWordCount, OC, TheType, TheId,
BB) {
Args = getIds(TheArgs);
SPIRVFunctionCallGeneric::validate();
assert(BB && "Invalid BB");
}
SPIRVFunctionCallGeneric(SPIRVModule *BM, SPIRVWord ResId, SPIRVType *TheType,
const std::vector<SPIRVWord> &TheArgs)
: SPIRVInstruction(TheArgs.size() + FixedWordCount, OC, TheType, ResId,
BM),
Args(TheArgs) {}
SPIRVFunctionCallGeneric() : SPIRVInstruction(OC) {}
const std::vector<SPIRVWord> &getArguments() const { return Args; }
void setArguments(const std::vector<SPIRVWord> &A) {
Args = A;
setWordCount(Args.size() + FixedWordCount);
}
std::vector<SPIRVValue *> getArgumentValues() { return getValues(Args); }
std::vector<SPIRVType *> getArgumentValueTypes() const {
std::vector<SPIRVType *> ArgTypes;
for (auto &I : Args)
ArgTypes.push_back(getValue(I)->getType());
return ArgTypes;
}
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
SPIRVCK(TheWordCount >= FixedWordCount, InvalidWordCount, "");
Args.resize(TheWordCount - FixedWordCount);
}
void validate() const override { SPIRVInstruction::validate(); }
protected:
std::vector<SPIRVWord> Args;
};
class SPIRVFunctionCall : public SPIRVFunctionCallGeneric<OpFunctionCall, 4> {
public:
SPIRVFunctionCall(SPIRVId TheId, SPIRVFunction *TheFunction,
const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB);
SPIRVFunctionCall() : FunctionId(SPIRVID_INVALID) {}
SPIRVFunction *getFunction() const { return get<SPIRVFunction>(FunctionId); }
_SPIRV_DEF_ENCDEC4(Type, Id, FunctionId, Args)
void validate() const override;
bool isOperandLiteral(unsigned Index) const override { return false; }
protected:
SPIRVId FunctionId;
};
class SPIRVFunctionPointerCallINTEL
: public SPIRVFunctionCallGeneric<OpFunctionPointerCallINTEL, 4> {
public:
SPIRVFunctionPointerCallINTEL(SPIRVId TheId, SPIRVValue *TheCalledValue,
SPIRVType *TheReturnType,
const std::vector<SPIRVWord> &TheArgs,
SPIRVBasicBlock *BB);
SPIRVFunctionPointerCallINTEL() : CalledValueId(SPIRVID_INVALID) {}
SPIRVValue *getCalledValue() const { return get<SPIRVValue>(CalledValueId); }
_SPIRV_DEF_ENCDEC4(Type, Id, CalledValueId, Args)
void validate() const override;
bool isOperandLiteral(unsigned Index) const override { return false; }
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_function_pointers;
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityFunctionPointersINTEL);
}
protected:
SPIRVId CalledValueId;
};
class SPIRVExtInst : public SPIRVFunctionCallGeneric<OpExtInst, 5> {
public:
SPIRVExtInst(SPIRVType *TheType, SPIRVId TheId, SPIRVId TheBuiltinSet,
SPIRVWord TheEntryPoint, const std::vector<SPIRVWord> &TheArgs,
SPIRVBasicBlock *BB)
: SPIRVFunctionCallGeneric(TheType, TheId, TheArgs, BB),
ExtSetId(TheBuiltinSet), ExtOp(TheEntryPoint) {
setExtSetKindById();
SPIRVExtInst::validate();
}
SPIRVExtInst(SPIRVType *TheType, SPIRVId TheId, SPIRVId TheBuiltinSet,
SPIRVWord TheEntryPoint,
const std::vector<SPIRVValue *> &TheArgs, SPIRVBasicBlock *BB)
: SPIRVFunctionCallGeneric(TheType, TheId, TheArgs, BB),
ExtSetId(TheBuiltinSet), ExtOp(TheEntryPoint) {
setExtSetKindById();
SPIRVExtInst::validate();
}
SPIRVExtInst(SPIRVModule *BM, SPIRVId ResId, SPIRVType *TheType,
SPIRVExtInstSetKind SetKind, SPIRVWord SetId, SPIRVWord InstId,
const std::vector<SPIRVWord> &Args)
: SPIRVFunctionCallGeneric(BM, ResId, TheType, Args), ExtSetKind(SetKind),
ExtSetId(SetId), ExtOp(InstId) {}
SPIRVExtInst(SPIRVExtInstSetKind SetKind = SPIRVEIS_Count,
unsigned ExtOC = SPIRVWORD_MAX)
: ExtSetKind(SetKind), ExtSetId(SPIRVWORD_MAX), ExtOp(ExtOC) {}
void setExtSetId(unsigned Set) { ExtSetId = Set; }
void setExtOp(unsigned ExtOC) { ExtOp = ExtOC; }
SPIRVId getExtSetId() const { return ExtSetId; }
SPIRVWord getExtOp() const { return ExtOp; }
SPIRVExtInstSetKind getExtSetKind() const { return ExtSetKind; }
void addContinuedInstruction(SPIRVExtInst *Inst) {
ContinuedInstructions.push_back(Inst);
}
std::vector<SPIRVExtInst *> getContinuedInstructions() {
return ContinuedInstructions;
}
void setExtSetKindById() {
assert(Module && "Invalid module");
ExtSetKind = Module->getBuiltinSet(ExtSetId);
assert((ExtSetKind == SPIRVEIS_OpenCL || ExtSetKind == SPIRVEIS_Debug ||
ExtSetKind == SPIRVEIS_OpenCL_DebugInfo_100 ||
ExtSetKind == SPIRVEIS_NonSemantic_Shader_DebugInfo_100 ||
ExtSetKind == SPIRVEIS_NonSemantic_Shader_DebugInfo_200 ||
ExtSetKind == SPIRVEIS_NonSemantic_AuxData ||
ExtSetKind == SPIRVEIS_NonSemantic_Unknown) &&
"not supported");
}
void encode(spv_ostream &O) const override {
getEncoder(O) << Type << Id << ExtSetId;
switch (ExtSetKind) {
case SPIRVEIS_OpenCL:
getEncoder(O) << ExtOpOCL;
break;
case SPIRVEIS_Debug:
case SPIRVEIS_OpenCL_DebugInfo_100:
case SPIRVEIS_NonSemantic_Shader_DebugInfo_100:
case SPIRVEIS_NonSemantic_Shader_DebugInfo_200:
getEncoder(O) << ExtOpDebug;
break;
case SPIRVEIS_NonSemantic_AuxData:
getEncoder(O) << ExtOpNonSemanticAuxData;
break;
case SPIRVEIS_NonSemantic_Unknown:
getEncoder(O) << ExtOp;
break;
default:
assert(0 && "not supported");
getEncoder(O) << ExtOp;
}
getEncoder(O) << Args;
}
void decode(std::istream &I) override {
getDecoder(I) >> Type >> Id >> ExtSetId;
setExtSetKindById();
switch (ExtSetKind) {
case SPIRVEIS_OpenCL:
getDecoder(I) >> ExtOpOCL;
break;
case SPIRVEIS_Debug:
case SPIRVEIS_OpenCL_DebugInfo_100:
case SPIRVEIS_NonSemantic_Shader_DebugInfo_100:
case SPIRVEIS_NonSemantic_Shader_DebugInfo_200:
getDecoder(I) >> ExtOpDebug;
break;
case SPIRVEIS_NonSemantic_AuxData:
getDecoder(I) >> ExtOpNonSemanticAuxData;
break;
case SPIRVEIS_NonSemantic_Unknown:
getDecoder(I) >> ExtOp;
break;
default:
assert(0 && "not supported");
getDecoder(I) >> ExtOp;
}
SPIRVDecoder Decoder = getDecoder(I);
Decoder >> Args;
if (ExtSetKind == SPIRVEIS_NonSemantic_Shader_DebugInfo_100 ||
ExtSetKind == SPIRVEIS_NonSemantic_Shader_DebugInfo_200) {
if (getExtOp() == SPIRVDebug::Instruction::Source) {
for (SPIRVEntry *E : Decoder.getSourceContinuedInstructions()) {
addContinuedInstruction(static_cast<SPIRVExtInst *>(E));
}
}
}
}
void validate() const override {
SPIRVFunctionCallGeneric::validate();
validateBuiltin(ExtSetId, ExtOp);
}
bool isOperandLiteral(unsigned Index) const override {
assert(ExtSetKind == SPIRVEIS_OpenCL &&
"Unsupported extended instruction set");
auto EOC = static_cast<OCLExtOpKind>(ExtOp);
switch (EOC) {
default:
return false;
case OpenCLLIB::Vloadn:
case OpenCLLIB::Vload_halfn:
case OpenCLLIB::Vloada_halfn:
return Index == 2;
case OpenCLLIB::Vstore_half_r:
case OpenCLLIB::Vstore_halfn_r:
case OpenCLLIB::Vstorea_halfn_r:
return Index == 3;
}
}
std::vector<SPIRVValue *> getArgValues() {
std::vector<SPIRVValue *> VArgs;
for (size_t I = 0; I < Args.size(); ++I)
VArgs.push_back(getArgValue(I));
return VArgs;
}
SPIRVValue *getArgValue(SPIRVWord I) {
if (isOperandLiteral(I))
return Module->getLiteralAsConstant(Args[I]);
return getValue(Args[I]);
}
std::vector<SPIRVType *> getArgTypes() {
std::vector<SPIRVType *> ArgTypes;
auto VArgs = getArgValues();
for (auto VArg : VArgs)
ArgTypes.push_back(VArg->getType());
return ArgTypes;
}
std::optional<ExtensionID> getRequiredExtension() const override {
if (ExtSetKind == SPIRVEIS_NonSemantic_Unknown ||
SPIRVBuiltinSetNameMap::map(ExtSetKind).find("NonSemantic.") == 0) {
if (!Module->isAllowedToUseVersion(VersionNumber::SPIRV_1_6))
return ExtensionID::SPV_KHR_non_semantic_info;
}
return {};
}
protected:
SPIRVExtInstSetKind ExtSetKind;
SPIRVId ExtSetId;
union {
SPIRVWord ExtOp;
OCLExtOpKind ExtOpOCL;
SPIRVDebugExtOpKind ExtOpDebug;
NonSemanticAuxDataOpKind ExtOpNonSemanticAuxData;
};
std::vector<SPIRVExtInst *> ContinuedInstructions;
};
class SPIRVCompositeConstruct : public SPIRVInstruction {
public:
const static Op OC = OpCompositeConstruct;
const static SPIRVWord FixedWordCount = 3;
// Complete constructor
SPIRVCompositeConstruct(SPIRVType *TheType, SPIRVId TheId,
const std::vector<SPIRVId> &TheConstituents,
SPIRVBasicBlock *TheBB)
: SPIRVInstruction(TheConstituents.size() + FixedWordCount, OC, TheType,
TheId, TheBB),
Constituents(TheConstituents) {
validate();
assert(TheBB && "Invalid BB");
}
// Incomplete constructor
SPIRVCompositeConstruct() : SPIRVInstruction(OC) {}
std::vector<SPIRVValue *> getOperands() override {
return getValues(Constituents);
}
protected:
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
SPIRVCK(TheWordCount >= FixedWordCount, InvalidWordCount, "");
Constituents.resize(TheWordCount - FixedWordCount);
}
_SPIRV_DEF_ENCDEC3(Type, Id, Constituents)
void validate() const override {
SPIRVInstruction::validate();
size_t TypeOpCode = this->getType()->getOpCode();
switch (TypeOpCode) {
case OpTypeVector:
assert(Constituents.size() > 1 &&
"There must be at least two Constituent operands in vector");
break;
case OpTypeArray:
case OpTypeStruct:
case OpTypeCooperativeMatrixKHR:
break;
default:
assert(false && "Invalid type");
}
}
std::vector<SPIRVId> Constituents;
};
class SPIRVCompositeExtractBase : public SPIRVInstTemplateBase {
public:
SPIRVValue *getComposite() { return getValue(Ops[0]); }
const std::vector<SPIRVWord> getIndices() const {
return std::vector<SPIRVWord>(Ops.begin() + 1, Ops.end());
}
protected:
// ToDo: validate the result type is consistent with the base type and indices
// need to trace through the base type for struct types
void validate() const override {
SPIRVInstruction::validate();
assert(OpCode == OpCompositeExtract);
SPIRVId Composite = Ops[0];
(void)Composite;
assert(getValueType(Composite)->isTypeArray() ||
getValueType(Composite)->isTypeStruct() ||
getValueType(Composite)->isTypeVector() ||
getValueType(Composite)->isTypeUntypedPointerKHR());
}
};
typedef SPIRVInstTemplate<SPIRVCompositeExtractBase, OpCompositeExtract, true,
4, true>
SPIRVCompositeExtract;
class SPIRVCompositeInsertBase : public SPIRVInstTemplateBase {
public:
SPIRVValue *getObject() { return getValue(Ops[0]); }
SPIRVValue *getComposite() { return getValue(Ops[1]); }
const std::vector<SPIRVWord> getIndices() const {
return std::vector<SPIRVWord>(Ops.begin() + 2, Ops.end());
}
protected:
// ToDo: validate the object type is consistent with the base type and indices
// need to trace through the base type for struct types
void validate() const override {
SPIRVInstruction::validate();
assert(OpCode == OpCompositeInsert);
SPIRVId Composite = Ops[1];
(void)Composite;
assert(getValueType(Composite)->isTypeArray() ||
getValueType(Composite)->isTypeStruct() ||
getValueType(Composite)->isTypeVector() ||
getValueType(Composite)->isTypeUntypedPointerKHR());
assert(Type == getValueType(Composite));
}
};
typedef SPIRVInstTemplate<SPIRVCompositeInsertBase, OpCompositeInsert, true, 5,
true>
SPIRVCompositeInsert;
class SPIRVCopyObject : public SPIRVInstruction {
public:
const static Op OC = OpCopyObject;
// Complete constructor
SPIRVCopyObject(SPIRVType *TheType, SPIRVId TheId, SPIRVValue *TheOperand,
SPIRVBasicBlock *TheBB)
: SPIRVInstruction(4, OC, TheType, TheId, TheBB),
Operand(TheOperand->getId()) {
validate();
assert(TheBB && "Invalid BB");
}
// Incomplete constructor
SPIRVCopyObject() : SPIRVInstruction(OC), Operand(SPIRVID_INVALID) {}
SPIRVValue *getOperand() { return getValue(Operand); }
protected:
_SPIRV_DEF_ENCDEC3(Type, Id, Operand)
void validate() const override { SPIRVInstruction::validate(); }
SPIRVId Operand;
};
class SPIRVCopyLogical : public SPIRVInstruction {
public:
const static Op OC = OpCopyLogical;
// Complete constructor
SPIRVCopyLogical(SPIRVType *TheType, SPIRVId TheId, SPIRVValue *TheOperand,
SPIRVBasicBlock *TheBB)
: SPIRVInstruction(4, OC, TheType, TheId, TheBB),
Operand(TheOperand->getId()) {
validate();
assert(TheBB && "Invalid BB");
}
// Incomplete constructor
SPIRVCopyLogical() : SPIRVInstruction(OC), Operand(SPIRVID_INVALID) {}
SPIRVValue *getOperand() { return getValue(Operand); }
std::vector<SPIRVValue *> getOperands() override { return {getOperand()}; }
protected:
_SPIRV_DEF_ENCDEC3(Type, Id, Operand)
void validate() const override { SPIRVInstruction::validate(); }
SPIRVId Operand;
};
class SPIRVCopyMemory : public SPIRVInstruction, public SPIRVMemoryAccess {
public:
const static Op OC = OpCopyMemory;
const static SPIRVWord FixedWords = 3;
// Complete constructor
SPIRVCopyMemory(SPIRVValue *TheTarget, SPIRVValue *TheSource,
const std::vector<SPIRVWord> &TheMemoryAccess,
SPIRVBasicBlock *TheBB)
: SPIRVInstruction(FixedWords + TheMemoryAccess.size(), OC, TheBB),
SPIRVMemoryAccess(TheMemoryAccess), MemoryAccess(TheMemoryAccess),
Target(TheTarget->getId()), Source(TheSource->getId()) {
validate();
assert(TheBB && "Invalid BB");
}
// Incomplete constructor
SPIRVCopyMemory()
: SPIRVInstruction(OC), SPIRVMemoryAccess(), Target(SPIRVID_INVALID),
Source(SPIRVID_INVALID) {
setHasNoId();
setHasNoType();
}
SPIRVValue *getSource() { return getValue(Source); }
SPIRVValue *getTarget() { return getValue(Target); }
protected:
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
SPIRVCK(TheWordCount >= FixedWords, InvalidWordCount, "");
MemoryAccess.resize(TheWordCount - FixedWords);
}
void encode(spv_ostream &O) const override {
getEncoder(O) << Target << Source << MemoryAccess;
}
void decode(std::istream &I) override {
getDecoder(I) >> Target >> Source >> MemoryAccess;
memoryAccessUpdate(MemoryAccess);
}
void validate() const override {
assert(getValueType(Target)->isTypePointer() && "Invalid Target type");
assert(getValueType(Source)->isTypePointer() && "Invalid Source type");
assert(!(getValueType(Target)->getPointerElementType()->isTypeVoid()) &&
"Invalid Target element type");
assert(!(getValueType(Source)->getPointerElementType()->isTypeVoid()) &&
"Invalid Source element type");
assert(getValueType(Target)->getPointerElementType() ==
getValueType(Source)->getPointerElementType() &&
"Mismatching Target and Source element types");
SPIRVInstruction::validate();
}
std::vector<SPIRVWord> MemoryAccess;
SPIRVId Target;
SPIRVId Source;
};
class SPIRVCopyMemorySized : public SPIRVInstruction, public SPIRVMemoryAccess {
public:
const static Op OC = OpCopyMemorySized;
const static SPIRVWord FixedWords = 4;
// Complete constructor
SPIRVCopyMemorySized(SPIRVValue *TheTarget, SPIRVValue *TheSource,
SPIRVValue *TheSize,
const std::vector<SPIRVWord> &TheMemoryAccess,
SPIRVBasicBlock *TheBB)
: SPIRVInstruction(FixedWords + TheMemoryAccess.size(), OC, TheBB),
SPIRVMemoryAccess(TheMemoryAccess), MemoryAccess(TheMemoryAccess),
Target(TheTarget->getId()), Source(TheSource->getId()),
Size(TheSize->getId()) {
validate();
assert(TheBB && "Invalid BB");
updateModuleVersion();
}
// Incomplete constructor
SPIRVCopyMemorySized()
: SPIRVInstruction(OC), SPIRVMemoryAccess(), Target(SPIRVID_INVALID),
Source(SPIRVID_INVALID), Size(0) {
setHasNoId();
setHasNoType();
updateModuleVersion();
}
VersionNumber getRequiredSPIRVVersion() const override {
if (getSrcAlignment())
return VersionNumber::SPIRV_1_4;
return VersionNumber::SPIRV_1_0;
}
SPIRVValue *getSource() { return getValue(Source); }
SPIRVValue *getTarget() { return getValue(Target); }
SPIRVValue *getSize() { return getValue(Size); }
protected:
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
SPIRVCK(TheWordCount >= FixedWords, InvalidWordCount, "");
MemoryAccess.resize(TheWordCount - FixedWords);
}
void encode(spv_ostream &O) const override {
getEncoder(O) << Target << Source << Size << MemoryAccess;
}
void decode(std::istream &I) override {
getDecoder(I) >> Target >> Source >> Size >> MemoryAccess;
memoryAccessUpdate(MemoryAccess);
}
void validate() const override { SPIRVInstruction::validate(); }
std::vector<SPIRVWord> MemoryAccess;
SPIRVId Target;
SPIRVId Source;
SPIRVId Size;
};
class SPIRVVectorExtractDynamic : public SPIRVInstruction {
public:
const static Op OC = OpVectorExtractDynamic;
// Complete constructor
SPIRVVectorExtractDynamic(SPIRVId TheId, SPIRVValue *TheVector,
SPIRVValue *TheIndex, SPIRVBasicBlock *TheBB)
: SPIRVInstruction(5, OC, TheVector->getType()->getVectorComponentType(),
TheId, TheBB),
VectorId(TheVector->getId()), IndexId(TheIndex->getId()) {
validate();
assert(TheBB && "Invalid BB");
}
// Incomplete constructor
SPIRVVectorExtractDynamic()
: SPIRVInstruction(OC), VectorId(SPIRVID_INVALID),
IndexId(SPIRVID_INVALID) {}
SPIRVValue *getVector() { return getValue(VectorId); }
SPIRVValue *getIndex() const { return getValue(IndexId); }
std::vector<SPIRVValue *> getOperands() override {
return {getVector(), getIndex()};
}
protected:
_SPIRV_DEF_ENCDEC4(Type, Id, VectorId, IndexId)
void validate() const override {
SPIRVInstruction::validate();
if (getValue(VectorId)->isForward())
return;
assert(getValueType(VectorId)->isTypeVector());
}
SPIRVId VectorId;
SPIRVId IndexId;
};
class SPIRVVectorInsertDynamic : public SPIRVInstruction {
public:
const static Op OC = OpVectorInsertDynamic;
// Complete constructor
SPIRVVectorInsertDynamic(SPIRVId TheId, SPIRVValue *TheVector,
SPIRVValue *TheComponent, SPIRVValue *TheIndex,
SPIRVBasicBlock *TheBB)
: SPIRVInstruction(6, OC, TheVector->getType(), TheId, TheBB),
VectorId(TheVector->getId()), IndexId(TheIndex->getId()),
ComponentId(TheComponent->getId()) {
validate();
assert(TheBB && "Invalid BB");
}
// Incomplete constructor
SPIRVVectorInsertDynamic()
: SPIRVInstruction(OC), VectorId(SPIRVID_INVALID),
IndexId(SPIRVID_INVALID), ComponentId(SPIRVID_INVALID) {}
SPIRVValue *getVector() { return getValue(VectorId); }
SPIRVValue *getComponent() { return getValue(ComponentId); }
SPIRVValue *getIndex() const { return getValue(IndexId); }
std::vector<SPIRVValue *> getOperands() override {
return {getVector(), getComponent(), getIndex()};
}
protected:
_SPIRV_DEF_ENCDEC5(Type, Id, VectorId, ComponentId, IndexId)
void validate() const override {
SPIRVInstruction::validate();
if (getValue(VectorId)->isForward())
return;
assert(getValueType(VectorId)->isTypeVector());
}
SPIRVId VectorId;
SPIRVId IndexId;
SPIRVId ComponentId;
};
class SPIRVVectorShuffleBase : public SPIRVInstTemplateBase {
public:
SPIRVValue *getVector1() { return getValue(Ops[0]); }
SPIRVValue *getVector2() { return getValue(Ops[1]); }
const std::vector<SPIRVWord> getComponents() const {
return std::vector<SPIRVWord>(Ops.begin() + 2, Ops.end());
}
protected:
void validate() const override {
SPIRVInstruction::validate();
[[maybe_unused]] SPIRVId Vector1 = Ops[0];
assert(OpCode == OpVectorShuffle);
assert(Type->isTypeVector());
assert(Type->getVectorComponentType() ==
getValueType(Vector1)->getVectorComponentType());
assert(Ops.size() - 2 == Type->getVectorComponentCount());
}
};
typedef SPIRVInstTemplate<SPIRVVectorShuffleBase, OpVectorShuffle, true, 5,
true>
SPIRVVectorShuffle;
class SPIRVControlBarrier : public SPIRVInstruction {
public:
static const Op OC = OpControlBarrier;
// Complete constructor
SPIRVControlBarrier(SPIRVValue *TheScope, SPIRVValue *TheMemScope,
SPIRVValue *TheMemSema, SPIRVBasicBlock *TheBB)
: SPIRVInstruction(4, OC, TheBB), ExecScope(TheScope->getId()),
MemScope(TheMemScope->getId()), MemSema(TheMemSema->getId()) {
validate();
assert(TheBB && "Invalid BB");
}
// Incomplete constructor
SPIRVControlBarrier() : SPIRVInstruction(OC), ExecScope(ScopeInvocation) {
setHasNoId();
setHasNoType();
}
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
}
SPIRVValue *getExecScope() const { return getValue(ExecScope); }
SPIRVValue *getMemScope() const { return getValue(MemScope); }
SPIRVValue *getMemSemantic() const { return getValue(MemSema); }
std::vector<SPIRVValue *> getOperands() override {
std::vector<SPIRVId> Operands;
Operands.push_back(ExecScope);
Operands.push_back(MemScope);
Operands.push_back(MemSema);
return getValues(Operands);
}
SPIRVCapVec getRequiredCapability() const override {
if (isDeviceBarrier()) {
return getVec(internal::CapabilityDeviceBarrierINTEL);
}
return SPIRVInstruction::getRequiredCapability();
}
std::optional<ExtensionID> getRequiredExtension() const override {
if (isDeviceBarrier()) {
return ExtensionID::SPV_INTEL_device_barrier;
}
return std::nullopt;
}
protected:
_SPIRV_DEF_ENCDEC3(ExecScope, MemScope, MemSema)
void validate() const override {
assert(OpCode == OC);
assert(WordCount == 4);
SPIRVInstruction::validate();
}
bool isDeviceBarrier() const {
if (!getModule()->isAllowedToUseExtension(
ExtensionID::SPV_INTEL_device_barrier))
return false;
SPIRVValue *ESV = getValue(ExecScope);
if (ESV && ESV->getOpCode() == OpConstant) {
if (static_cast<SPIRVConstant *>(ESV)->getZExtIntValue() != ScopeDevice) {
return false;
}
}
return true;
}
SPIRVId ExecScope;
SPIRVId MemScope = SPIRVID_INVALID;
SPIRVId MemSema = SPIRVID_INVALID;
};
template <Op OC> class SPIRVLifetime : public SPIRVInstruction {
public:
// Complete constructor
SPIRVLifetime(SPIRVId TheObject, SPIRVWord TheSize, SPIRVBasicBlock *TheBB)
: SPIRVInstruction(3, OC, TheBB), Object(TheObject), Size(TheSize) {
auto ObjType = getValue(Object)->getType();
// Size must be 0 if Pointer is a pointer to a non-void type or the
// Addresses capability is not being used. If Size is non-zero, it is the
// number of bytes of memory whose lifetime is starting. Its type must be an
// integer type scalar. It is treated as unsigned; if its type has
// Signedness of 1, its sign bit cannot be set.
if (!(ObjType->getPointerElementType()->isTypeVoid() ||
// (void *) is i8* in LLVM IR
ObjType->getPointerElementType()->isTypeInt(8) ||
ObjType->getPointerElementType()->isTypeUntypedPointerKHR()) ||
!Module->hasCapability(CapabilityAddresses))
Size = 0;
validate();
assert(TheBB && "Invalid BB");
}
// Incomplete constructor
SPIRVLifetime()
: SPIRVInstruction(OC), Object(SPIRVID_INVALID), Size(SPIRVWORD_MAX) {
setHasNoId();
setHasNoType();
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityKernel);
}
SPIRVValue *getObject() { return getValue(Object); }
SPIRVWord getSize() { return Size; }
protected:
void validate() const override {
[[maybe_unused]] auto ObjType = getValue(Object)->getType();
// Type must be an OpTypePointer with Storage Class Function.
assert(ObjType->isTypePointer() && "Objects type must be a pointer");
assert(static_cast<SPIRVTypePointer *>(ObjType)->getStorageClass() ==
StorageClassFunction &&
"Invalid storage class");
}
_SPIRV_DEF_ENCDEC2(Object, Size)
SPIRVId Object;
SPIRVWord Size;
};
typedef SPIRVLifetime<OpLifetimeStart> SPIRVLifetimeStart;
typedef SPIRVLifetime<OpLifetimeStop> SPIRVLifetimeStop;
class SPIRVGroupAsyncCopy : public SPIRVInstruction {
public:
static const Op OC = OpGroupAsyncCopy;
static const SPIRVWord WC = 9;
// Complete constructor
SPIRVGroupAsyncCopy(SPIRVValue *TheScope, SPIRVId TheId, SPIRVValue *TheDest,
SPIRVValue *TheSrc, SPIRVValue *TheNumElems,
SPIRVValue *TheStride, SPIRVValue *TheEvent,
SPIRVBasicBlock *TheBB)
: SPIRVInstruction(WC, OC, TheEvent->getType(), TheId, TheBB),
ExecScope(TheScope->getId()), Destination(TheDest->getId()),
Source(TheSrc->getId()), NumElements(TheNumElems->getId()),
Stride(TheStride->getId()), Event(TheEvent->getId()) {
validate();
assert(TheBB && "Invalid BB");
}
// Incomplete constructor
SPIRVGroupAsyncCopy()
: SPIRVInstruction(OC), ExecScope(SPIRVID_INVALID),
Destination(SPIRVID_INVALID), Source(SPIRVID_INVALID),
NumElements(SPIRVID_INVALID), Stride(SPIRVID_INVALID),
Event(SPIRVID_INVALID) {}
SPIRVValue *getExecScope() const { return getValue(ExecScope); }
SPIRVValue *getDestination() const { return getValue(Destination); }
SPIRVValue *getSource() const { return getValue(Source); }
SPIRVValue *getNumElements() const { return getValue(NumElements); }
SPIRVValue *getStride() const { return getValue(Stride); }
SPIRVValue *getEvent() const { return getValue(Event); }
std::vector<SPIRVValue *> getOperands() override {
std::vector<SPIRVId> Operands;
Operands.push_back(ExecScope);
Operands.push_back(Destination);
Operands.push_back(Source);
Operands.push_back(NumElements);
Operands.push_back(Stride);
Operands.push_back(Event);
return getValues(Operands);
}
protected:
_SPIRV_DEF_ENCDEC8(Type, Id, ExecScope, Destination, Source, NumElements,
Stride, Event)
void validate() const override {
assert(OpCode == OC);
assert(WordCount == WC);
SPIRVInstruction::validate();
}
SPIRVId ExecScope;
SPIRVId Destination;
SPIRVId Source;
SPIRVId NumElements;
SPIRVId Stride;
SPIRVId Event;
};
enum SPIRVOpKind { SPIRVOPK_Id, SPIRVOPK_Literal, SPIRVOPK_Count };
class SPIRVDevEnqInstBase : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityDeviceEnqueue);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVDevEnqInstBase, Op##x, __VA_ARGS__> SPIRV##x;
// CL 2.0 enqueue kernel builtins
_SPIRV_OP(EnqueueMarker, true, 7)
_SPIRV_OP(EnqueueKernel, true, 13, true)
_SPIRV_OP(GetKernelNDrangeSubGroupCount, true, 8)
_SPIRV_OP(GetKernelNDrangeMaxSubGroupSize, true, 8)
_SPIRV_OP(GetKernelWorkGroupSize, true, 7)
_SPIRV_OP(GetKernelPreferredWorkGroupSizeMultiple, true, 7)
_SPIRV_OP(RetainEvent, false, 2)
_SPIRV_OP(ReleaseEvent, false, 2)
_SPIRV_OP(CreateUserEvent, true, 3)
_SPIRV_OP(IsValidEvent, true, 4)
_SPIRV_OP(SetUserEventStatus, false, 3)
_SPIRV_OP(CaptureEventProfilingInfo, false, 4)
_SPIRV_OP(GetDefaultQueue, true, 3)
_SPIRV_OP(BuildNDRange, true, 6)
#undef _SPIRV_OP
class SPIRVPipeInstBase : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityPipes);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVPipeInstBase, Op##x, __VA_ARGS__> SPIRV##x;
// CL 2.0 pipe builtins
_SPIRV_OP(ReadPipe, true, 7)
_SPIRV_OP(WritePipe, true, 7)
_SPIRV_OP(ReservedReadPipe, true, 9)
_SPIRV_OP(ReservedWritePipe, true, 9)
_SPIRV_OP(ReserveReadPipePackets, true, 7)
_SPIRV_OP(ReserveWritePipePackets, true, 7)
_SPIRV_OP(CommitReadPipe, false, 5)
_SPIRV_OP(CommitWritePipe, false, 5)
_SPIRV_OP(IsValidReserveId, true, 4)
_SPIRV_OP(GetNumPipePackets, true, 6)
_SPIRV_OP(GetMaxPipePackets, true, 6)
#undef _SPIRV_OP
class SPIRVPipeStorageInstBase : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityPipeStorage, CapabilityPipes);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVPipeStorageInstBase, Op##x, __VA_ARGS__> \
SPIRV##x;
_SPIRV_OP(CreatePipeFromPipeStorage, true, 4)
#undef _SPIRV_OP
class SPIRVGroupInstBase : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityGroups);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVGroupInstBase, Op##x, __VA_ARGS__> SPIRV##x;
// Group instructions.
// Even though GroupWaitEvents has Group in its name, it doesn't require the
// Group capability
typedef SPIRVInstTemplate<SPIRVInstTemplateBase, OpGroupWaitEvents, false, 4>
SPIRVGroupWaitEvents;
_SPIRV_OP(GroupAll, true, 5)
_SPIRV_OP(GroupAny, true, 5)
_SPIRV_OP(GroupBroadcast, true, 6)
_SPIRV_OP(GroupIAdd, true, 6, false, 1)
_SPIRV_OP(GroupFAdd, true, 6, false, 1)
_SPIRV_OP(GroupFMin, true, 6, false, 1)
_SPIRV_OP(GroupUMin, true, 6, false, 1)
_SPIRV_OP(GroupSMin, true, 6, false, 1)
_SPIRV_OP(GroupFMax, true, 6, false, 1)
_SPIRV_OP(GroupUMax, true, 6, false, 1)
_SPIRV_OP(GroupSMax, true, 6, false, 1)
_SPIRV_OP(GroupReserveReadPipePackets, true, 8)
_SPIRV_OP(GroupReserveWritePipePackets, true, 8)
_SPIRV_OP(GroupCommitReadPipe, false, 6)
_SPIRV_OP(GroupCommitWritePipe, false, 6)
#undef _SPIRV_OP
class SPIRVGroupNonUniformElectInst : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityGroupNonUniform);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVGroupNonUniformElectInst, Op##x, __VA_ARGS__> \
SPIRV##x;
_SPIRV_OP(GroupNonUniformElect, true, 4)
#undef _SPIRV_OP
class SPIRVGroupNonUniformVoteInst : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityGroupNonUniformVote);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVGroupNonUniformVoteInst, Op##x, __VA_ARGS__> \
SPIRV##x;
_SPIRV_OP(GroupNonUniformAll, true, 5)
_SPIRV_OP(GroupNonUniformAny, true, 5)
_SPIRV_OP(GroupNonUniformAllEqual, true, 5)
#undef _SPIRV_OP
class SPIRVGroupNonUniformBallotInst : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityGroupNonUniformBallot);
}
VersionNumber getRequiredSPIRVVersion() const override {
switch (OpCode) {
case OpGroupNonUniformBroadcast: {
assert(Ops.size() == 3 && "Expecting (Execution, Value, Id) operands");
if (!isConstantOpCode(getOperand(2)->getOpCode())) {
// Before version 1.5, Id must come from a constant instruction.
return VersionNumber::SPIRV_1_5;
}
break;
}
default:
break;
}
return VersionNumber::SPIRV_1_3;
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVGroupNonUniformBallotInst, Op##x, \
__VA_ARGS__> \
SPIRV##x;
_SPIRV_OP(GroupNonUniformBroadcast, true, 6)
_SPIRV_OP(GroupNonUniformBroadcastFirst, true, 5)
_SPIRV_OP(GroupNonUniformBallot, true, 5)
_SPIRV_OP(GroupNonUniformInverseBallot, true, 5)
_SPIRV_OP(GroupNonUniformBallotBitExtract, true, 6)
_SPIRV_OP(GroupNonUniformBallotBitCount, true, 6, false, 1)
_SPIRV_OP(GroupNonUniformBallotFindLSB, true, 5)
_SPIRV_OP(GroupNonUniformBallotFindMSB, true, 5)
#undef _SPIRV_OP
class SPIRVGroupNonUniformArithmeticInst : public SPIRVInstTemplateBase {
public:
void setOpWords(const std::vector<SPIRVWord> &Ops) override {
SPIRVInstTemplateBase::setOpWords(Ops);
SPIRVGroupOperationKind GroupOp;
if (getSPIRVGroupOperation(GroupOp)) {
if (GroupOp == GroupOperationClusteredReduce)
Module->addCapability(CapabilityGroupNonUniformClustered);
else
Module->addCapability(CapabilityGroupNonUniformArithmetic);
} else
llvm_unreachable(
"GroupNonUniformArithmeticInst has no group operation operand!");
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVGroupNonUniformArithmeticInst, Op##x, \
__VA_ARGS__> \
SPIRV##x;
_SPIRV_OP(GroupNonUniformIAdd, true, 6, true, 1)
_SPIRV_OP(GroupNonUniformFAdd, true, 6, true, 1)
_SPIRV_OP(GroupNonUniformIMul, true, 6, true, 1)
_SPIRV_OP(GroupNonUniformFMul, true, 6, true, 1)
_SPIRV_OP(GroupNonUniformSMin, true, 6, true, 1)
_SPIRV_OP(GroupNonUniformUMin, true, 6, true, 1)
_SPIRV_OP(GroupNonUniformFMin, true, 6, true, 1)
_SPIRV_OP(GroupNonUniformSMax, true, 6, true, 1)
_SPIRV_OP(GroupNonUniformUMax, true, 6, true, 1)
_SPIRV_OP(GroupNonUniformFMax, true, 6, true, 1)
_SPIRV_OP(GroupNonUniformBitwiseAnd, true, 6, true, 1)
_SPIRV_OP(GroupNonUniformBitwiseOr, true, 6, true, 1)
_SPIRV_OP(GroupNonUniformBitwiseXor, true, 6, true, 1)
_SPIRV_OP(GroupNonUniformLogicalAnd, true, 6, true, 1)
_SPIRV_OP(GroupNonUniformLogicalOr, true, 6, true, 1)
_SPIRV_OP(GroupNonUniformLogicalXor, true, 6, true, 1)
#undef _SPIRV_OP
class SPIRVGroupNonUniformShuffleInst : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityGroupNonUniformShuffle);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVGroupNonUniformShuffleInst, Op##x, \
__VA_ARGS__> \
SPIRV##x;
_SPIRV_OP(GroupNonUniformShuffle, true, 6)
_SPIRV_OP(GroupNonUniformShuffleXor, true, 6)
#undef _SPIRV_OP
class SPIRVGroupNonUniformShuffleRelativeInst : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityGroupNonUniformShuffleRelative);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVGroupNonUniformShuffleRelativeInst, Op##x, \
__VA_ARGS__> \
SPIRV##x;
_SPIRV_OP(GroupNonUniformShuffleUp, true, 6)
_SPIRV_OP(GroupNonUniformShuffleDown, true, 6)
#undef _SPIRV_OP
class SPIRVGroupNonUniformRotateKHRInst : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityGroupNonUniformRotateKHR);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_KHR_subgroup_rotate;
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVGroupNonUniformRotateKHRInst, Op##x, \
__VA_ARGS__> \
SPIRV##x;
_SPIRV_OP(GroupNonUniformRotateKHR, true, 6, true)
#undef _SPIRV_OP
class SPIRVBlockingPipesIntelInst : public SPIRVInstTemplateBase {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityBlockingPipesINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_blocking_pipes;
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVBlockingPipesIntelInst, Op##x, __VA_ARGS__> \
SPIRV##x;
_SPIRV_OP(ReadPipeBlockingINTEL, false, 5)
_SPIRV_OP(WritePipeBlockingINTEL, false, 5)
#undef _SPIRV_OP
class SPIRVFixedPointIntelInst : public SPIRVInstTemplateBase {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityArbitraryPrecisionFixedPointINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_arbitrary_precision_fixed_point;
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVFixedPointIntelInst, Op##x, __VA_ARGS__> \
SPIRV##x;
_SPIRV_OP(FixedSqrtINTEL, true, 9)
_SPIRV_OP(FixedRecipINTEL, true, 9)
_SPIRV_OP(FixedRsqrtINTEL, true, 9)
_SPIRV_OP(FixedSinINTEL, true, 9)
_SPIRV_OP(FixedCosINTEL, true, 9)
_SPIRV_OP(FixedSinCosINTEL, true, 9)
_SPIRV_OP(FixedSinPiINTEL, true, 9)
_SPIRV_OP(FixedCosPiINTEL, true, 9)
_SPIRV_OP(FixedSinCosPiINTEL, true, 9)
_SPIRV_OP(FixedLogINTEL, true, 9)
_SPIRV_OP(FixedExpINTEL, true, 9)
#undef _SPIRV_OP
class SPIRVArbFloatIntelInst : public SPIRVInstTemplateBase {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityArbitraryPrecisionFloatingPointINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_arbitrary_precision_floating_point;
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVArbFloatIntelInst, \
OpArbitraryFloat##x##INTEL, __VA_ARGS__> \
SPIRVArbitraryFloat##x##INTEL;
_SPIRV_OP(Cast, true, 9)
_SPIRV_OP(CastFromInt, true, 9)
_SPIRV_OP(CastToInt, true, 9)
_SPIRV_OP(Add, true, 11)
_SPIRV_OP(Sub, true, 11)
_SPIRV_OP(Mul, true, 11)
_SPIRV_OP(Div, true, 11)
_SPIRV_OP(GT, true, 7)
_SPIRV_OP(GE, true, 7)
_SPIRV_OP(LT, true, 7)
_SPIRV_OP(LE, true, 7)
_SPIRV_OP(EQ, true, 7)
_SPIRV_OP(Recip, true, 9)
_SPIRV_OP(RSqrt, true, 9)
_SPIRV_OP(Cbrt, true, 9)
_SPIRV_OP(Hypot, true, 11)
_SPIRV_OP(Sqrt, true, 9)
_SPIRV_OP(Log, true, 9)
_SPIRV_OP(Log2, true, 9)
_SPIRV_OP(Log10, true, 9)
_SPIRV_OP(Log1p, true, 9)
_SPIRV_OP(Exp, true, 9)
_SPIRV_OP(Exp2, true, 9)
_SPIRV_OP(Exp10, true, 9)
_SPIRV_OP(Expm1, true, 9)
_SPIRV_OP(Sin, true, 9)
_SPIRV_OP(Cos, true, 9)
_SPIRV_OP(SinCos, true, 9)
_SPIRV_OP(SinPi, true, 9)
_SPIRV_OP(CosPi, true, 9)
_SPIRV_OP(SinCosPi, true, 9)
_SPIRV_OP(ASin, true, 9)
_SPIRV_OP(ASinPi, true, 9)
_SPIRV_OP(ACos, true, 9)
_SPIRV_OP(ACosPi, true, 9)
_SPIRV_OP(ATan, true, 9)
_SPIRV_OP(ATanPi, true, 9)
_SPIRV_OP(ATan2, true, 11)
_SPIRV_OP(Pow, true, 11)
_SPIRV_OP(PowR, true, 11)
_SPIRV_OP(PowN, true, 11)
#undef _SPIRV_OP
class SPIRVAtomicInstBase : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
// Most of the atomic instructions require a specific capability when
// operating on 64-bit integers.
// In SPIRV 1.2 spec, only 2 atomic instructions have no result type:
// 1. OpAtomicStore - need to check type of the Value operand
// 2. OpAtomicFlagClear - doesn't require Int64Atomics capability.
// Besides, OpAtomicCompareExchangeWeak, OpAtomicFlagTestAndSet and
// OpAtomicFlagClear instructions require the "kernel" capability. But this
// capability should be added by setting the OpenCL memory model.
if (hasType()) {
if (getType()->isTypeInt(64))
return {CapabilityInt64Atomics};
if (getType()->isTypeInt(16) &&
Module->isAllowedToUseExtension(
ExtensionID::SPV_INTEL_16bit_atomics)) {
Module->addExtension(ExtensionID::SPV_INTEL_16bit_atomics);
return {internal::CapabilityInt16AtomicsINTEL};
}
}
return {};
}
// Overriding the following method because of particular OpAtomic*
// instructions that declare additional capabilities, e.g. based on operand
// types.
void setOpWords(const std::vector<SPIRVWord> &TheOps) override {
SPIRVInstTemplateBase::setOpWords(TheOps);
for (auto RC : getRequiredCapability())
Module->addCapability(RC);
}
void validate() const override {
if (OpCode == OpAtomicCompareExchangeWeak)
assert(this->getModule()->getSPIRVVersion() < VersionNumber::SPIRV_1_4 &&
"OpAtomicCompareExchangeWeak is removed starting from SPIR-V 1.4");
}
// This method is needed for correct translation of atomic instructions when
// SPV_KHR_untyped_pointers is enabled.
// The interpreted data type for untyped pointers is specified by the Result
// Type if it exists, or from the type of the object being stored in other
// case.
SPIRVType *getSemanticType() {
switch (OpCode) {
case OpAtomicStore:
// Get type of Value operand
return getOperand(3)->getType();
default: {
if (hasType())
return getType();
return nullptr;
}
}
}
};
// This specialization will handle smaller set of compare-and-swap instructions
// that require only one capability. The instructions are: OpAtomicLoad,
// OpAtomicStore, OpAtomicExchange, OpAtomicCompareExchange and
// OpAtomicCompareExchangeWeak.
class SPIRVAtomicCompareExchangeInstructions : public SPIRVAtomicInstBase {
public:
SPIRVCapVec getRequiredCapability() const override {
if (hasType() && getType()->isTypeInt(16) &&
this->getModule()->isAllowedToUseExtension(
ExtensionID::SPV_INTEL_16bit_atomics)) {
Module->addExtension(ExtensionID::SPV_INTEL_16bit_atomics);
return {internal::CapabilityAtomicInt16CompareExchangeINTEL};
}
return SPIRVAtomicInstBase::getRequiredCapability();
}
};
class SPIRVAtomicStoreInst : public SPIRVAtomicCompareExchangeInstructions {
public:
// Overriding the following method because of 'const'-related
// issues with overriding getRequiredCapability(). TODO: Resolve.
void setOpWords(const std::vector<SPIRVWord> &TheOps) override {
SPIRVInstTemplateBase::setOpWords(TheOps);
static const unsigned ValueOperandIndex = 3;
if (getOperand(ValueOperandIndex)->getType()->isTypeInt(64))
Module->addCapability(CapabilityInt64Atomics);
}
};
class SPIRVAtomicFAddEXTInst : public SPIRVAtomicInstBase {
public:
std::optional<ExtensionID> getRequiredExtension() const override {
assert(hasType());
if (getType()->isTypeFloat(16, FPEncodingBFloat16KHR))
Module->addExtension(ExtensionID::SPV_INTEL_16bit_atomics);
if (getType()->isTypeFloat(16))
return ExtensionID::SPV_EXT_shader_atomic_float16_add;
return ExtensionID::SPV_EXT_shader_atomic_float_add;
}
SPIRVCapVec getRequiredCapability() const override {
assert(hasType());
if (getType()->isTypeFloat(16, FPEncodingBFloat16KHR))
return {internal::CapabilityAtomicBFloat16AddINTEL};
if (getType()->isTypeFloat(16))
return {CapabilityAtomicFloat16AddEXT};
if (getType()->isTypeFloat(32))
return {CapabilityAtomicFloat32AddEXT};
if (getType()->isTypeFloat(64))
return {CapabilityAtomicFloat64AddEXT};
// TODO: Temporary workaround to allow both FP16 and BF16 atomics.
if (getType()->isTypeVectorFloat() &&
(getType()->getVectorComponentType()->isTypeFloat(16) ||
getType()->getVectorComponentType()->isTypeFloat(16,
FPEncodingBFloat16KHR)))
return {CapabilityAtomicFloat16VectorNV};
llvm_unreachable(
"AtomicFAddEXT can only be generated for bf16, f16, f32, f64 types");
}
};
class SPIRVAtomicFMinMaxEXTBase : public SPIRVAtomicInstBase {
public:
std::optional<ExtensionID> getRequiredExtension() const override {
if (getType()->isTypeFloat(16, FPEncodingBFloat16KHR))
Module->addExtension(ExtensionID::SPV_INTEL_16bit_atomics);
return ExtensionID::SPV_EXT_shader_atomic_float_min_max;
}
SPIRVCapVec getRequiredCapability() const override {
assert(hasType());
if (getType()->isTypeFloat(16, FPEncodingBFloat16KHR))
return {internal::CapabilityAtomicBFloat16MinMaxINTEL};
if (getType()->isTypeFloat(16))
return {CapabilityAtomicFloat16MinMaxEXT};
if (getType()->isTypeFloat(32))
return {CapabilityAtomicFloat32MinMaxEXT};
if (getType()->isTypeFloat(64))
return {CapabilityAtomicFloat64MinMaxEXT};
llvm_unreachable("AtomicF(Min|Max)EXT can only be generated for bf16, f16, "
"f32, f64 types");
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVAtomicInstBase, Op##x, __VA_ARGS__> SPIRV##x;
// Atomic builtins
_SPIRV_OP(AtomicFlagTestAndSet, true, 6)
_SPIRV_OP(AtomicFlagClear, false, 4)
_SPIRV_OP(AtomicIIncrement, true, 6)
_SPIRV_OP(AtomicIDecrement, true, 6)
_SPIRV_OP(AtomicIAdd, true, 7)
_SPIRV_OP(AtomicISub, true, 7)
_SPIRV_OP(AtomicUMin, true, 7)
_SPIRV_OP(AtomicUMax, true, 7)
_SPIRV_OP(AtomicSMin, true, 7)
_SPIRV_OP(AtomicSMax, true, 7)
_SPIRV_OP(AtomicAnd, true, 7)
_SPIRV_OP(AtomicOr, true, 7)
_SPIRV_OP(AtomicXor, true, 7)
_SPIRV_OP(MemoryBarrier, false, 3)
#undef _SPIRV_OP
#define _SPIRV_OP(x, BaseClass, ...) \
typedef SPIRVInstTemplate<SPIRV##BaseClass, Op##x, __VA_ARGS__> SPIRV##x;
// Specialized atomic builtins
_SPIRV_OP(AtomicLoad, AtomicCompareExchangeInstructions, true, 6)
_SPIRV_OP(AtomicStore, AtomicStoreInst, false, 5)
_SPIRV_OP(AtomicExchange, AtomicCompareExchangeInstructions, true, 7)
_SPIRV_OP(AtomicCompareExchange, AtomicCompareExchangeInstructions, true, 9)
_SPIRV_OP(AtomicCompareExchangeWeak, AtomicCompareExchangeInstructions, true, 9)
_SPIRV_OP(AtomicFAddEXT, AtomicFAddEXTInst, true, 7)
_SPIRV_OP(AtomicFMinEXT, AtomicFMinMaxEXTBase, true, 7)
_SPIRV_OP(AtomicFMaxEXT, AtomicFMinMaxEXTBase, true, 7)
#undef _SPIRV_OP
class SPIRVImageInstBase : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityImageBasic);
}
bool hasImageOperand(ImageOperandsMask Mask) const;
protected:
void setOpWords(const std::vector<SPIRVWord> &OpsArg) override;
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVImageInstBase, Op##x, __VA_ARGS__> SPIRV##x;
// Image instructions
_SPIRV_OP(SampledImage, true, 5)
_SPIRV_OP(ImageSampleImplicitLod, true, 5, true)
_SPIRV_OP(ImageSampleExplicitLod, true, 7, true, 2)
_SPIRV_OP(ImageRead, true, 5, true, 2)
_SPIRV_OP(ImageWrite, false, 4, true, 3)
_SPIRV_OP(Image, true, 4)
_SPIRV_OP(ImageQueryFormat, true, 4)
_SPIRV_OP(ImageQueryOrder, true, 4)
_SPIRV_OP(ImageQuerySizeLod, true, 5)
_SPIRV_OP(ImageQuerySize, true, 4)
_SPIRV_OP(ImageQueryLod, true, 5)
_SPIRV_OP(ImageQueryLevels, true, 4)
_SPIRV_OP(ImageQuerySamples, true, 4)
#undef _SPIRV_OP
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVInstTemplateBase, Op##x, __VA_ARGS__> SPIRV##x;
// Other instructions
_SPIRV_OP(GenericPtrMemSemantics, true, 4, false)
_SPIRV_OP(GenericCastToPtrExplicit, true, 5, false, 1)
#undef _SPIRV_OP
class SPIRVSpecConstantOpBase : public SPIRVInstTemplateBase {
public:
bool isOperandLiteral(unsigned I) const override {
// If SpecConstant results from CompositeExtract/Insert operation, then all
// operands are expected to be literals.
switch (Ops[0]) { // Opcode of underlying SpecConstant operation
case OpCompositeExtract:
case OpCompositeInsert:
return true;
default:
return SPIRVInstTemplateBase::isOperandLiteral(I);
}
}
};
typedef SPIRVInstTemplate<SPIRVSpecConstantOpBase, OpSpecConstantOp, true, 4,
true, 0>
SPIRVSpecConstantOp;
class SPIRVAssumeTrueKHR : public SPIRVInstruction {
public:
static const Op OC = OpAssumeTrueKHR;
static const SPIRVWord FixedWordCount = 2;
SPIRVAssumeTrueKHR(SPIRVId TheCondition, SPIRVBasicBlock *BB)
: SPIRVInstruction(FixedWordCount, OC, BB), ConditionId(TheCondition) {
validate();
setHasNoId();
setHasNoType();
assert(BB && "Invalid BB");
}
SPIRVAssumeTrueKHR() : SPIRVInstruction(OC), ConditionId(SPIRVID_MAX) {
setHasNoId();
setHasNoType();
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityExpectAssumeKHR);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_KHR_expect_assume;
}
SPIRVValue *getCondition() const { return getValue(ConditionId); }
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
}
_SPIRV_DEF_ENCDEC1(ConditionId)
protected:
SPIRVId ConditionId;
};
class SPIRVExpectKHRInstBase : public SPIRVInstTemplateBase {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityExpectAssumeKHR);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_KHR_expect_assume;
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVExpectKHRInstBase, Op##x, __VA_ARGS__> \
SPIRV##x;
_SPIRV_OP(ExpectKHR, true, 5)
#undef _SPIRV_OP
class SPIRVDotKHRBase : public SPIRVInstTemplateBase {
protected:
SPIRVCapVec getRequiredCapability() const override {
// Both vector operands must have the same type, so analyzing the
// first operand will suffice.
SPIRVCapabilityKind ArgCap = getRequiredCapabilityForOperand(Ops[0]);
return getVec(ArgCap, CapabilityDotProductKHR);
}
std::optional<ExtensionID> getRequiredExtension() const override {
if (!Module->isAllowedToUseVersion(VersionNumber::SPIRV_1_6))
return ExtensionID::SPV_KHR_integer_dot_product;
return {};
}
void validate() const override {
SPIRVInstruction::validate();
SPIRVId Vec1 = Ops[0];
SPIRVId Vec2 = Ops[1];
(void)Vec1;
(void)Vec2;
assert(getValueType(Vec1) == getValueType(Vec2) &&
"Input vectors must have the same type");
assert(getType()->isTypeInt() && "Result type must be an integer type");
assert(!getType()->isTypeVector() && "Result type must be scalar");
}
private:
bool isAccSat() const {
return (OpCode == OpSDotAccSatKHR || OpCode == OpUDotAccSatKHR ||
OpCode == OpSUDotAccSatKHR);
}
std::optional<PackedVectorFormat> getPackedVectorFormat() const {
size_t PackFmtIdx = 2;
if (isAccSat()) {
// AccSat instructions have an additional Accumulator operand.
PackFmtIdx++;
}
if (PackFmtIdx == Ops.size() - 1)
return static_cast<PackedVectorFormat>(Ops[PackFmtIdx]);
return std::nullopt;
}
SPIRVCapabilityKind getRequiredCapabilityForOperand(SPIRVId ArgId) const {
const SPIRVType *T = getValueType(ArgId);
if (auto PackFmt = getPackedVectorFormat()) {
switch (*PackFmt) {
case PackedVectorFormatPackedVectorFormat4x8BitKHR:
assert(!T->isTypeVector() && T->isTypeInt() && T->getBitWidth() == 32 &&
"Type does not match pack format");
return CapabilityDotProductInput4x8BitPackedKHR;
case PackedVectorFormatMax:
break;
}
llvm_unreachable("Unknown Packed Vector Format");
}
if (T->isTypeVector()) {
const SPIRVType *EltT = T->getVectorComponentType();
if (T->getVectorComponentCount() == 4 && EltT->isTypeInt() &&
EltT->getBitWidth() == 8)
return CapabilityDotProductInput4x8BitKHR;
if (EltT->isTypeInt())
return CapabilityDotProductInputAllKHR;
}
llvm_unreachable("No mapping for argument type to capability.");
}
VersionNumber getRequiredSPIRVVersion() const override {
if (Module->isAllowedToUseVersion(VersionNumber::SPIRV_1_6))
return VersionNumber::SPIRV_1_6;
return VersionNumber::SPIRV_1_0;
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVDotKHRBase, Op##x, __VA_ARGS__> SPIRV##x;
_SPIRV_OP(SDotKHR, true, 5, true, 2)
_SPIRV_OP(UDotKHR, true, 5, true, 2)
_SPIRV_OP(SUDotKHR, true, 5, true, 2)
_SPIRV_OP(SDotAccSatKHR, true, 6, true, 3)
_SPIRV_OP(UDotAccSatKHR, true, 6, true, 3)
_SPIRV_OP(SUDotAccSatKHR, true, 6, true, 3)
#undef _SPIRV_OP
class SPIRVBitOp : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityBitInstructions);
}
std::optional<ExtensionID> getRequiredExtension() const override {
for (auto Cap : getRequiredCapability()) {
if (Cap == CapabilityBitInstructions)
return ExtensionID::SPV_KHR_bit_instructions;
}
return std::nullopt;
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVBitOp, Op##x, __VA_ARGS__> SPIRV##x;
_SPIRV_OP(BitFieldInsert, true, 7)
_SPIRV_OP(BitFieldSExtract, true, 6)
_SPIRV_OP(BitFieldUExtract, true, 6)
_SPIRV_OP(BitReverse, true, 4)
#undef _SPIRV_OP
class SPIRVSubgroupShuffleINTELInstBase : public SPIRVInstTemplateBase {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilitySubgroupShuffleINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_subgroups;
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVSubgroupShuffleINTELInstBase, Op##x, \
__VA_ARGS__> \
SPIRV##x;
// Intel Subgroup Shuffle Instructions
_SPIRV_OP(SubgroupShuffleINTEL, true, 5)
_SPIRV_OP(SubgroupShuffleDownINTEL, true, 6)
_SPIRV_OP(SubgroupShuffleUpINTEL, true, 6)
_SPIRV_OP(SubgroupShuffleXorINTEL, true, 5)
#undef _SPIRV_OP
class SPIRVSubgroupBufferBlockIOINTELInstBase : public SPIRVInstTemplateBase {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilitySubgroupBufferBlockIOINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_subgroups;
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVSubgroupBufferBlockIOINTELInstBase, Op##x, \
__VA_ARGS__> \
SPIRV##x;
// Intel Subgroup Buffer Block Read and Write Instructions
_SPIRV_OP(SubgroupBlockReadINTEL, true, 4)
_SPIRV_OP(SubgroupBlockWriteINTEL, false, 3)
#undef _SPIRV_OP
class SPIRVSubgroupImageBlockIOINTELInstBase : public SPIRVInstTemplateBase {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilitySubgroupImageBlockIOINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_subgroups;
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVSubgroupImageBlockIOINTELInstBase, Op##x, \
__VA_ARGS__> \
SPIRV##x;
// Intel Subgroup Image Block Read and Write Instructions
_SPIRV_OP(SubgroupImageBlockReadINTEL, true, 5)
_SPIRV_OP(SubgroupImageBlockWriteINTEL, false, 4)
#undef _SPIRV_OP
class SPIRVSubgroupImageMediaBlockIOINTELInstBase
: public SPIRVInstTemplateBase {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilitySubgroupImageMediaBlockIOINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_media_block_io;
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVSubgroupImageMediaBlockIOINTELInstBase, \
Op##x, __VA_ARGS__> \
SPIRV##x;
// Intel Subgroup Image Media Block Read and Write Instructions
_SPIRV_OP(SubgroupImageMediaBlockReadINTEL, true, 7)
_SPIRV_OP(SubgroupImageMediaBlockWriteINTEL, false, 6)
#undef _SPIRV_OP
class SPIRVSubgroupAVCIntelInstBase : public SPIRVInstTemplateBase {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilitySubgroupAvcMotionEstimationINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_device_side_avc_motion_estimation;
}
};
// Intel Subgroup AVC Motion Estimation Instructions
typedef SPIRVInstTemplate<SPIRVSubgroupAVCIntelInstBase, OpVmeImageINTEL, true,
5>
SPIRVVmeImageINTEL;
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVSubgroupAVCIntelInstBase, \
OpSubgroupAvc##x##INTEL, __VA_ARGS__> \
SPIRVSubgroupAvc##x##INTEL;
_SPIRV_OP(MceGetDefaultInterBaseMultiReferencePenalty, true, 5)
_SPIRV_OP(MceSetInterBaseMultiReferencePenalty, true, 5)
_SPIRV_OP(MceGetDefaultInterShapePenalty, true, 5)
_SPIRV_OP(MceSetInterShapePenalty, true, 5)
_SPIRV_OP(MceGetDefaultInterDirectionPenalty, true, 5)
_SPIRV_OP(MceSetInterDirectionPenalty, true, 5)
_SPIRV_OP(MceGetDefaultInterMotionVectorCostTable, true, 5)
_SPIRV_OP(MceGetDefaultHighPenaltyCostTable, true, 3)
_SPIRV_OP(MceGetDefaultMediumPenaltyCostTable, true, 3)
_SPIRV_OP(MceGetDefaultLowPenaltyCostTable, true, 3)
_SPIRV_OP(MceSetMotionVectorCostFunction, true, 7)
_SPIRV_OP(MceSetAcOnlyHaar, true, 4)
_SPIRV_OP(MceSetSourceInterlacedFieldPolarity, true, 5)
_SPIRV_OP(MceSetSingleReferenceInterlacedFieldPolarity, true, 5)
_SPIRV_OP(MceSetDualReferenceInterlacedFieldPolarities, true, 6)
_SPIRV_OP(MceConvertToImePayload, true, 4)
_SPIRV_OP(MceConvertToImeResult, true, 4)
_SPIRV_OP(MceConvertToRefPayload, true, 4)
_SPIRV_OP(MceConvertToRefResult, true, 4)
_SPIRV_OP(MceConvertToSicPayload, true, 4)
_SPIRV_OP(MceConvertToSicResult, true, 4)
_SPIRV_OP(MceGetMotionVectors, true, 4)
_SPIRV_OP(MceGetInterDistortions, true, 4)
_SPIRV_OP(MceGetBestInterDistortions, true, 4)
_SPIRV_OP(MceGetInterMajorShape, true, 4)
_SPIRV_OP(MceGetInterMinorShape, true, 4)
_SPIRV_OP(MceGetInterDirections, true, 4)
_SPIRV_OP(MceGetInterMotionVectorCount, true, 4)
_SPIRV_OP(MceGetInterReferenceIds, true, 4)
_SPIRV_OP(MceGetInterReferenceInterlacedFieldPolarities, true, 6)
_SPIRV_OP(ImeInitialize, true, 6)
_SPIRV_OP(ImeSetSingleReference, true, 6)
_SPIRV_OP(ImeSetDualReference, true, 7)
_SPIRV_OP(ImeRefWindowSize, true, 5)
_SPIRV_OP(ImeAdjustRefOffset, true, 7)
_SPIRV_OP(ImeConvertToMcePayload, true, 4)
_SPIRV_OP(ImeSetMaxMotionVectorCount, true, 5)
_SPIRV_OP(ImeSetUnidirectionalMixDisable, true, 4)
_SPIRV_OP(ImeSetEarlySearchTerminationThreshold, true, 5)
_SPIRV_OP(ImeSetWeightedSad, true, 5)
_SPIRV_OP(ImeEvaluateWithSingleReference, true, 6)
_SPIRV_OP(ImeEvaluateWithDualReference, true, 7)
_SPIRV_OP(ImeEvaluateWithSingleReferenceStreamin, true, 7)
_SPIRV_OP(ImeEvaluateWithDualReferenceStreamin, true, 8)
_SPIRV_OP(ImeEvaluateWithSingleReferenceStreamout, true, 6)
_SPIRV_OP(ImeEvaluateWithDualReferenceStreamout, true, 7)
_SPIRV_OP(ImeEvaluateWithSingleReferenceStreaminout, true, 7)
_SPIRV_OP(ImeEvaluateWithDualReferenceStreaminout, true, 8)
_SPIRV_OP(ImeConvertToMceResult, true, 4)
_SPIRV_OP(ImeGetSingleReferenceStreamin, true, 4)
_SPIRV_OP(ImeGetDualReferenceStreamin, true, 4)
_SPIRV_OP(ImeStripSingleReferenceStreamout, true, 4)
_SPIRV_OP(ImeStripDualReferenceStreamout, true, 4)
_SPIRV_OP(ImeGetStreamoutSingleReferenceMajorShapeMotionVectors, true, 5)
_SPIRV_OP(ImeGetStreamoutSingleReferenceMajorShapeDistortions, true, 5)
_SPIRV_OP(ImeGetStreamoutSingleReferenceMajorShapeReferenceIds, true, 5)
_SPIRV_OP(ImeGetStreamoutDualReferenceMajorShapeMotionVectors, true, 6)
_SPIRV_OP(ImeGetStreamoutDualReferenceMajorShapeDistortions, true, 6)
_SPIRV_OP(ImeGetStreamoutDualReferenceMajorShapeReferenceIds, true, 6)
_SPIRV_OP(ImeGetBorderReached, true, 5)
_SPIRV_OP(ImeGetTruncatedSearchIndication, true, 4)
_SPIRV_OP(ImeGetUnidirectionalEarlySearchTermination, true, 4)
_SPIRV_OP(ImeGetWeightingPatternMinimumMotionVector, true, 4)
_SPIRV_OP(ImeGetWeightingPatternMinimumDistortion, true, 4)
_SPIRV_OP(FmeInitialize, true, 10)
_SPIRV_OP(BmeInitialize, true, 11)
_SPIRV_OP(RefConvertToMcePayload, true, 4)
_SPIRV_OP(RefSetBidirectionalMixDisable, true, 4)
_SPIRV_OP(RefSetBilinearFilterEnable, true, 4)
_SPIRV_OP(RefEvaluateWithSingleReference, true, 6)
_SPIRV_OP(RefEvaluateWithDualReference, true, 7)
_SPIRV_OP(RefEvaluateWithMultiReference, true, 6)
_SPIRV_OP(RefEvaluateWithMultiReferenceInterlaced, true, 7)
_SPIRV_OP(RefConvertToMceResult, true, 4)
_SPIRV_OP(SicInitialize, true, 4)
_SPIRV_OP(SicConfigureSkc, true, 9)
_SPIRV_OP(SicGetMotionVectorMask, true, 5)
_SPIRV_OP(SicConvertToMcePayload, true, 4)
_SPIRV_OP(SicSetIntraLumaShapePenalty, true, 5)
_SPIRV_OP(SicSetBilinearFilterEnable, true, 4)
_SPIRV_OP(SicSetSkcForwardTransformEnable, true, 5)
_SPIRV_OP(SicSetBlockBasedRawSkipSad, true, 5)
_SPIRV_OP(SicEvaluateWithSingleReference, true, 6)
_SPIRV_OP(SicEvaluateWithDualReference, true, 7)
_SPIRV_OP(SicEvaluateWithMultiReference, true, 6)
_SPIRV_OP(SicEvaluateWithMultiReferenceInterlaced, true, 7)
_SPIRV_OP(SicConvertToMceResult, true, 4)
_SPIRV_OP(SicGetInterRawSads, true, 4)
#undef _SPIRV_OP
class SPIRVSubgroupAVCIntelInstBaseIntra : public SPIRVInstTemplateBase {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilitySubgroupAvcMotionEstimationIntraINTEL);
}
};
// Intel Subgroup AVC Motion Estimation Intra Instructions
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVSubgroupAVCIntelInstBaseIntra, \
OpSubgroupAvc##x##INTEL, __VA_ARGS__> \
SPIRVSubgroupAvc##x##INTEL;
_SPIRV_OP(MceGetDefaultIntraLumaShapePenalty, true, 5)
_SPIRV_OP(MceGetDefaultIntraLumaModePenalty, true, 5)
_SPIRV_OP(MceGetDefaultNonDcLumaIntraPenalty, true, 3)
_SPIRV_OP(SicConfigureIpeLuma, true, 11)
_SPIRV_OP(SicSetIntraLumaModeCostFunction, true, 7)
_SPIRV_OP(SicEvaluateIpe, true, 5)
_SPIRV_OP(SicGetIpeLumaShape, true, 4)
_SPIRV_OP(SicGetBestIpeLumaDistortion, true, 4)
_SPIRV_OP(SicGetPackedIpeLumaModes, true, 4)
_SPIRV_OP(SicGetPackedSkcLumaCountThreshold, true, 4)
_SPIRV_OP(SicGetPackedSkcLumaSumThreshold, true, 4)
#undef _SPIRV_OP
class SPIRVSubgroupAVCIntelInstBaseChroma : public SPIRVInstTemplateBase {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilitySubgroupAvcMotionEstimationChromaINTEL);
}
};
// Intel Subgroup AVC Motion Estimation Chroma Instructions
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVSubgroupAVCIntelInstBaseChroma, \
OpSubgroupAvc##x##INTEL, __VA_ARGS__> \
SPIRVSubgroupAvc##x##INTEL;
_SPIRV_OP(MceGetDefaultIntraChromaModeBasePenalty, true, 3)
_SPIRV_OP(SicConfigureIpeLumaChroma, true, 14)
_SPIRV_OP(SicSetIntraChromaModeCostFunction, true, 5)
_SPIRV_OP(SicGetBestIpeChromaDistortion, true, 4)
_SPIRV_OP(SicGetIpeChromaMode, true, 4)
#undef _SPIRV_OP
SPIRVSpecConstantOp *createSpecConstantOpInst(SPIRVInstruction *Inst);
SPIRVInstruction *createInstFromSpecConstantOp(SPIRVSpecConstantOp *C);
class SPIRVVariableLengthArrayINTELInstBase : public SPIRVInstTemplateBase {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityVariableLengthArrayINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_variable_length_array;
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVVariableLengthArrayINTELInstBase, \
Op##x##INTEL, __VA_ARGS__> \
SPIRV##x##INTEL;
_SPIRV_OP(VariableLengthArray, true, 4)
_SPIRV_OP(SaveMemory, true, 3)
_SPIRV_OP(RestoreMemory, false, 2)
#undef _SPIRV_OP
template <Op OC>
class SPIRVBfloat16ConversionINTELInstBase : public SPIRVUnaryInst<OC> {
protected:
SPIRVCapVec getRequiredCapability() const override {
SPIRVType *ResCompTy = this->getType();
if (ResCompTy->isTypeCooperativeMatrixKHR())
return getVec(
CapabilityBFloat16ConversionINTEL,
internal::CapabilityCooperativeMatrixBFloat16ComponentTypeINTEL);
return getVec(CapabilityBFloat16ConversionINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
SPIRVType *ResCompTy = this->getType();
if (ResCompTy->isTypeCooperativeMatrixKHR())
this->getModule()->addExtension(ExtensionID::SPV_INTEL_joint_matrix);
return ExtensionID::SPV_INTEL_bfloat16_conversion;
}
void validate() const override {
SPIRVUnaryInst<OC>::validate();
SPIRVType *ResCompTy = this->getType();
SPIRVWord ResCompCount = 1;
if (ResCompTy->isTypeVector()) {
ResCompCount = ResCompTy->getVectorComponentCount();
ResCompTy = ResCompTy->getVectorComponentType();
}
// validate is a const method, whilst getOperand is non-const method
// because it may call a method of class Module that may modify LiteralMap
// of Module field. That modification is not impacting validate method for
// these instructions, so const_cast is safe here.
using SPVBf16ConvTy = SPIRVBfloat16ConversionINTELInstBase<OC>;
SPIRVValue *Input = const_cast<SPVBf16ConvTy *>(this)->getOperand(0);
SPIRVType *InCompTy = Input->getType();
SPIRVWord InCompCount = 1;
if (InCompTy->isTypeVector()) {
InCompCount = InCompTy->getVectorComponentCount();
InCompTy = InCompTy->getVectorComponentType();
}
auto InstName = OpCodeNameMap::map(OC);
auto *Module = this->getModule();
SPIRVErrorLog &SPVErrLog = Module->getErrorLog();
// Cooperative matrix type is allowed as input/output of the instruction
// if SPV_INTEL_joint_matrix is enabled
if (ResCompTy->isTypeCooperativeMatrixKHR()) {
SPVErrLog.checkError(
Module->isAllowedToUseExtension(ExtensionID::SPV_INTEL_joint_matrix),
SPIRVEC_InvalidInstruction,
InstName + "\nCan be used with "
"cooperative matrices only when SPV_INTEL_joint_matrix is "
"enabled\n");
assert(InCompTy->isTypeCooperativeMatrixKHR() &&
"Input must also be a cooperative matrix");
ResCompTy = static_cast<SPIRVTypeCooperativeMatrixKHR *>(ResCompTy)
->getCompType();
InCompTy =
static_cast<SPIRVTypeCooperativeMatrixKHR *>(InCompTy)->getCompType();
}
if (OC == OpConvertFToBF16INTEL) {
SPVErrLog.checkError(
ResCompTy->isTypeInt(16), SPIRVEC_InvalidInstruction,
InstName + "\nResult value must be a scalar or vector of integer "
"16-bit type\n");
SPVErrLog.checkError(
InCompTy->isTypeFloat(32), SPIRVEC_InvalidInstruction,
InstName + "\nInput value must be a scalar or vector of "
"floating-point 32-bit type\n");
} else {
SPVErrLog.checkError(
ResCompTy->isTypeFloat(32), SPIRVEC_InvalidInstruction,
InstName + "\nResult value must be a scalar or vector of "
"floating-point 32-bit type\n");
SPVErrLog.checkError(
InCompTy->isTypeInt(16), SPIRVEC_InvalidInstruction,
InstName + "\nInput value must be a scalar or vector of integer "
"16-bit type\n");
}
SPVErrLog.checkError(
ResCompCount == InCompCount, SPIRVEC_InvalidInstruction,
InstName + "\nInput type must have the same number of components as "
"result type\n");
}
};
#define _SPIRV_OP(x) \
typedef SPIRVBfloat16ConversionINTELInstBase<Op##x> SPIRV##x;
_SPIRV_OP(ConvertFToBF16INTEL)
_SPIRV_OP(ConvertBF16ToFINTEL)
#undef _SPIRV_OP
class SPIRVJointMatrixINTELInstBase : public SPIRVInstTemplateBase {
protected:
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_joint_matrix;
}
};
class SPIRVJointMatrixINTELWorkItemInst : public SPIRVJointMatrixINTELInstBase {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(internal::CapabilityJointMatrixWIInstructionsINTEL);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVJointMatrixINTELWorkItemInst, \
internal::Op##x##INTEL, __VA_ARGS__> \
SPIRV##x##INTEL;
_SPIRV_OP(JointMatrixGetElementCoord, true, 5)
#undef _SPIRV_OP
class SPIRVCooperativeMatrixPrefetchINTELInstBase
: public SPIRVInstTemplateBase {
protected:
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_joint_matrix;
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(internal::CapabilityCooperativeMatrixPrefetchINTEL);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVCooperativeMatrixPrefetchINTELInstBase, \
internal::Op##x##INTEL, __VA_ARGS__> \
SPIRV##x##INTEL;
_SPIRV_OP(CooperativeMatrixPrefetch, false, 6, true, 3)
#undef _SPIRV_OP
class SPIRVCooperativeMatrixCheckedInstructionsINTELInstBase
: public SPIRVInstTemplateBase {
protected:
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_joint_matrix;
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(
internal::CapabilityCooperativeMatrixCheckedInstructionsINTEL);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate< \
SPIRVCooperativeMatrixCheckedInstructionsINTELInstBase, \
internal::Op##x##INTEL, __VA_ARGS__> \
SPIRV##x##INTEL;
_SPIRV_OP(CooperativeMatrixLoadChecked, true, 9, true, 7)
_SPIRV_OP(CooperativeMatrixStoreChecked, false, 8, true, 8)
_SPIRV_OP(CooperativeMatrixConstructChecked, true, 8)
#undef _SPIRV_OP
class SPIRVCooperativeMatrixOffsetInstructionsINTELInstBase
: public SPIRVInstTemplateBase {
protected:
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_joint_matrix;
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(internal::CapabilityCooperativeMatrixOffsetInstructionsINTEL);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate< \
SPIRVCooperativeMatrixOffsetInstructionsINTELInstBase, \
internal::Op##x##INTEL, __VA_ARGS__> \
SPIRV##x##INTEL;
_SPIRV_OP(CooperativeMatrixLoadOffset, true, 8, true, 5)
_SPIRV_OP(CooperativeMatrixStoreOffset, false, 7, true, 6)
#undef _SPIRV_OP
class SPIRVCooperativeMatrixInvocationInstructionsINTELInstBase
: public SPIRVInstTemplateBase {
protected:
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_joint_matrix;
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(
internal::CapabilityCooperativeMatrixInvocationInstructionsINTEL);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate< \
SPIRVCooperativeMatrixInvocationInstructionsINTELInstBase, \
internal::Op##x##INTEL, __VA_ARGS__> \
SPIRV##x##INTEL;
_SPIRV_OP(CooperativeMatrixApplyFunction, true, 5)
#undef _SPIRV_OP
class SPIRVCooperativeMatrixKHRInstBase : public SPIRVInstTemplateBase {
protected:
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_KHR_cooperative_matrix;
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityCooperativeMatrixKHR);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVCooperativeMatrixKHRInstBase, Op##x, \
__VA_ARGS__> \
SPIRV##x;
_SPIRV_OP(CooperativeMatrixLoadKHR, true, 5, true, 3)
_SPIRV_OP(CooperativeMatrixStoreKHR, false, 4, true, 4)
_SPIRV_OP(CooperativeMatrixLengthKHR, true, 4, false)
_SPIRV_OP(CooperativeMatrixMulAddKHR, true, 6, true, 3)
#undef _SPIRV_OP
class SPIRVSplitBarrierINTELBase : public SPIRVInstTemplateBase {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilitySplitBarrierINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_split_barrier;
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVSplitBarrierINTELBase, Op##x, __VA_ARGS__> \
SPIRV##x;
_SPIRV_OP(ControlBarrierArriveINTEL, false, 4)
_SPIRV_OP(ControlBarrierWaitINTEL, false, 4)
#undef _SPIRV_OP
class SPIRVGroupUniformArithmeticKHRInstBase : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityGroupUniformArithmeticKHR);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_KHR_uniform_group_instructions;
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVGroupUniformArithmeticKHRInstBase, \
Op##x##KHR, __VA_ARGS__> \
SPIRV##x##KHR;
_SPIRV_OP(GroupIMul, true, 6, false, 1)
_SPIRV_OP(GroupFMul, true, 6, false, 1)
_SPIRV_OP(GroupBitwiseAnd, true, 6, false, 1)
_SPIRV_OP(GroupBitwiseOr, true, 6, false, 1)
_SPIRV_OP(GroupBitwiseXor, true, 6, false, 1)
_SPIRV_OP(GroupLogicalAnd, true, 6, false, 1)
_SPIRV_OP(GroupLogicalOr, true, 6, false, 1)
_SPIRV_OP(GroupLogicalXor, true, 6, false, 1)
#undef _SPIRV_OP
class SPIRVMaskedGatherScatterINTELInstBase : public SPIRVInstTemplateBase {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(internal::CapabilityMaskedGatherScatterINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_masked_gather_scatter;
}
};
class SPIRVMaskedGatherINTELInst
: public SPIRVMaskedGatherScatterINTELInstBase {
void validate() const override {
SPIRVInstruction::validate();
SPIRVErrorLog &SPVErrLog = this->getModule()->getErrorLog();
std::string InstName = "MaskedGatherINTEL";
SPIRVType *ResTy = this->getType();
SPVErrLog.checkError(ResTy->isTypeVector(), SPIRVEC_InvalidInstruction,
InstName + "\nResult must be a vector type\n");
SPIRVWord ResCompCount = ResTy->getVectorComponentCount();
SPIRVType *ResCompTy = ResTy->getVectorComponentType();
SPIRVValue *PtrVec =
const_cast<SPIRVMaskedGatherINTELInst *>(this)->getOperand(0);
SPIRVType *PtrVecTy = PtrVec->getType();
SPVErrLog.checkError(
PtrVecTy->isTypeVectorPointer(), SPIRVEC_InvalidInstruction,
InstName + "\nPtrVector must be a vector of pointers type\n");
SPIRVWord PtrVecCompCount = PtrVecTy->getVectorComponentCount();
SPIRVType *PtrVecCompTy = PtrVecTy->getVectorComponentType();
SPIRVType *PtrElemTy = PtrVecCompTy->getPointerElementType();
SPVErrLog.checkError(
this->isOperandLiteral(1), SPIRVEC_InvalidInstruction,
InstName + "\nAlignment must be a constant expression integer\n");
const uint32_t Align =
static_cast<SPIRVConstant *>(
const_cast<SPIRVMaskedGatherINTELInst *>(this)->getOperand(2))
->getZExtIntValue();
SPVErrLog.checkError(
((Align & (Align - 1)) == 0), SPIRVEC_InvalidInstruction,
InstName + "\nAlignment must be 0 or power-of-two integer\n");
SPIRVValue *Mask =
const_cast<SPIRVMaskedGatherINTELInst *>(this)->getOperand(2);
SPIRVType *MaskTy = Mask->getType();
SPVErrLog.checkError(MaskTy->isTypeVector(), SPIRVEC_InvalidInstruction,
InstName + "\nMask must be a vector type\n");
SPIRVType *MaskCompTy = MaskTy->getVectorComponentType();
SPVErrLog.checkError(MaskCompTy->isTypeBool(), SPIRVEC_InvalidInstruction,
InstName + "\nMask must be a boolean vector type\n");
SPIRVWord MaskCompCount = MaskTy->getVectorComponentCount();
SPIRVValue *FillEmpty =
const_cast<SPIRVMaskedGatherINTELInst *>(this)->getOperand(3);
SPIRVType *FillEmptyTy = FillEmpty->getType();
SPVErrLog.checkError(FillEmptyTy->isTypeVector(),
SPIRVEC_InvalidInstruction,
InstName + "\nFillEmpty must be a vector type\n");
SPIRVWord FillEmptyCompCount = FillEmptyTy->getVectorComponentCount();
SPIRVType *FillEmptyCompTy = FillEmptyTy->getVectorComponentType();
SPVErrLog.checkError(
ResCompCount == PtrVecCompCount &&
PtrVecCompCount == FillEmptyCompCount &&
FillEmptyCompCount == MaskCompCount,
SPIRVEC_InvalidInstruction,
InstName + "\nResult, PtrVector, Mask and FillEmpty vectors must have "
"the same size\n");
SPVErrLog.checkError(
ResCompTy == PtrElemTy && PtrElemTy == FillEmptyCompTy,
SPIRVEC_InvalidInstruction,
InstName + "\nComponent Type of Result and FillEmpty vector must be "
"same as base type of PtrVector the same base type\n");
}
};
class SPIRVMaskedScatterINTELInst
: public SPIRVMaskedGatherScatterINTELInstBase {
void validate() const override {
SPIRVInstruction::validate();
SPIRVErrorLog &SPVErrLog = this->getModule()->getErrorLog();
std::string InstName = "MaskedScatterINTEL";
SPIRVValue *InputVec =
const_cast<SPIRVMaskedScatterINTELInst *>(this)->getOperand(0);
SPIRVType *InputVecTy = InputVec->getType();
SPVErrLog.checkError(
InputVecTy->isTypeVector(), SPIRVEC_InvalidInstruction,
InstName + "\nInputVector must be a vector of pointers type\n");
SPIRVWord InputVecCompCount = InputVecTy->getVectorComponentCount();
SPIRVType *InputVecCompTy = InputVecTy->getVectorComponentType();
SPIRVValue *PtrVec =
const_cast<SPIRVMaskedScatterINTELInst *>(this)->getOperand(1);
SPIRVType *PtrVecTy = PtrVec->getType();
SPVErrLog.checkError(
PtrVecTy->isTypeVectorPointer(), SPIRVEC_InvalidInstruction,
InstName + "\nPtrVector must be a vector of pointers type\n");
SPIRVWord PtrVecCompCount = PtrVecTy->getVectorComponentCount();
SPIRVType *PtrVecCompTy = PtrVecTy->getVectorComponentType();
SPIRVType *PtrElemTy = PtrVecCompTy->getPointerElementType();
SPVErrLog.checkError(
this->isOperandLiteral(2), SPIRVEC_InvalidInstruction,
InstName + "\nAlignment must be a constant expression integer\n");
const uint32_t Align =
static_cast<SPIRVConstant *>(
const_cast<SPIRVMaskedScatterINTELInst *>(this)->getOperand(2))
->getZExtIntValue();
SPVErrLog.checkError(
((Align & (Align - 1)) == 0), SPIRVEC_InvalidInstruction,
InstName + "\nAlignment must be 0 or power-of-two integer\n");
SPIRVValue *Mask =
const_cast<SPIRVMaskedScatterINTELInst *>(this)->getOperand(2);
SPIRVType *MaskTy = Mask->getType();
SPVErrLog.checkError(MaskTy->isTypeVector(), SPIRVEC_InvalidInstruction,
InstName + "\nMask must be a vector type\n");
SPIRVType *MaskCompTy = MaskTy->getVectorComponentType();
SPVErrLog.checkError(MaskCompTy->isTypeBool(), SPIRVEC_InvalidInstruction,
InstName + "\nMask must be a boolean vector type\n");
SPIRVWord MaskCompCount = MaskTy->getVectorComponentCount();
SPVErrLog.checkError(
InputVecCompCount == PtrVecCompCount &&
PtrVecCompCount == MaskCompCount,
SPIRVEC_InvalidInstruction,
InstName + "\nInputVector, PtrVector and Mask vectors must have "
"the same size\n");
SPVErrLog.checkError(
InputVecCompTy == PtrElemTy, SPIRVEC_InvalidInstruction,
InstName + "\nComponent Type of InputVector must be "
"same as base type of PtrVector the same base type\n");
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVMaskedGatherScatterINTELInstBase, \
internal::Op##x##INTEL, __VA_ARGS__> \
SPIRV##x##INTEL;
_SPIRV_OP(MaskedGather, true, 7)
_SPIRV_OP(MaskedScatter, false, 5)
#undef _SPIRV_OP
template <Op OC>
class SPIRVTensorFloat32RoundingINTELInstBase : public SPIRVUnaryInst<OC> {
protected:
SPIRVCapVec getRequiredCapability() const override {
SPIRVType *ResCompTy = this->getType();
if (ResCompTy->isTypeCooperativeMatrixKHR())
return getVec(
CapabilityTensorFloat32RoundingINTEL,
internal::CapabilityCooperativeMatrixTF32ComponentTypeINTEL);
return getVec(CapabilityTensorFloat32RoundingINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
SPIRVType *ResCompTy = this->getType();
if (ResCompTy->isTypeCooperativeMatrixKHR())
this->getModule()->addExtension(ExtensionID::SPV_INTEL_joint_matrix);
return ExtensionID::SPV_INTEL_tensor_float32_conversion;
}
void validate() const override {
SPIRVUnaryInst<OC>::validate();
SPIRVType *ResCompTy = this->getType();
SPIRVWord ResCompCount = 1;
if (ResCompTy->isTypeVector()) {
ResCompCount = ResCompTy->getVectorComponentCount();
ResCompTy = ResCompTy->getVectorComponentType();
}
// validate is a const method, whilst getOperand is non-const method
// because it may call a method of class Module that may modify LiteralMap
// of Module field. That modification is not impacting validate method for
// these instructions, so const_cast is safe here.
using SPVTF32RoundTy = SPIRVTensorFloat32RoundingINTELInstBase<OC>;
SPIRVValue *Input = const_cast<SPVTF32RoundTy *>(this)->getOperand(0);
SPIRVType *InCompTy = Input->getType();
SPIRVWord InCompCount = 1;
if (InCompTy->isTypeVector()) {
InCompCount = InCompTy->getVectorComponentCount();
InCompTy = InCompTy->getVectorComponentType();
}
auto InstName = OpCodeNameMap::map(OC);
auto *Module = this->getModule();
SPIRVErrorLog &SPVErrLog = Module->getErrorLog();
// Cooperative matrix type is allowed as input/output of the instruction
// if SPV_INTEL_joint_matrix is enabled
if (ResCompTy->isTypeCooperativeMatrixKHR()) {
SPVErrLog.checkError(
Module->isAllowedToUseExtension(ExtensionID::SPV_INTEL_joint_matrix),
SPIRVEC_InvalidInstruction,
InstName + "\nCan be used with "
"cooperative matrices only when SPV_INTEL_joint_matrix is "
"enabled\n");
assert(InCompTy->isTypeCooperativeMatrixKHR() &&
"Input must also be a cooperative matrix");
ResCompTy = static_cast<SPIRVTypeCooperativeMatrixKHR *>(ResCompTy)
->getCompType();
InCompTy =
static_cast<SPIRVTypeCooperativeMatrixKHR *>(InCompTy)->getCompType();
}
SPVErrLog.checkError(
ResCompTy->isTypeFloat(32), SPIRVEC_InvalidInstruction,
InstName + "\nResult value must be a scalar or vector of floating-point"
" 32-bit type\n");
SPVErrLog.checkError(InCompTy->isTypeFloat(32), SPIRVEC_InvalidInstruction,
InstName +
"\nInput value must be a scalar or vector of "
"floating-point 32-bit type\n");
SPVErrLog.checkError(
ResCompCount == InCompCount, SPIRVEC_InvalidInstruction,
InstName + "\nInput type must have the same number of components as "
"result type\n");
}
};
#define _SPIRV_OP(x) \
typedef SPIRVTensorFloat32RoundingINTELInstBase<Op##x> SPIRV##x;
_SPIRV_OP(RoundFToTF32INTEL)
#undef _SPIRV_OP
template <Op OC> class SPIRVReadClockKHRInstBase : public SPIRVUnaryInst<OC> {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityShaderClockKHR);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_KHR_shader_clock;
}
void validate() const override {
SPIRVUnaryInst<OC>::validate();
SPIRVType *ResCompTy = this->getType();
SPIRVWord ResCompCount = 1;
if (ResCompTy->isTypeVector()) {
ResCompCount = ResCompTy->getVectorComponentCount();
ResCompTy = ResCompTy->getVectorComponentType();
}
auto InstName = OpCodeNameMap::map(OC);
SPIRVErrorLog &SPVErrLog = this->getModule()->getErrorLog();
// check for either 64 bit int type or two element vector of 32 bit int
// types.
SPVErrLog.checkError(
ResCompTy->isTypeInt(64) ||
(ResCompCount == 2 && ResCompTy->isTypeInt(32)),
SPIRVEC_InvalidInstruction,
InstName + "\nResult value must be a scalar of integer"
" 64-bit type or two element vector of 32-bit type\n");
}
};
#define _SPIRV_OP(x) typedef SPIRVReadClockKHRInstBase<Op##x> SPIRV##x;
_SPIRV_OP(ReadClockKHR)
#undef _SPIRV_OP
class SPIRVTaskSequenceINTELInstBase : public SPIRVInstTemplateBase {
public:
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_task_sequence;
}
};
class SPIRVTaskSequenceINTELInst : public SPIRVTaskSequenceINTELInstBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(internal::CapabilityTaskSequenceINTEL);
}
};
class SPIRVTaskSequenceCreateINTELInst : public SPIRVTaskSequenceINTELInst {
protected:
void validate() const override {
SPIRVInstruction::validate();
std::string InstName = "TaskSequenceCreateINTEL";
SPIRVErrorLog &SPVErrLog = this->getModule()->getErrorLog();
SPIRVType *ResTy = this->getType();
SPVErrLog.checkError(
ResTy->isTypeTaskSequenceINTEL(), SPIRVEC_InvalidInstruction,
InstName + "\nResult must be TaskSequenceINTEL type\n");
SPIRVValue *Func =
const_cast<SPIRVTaskSequenceCreateINTELInst *>(this)->getOperand(0);
SPVErrLog.checkError(
Func->getOpCode() == OpFunction, SPIRVEC_InvalidInstruction,
InstName + "\nFirst argument is expected to be a function.\n");
SPIRVConstant *PipelinedConst = static_cast<SPIRVConstant *>(
const_cast<SPIRVTaskSequenceCreateINTELInst *>(this)->getOperand(1));
const int Pipelined = PipelinedConst->getZExtIntValue();
SPVErrLog.checkError(Pipelined >= -1, SPIRVEC_InvalidInstruction,
InstName + "\nPipeline must be a 32 bit integer with "
"the value bigger or equal to -1.\n");
const int ClusterMode =
static_cast<SPIRVConstant *>(
const_cast<SPIRVTaskSequenceCreateINTELInst *>(this)->getOperand(2))
->getZExtIntValue();
SPVErrLog.checkError(
ClusterMode >= -1 && ClusterMode <= 1, SPIRVEC_InvalidInstruction,
InstName + "\nClusterMode valid values are -1, 0, 1.\n");
const int GetCapacity =
static_cast<SPIRVConstant *>(
const_cast<SPIRVTaskSequenceCreateINTELInst *>(this)->getOperand(3))
->getZExtIntValue();
SPVErrLog.checkError(
GetCapacity >= 0, SPIRVEC_InvalidInstruction,
InstName + "\nGetCapacity must be an unsigned 32-bit integer.\n");
const int AsyncCapacity =
static_cast<SPIRVConstant *>(
const_cast<SPIRVTaskSequenceCreateINTELInst *>(this)->getOperand(4))
->getZExtIntValue();
SPVErrLog.checkError(
AsyncCapacity >= 0, SPIRVEC_InvalidInstruction,
InstName + "\nAsyncCapacity must be an unsigned 32-bit integer.\n");
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVTaskSequenceINTELInst, \
internal::Op##x##INTEL, __VA_ARGS__> \
SPIRV##x##INTEL;
_SPIRV_OP(TaskSequenceAsync, false, 2, true)
_SPIRV_OP(TaskSequenceGet, true, 4, false)
_SPIRV_OP(TaskSequenceRelease, false, 2, false)
#undef _SPIRV_OP
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVTaskSequenceCreateINTELInst, \
internal::Op##x##INTEL, __VA_ARGS__> \
SPIRV##x##INTEL;
_SPIRV_OP(TaskSequenceCreate, true, 8, false, 1, 2, 3, 4)
#undef _SPIRV_OP
template <Op OC> class SPIRVBindlessImagesInstBase : public SPIRVUnaryInst<OC> {
protected:
SPIRVCapVec getRequiredCapability() const override {
return getVec(internal::CapabilityBindlessImagesINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_bindless_images;
}
void validate() const override {
SPIRVUnary::validate();
// validate is a const method, whilst getOperand is non-const method
// because it may call a method of class Module that may modify LiteralMap
// of Module field. That modification is not impacting validate method for
// these instructions, so const_cast is safe here.
using SPVBindlessImagesInst = SPIRVBindlessImagesInstBase<OC>;
SPIRVValue *Input =
const_cast<SPVBindlessImagesInst *>(this)->getOperand(0);
SPIRVType *InCompTy = Input->getType();
auto StringAddrMod = [](SPIRVAddressingModelKind Kind) -> std::string {
if (Kind == AddressingModelPhysical32)
return std::string("Physical32");
if (Kind == AddressingModelPhysical64)
return std::string("Physical64");
return std::string("AddressingModel: ") + std::to_string(Kind);
};
auto InstName = OpCodeNameMap::map(OC);
auto AddrMod = this->getModule()->getAddressingModel();
SPIRVErrorLog &SPVErrLog = this->getModule()->getErrorLog();
SPVErrLog.checkError(
(InCompTy->isTypeInt(32) && AddrMod == AddressingModelPhysical32) ||
(InCompTy->isTypeInt(64) && AddrMod == AddressingModelPhysical64),
SPIRVEC_InvalidInstruction,
InstName +
"\nParameter value must be a 32-bit scalar in case of "
"Physical32 addressing model or a 64-bit scalar in case of "
"Physical64 addressing model\n"
"Type size: " +
std::to_string(InCompTy->getBitWidth()) +
"\nAddressing model: " + StringAddrMod(AddrMod) + "\n");
SPIRVType *ResTy = this->getType();
SPVErrLog.checkError(
(ResTy->isTypeImage() && OC == internal::OpConvertHandleToImageINTEL) ||
(ResTy->isTypeSampler() &&
OC == internal::OpConvertHandleToSamplerINTEL) ||
(ResTy->isTypeSampledImage() &&
OC == internal::OpConvertHandleToSampledImageINTEL),
SPIRVEC_InvalidInstruction,
InstName + "\nIncorrect return type of the instruction must be "
"image/sampler\n");
}
};
#define _SPIRV_OP(x) \
typedef SPIRVBindlessImagesInstBase<internal::Op##x> SPIRV##x;
_SPIRV_OP(ConvertHandleToImageINTEL)
_SPIRV_OP(ConvertHandleToSamplerINTEL)
_SPIRV_OP(ConvertHandleToSampledImageINTEL)
#undef _SPIRV_OP
class SPIRVUntypedPrefetchKHR : public SPIRVInstruction {
public:
static const Op OC = OpUntypedPrefetchKHR;
static const SPIRVWord FixedWordCount = 3;
SPIRVUntypedPrefetchKHR(SPIRVType *Ty, std::vector<SPIRVWord> &TheArgs,
SPIRVBasicBlock *BB)
: SPIRVInstruction(FixedWordCount, OC, BB) {
setHasNoId();
setHasNoType();
PtrTy = TheArgs[0];
NumBytes = TheArgs[1];
if (TheArgs.size() > 2)
RW.push_back(TheArgs[2]);
if (TheArgs.size() > 3)
Locality.push_back(TheArgs[3]);
if (TheArgs.size() > 4)
CacheTy.push_back(TheArgs[4]);
assert(BB && "Invalid BB");
validate();
}
SPIRVUntypedPrefetchKHR()
: SPIRVInstruction(OC), PtrTy(SPIRVID_INVALID),
NumBytes(SPIRVID_INVALID) {
setHasNoId();
setHasNoType();
}
void validate() const override {
SPIRVInstruction::validate();
SPIRVErrorLog &SPVErrLog = this->getModule()->getErrorLog();
std::string InstName = "OpUntypedPrefetchKHR";
SPVErrLog.checkError(getValueType(PtrTy)->isTypePointer(),
SPIRVEC_InvalidInstruction,
InstName + "\nFirst argument must be a pointer\n");
SPVErrLog.checkError(
getValueType(PtrTy)->getPointerStorageClass() ==
StorageClassCrossWorkgroup,
SPIRVEC_InvalidInstruction,
InstName + "\nFirst argument must be a pointer in CrossWorkgroup "
"storage class\n");
SPVErrLog.checkError(
getValueType(NumBytes)->isTypeInt(), SPIRVEC_InvalidInstruction,
InstName + "\nSecond argument (Num Bytes) must be an integer\n");
SPVErrLog.checkError(
RW.empty() || (RW.size() == 1 && getValueType(RW[0])->isTypeInt()),
SPIRVEC_InvalidInstruction,
InstName + "\nThird argument (RW) must be an integer\n");
SPVErrLog.checkError(
Locality.empty() ||
(Locality.size() == 1 && getValueType(Locality[0])->isTypeInt()),
SPIRVEC_InvalidInstruction,
InstName + "\nFourth argument (Locality) must be an integer\n");
SPVErrLog.checkError(
CacheTy.empty() ||
(CacheTy.size() == 1 && getValueType(CacheTy[0])->isTypeInt()),
SPIRVEC_InvalidInstruction,
InstName + "\nFifth argument (Cache Type) must be an integer\n");
}
void setWordCount(SPIRVWord TheWordCount) override {
SPIRVEntry::setWordCount(TheWordCount);
if (TheWordCount > 3)
RW.resize(1);
if (TheWordCount > 4)
Locality.resize(1);
if (TheWordCount > 5)
CacheTy.resize(1);
}
const std::vector<SPIRVWord> getArguments() const {
std::vector<SPIRVWord> Args;
Args.push_back(PtrTy);
Args.push_back(NumBytes);
if (!RW.empty())
Args.push_back(RW[0]);
if (!Locality.empty())
Args.push_back(Locality[0]);
if (!CacheTy.empty())
Args.push_back(CacheTy[0]);
return Args;
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityUntypedPointersKHR);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_KHR_untyped_pointers;
}
_SPIRV_DEF_ENCDEC5(PtrTy, NumBytes, RW, Locality, CacheTy)
protected:
SPIRVId PtrTy;
SPIRVId NumBytes;
std::vector<SPIRVId> RW;
std::vector<SPIRVId> Locality;
std::vector<SPIRVId> CacheTy;
};
class SPIRVSubgroupBlockPrefetchINTELInst : public SPIRVInstTemplateBase {
public:
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_subgroup_buffer_prefetch;
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilitySubgroupBufferPrefetchINTEL);
}
// Operand 2, if present, is the Memory Operands bitmask.
bool isOperandLiteral(unsigned I) const override { return I == 2; }
protected:
void validate() const override {
SPIRVInstruction::validate();
if (getValue(Ops[0])->isForward())
return;
SPIRVErrorLog &SPVErrLog = getModule()->getErrorLog();
SPIRVType *PtrType = getValueType(Ops[0]);
std::string InstName = "OpSubgroupBlockPrefetchINTEL";
SPVErrLog.checkError(
PtrType->isTypePointer() || PtrType->isTypeUntypedPointerKHR(),
SPIRVEC_InvalidInstruction, InstName + "\nPtr must be a pointer\n");
SPVErrLog.checkError(
PtrType->getPointerStorageClass() == StorageClassCrossWorkgroup,
SPIRVEC_InvalidInstruction,
InstName + "\nPtr must be in CrossWorkgroup storage class\n");
if (!PtrType->isTypeUntypedPointerKHR())
SPVErrLog.checkError(PtrType->getPointerElementType()->isTypeInt(),
SPIRVEC_InvalidInstruction,
InstName +
"\nPtr must point to a scalar integer type\n");
SPVErrLog.checkError(
getValueType(Ops[1])->isTypeInt(32), SPIRVEC_InvalidInstruction,
InstName + "\nNumBytes must be a 32-bit integer scalar\n");
}
};
typedef SPIRVInstTemplate<SPIRVSubgroupBlockPrefetchINTELInst,
OpSubgroupBlockPrefetchINTEL, false, 3, true>
SPIRVSubgroupBlockPrefetchINTEL;
class SPIRVSubgroup2DBlockIOINTELInst : public SPIRVInstTemplateBase {
public:
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_2d_block_io;
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilitySubgroup2DBlockIOINTEL);
}
};
class SPIRVSubgroup2DBlockLoadTransposeINTELInst
: public SPIRVSubgroup2DBlockIOINTELInst {
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilitySubgroup2DBlockTransposeINTEL);
}
};
class SPIRVSubgroup2DBlockLoadTransformINTELInst
: public SPIRVSubgroup2DBlockIOINTELInst {
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilitySubgroup2DBlockTransformINTEL);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVSubgroup2DBlockIOINTELInst, Op##x##INTEL, \
__VA_ARGS__> \
SPIRV##x##INTEL;
_SPIRV_OP(Subgroup2DBlockLoad, false, 11)
_SPIRV_OP(Subgroup2DBlockPrefetch, false, 10)
_SPIRV_OP(Subgroup2DBlockStore, false, 11)
#undef _SPIRV_OP
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVSubgroup2DBlockLoadTransposeINTELInst, \
Op##x##INTEL, __VA_ARGS__> \
SPIRV##x##INTEL;
_SPIRV_OP(Subgroup2DBlockLoadTranspose, false, 11)
#undef _SPIRV_OP
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVSubgroup2DBlockLoadTransformINTELInst, \
Op##x##INTEL, __VA_ARGS__> \
SPIRV##x##INTEL;
_SPIRV_OP(Subgroup2DBlockLoadTransform, false, 11)
#undef _SPIRV_OP
class SPIRVSubgroupMatrixMultiplyAccumulateINTELInst
: public SPIRVInstTemplateBase {
public:
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_subgroup_matrix_multiply_accumulate;
}
protected:
void validate() const override {
SPIRVInstTemplateBase::validate();
// Check if FP4 or FP8 matrix operands are used
// Operands parameter is the last operand (index 4)
auto *NonConstThis =
const_cast<SPIRVSubgroupMatrixMultiplyAccumulateINTELInst *>(this);
if (NonConstThis->getOperands().size() > 4) {
const SPIRVConstant *OperandsConst =
static_cast<const SPIRVConstant *>(NonConstThis->getOperand(4));
uint64_t OperandsMask = OperandsConst->getZExtIntValue();
// FP4 operand bits
constexpr uint64_t FP4Mask =
spv::internal::
IMatrixMultiplyAccumulateOperandsMatrixAPackedFloat4E2M1INTELMask |
spv::internal::
IMatrixMultiplyAccumulateOperandsMatrixBPackedFloat4E2M1INTELMask;
// FP8 operand bits
constexpr uint64_t FP8Mask =
spv::internal::
IMatrixMultiplyAccumulateOperandsMatrixAPackedFloat8E4M3INTELMask |
spv::internal::
IMatrixMultiplyAccumulateOperandsMatrixBPackedFloat8E4M3INTELMask |
spv::internal::
IMatrixMultiplyAccumulateOperandsMatrixAPackedFloat8E5M2INTELMask |
spv::internal::
IMatrixMultiplyAccumulateOperandsMatrixBPackedFloat8E5M2INTELMask;
if ((OperandsMask & FP4Mask) != 0) {
getModule()->getErrorLog().checkError(
getModule()->isAllowedToUseExtension(
ExtensionID::
SPV_INTEL_subgroup_matrix_multiply_accumulate_float4),
SPIRVEC_RequiresExtension,
"SPV_INTEL_subgroup_matrix_multiply_accumulate_float4\n"
"SubgroupMatrixMultiplyAccumulateINTEL with FP4 operand flags "
"requires this extension");
getModule()->addExtension(
ExtensionID::SPV_INTEL_subgroup_matrix_multiply_accumulate_float4);
}
if ((OperandsMask & FP8Mask) != 0) {
getModule()->getErrorLog().checkError(
getModule()->isAllowedToUseExtension(
ExtensionID::
SPV_INTEL_subgroup_matrix_multiply_accumulate_float8),
SPIRVEC_RequiresExtension,
"SPV_INTEL_subgroup_matrix_multiply_accumulate_float8\n"
"SubgroupMatrixMultiplyAccumulateINTEL with FP8 operand flags "
"requires this extension");
getModule()->addExtension(
ExtensionID::SPV_INTEL_subgroup_matrix_multiply_accumulate_float8);
}
}
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilitySubgroupMatrixMultiplyAccumulateINTEL);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVSubgroupMatrixMultiplyAccumulateINTELInst, \
Op##x##INTEL, __VA_ARGS__> \
SPIRV##x##INTEL;
_SPIRV_OP(SubgroupMatrixMultiplyAccumulate, true, 7, true, 4)
#undef _SPIRV_OP
class SPIRVTernaryBitwiseFunctionINTELInst : public SPIRVInstTemplateBase {
public:
void validate() const override {
SPIRVInstruction::validate();
SPIRVErrorLog &SPVErrLog = this->getModule()->getErrorLog();
std::string InstName = "BitwiseFunctionINTEL";
const SPIRVType *ResTy = this->getType();
SPVErrLog.checkError(
ResTy->isTypeInt() || (ResTy->isTypeVector() &&
ResTy->getVectorComponentType()->isTypeInt()),
SPIRVEC_InvalidInstruction,
InstName + "\nResult type must be an integer scalar or vector.\n");
auto CommonArgCheck = [this, ResTy, &InstName,
&SPVErrLog](size_t ArgI, const char *ArgPlacement) {
SPIRVValue *Arg =
const_cast<SPIRVTernaryBitwiseFunctionINTELInst *>(this)->getOperand(
ArgI);
SPVErrLog.checkError(
Arg->getType() == ResTy, SPIRVEC_InvalidInstruction,
InstName + "\n" + ArgPlacement +
" argument must be the same as the result type.\n");
};
CommonArgCheck(0, "First");
CommonArgCheck(1, "Second");
CommonArgCheck(2, "Third");
SPIRVValue *LUTIndexArg =
const_cast<SPIRVTernaryBitwiseFunctionINTELInst *>(this)->getOperand(3);
const SPIRVType *LUTIndexArgTy = LUTIndexArg->getType();
SPVErrLog.checkError(
LUTIndexArgTy->isTypeInt(32), SPIRVEC_InvalidInstruction,
InstName + "\nFourth argument must be a 32-bit integer scalar.\n");
SPVErrLog.checkError(
isConstantOpCode(LUTIndexArg->getOpCode()), SPIRVEC_InvalidInstruction,
InstName + "\nFourth argument must be constant instruction.\n");
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_ternary_bitwise_function;
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityTernaryBitwiseFunctionINTEL);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVTernaryBitwiseFunctionINTELInst, \
Op##x##INTEL, __VA_ARGS__> \
SPIRV##x##INTEL;
_SPIRV_OP(BitwiseFunction, true, 7)
#undef _SPIRV_OP
class SPIRVPredicatedIOINTELInst : public SPIRVInstTemplateBase {
public:
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_predicated_io;
}
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityPredicatedIOINTEL);
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVPredicatedIOINTELInst, Op##x##INTEL, \
__VA_ARGS__> \
SPIRV##x##INTEL;
_SPIRV_OP(PredicatedLoad, true, 6, true)
_SPIRV_OP(PredicatedStore, false, 4, true)
#undef _SPIRV_OP
template <Op OC> class SPIRVFSigmoidINTELInstBase : public SPIRVUnaryInst<OC> {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(internal::CapabilitySigmoidINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_sigmoid;
}
void validate() const override {
SPIRVUnaryInst<OC>::validate();
SPIRVType *ResCompTy = this->getType();
SPIRVWord ResCompCount = 1;
if (ResCompTy->isTypeVector()) {
ResCompCount = ResCompTy->getVectorComponentCount();
ResCompTy = ResCompTy->getVectorComponentType();
}
// validate is a const method, whilst getOperand is non-const method
// because it may call a method of class Module that may modify LiteralMap
// of Module field. That modification is not impacting validate method for
// these instructions, so const_cast is safe here.
using SPVFSigmoidTy = SPIRVFSigmoidINTELInstBase<OC>;
const SPIRVValue *Input = const_cast<SPVFSigmoidTy *>(this)->getOperand(0);
SPIRVType *InCompTy = Input->getType();
SPIRVWord InCompCount = 1;
if (InCompTy->isTypeVector()) {
InCompCount = InCompTy->getVectorComponentCount();
InCompTy = InCompTy->getVectorComponentType();
}
auto InstName = OpCodeNameMap::map(OC);
SPIRVErrorLog &SPVErrLog = this->getModule()->getErrorLog();
SPVErrLog.checkError(
ResCompTy->isTypeFloat(16) || ResCompTy->isTypeFloat(32) ||
ResCompTy->isTypeFloat(16, FPEncodingBFloat16KHR),
SPIRVEC_InvalidInstruction,
InstName + "\nResult value must be a scalar or vector of floating-point"
" 16-bit or 32-bit type\n");
SPVErrLog.checkError(
ResCompTy == InCompTy, SPIRVEC_InvalidInstruction,
InstName +
"\nInput type must have the same component type as result type\n");
SPVErrLog.checkError(
ResCompCount == InCompCount, SPIRVEC_InvalidInstruction,
InstName + "\nInput type must have the same number of components as "
"result type\n");
}
};
#define _SPIRV_OP(x) \
typedef SPIRVFSigmoidINTELInstBase<internal::Op##x> SPIRV##x;
_SPIRV_OP(FSigmoidINTEL)
#undef _SPIRV_OP
class SPIRVFPConversionINTELInstBase : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(internal::CapabilityFloatConversionsINTEL);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_INTEL_fp_conversions;
}
};
#define _SPIRV_OP(x, ...) \
typedef SPIRVInstTemplate<SPIRVFPConversionINTELInstBase, \
internal::Op##x##INTEL, __VA_ARGS__> \
SPIRV##x##INTEL;
_SPIRV_OP(ClampConvertFToF, true, 4, false)
_SPIRV_OP(ClampConvertFToS, true, 4, false)
_SPIRV_OP(StochasticRoundFToF, true, 5, true)
_SPIRV_OP(ClampStochasticRoundFToF, true, 5, true)
_SPIRV_OP(ClampStochasticRoundFToS, true, 5, true)
#undef _SPIRV_OP
class SPIRVFmaKHRInstBase : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityFMAKHR);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_KHR_fma;
}
};
typedef SPIRVInstTemplate<SPIRVFmaKHRInstBase, OpFmaKHR, true, 6, false>
SPIRVFmaKHR;
class SPIRVFreezeKHRInstBase : public SPIRVInstTemplateBase {
public:
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityPoisonFreezeKHR);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_KHR_poison_freeze;
}
};
typedef SPIRVInstTemplate<SPIRVFreezeKHRInstBase, OpFreezeKHR, true, 4, false>
SPIRVFreezeKHR;
} // namespace SPIRV
#endif // SPIRV_LIBSPIRV_SPIRVINSTRUCTION_H