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

494 lines
16 KiB
C++

//===- SPIRVValue.h - Class to represent a SPIR-V Value ---------*- C++ -*-===//
//
// The LLVM/SPIRV Translator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
// Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal with the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimers in the documentation
// and/or other materials provided with the distribution.
// Neither the names of Advanced Micro Devices, Inc., nor the names of its
// contributors may be used to endorse or promote products derived from this
// Software without specific prior written permission.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
//
//===----------------------------------------------------------------------===//
/// \file
///
/// This file defines the values defined in SPIR-V spec with op codes.
///
/// The name of the SPIR-V values follow the op code name in the spec.
/// This is for readability and ease of using macro to handle types.
//
//===----------------------------------------------------------------------===//
#ifndef SPIRV_LIBSPIRV_SPIRVVALUE_H
#define SPIRV_LIBSPIRV_SPIRVVALUE_H
#include "SPIRVDecorate.h"
#include "SPIRVEntry.h"
#include "SPIRVType.h"
namespace llvm {
class APInt;
} // namespace llvm
#include <iostream>
namespace SPIRV {
class SPIRVValue : public SPIRVEntry {
public:
// Complete constructor for value with id and type
SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
SPIRVType *TheType, SPIRVId TheId)
: SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(TheType) {
validate();
}
// Complete constructor for value with type but without id
SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
SPIRVType *TheType)
: SPIRVEntry(M, TheWordCount, TheOpCode), Type(TheType) {
setHasNoId();
SPIRVValue::validate();
}
// Complete constructor for value with id but without type
SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, SPIRVId TheId)
: SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(NULL) {
setHasNoType();
SPIRVValue::validate();
}
// Complete constructor for value without id and type
SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode)
: SPIRVEntry(M, TheWordCount, TheOpCode), Type(NULL) {
setHasNoId();
setHasNoType();
SPIRVValue::validate();
}
// Incomplete constructor
SPIRVValue(Op TheOpCode) : SPIRVEntry(TheOpCode), Type(NULL) {}
bool hasType() const { return !(Attrib & SPIRVEA_NOTYPE); }
SPIRVType *getType() const {
assert(hasType() && "value has no type");
return Type;
}
bool isVolatile() const;
bool hasAlignment(SPIRVWord *Result = 0) const;
bool hasNoSignedWrap() const;
bool hasNoUnsignedWrap() const;
void setAlignment(SPIRVWord);
void setVolatile(bool IsVolatile);
template <spv::Decoration NoIntegerWrapDecoration>
void setNoIntegerDecorationWrap(bool HasNoIntegerWrap);
void setFPFastMathMode(SPIRVWord FPFastMathMode);
void validate() const override {
SPIRVEntry::validate();
assert((!hasType() || Type) && "Invalid type");
}
void setType(SPIRVType *Ty) {
Type = Ty;
assert(!Ty || !Ty->isTypeVoid() || OpCode == OpFunction ||
OpCode == internal::OpTaskSequenceGetINTEL);
if (Ty && (!Ty->isTypeVoid() || OpCode == OpFunction ||
OpCode == internal::OpTaskSequenceGetINTEL))
setHasType();
else
setHasNoType();
}
SPIRVCapVec getRequiredCapability() const override {
SPIRVCapVec CV;
if (!hasType())
return CV;
return Type->getRequiredCapability();
}
std::optional<ExtensionID> getRequiredExtension() const override {
std::optional<ExtensionID> EV;
if (!hasType())
return EV;
EV = Type->getRequiredExtension();
assert(Module &&
(!EV.has_value() || Module->isAllowedToUseExtension(EV.value())));
return EV;
}
protected:
void setHasNoType() { Attrib |= SPIRVEA_NOTYPE; }
void setHasType() { Attrib &= ~SPIRVEA_NOTYPE; }
SPIRVType *Type; // Value Type
};
template <spv::Op OC> class SPIRVConstantBase : public SPIRVValue {
public:
// Complete constructor for integer constant
SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
uint64_t TheValue)
: SPIRVValue(M, 0, OC, TheType, TheId) {
setWords(&TheValue);
}
// Incomplete constructor for AP integer constant
SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
const llvm::APInt &TheValue);
// Complete constructor for float constant
SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
float TheValue)
: SPIRVValue(M, 0, OC, TheType, TheId) {
setWords(reinterpret_cast<uint64_t *>(&TheValue));
}
// Complete constructor for double constant
SPIRVConstantBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
double TheValue)
: SPIRVValue(M, 0, OC, TheType, TheId) {
setWords(reinterpret_cast<uint64_t *>(&TheValue));
}
// Incomplete constructor
SPIRVConstantBase() : SPIRVValue(OC), NumWords(0) {}
uint64_t getZExtIntValue() const { return getValue<uint64_t>(); }
float getFloatValue() const { return getValue<float>(); }
double getDoubleValue() const { return getValue<double>(); }
unsigned getNumWords() const { return NumWords; }
const std::vector<SPIRVWord> &getSPIRVWords() { return Words; }
protected:
constexpr static SPIRVWord FixedWC = 3;
// Common method for getting values of size less or equal to 64 bits.
template <typename T> T getValue() const {
if (OpCode == OpConstantNull) {
assert(std::is_arithmetic_v<T> &&
"OpConstantNull has no defined value for this type");
return 0;
}
constexpr auto ValueSize = static_cast<unsigned>(sizeof(T));
assert((ValueSize <= 8) && "Incorrect result type of requested value");
T TheValue{};
unsigned CopyBytes = std::min(ValueSize, NumWords * SpirvWordSize);
std::memcpy(&TheValue, Words.data(), CopyBytes);
return TheValue;
}
void setWords(const uint64_t *TheValue);
void recalculateWordCount() {
NumWords =
(Type->getBitWidth() + SpirvWordBitWidth - 1) / SpirvWordBitWidth;
WordCount = FixedWC + NumWords;
}
void validate() const override {
SPIRVValue::validate();
assert(NumWords >= 1 && "Invalid constant size");
}
void encode(spv_ostream &O) const override {
getEncoder(O) << Type << Id;
for (const auto &Word : Words)
getEncoder(O) << Word;
}
void setWordCount(SPIRVWord WordCount) override {
SPIRVValue::setWordCount(WordCount);
NumWords = WordCount - FixedWC;
}
void decode(std::istream &I) override {
getDecoder(I) >> Type >> Id;
Words.resize(NumWords);
for (auto &Word : Words)
getDecoder(I) >> Word;
}
unsigned NumWords;
private:
std::vector<SPIRVWord> Words;
};
using SPIRVConstant = SPIRVConstantBase<OpConstant>;
using SPIRVSpecConstant = SPIRVConstantBase<OpSpecConstant>;
template <Op OC> class SPIRVConstantEmpty : public SPIRVValue {
public:
// Complete constructor
SPIRVConstantEmpty(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
: SPIRVValue(M, 3, OC, TheType, TheId) {
validate();
}
// Incomplete constructor
SPIRVConstantEmpty() : SPIRVValue(OC) {}
protected:
void validate() const override { SPIRVValue::validate(); }
_SPIRV_DEF_ENCDEC2(Type, Id)
};
template <Op OC> class SPIRVConstantBool : public SPIRVConstantEmpty<OC> {
public:
// Complete constructor
SPIRVConstantBool(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
: SPIRVConstantEmpty<OC>(M, TheType, TheId) {}
// Incomplete constructor
SPIRVConstantBool() {}
protected:
void validate() const override {
SPIRVConstantEmpty<OC>::validate();
assert(this->Type->isTypeBool() && "Invalid type");
}
};
typedef SPIRVConstantBool<OpConstantTrue> SPIRVConstantTrue;
typedef SPIRVConstantBool<OpConstantFalse> SPIRVConstantFalse;
typedef SPIRVConstantBool<OpSpecConstantTrue> SPIRVSpecConstantTrue;
typedef SPIRVConstantBool<OpSpecConstantFalse> SPIRVSpecConstantFalse;
class SPIRVConstantNull : public SPIRVConstantEmpty<OpConstantNull> {
public:
// Complete constructor
SPIRVConstantNull(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
: SPIRVConstantEmpty(M, TheType, TheId) {
validate();
}
// Incomplete constructor
SPIRVConstantNull() {}
protected:
void validate() const override {
SPIRVConstantEmpty::validate();
assert((Type->isTypeBool() || Type->isTypeInt() || Type->isTypeFloat() ||
Type->isTypeComposite() || Type->isTypeOpaque() ||
Type->isTypeEvent() || Type->isTypePointer() ||
Type->isTypeReserveId() || Type->isTypeDeviceEvent() ||
(Type->isTypeSubgroupAvcINTEL() &&
!Type->isTypeSubgroupAvcMceINTEL())) &&
"Invalid type");
}
};
class SPIRVUndef : public SPIRVConstantEmpty<OpUndef> {
public:
// Complete constructor
SPIRVUndef(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
: SPIRVConstantEmpty(M, TheType, TheId) {
validate();
}
// Incomplete constructor
SPIRVUndef() {}
protected:
void validate() const override { SPIRVConstantEmpty::validate(); }
};
class SPIRVPoisonKHR : public SPIRVConstantEmpty<OpPoisonKHR> {
public:
SPIRVPoisonKHR(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
: SPIRVConstantEmpty(M, TheType, TheId) {
validate();
}
SPIRVPoisonKHR() {}
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityPoisonFreezeKHR);
}
std::optional<ExtensionID> getRequiredExtension() const override {
return ExtensionID::SPV_KHR_poison_freeze;
}
protected:
void validate() const override { SPIRVConstantEmpty::validate(); }
};
template <spv::Op OC> class SPIRVConstantCompositeBase : public SPIRVValue {
public:
// There are always 3 words in this instruction except constituents:
// 1) WordCount + OpCode
// 2) Result type
// 3) Result Id
constexpr static SPIRVWord FixedWC = 3;
using ContinuedInstType = typename InstToContinued<OC>::Type;
// Complete constructor for composite constant
SPIRVConstantCompositeBase(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
const std::vector<SPIRVValue *> TheElements)
: SPIRVValue(M, TheElements.size() + FixedWC, OC, TheType, TheId) {
Elements = getIds(TheElements);
validate();
}
// Incomplete constructor
SPIRVConstantCompositeBase() : SPIRVValue(OC) {}
std::vector<SPIRVValue *> getElements() const { return getValues(Elements); }
// TODO: Should we attach operands of continued instructions as well?
std::vector<SPIRVEntry *> getNonLiteralOperands() const override {
std::vector<SPIRVValue *> Elements = getElements();
return std::vector<SPIRVEntry *>(Elements.begin(), Elements.end());
}
std::vector<ContinuedInstType> getContinuedInstructions() {
return ContinuedInstructions;
}
void addContinuedInstruction(ContinuedInstType Inst) {
ContinuedInstructions.push_back(Inst);
}
void encodeChildren(spv_ostream &O) const override {
O << SPIRVNL();
for (auto &I : ContinuedInstructions)
O << *I;
}
protected:
void validate() const override {
SPIRVValue::validate();
for (auto &I : Elements)
getValue(I)->validate();
}
void setWordCount(SPIRVWord WordCount) override {
SPIRVEntry::setWordCount(WordCount);
SPIRVCK(WordCount >= FixedWC, InvalidWordCount, "");
Elements.resize(WordCount - FixedWC);
}
void encode(spv_ostream &O) const override {
getEncoder(O) << Type << Id << Elements;
}
void decode(std::istream &I) override {
SPIRVDecoder Decoder = getDecoder(I);
Decoder >> Type >> Id >> Elements;
for (SPIRVEntry *E : Decoder.getContinuedInstructions(ContinuedOpCode)) {
addContinuedInstruction(static_cast<ContinuedInstType>(E));
}
}
std::vector<SPIRVId> Elements;
std::vector<ContinuedInstType> ContinuedInstructions;
const spv::Op ContinuedOpCode = InstToContinued<OC>::OpCode;
};
using SPIRVConstantComposite = SPIRVConstantCompositeBase<OpConstantComposite>;
using SPIRVSpecConstantComposite =
SPIRVConstantCompositeBase<OpSpecConstantComposite>;
class SPIRVConstantSampler : public SPIRVValue {
public:
const static Op OC = OpConstantSampler;
const static SPIRVWord WC = 6;
// Complete constructor
SPIRVConstantSampler(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
SPIRVWord TheAddrMode, SPIRVWord TheNormalized,
SPIRVWord TheFilterMode)
: SPIRVValue(M, WC, OC, TheType, TheId), AddrMode(TheAddrMode),
Normalized(TheNormalized), FilterMode(TheFilterMode) {
validate();
}
// Incomplete constructor
SPIRVConstantSampler()
: SPIRVValue(OC), AddrMode(SPIRVSAM_Invalid), Normalized(SPIRVWORD_MAX),
FilterMode(SPIRVSFM_Invalid) {}
SPIRVWord getAddrMode() const { return AddrMode; }
SPIRVWord getFilterMode() const { return FilterMode; }
SPIRVWord getNormalized() const { return Normalized; }
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityLiteralSampler);
}
protected:
SPIRVWord AddrMode;
SPIRVWord Normalized;
SPIRVWord FilterMode;
void validate() const override {
SPIRVValue::validate();
assert(OpCode == OC);
assert(WordCount == WC);
assert(Type->isTypeSampler());
}
_SPIRV_DEF_ENCDEC5(Type, Id, AddrMode, Normalized, FilterMode)
};
class SPIRVConstantPipeStorage : public SPIRVValue {
public:
const static Op OC = OpConstantPipeStorage;
const static SPIRVWord WC = 6;
// Complete constructor
SPIRVConstantPipeStorage(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
SPIRVWord ThePacketSize, SPIRVWord ThePacketAlign,
SPIRVWord TheCapacity)
: SPIRVValue(M, WC, OC, TheType, TheId), PacketSize(ThePacketSize),
PacketAlign(ThePacketAlign), Capacity(TheCapacity) {
validate();
}
// Incomplete constructor
SPIRVConstantPipeStorage()
: SPIRVValue(OC), PacketSize(0), PacketAlign(0), Capacity(0) {}
SPIRVWord getPacketSize() const { return PacketSize; }
SPIRVWord getPacketAlign() const { return PacketAlign; }
SPIRVWord getCapacity() const { return Capacity; }
SPIRVCapVec getRequiredCapability() const override {
return getVec(CapabilityPipes, CapabilityPipeStorage);
}
protected:
SPIRVWord PacketSize;
SPIRVWord PacketAlign;
SPIRVWord Capacity;
void validate() const override {
SPIRVValue::validate();
assert(OpCode == OC);
assert(WordCount == WC);
assert(Type->isTypePipeStorage());
}
_SPIRV_DEF_ENCDEC5(Type, Id, PacketSize, PacketAlign, Capacity)
};
class SPIRVForward : public SPIRVValue, public SPIRVComponentExecutionModes {
public:
const static Op OC = internal::OpForward;
// Complete constructor
SPIRVForward(SPIRVModule *TheModule, SPIRVType *TheTy, SPIRVId TheId)
: SPIRVValue(TheModule, 0, OC, TheId) {
if (TheTy)
setType(TheTy);
}
SPIRVForward() : SPIRVValue(OC) { assert(0 && "should never be called"); }
_SPIRV_DEF_ENCDEC1(Id)
friend class SPIRVFunction;
protected:
void validate() const override {}
};
} // namespace SPIRV
#endif // SPIRV_LIBSPIRV_SPIRVVALUE_H