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
374 lines
12 KiB
C++
374 lines
12 KiB
C++
//===- SPIRVStream.cpp - Class to represent a SPIR-V Stream -----*- 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 implements SPIR-V stream class.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
#include "SPIRVStream.h"
|
|
#include "SPIRVDebug.h"
|
|
#include "SPIRVFunction.h"
|
|
#include "SPIRVInstruction.h"
|
|
#include "SPIRVNameMapEnum.h"
|
|
#include "SPIRVOpCode.h"
|
|
|
|
#include <limits> // std::numeric_limits
|
|
|
|
namespace SPIRV {
|
|
|
|
/// Write string with quote. Replace " with \".
|
|
static void writeQuotedString(spv_ostream &O, const std::string &Str) {
|
|
O << '"';
|
|
for (auto I : Str) {
|
|
if (I == '"')
|
|
O << '\\';
|
|
O << I;
|
|
}
|
|
O << '"';
|
|
}
|
|
|
|
/// Read quoted string. Replace \" with ".
|
|
static void readQuotedString(std::istream &IS, std::string &Str) {
|
|
char Ch = ' ';
|
|
char PreCh = ' ';
|
|
while (IS >> Ch && Ch != '"')
|
|
;
|
|
|
|
if (IS >> PreCh && PreCh != '"') {
|
|
while (IS >> Ch) {
|
|
if (Ch == '"') {
|
|
if (PreCh != '\\') {
|
|
Str += PreCh;
|
|
break;
|
|
} else
|
|
PreCh = Ch;
|
|
} else {
|
|
Str += PreCh;
|
|
PreCh = Ch;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
|
bool SPIRVUseTextFormat = false;
|
|
#endif
|
|
|
|
SPIRVDecoder::SPIRVDecoder(std::istream &InputStream, SPIRVFunction &F)
|
|
: IS(InputStream), M(*F.getModule()), WordCount(0), OpCode(OpNop),
|
|
Scope(&F) {}
|
|
|
|
SPIRVDecoder::SPIRVDecoder(std::istream &InputStream, SPIRVBasicBlock &BB)
|
|
: IS(InputStream), M(*BB.getModule()), WordCount(0), OpCode(OpNop),
|
|
Scope(&BB) {}
|
|
|
|
void SPIRVDecoder::setScope(SPIRVEntry *TheScope) {
|
|
assert(TheScope && (TheScope->getOpCode() == OpFunction ||
|
|
TheScope->getOpCode() == OpLabel));
|
|
Scope = TheScope;
|
|
}
|
|
|
|
template <class T> const SPIRVDecoder &decode(const SPIRVDecoder &I, T &V) {
|
|
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
|
if (SPIRVUseTextFormat) {
|
|
std::string W;
|
|
I.IS >> W;
|
|
V = getNameMap(V).rmap(W);
|
|
SPIRVDBG(spvdbgs() << "Read word: W = " << W << " V = " << V << '\n');
|
|
return I;
|
|
}
|
|
#endif
|
|
return decodeBinary(I, V);
|
|
}
|
|
|
|
template <class T> const SPIRVEncoder &encode(const SPIRVEncoder &O, T V) {
|
|
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
|
if (SPIRVUseTextFormat) {
|
|
O.OS << getNameMap(V).map(V) << " ";
|
|
return O;
|
|
}
|
|
#endif
|
|
return O << static_cast<SPIRVWord>(V);
|
|
}
|
|
|
|
template <>
|
|
const SPIRVEncoder &operator<<(const SPIRVEncoder &O, SPIRVType *P) {
|
|
if (!P->hasId() && P->getOpCode() == OpTypeForwardPointer)
|
|
return O << static_cast<SPIRVTypeForwardPointer *>(
|
|
static_cast<SPIRVEntry *>(P))
|
|
->getPointerId();
|
|
return O << P->getId();
|
|
}
|
|
|
|
#define SPIRV_DEF_ENCDEC(Type) \
|
|
const SPIRVDecoder &operator>>(const SPIRVDecoder &I, Type &V) { \
|
|
return decode(I, V); \
|
|
} \
|
|
const SPIRVEncoder &operator<<(const SPIRVEncoder &O, Type V) { \
|
|
return encode(O, V); \
|
|
}
|
|
|
|
SPIRV_DEF_ENCDEC(Op)
|
|
SPIRV_DEF_ENCDEC(Capability)
|
|
SPIRV_DEF_ENCDEC(Decoration)
|
|
SPIRV_DEF_ENCDEC(OCLExtOpKind)
|
|
SPIRV_DEF_ENCDEC(SPIRVDebugExtOpKind)
|
|
SPIRV_DEF_ENCDEC(NonSemanticAuxDataOpKind)
|
|
SPIRV_DEF_ENCDEC(InitializationModeQualifier)
|
|
SPIRV_DEF_ENCDEC(HostAccessQualifier)
|
|
SPIRV_DEF_ENCDEC(NamedMaximumNumberOfRegisters)
|
|
SPIRV_DEF_ENCDEC(LinkageType)
|
|
|
|
// Read a string with padded 0's at the end so that they form a stream of
|
|
// words.
|
|
const SPIRVDecoder &operator>>(const SPIRVDecoder &I, std::string &Str) {
|
|
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
|
if (SPIRVUseTextFormat) {
|
|
readQuotedString(I.IS, Str);
|
|
SPIRVDBG(spvdbgs() << "Read string: \"" << Str << "\"\n");
|
|
return I;
|
|
}
|
|
#endif
|
|
|
|
uint64_t Count = 0;
|
|
char Ch;
|
|
while (I.IS.get(Ch) && Ch != '\0') {
|
|
Str += Ch;
|
|
++Count;
|
|
}
|
|
Count = (Count + 1) % 4;
|
|
Count = Count ? 4 - Count : 0;
|
|
for (; Count; --Count) {
|
|
I.IS >> Ch;
|
|
assert(Ch == '\0' && "Invalid string in SPIRV");
|
|
}
|
|
SPIRVDBG(spvdbgs() << "Read string: \"" << Str << "\"\n");
|
|
return I;
|
|
}
|
|
|
|
// Write a string with padded 0's at the end so that they form a stream of
|
|
// words.
|
|
const SPIRVEncoder &operator<<(const SPIRVEncoder &O, const std::string &Str) {
|
|
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
|
if (SPIRVUseTextFormat) {
|
|
writeQuotedString(O.OS, Str);
|
|
O.OS << " ";
|
|
return O;
|
|
}
|
|
#endif
|
|
|
|
size_t L = Str.length();
|
|
O.OS.write(Str.c_str(), L);
|
|
char Zeros[4] = {0, 0, 0, 0};
|
|
O.OS.write(Zeros, 4 - L % 4);
|
|
return O;
|
|
}
|
|
|
|
bool SPIRVDecoder::getWordCountAndOpCode() {
|
|
if (IS.eof()) {
|
|
WordCount = 0;
|
|
OpCode = OpNop;
|
|
SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode EOF "
|
|
<< WordCount << " " << OpCode << '\n');
|
|
return false;
|
|
}
|
|
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
|
if (SPIRVUseTextFormat) {
|
|
*this >> WordCount;
|
|
assert(!IS.bad() && "SPIRV stream is bad");
|
|
if (IS.fail()) {
|
|
WordCount = 0;
|
|
OpCode = OpNop;
|
|
SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode FAIL "
|
|
<< WordCount << " " << OpCode << '\n');
|
|
return false;
|
|
}
|
|
*this >> OpCode;
|
|
} else {
|
|
#endif
|
|
SPIRVWord WordCountAndOpCode;
|
|
*this >> WordCountAndOpCode;
|
|
WordCount = WordCountAndOpCode >> 16;
|
|
OpCode = static_cast<Op>(WordCountAndOpCode & 0xFFFF);
|
|
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
|
}
|
|
#endif
|
|
assert(!IS.bad() && "SPIRV stream is bad");
|
|
if (IS.fail()) {
|
|
WordCount = 0;
|
|
OpCode = OpNop;
|
|
SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode FAIL "
|
|
<< WordCount << " " << OpCode << '\n');
|
|
return false;
|
|
}
|
|
SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode " << WordCount
|
|
<< " " << OpCodeNameMap::map(OpCode) << '\n');
|
|
return true;
|
|
}
|
|
|
|
SPIRVEntry *SPIRVDecoder::getEntry() {
|
|
if (WordCount == 0 || OpCode == OpNop)
|
|
return nullptr;
|
|
SPIRVEntry *Entry = SPIRVEntry::create(OpCode);
|
|
assert(Entry);
|
|
Entry->setModule(&M);
|
|
if (isModuleScopeAllowedOpCode(OpCode) && !Scope) {
|
|
} else
|
|
Entry->setScope(Scope);
|
|
Entry->setWordCount(WordCount);
|
|
if (OpCode != OpLine)
|
|
Entry->setLine(M.getCurrentLine());
|
|
if (!Entry->isExtInst(SPIRVEIS_NonSemantic_Shader_DebugInfo_100,
|
|
SPIRVDebug::DebugLine) &&
|
|
!Entry->isExtInst(SPIRVEIS_NonSemantic_Shader_DebugInfo_200,
|
|
SPIRVDebug::DebugLine))
|
|
Entry->setDebugLine(M.getCurrentDebugLine());
|
|
|
|
IS >> *Entry;
|
|
if (Entry->isEndOfBlock() || OpCode == OpNoLine)
|
|
M.setCurrentLine(nullptr);
|
|
if (Entry->isEndOfBlock() ||
|
|
Entry->isExtInst(SPIRVEIS_NonSemantic_Shader_DebugInfo_100,
|
|
SPIRVDebug::DebugNoLine) ||
|
|
Entry->isExtInst(SPIRVEIS_NonSemantic_Shader_DebugInfo_200,
|
|
SPIRVDebug::DebugNoLine))
|
|
M.setCurrentDebugLine(nullptr);
|
|
|
|
if (OpExtension == OpCode) {
|
|
auto *OpExt = static_cast<SPIRVExtension *>(Entry);
|
|
ExtensionID ExtID = {};
|
|
bool ExtIsKnown = SPIRVMap<ExtensionID, std::string>::rfind(
|
|
OpExt->getExtensionName(), &ExtID);
|
|
if (!M.getErrorLog().checkError(
|
|
ExtIsKnown, SPIRVEC_InvalidModule,
|
|
"input SPIR-V module uses unknown extension '" +
|
|
OpExt->getExtensionName() + "'")) {
|
|
M.setInvalid();
|
|
}
|
|
|
|
if (!M.getErrorLog().checkError(
|
|
M.isAllowedToUseExtension(ExtID), SPIRVEC_InvalidModule,
|
|
"input SPIR-V module uses extension '" + OpExt->getExtensionName() +
|
|
"' which were disabled by --spirv-ext option")) {
|
|
M.setInvalid();
|
|
}
|
|
}
|
|
|
|
if (!M.getErrorLog().checkError(Entry->isImplemented(),
|
|
SPIRVEC_UnimplementedOpCode,
|
|
std::to_string(Entry->getOpCode()))) {
|
|
M.setInvalid();
|
|
}
|
|
|
|
assert(!IS.bad() && !IS.fail() && "SPIRV stream fails");
|
|
return Entry;
|
|
}
|
|
|
|
void SPIRVDecoder::validate() const {
|
|
assert(OpCode != OpNop && "Invalid op code");
|
|
assert(WordCount && "Invalid word count");
|
|
assert(!IS.bad() && "Bad iInput stream");
|
|
}
|
|
|
|
// Skip \param n words in SPIR-V binary stream.
|
|
// In case of SPIR-V text format always skip until the end of the line.
|
|
void SPIRVDecoder::ignore(size_t N) {
|
|
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
|
if (SPIRVUseTextFormat) {
|
|
IS.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
|
return;
|
|
}
|
|
#endif
|
|
IS.ignore(N * sizeof(SPIRVWord));
|
|
}
|
|
|
|
void SPIRVDecoder::ignoreInstruction() { ignore(WordCount - 1); }
|
|
|
|
spv_ostream &operator<<(spv_ostream &O, const SPIRVNL &E) {
|
|
#ifdef _SPIRV_SUPPORT_TEXT_FMT
|
|
if (SPIRVUseTextFormat)
|
|
O << '\n';
|
|
#endif
|
|
return O;
|
|
}
|
|
|
|
// Read the next word from the stream and if OpCode matches the argument,
|
|
// decode the whole instruction. Multiple such instructions are possible. If
|
|
// OpCode doesn't match the argument, set position of the next character to be
|
|
// extracted from the stream to the beginning of the non-matching instruction.
|
|
// Returns vector of extracted instructions.
|
|
// Used to decode SPIRVTypeStructContinuedINTEL,
|
|
// SPIRVConstantCompositeContinuedINTEL and
|
|
// SPIRVSpecConstantCompositeContinuedINTEL.
|
|
std::vector<SPIRVEntry *>
|
|
SPIRVDecoder::getContinuedInstructions(const spv::Op ContinuedOpCode) {
|
|
std::vector<SPIRVEntry *> ContinuedInst;
|
|
std::streampos Pos = IS.tellg(); // remember position
|
|
getWordCountAndOpCode();
|
|
while (OpCode == ContinuedOpCode) {
|
|
SPIRVEntry *Entry = getEntry();
|
|
assert(Entry && "Failed to decode entry! Invalid instruction!");
|
|
M.add(Entry);
|
|
ContinuedInst.push_back(Entry);
|
|
Pos = IS.tellg();
|
|
getWordCountAndOpCode();
|
|
}
|
|
IS.seekg(Pos); // restore position
|
|
return ContinuedInst;
|
|
}
|
|
|
|
std::vector<SPIRVEntry *> SPIRVDecoder::getSourceContinuedInstructions() {
|
|
std::vector<SPIRVEntry *> ContinuedInst;
|
|
std::streampos Pos = IS.tellg(); // remember position
|
|
getWordCountAndOpCode();
|
|
while (OpCode == OpExtInst) {
|
|
SPIRVEntry *Entry = getEntry();
|
|
assert(Entry && "Failed to decode entry! Invalid instruction!");
|
|
SPIRVExtInst *Inst = static_cast<SPIRVExtInst *>(Entry);
|
|
if (Inst->getExtOp() != SPIRVDebug::Instruction::SourceContinued) {
|
|
IS.seekg(Pos); // restore position
|
|
delete Entry;
|
|
return ContinuedInst;
|
|
}
|
|
M.add(Entry);
|
|
ContinuedInst.push_back(Entry);
|
|
Pos = IS.tellg();
|
|
getWordCountAndOpCode();
|
|
}
|
|
IS.seekg(Pos); // restore position
|
|
return ContinuedInst;
|
|
}
|
|
|
|
} // namespace SPIRV
|