Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -3,27 +3,46 @@ set(SOURCES
|
||||
InReadableOrder.cpp
|
||||
Logger.cpp
|
||||
SpvBuilder.cpp
|
||||
SPVRemapper.cpp
|
||||
doc.cpp
|
||||
disassemble.cpp)
|
||||
|
||||
set(SPVREMAP_SOURCES
|
||||
SPVRemapper.cpp
|
||||
doc.cpp)
|
||||
|
||||
set(HEADERS
|
||||
bitutils.h
|
||||
spirv.hpp
|
||||
GLSL.std.450.h
|
||||
GLSL.ext.KHR.h
|
||||
GlslangToSpv.h
|
||||
hex_float.h
|
||||
Logger.h
|
||||
SpvBuilder.h
|
||||
SPVRemapper.h
|
||||
spvIR.h
|
||||
doc.h
|
||||
disassemble.h)
|
||||
|
||||
set(SPVREMAP_HEADERS
|
||||
SPVRemapper.h
|
||||
doc.h)
|
||||
|
||||
if(ENABLE_AMD_EXTENSIONS)
|
||||
list(APPEND
|
||||
HEADERS
|
||||
GLSL.ext.AMD.h)
|
||||
endif(ENABLE_AMD_EXTENSIONS)
|
||||
|
||||
add_library(SPIRV STATIC ${SOURCES} ${HEADERS})
|
||||
set_property(TARGET SPIRV PROPERTY FOLDER glslang)
|
||||
|
||||
add_library(SPVRemapper STATIC ${SPVREMAP_SOURCES} ${SPVREMAP_HEADERS})
|
||||
set_property(TARGET SPVRemapper PROPERTY FOLDER glslang)
|
||||
|
||||
if(WIN32)
|
||||
source_group("Source" FILES ${SOURCES} ${HEADERS})
|
||||
source_group("Source" FILES ${SPVREMAP_SOURCES} ${SPVREMAP_HEADERS})
|
||||
endif(WIN32)
|
||||
|
||||
install(TARGETS SPIRV
|
||||
install(TARGETS SPIRV SPVRemapper
|
||||
ARCHIVE DESTINATION lib)
|
||||
|
||||
116
SPIRV/GLSL.ext.AMD.h
Normal file
116
SPIRV/GLSL.ext.AMD.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
** Copyright (c) 2014-2016 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and/or associated documentation files (the "Materials"),
|
||||
** to deal in the Materials without restriction, including without limitation
|
||||
** the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
** and/or sell copies of the Materials, and to permit persons to whom the
|
||||
** Materials are furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Materials.
|
||||
**
|
||||
** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
|
||||
** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
|
||||
** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
|
||||
**
|
||||
** THE MATERIALS ARE 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 AUTHORS 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 MATERIALS OR THE USE OR OTHER DEALINGS
|
||||
** IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
#ifndef GLSLextAMD_H
|
||||
#define GLSLextAMD_H
|
||||
|
||||
enum BuiltIn;
|
||||
enum Decoration;
|
||||
enum Op;
|
||||
|
||||
static const int GLSLextAMDVersion = 100;
|
||||
static const int GLSLextAMDRevision = 2;
|
||||
|
||||
// SPV_AMD_shader_ballot
|
||||
static const char* const E_SPV_AMD_shader_ballot = "SPV_AMD_shader_ballot";
|
||||
|
||||
static const Op OpGroupIAddNonUniformAMD = static_cast<Op>(5000);
|
||||
static const Op OpGroupFAddNonUniformAMD = static_cast<Op>(5001);
|
||||
static const Op OpGroupFMinNonUniformAMD = static_cast<Op>(5002);
|
||||
static const Op OpGroupUMinNonUniformAMD = static_cast<Op>(5003);
|
||||
static const Op OpGroupSMinNonUniformAMD = static_cast<Op>(5004);
|
||||
static const Op OpGroupFMaxNonUniformAMD = static_cast<Op>(5005);
|
||||
static const Op OpGroupUMaxNonUniformAMD = static_cast<Op>(5006);
|
||||
static const Op OpGroupSMaxNonUniformAMD = static_cast<Op>(5007);
|
||||
|
||||
enum ShaderBallotAMD {
|
||||
ShaderBallotBadAMD = 0, // Don't use
|
||||
|
||||
SwizzleInvocationsAMD = 1,
|
||||
SwizzleInvocationsMaskedAMD = 2,
|
||||
WriteInvocationAMD = 3,
|
||||
MbcntAMD = 4,
|
||||
|
||||
ShaderBallotCountAMD
|
||||
};
|
||||
|
||||
// SPV_AMD_shader_trinary_minmax
|
||||
static const char* const E_SPV_AMD_shader_trinary_minmax = "SPV_AMD_shader_trinary_minmax";
|
||||
|
||||
enum ShaderTrinaryMinMaxAMD {
|
||||
ShaderTrinaryMinMaxBadAMD = 0, // Don't use
|
||||
|
||||
FMin3AMD = 1,
|
||||
UMin3AMD = 2,
|
||||
SMin3AMD = 3,
|
||||
FMax3AMD = 4,
|
||||
UMax3AMD = 5,
|
||||
SMax3AMD = 6,
|
||||
FMid3AMD = 7,
|
||||
UMid3AMD = 8,
|
||||
SMid3AMD = 9,
|
||||
|
||||
ShaderTrinaryMinMaxCountAMD
|
||||
};
|
||||
|
||||
// SPV_AMD_shader_explicit_vertex_parameter
|
||||
static const char* const E_SPV_AMD_shader_explicit_vertex_parameter = "SPV_AMD_shader_explicit_vertex_parameter";
|
||||
|
||||
static const BuiltIn BuiltInBaryCoordNoPerspAMD = static_cast<BuiltIn>(4992);
|
||||
static const BuiltIn BuiltInBaryCoordNoPerspCentroidAMD = static_cast<BuiltIn>(4993);
|
||||
static const BuiltIn BuiltInBaryCoordNoPerspSampleAMD = static_cast<BuiltIn>(4994);
|
||||
static const BuiltIn BuiltInBaryCoordSmoothAMD = static_cast<BuiltIn>(4995);
|
||||
static const BuiltIn BuiltInBaryCoordSmoothCentroidAMD = static_cast<BuiltIn>(4996);
|
||||
static const BuiltIn BuiltInBaryCoordSmoothSampleAMD = static_cast<BuiltIn>(4997);
|
||||
static const BuiltIn BuiltInBaryCoordPullModelAMD = static_cast<BuiltIn>(4998);
|
||||
|
||||
static const Decoration DecorationExplicitInterpAMD = static_cast<Decoration>(4999);
|
||||
|
||||
enum ShaderExplicitVertexParameterAMD {
|
||||
ShaderExplicitVertexParameterBadAMD = 0, // Don't use
|
||||
|
||||
InterpolateAtVertexAMD = 1,
|
||||
|
||||
ShaderExplicitVertexParameterCountAMD
|
||||
};
|
||||
|
||||
// SPV_AMD_gcn_shader
|
||||
static const char* const E_SPV_AMD_gcn_shader = "SPV_AMD_gcn_shader";
|
||||
|
||||
enum GcnShaderAMD {
|
||||
GcnShaderBadAMD = 0, // Don't use
|
||||
|
||||
CubeFaceIndexAMD = 1,
|
||||
CubeFaceCoordAMD = 2,
|
||||
TimeAMD = 3,
|
||||
|
||||
GcnShaderCountAMD
|
||||
};
|
||||
|
||||
// SPV_AMD_gpu_shader_half_float
|
||||
static const char* const E_SPV_AMD_gpu_shader_half_float = "SPV_AMD_gpu_shader_half_float";
|
||||
|
||||
#endif // #ifndef GLSLextAMD_H
|
||||
36
SPIRV/GLSL.ext.KHR.h
Normal file
36
SPIRV/GLSL.ext.KHR.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
** Copyright (c) 2014-2016 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and/or associated documentation files (the "Materials"),
|
||||
** to deal in the Materials without restriction, including without limitation
|
||||
** the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
** and/or sell copies of the Materials, and to permit persons to whom the
|
||||
** Materials are furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Materials.
|
||||
**
|
||||
** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
|
||||
** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
|
||||
** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
|
||||
**
|
||||
** THE MATERIALS ARE 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 AUTHORS 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 MATERIALS OR THE USE OR OTHER DEALINGS
|
||||
** IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
#ifndef GLSLextKHR_H
|
||||
#define GLSLextKHR_H
|
||||
|
||||
// SPV_KHR_shader_ballot
|
||||
static const char* const E_SPV_KHR_shader_ballot = "SPV_KHR_shader_ballot";
|
||||
|
||||
// SPV_KHR_shader_draw_parameters
|
||||
static const char* const E_SPV_KHR_shader_draw_parameters = "SPV_KHR_shader_draw_parameters";
|
||||
|
||||
#endif // #ifndef GLSLextKHR_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -127,6 +127,33 @@ namespace spv {
|
||||
}
|
||||
}
|
||||
|
||||
// Return the size of a type in 32-bit words. This currently only
|
||||
// handles ints and floats, and is only invoked by queries which must be
|
||||
// integer types. If ever needed, it can be generalized.
|
||||
unsigned spirvbin_t::typeSizeInWords(spv::Id id) const
|
||||
{
|
||||
const unsigned typeStart = idPos(id);
|
||||
const spv::Op opCode = asOpCode(typeStart);
|
||||
|
||||
switch (opCode) {
|
||||
case spv::OpTypeInt: // fall through...
|
||||
case spv::OpTypeFloat: return (spv[typeStart+2]+31)/32;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Looks up the type of a given const or variable ID, and
|
||||
// returns its size in 32-bit words.
|
||||
unsigned spirvbin_t::idTypeSizeInWords(spv::Id id) const
|
||||
{
|
||||
const auto tid_it = idTypeSizeMap.find(id);
|
||||
if (tid_it == idTypeSizeMap.end())
|
||||
error("type size for ID not found");
|
||||
|
||||
return tid_it->second;
|
||||
}
|
||||
|
||||
// Is this an opcode we should remove when using --strip?
|
||||
bool spirvbin_t::isStripOp(spv::Op opCode) const
|
||||
{
|
||||
@@ -140,6 +167,7 @@ namespace spv {
|
||||
}
|
||||
}
|
||||
|
||||
// Return true if this opcode is flow control
|
||||
bool spirvbin_t::isFlowCtrl(spv::Op opCode) const
|
||||
{
|
||||
switch (opCode) {
|
||||
@@ -155,6 +183,7 @@ namespace spv {
|
||||
}
|
||||
}
|
||||
|
||||
// Return true if this opcode defines a type
|
||||
bool spirvbin_t::isTypeOp(spv::Op opCode) const
|
||||
{
|
||||
switch (opCode) {
|
||||
@@ -182,6 +211,7 @@ namespace spv {
|
||||
}
|
||||
}
|
||||
|
||||
// Return true if this opcode defines a constant
|
||||
bool spirvbin_t::isConstOp(spv::Op opCode) const
|
||||
{
|
||||
switch (opCode) {
|
||||
@@ -324,7 +354,7 @@ namespace spv {
|
||||
fnPosDCE.clear();
|
||||
fnCalls.clear();
|
||||
typeConstPos.clear();
|
||||
typeConstPosR.clear();
|
||||
idPosR.clear();
|
||||
entryPoint = spv::NoResult;
|
||||
largestNewId = 0;
|
||||
|
||||
@@ -340,6 +370,25 @@ namespace spv {
|
||||
if ((options & STRIP) && isStripOp(opCode))
|
||||
stripInst(start);
|
||||
|
||||
unsigned word = start+1;
|
||||
spv::Id typeId = spv::NoResult;
|
||||
|
||||
if (spv::InstructionDesc[opCode].hasType())
|
||||
typeId = asId(word++);
|
||||
|
||||
// If there's a result ID, remember the size of its type
|
||||
if (spv::InstructionDesc[opCode].hasResult()) {
|
||||
const spv::Id resultId = asId(word++);
|
||||
idPosR[resultId] = start;
|
||||
|
||||
if (typeId != spv::NoResult) {
|
||||
const unsigned idTypeSize = typeSizeInWords(typeId);
|
||||
|
||||
if (idTypeSize != 0)
|
||||
idTypeSizeMap[resultId] = idTypeSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (opCode == spv::Op::OpName) {
|
||||
const spv::Id target = asId(start+1);
|
||||
const std::string name = literalString(start+2);
|
||||
@@ -363,11 +412,9 @@ namespace spv {
|
||||
} else if (isConstOp(opCode)) {
|
||||
assert(asId(start + 2) != spv::NoResult);
|
||||
typeConstPos.insert(start);
|
||||
typeConstPosR[asId(start + 2)] = start;
|
||||
} else if (isTypeOp(opCode)) {
|
||||
assert(asId(start + 1) != spv::NoResult);
|
||||
typeConstPos.insert(start);
|
||||
typeConstPosR[asId(start + 1)] = start;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -436,10 +483,19 @@ namespace spv {
|
||||
return nextInst;
|
||||
}
|
||||
|
||||
// Circular buffer so we can look back at previous unmapped values during the mapping pass.
|
||||
static const unsigned idBufferSize = 4;
|
||||
spv::Id idBuffer[idBufferSize];
|
||||
unsigned idBufferPos = 0;
|
||||
|
||||
// Store IDs from instruction in our map
|
||||
for (int op = 0; numOperands > 0; ++op, --numOperands) {
|
||||
switch (spv::InstructionDesc[opCode].operands.getClass(op)) {
|
||||
case spv::OperandId:
|
||||
case spv::OperandScope:
|
||||
case spv::OperandMemorySemantics:
|
||||
idBuffer[idBufferPos] = asId(word);
|
||||
idBufferPos = (idBufferPos + 1) % idBufferSize;
|
||||
idFn(asId(word++));
|
||||
break;
|
||||
|
||||
@@ -457,13 +513,25 @@ namespace spv {
|
||||
// word += numOperands;
|
||||
return nextInst;
|
||||
|
||||
case spv::OperandVariableLiteralId:
|
||||
while (numOperands > 0) {
|
||||
++word; // immediate
|
||||
idFn(asId(word++)); // ID
|
||||
numOperands -= 2;
|
||||
case spv::OperandVariableLiteralId: {
|
||||
if (opCode == OpSwitch) {
|
||||
// word-2 is the position of the selector ID. OpSwitch Literals match its type.
|
||||
// In case the IDs are currently being remapped, we get the word[-2] ID from
|
||||
// the circular idBuffer.
|
||||
const unsigned literalSizePos = (idBufferPos+idBufferSize-2) % idBufferSize;
|
||||
const unsigned literalSize = idTypeSizeInWords(idBuffer[literalSizePos]);
|
||||
const unsigned numLiteralIdPairs = (nextInst-word) / (1+literalSize);
|
||||
|
||||
for (unsigned arg=0; arg<numLiteralIdPairs; ++arg) {
|
||||
word += literalSize; // literal
|
||||
idFn(asId(word++)); // label
|
||||
}
|
||||
} else {
|
||||
assert(0); // currentely, only OpSwitch uses OperandVariableLiteralId
|
||||
}
|
||||
|
||||
return nextInst;
|
||||
}
|
||||
|
||||
case spv::OperandLiteralString: {
|
||||
const int stringWordCount = literalStringWords(literalString(word));
|
||||
@@ -500,9 +568,7 @@ namespace spv {
|
||||
case spv::OperandSelect:
|
||||
case spv::OperandLoop:
|
||||
case spv::OperandFunction:
|
||||
case spv::OperandMemorySemantics:
|
||||
case spv::OperandMemoryAccess:
|
||||
case spv::OperandScope:
|
||||
case spv::OperandGroupOperation:
|
||||
case spv::OperandKernelEnqueueFlags:
|
||||
case spv::OperandKernelProfilingInfo:
|
||||
@@ -966,23 +1032,27 @@ namespace spv {
|
||||
|
||||
std::unordered_map<spv::Id, int> typeUseCount;
|
||||
|
||||
// Count total type usage
|
||||
process(inst_fn_nop,
|
||||
[&](spv::Id& id) { if (isType[id]) ++typeUseCount[id]; }
|
||||
);
|
||||
// This is not the most efficient algorithm, but this is an offline tool, and
|
||||
// it's easy to write this way. Can be improved opportunistically if needed.
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
strip();
|
||||
typeUseCount.clear();
|
||||
|
||||
// Remove types from deleted code
|
||||
for (const auto& fn : fnPosDCE)
|
||||
// Count total type usage
|
||||
process(inst_fn_nop,
|
||||
[&](spv::Id& id) { if (isType[id]) --typeUseCount[id]; },
|
||||
fn.second.first, fn.second.second);
|
||||
[&](spv::Id& id) { if (isType[id]) ++typeUseCount[id]; }
|
||||
);
|
||||
|
||||
// Remove single reference types
|
||||
for (const auto typeStart : typeConstPos) {
|
||||
const spv::Id typeId = asTypeConstId(typeStart);
|
||||
if (typeUseCount[typeId] == 1) {
|
||||
--typeUseCount[typeId];
|
||||
stripInst(typeStart);
|
||||
// Remove single reference types
|
||||
for (const auto typeStart : typeConstPos) {
|
||||
const spv::Id typeId = asTypeConstId(typeStart);
|
||||
if (typeUseCount[typeId] == 1) {
|
||||
changed = true;
|
||||
--typeUseCount[typeId];
|
||||
stripInst(typeStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1060,12 +1130,12 @@ namespace spv {
|
||||
}
|
||||
#endif // NOTDEF
|
||||
|
||||
// Return start position in SPV of given type. error if not found.
|
||||
unsigned spirvbin_t::typePos(spv::Id id) const
|
||||
// Return start position in SPV of given Id. error if not found.
|
||||
unsigned spirvbin_t::idPos(spv::Id id) const
|
||||
{
|
||||
const auto tid_it = typeConstPosR.find(id);
|
||||
if (tid_it == typeConstPosR.end())
|
||||
error("type ID not found");
|
||||
const auto tid_it = idPosR.find(id);
|
||||
if (tid_it == idPosR.end())
|
||||
error("ID not found");
|
||||
|
||||
return tid_it->second;
|
||||
}
|
||||
@@ -1083,11 +1153,11 @@ namespace spv {
|
||||
case spv::OpTypeInt: return 3 + (spv[typeStart+3]);
|
||||
case spv::OpTypeFloat: return 5;
|
||||
case spv::OpTypeVector:
|
||||
return 6 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);
|
||||
return 6 + hashType(idPos(spv[typeStart+2])) * (spv[typeStart+3] - 1);
|
||||
case spv::OpTypeMatrix:
|
||||
return 30 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);
|
||||
return 30 + hashType(idPos(spv[typeStart+2])) * (spv[typeStart+3] - 1);
|
||||
case spv::OpTypeImage:
|
||||
return 120 + hashType(typePos(spv[typeStart+2])) +
|
||||
return 120 + hashType(idPos(spv[typeStart+2])) +
|
||||
spv[typeStart+3] + // dimensionality
|
||||
spv[typeStart+4] * 8 * 16 + // depth
|
||||
spv[typeStart+5] * 4 * 16 + // arrayed
|
||||
@@ -1098,24 +1168,24 @@ namespace spv {
|
||||
case spv::OpTypeSampledImage:
|
||||
return 502;
|
||||
case spv::OpTypeArray:
|
||||
return 501 + hashType(typePos(spv[typeStart+2])) * spv[typeStart+3];
|
||||
return 501 + hashType(idPos(spv[typeStart+2])) * spv[typeStart+3];
|
||||
case spv::OpTypeRuntimeArray:
|
||||
return 5000 + hashType(typePos(spv[typeStart+2]));
|
||||
return 5000 + hashType(idPos(spv[typeStart+2]));
|
||||
case spv::OpTypeStruct:
|
||||
{
|
||||
std::uint32_t hash = 10000;
|
||||
for (unsigned w=2; w < wordCount; ++w)
|
||||
hash += w * hashType(typePos(spv[typeStart+w]));
|
||||
hash += w * hashType(idPos(spv[typeStart+w]));
|
||||
return hash;
|
||||
}
|
||||
|
||||
case spv::OpTypeOpaque: return 6000 + spv[typeStart+2];
|
||||
case spv::OpTypePointer: return 100000 + hashType(typePos(spv[typeStart+3]));
|
||||
case spv::OpTypePointer: return 100000 + hashType(idPos(spv[typeStart+3]));
|
||||
case spv::OpTypeFunction:
|
||||
{
|
||||
std::uint32_t hash = 200000;
|
||||
for (unsigned w=2; w < wordCount; ++w)
|
||||
hash += w * hashType(typePos(spv[typeStart+w]));
|
||||
hash += w * hashType(idPos(spv[typeStart+w]));
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -1132,14 +1202,14 @@ namespace spv {
|
||||
case spv::OpConstantFalse: return 300008;
|
||||
case spv::OpConstantComposite:
|
||||
{
|
||||
std::uint32_t hash = 300011 + hashType(typePos(spv[typeStart+1]));
|
||||
std::uint32_t hash = 300011 + hashType(idPos(spv[typeStart+1]));
|
||||
for (unsigned w=3; w < wordCount; ++w)
|
||||
hash += w * hashType(typePos(spv[typeStart+w]));
|
||||
hash += w * hashType(idPos(spv[typeStart+w]));
|
||||
return hash;
|
||||
}
|
||||
case spv::OpConstant:
|
||||
{
|
||||
std::uint32_t hash = 400011 + hashType(typePos(spv[typeStart+1]));
|
||||
std::uint32_t hash = 400011 + hashType(idPos(spv[typeStart+1]));
|
||||
for (unsigned w=3; w < wordCount; ++w)
|
||||
hash += w * spv[typeStart+w];
|
||||
return hash;
|
||||
@@ -1212,19 +1282,19 @@ namespace spv {
|
||||
msg(3, 4, std::string("ID bound: ") + std::to_string(bound()));
|
||||
|
||||
strip(); // strip out data we decided to eliminate
|
||||
|
||||
if (options & OPT_LOADSTORE) optLoadStore();
|
||||
if (options & OPT_FWD_LS) forwardLoadStores();
|
||||
if (options & DCE_FUNCS) dceFuncs();
|
||||
if (options & DCE_VARS) dceVars();
|
||||
if (options & DCE_TYPES) dceTypes();
|
||||
strip(); // strip out data we decided to eliminate
|
||||
|
||||
if (options & MAP_TYPES) mapTypeConst();
|
||||
if (options & MAP_NAMES) mapNames();
|
||||
if (options & MAP_FUNCS) mapFnBodies();
|
||||
|
||||
mapRemainder(); // map any unmapped IDs
|
||||
applyMap(); // Now remap each shader to the new IDs we've come up with
|
||||
strip(); // strip out data we decided to eliminate
|
||||
}
|
||||
|
||||
// remap from a memory image
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace spv {
|
||||
|
||||
@@ -74,7 +74,8 @@ public:
|
||||
} // namespace SPV
|
||||
|
||||
#if !defined (use_cpp11)
|
||||
#include <stdio.h>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
|
||||
namespace spv {
|
||||
class spirvbin_t : public spirvbin_base_t
|
||||
@@ -82,7 +83,7 @@ class spirvbin_t : public spirvbin_base_t
|
||||
public:
|
||||
spirvbin_t(int /*verbose = 0*/) { }
|
||||
|
||||
void remap(std::vector<unsigned int>& /*spv*/, unsigned int /*opts = 0*/)
|
||||
void remap(std::vector<std::uint32_t>& /*spv*/, unsigned int /*opts = 0*/)
|
||||
{
|
||||
printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");
|
||||
exit(5);
|
||||
@@ -159,16 +160,21 @@ private:
|
||||
typedef std::set<int> posmap_t;
|
||||
typedef std::unordered_map<spv::Id, int> posmap_rev_t;
|
||||
|
||||
// Maps and ID to the size of its base type, if known.
|
||||
typedef std::unordered_map<spv::Id, unsigned> typesize_map_t;
|
||||
|
||||
// handle error
|
||||
void error(const std::string& txt) const { errorHandler(txt); }
|
||||
|
||||
bool isConstOp(spv::Op opCode) const;
|
||||
bool isTypeOp(spv::Op opCode) const;
|
||||
bool isStripOp(spv::Op opCode) const;
|
||||
bool isFlowCtrl(spv::Op opCode) const;
|
||||
range_t literalRange(spv::Op opCode) const;
|
||||
range_t typeRange(spv::Op opCode) const;
|
||||
range_t constRange(spv::Op opCode) const;
|
||||
bool isConstOp(spv::Op opCode) const;
|
||||
bool isTypeOp(spv::Op opCode) const;
|
||||
bool isStripOp(spv::Op opCode) const;
|
||||
bool isFlowCtrl(spv::Op opCode) const;
|
||||
range_t literalRange(spv::Op opCode) const;
|
||||
range_t typeRange(spv::Op opCode) const;
|
||||
range_t constRange(spv::Op opCode) const;
|
||||
unsigned typeSizeInWords(spv::Id id) const;
|
||||
unsigned idTypeSizeInWords(spv::Id id) const;
|
||||
|
||||
spv::Id& asId(unsigned word) { return spv[word]; }
|
||||
const spv::Id& asId(unsigned word) const { return spv[word]; }
|
||||
@@ -177,10 +183,10 @@ private:
|
||||
spv::Decoration asDecoration(unsigned word) const { return spv::Decoration(spv[word]); }
|
||||
unsigned asWordCount(unsigned word) const { return opWordCount(spv[word]); }
|
||||
spv::Id asTypeConstId(unsigned word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }
|
||||
unsigned typePos(spv::Id id) const;
|
||||
unsigned idPos(spv::Id id) const;
|
||||
|
||||
static unsigned opWordCount(spirword_t data) { return data >> spv::WordCountShift; }
|
||||
static spv::Op opOpCode(spirword_t data) { return spv::Op(data & spv::OpCodeMask); }
|
||||
static unsigned opWordCount(spirword_t data) { return data >> spv::WordCountShift; }
|
||||
static spv::Op opOpCode(spirword_t data) { return spv::Op(data & spv::OpCodeMask); }
|
||||
|
||||
// Header access & set methods
|
||||
spirword_t magic() const { return spv[0]; } // return magic number
|
||||
@@ -263,8 +269,9 @@ private:
|
||||
// Which functions are called, anywhere in the module, with a call count
|
||||
std::unordered_map<spv::Id, int> fnCalls;
|
||||
|
||||
posmap_t typeConstPos; // word positions that define types & consts (ordered)
|
||||
posmap_rev_t typeConstPosR; // reverse map from IDs to positions
|
||||
posmap_t typeConstPos; // word positions that define types & consts (ordered)
|
||||
posmap_rev_t idPosR; // reverse map from IDs to positions
|
||||
typesize_map_t idTypeSizeMap; // maps each ID to its type size, if known.
|
||||
|
||||
std::vector<spv::Id> idMapL; // ID {M}ap from {L}ocal to {G}lobal IDs
|
||||
|
||||
|
||||
@@ -38,14 +38,18 @@
|
||||
// SpvBuilder.h.
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <unordered_set>
|
||||
#include <algorithm>
|
||||
|
||||
#include "SpvBuilder.h"
|
||||
|
||||
#ifdef AMD_EXTENSIONS
|
||||
#include "hex_float.h"
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <cstdio>
|
||||
#endif
|
||||
@@ -785,6 +789,36 @@ Id Builder::makeDoubleConstant(double d, bool specConstant)
|
||||
return c->getResultId();
|
||||
}
|
||||
|
||||
#ifdef AMD_EXTENSIONS
|
||||
Id Builder::makeFloat16Constant(float f16, bool specConstant)
|
||||
{
|
||||
Op opcode = specConstant ? OpSpecConstant : OpConstant;
|
||||
Id typeId = makeFloatType(16);
|
||||
|
||||
spvutils::HexFloat<spvutils::FloatProxy<float>> fVal(f16);
|
||||
spvutils::HexFloat<spvutils::FloatProxy<spvutils::Float16>> f16Val(0);
|
||||
fVal.castTo(f16Val, spvutils::kRoundToZero);
|
||||
|
||||
unsigned value = f16Val.value().getAsFloat().get_value();
|
||||
|
||||
// See if we already made it. Applies only to regular constants, because specialization constants
|
||||
// must remain distinct for the purpose of applying a SpecId decoration.
|
||||
if (!specConstant) {
|
||||
Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
|
||||
if (existing)
|
||||
return existing;
|
||||
}
|
||||
|
||||
Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
|
||||
c->addImmediateOperand(value);
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
|
||||
groupedConstants[OpTypeFloat].push_back(c);
|
||||
module.mapInstruction(c);
|
||||
|
||||
return c->getResultId();
|
||||
}
|
||||
#endif
|
||||
|
||||
Id Builder::findCompositeConstant(Op typeClass, std::vector<Id>& comps) const
|
||||
{
|
||||
Instruction* constant = 0;
|
||||
@@ -907,7 +941,7 @@ void Builder::addLine(Id target, Id fileName, int lineNum, int column)
|
||||
|
||||
void Builder::addDecoration(Id id, Decoration decoration, int num)
|
||||
{
|
||||
if (decoration == (spv::Decoration)spv::BadValue)
|
||||
if (decoration == spv::DecorationMax)
|
||||
return;
|
||||
Instruction* dec = new Instruction(OpDecorate);
|
||||
dec->addIdOperand(id);
|
||||
@@ -931,7 +965,7 @@ void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decorat
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
Function* Builder::makeEntrypoint(const char* entryPoint)
|
||||
Function* Builder::makeEntryPoint(const char* entryPoint)
|
||||
{
|
||||
assert(! mainFunction);
|
||||
|
||||
@@ -1328,15 +1362,20 @@ Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, std:
|
||||
// Comments in header
|
||||
Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels)
|
||||
{
|
||||
assert(getNumComponents(source) == (int)channels.size());
|
||||
if (channels.size() == 1 && getNumComponents(source) == 1)
|
||||
return createCompositeInsert(source, target, typeId, channels.front());
|
||||
|
||||
Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
|
||||
assert(isVector(source));
|
||||
assert(isVector(target));
|
||||
swizzle->addIdOperand(target);
|
||||
swizzle->addIdOperand(source);
|
||||
if (accessChain.component != NoResult)
|
||||
// For dynamic component selection, source does not involve in l-value swizzle
|
||||
swizzle->addIdOperand(target);
|
||||
else {
|
||||
assert(getNumComponents(source) == (int)channels.size());
|
||||
assert(isVector(source));
|
||||
swizzle->addIdOperand(source);
|
||||
}
|
||||
|
||||
// Set up an identity shuffle from the base value to the result value
|
||||
unsigned int components[4];
|
||||
@@ -1345,8 +1384,12 @@ Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<uns
|
||||
components[i] = i;
|
||||
|
||||
// Punch in the l-value swizzle
|
||||
for (int i = 0; i < (int)channels.size(); ++i)
|
||||
components[channels[i]] = numTargetComponents + i;
|
||||
for (int i = 0; i < (int)channels.size(); ++i) {
|
||||
if (accessChain.component != NoResult)
|
||||
components[i] = channels[i]; // Only shuffle the base value
|
||||
else
|
||||
components[channels[i]] = numTargetComponents + i;
|
||||
}
|
||||
|
||||
// finish the instruction with these components selectors
|
||||
for (int i = 0; i < numTargetComponents; ++i)
|
||||
@@ -2118,9 +2161,6 @@ void Builder::accessChainStore(Id rvalue)
|
||||
transferAccessChainSwizzle(true);
|
||||
Id base = collapseAccessChain();
|
||||
|
||||
if (accessChain.swizzle.size() && accessChain.component != NoResult)
|
||||
logger->missingFunctionality("simultaneous l-value swizzle and dynamic component selection");
|
||||
|
||||
// If swizzle still exists, it is out-of-order or not full, we must load the target vector,
|
||||
// extract and insert elements to perform writeMask and/or swizzle.
|
||||
Id source = NoResult;
|
||||
@@ -2312,7 +2352,11 @@ void Builder::dump(std::vector<unsigned int>& out) const
|
||||
capInst.dump(out);
|
||||
}
|
||||
|
||||
// TBD: OpExtension ...
|
||||
for (auto it = extensions.cbegin(); it != extensions.cend(); ++it) {
|
||||
Instruction extInst(0, 0, OpExtension);
|
||||
extInst.addStringOperand(*it);
|
||||
extInst.dump(out);
|
||||
}
|
||||
|
||||
dumpInstructions(out, imports);
|
||||
Instruction memInst(0, 0, OpMemoryModel);
|
||||
@@ -2331,10 +2375,10 @@ void Builder::dump(std::vector<unsigned int>& out) const
|
||||
sourceInst.addImmediateOperand(sourceVersion);
|
||||
sourceInst.dump(out);
|
||||
}
|
||||
for (int e = 0; e < (int)extensions.size(); ++e) {
|
||||
Instruction extInst(0, 0, OpSourceExtension);
|
||||
extInst.addStringOperand(extensions[e]);
|
||||
extInst.dump(out);
|
||||
for (int e = 0; e < (int)sourceExtensions.size(); ++e) {
|
||||
Instruction sourceExtInst(0, 0, OpSourceExtension);
|
||||
sourceExtInst.addStringOperand(sourceExtensions[e]);
|
||||
sourceExtInst.dump(out);
|
||||
}
|
||||
dumpInstructions(out, names);
|
||||
dumpInstructions(out, lines);
|
||||
|
||||
@@ -70,7 +70,8 @@ public:
|
||||
source = lang;
|
||||
sourceVersion = version;
|
||||
}
|
||||
void addSourceExtension(const char* ext) { extensions.push_back(ext); }
|
||||
void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); }
|
||||
void addExtension(const char* ext) { extensions.insert(ext); }
|
||||
Id import(const char*);
|
||||
void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
|
||||
{
|
||||
@@ -190,6 +191,9 @@ public:
|
||||
Id makeUint64Constant(unsigned long long u, bool specConstant = false) { return makeInt64Constant(makeUintType(64), u, specConstant); }
|
||||
Id makeFloatConstant(float f, bool specConstant = false);
|
||||
Id makeDoubleConstant(double d, bool specConstant = false);
|
||||
#ifdef AMD_EXTENSIONS
|
||||
Id makeFloat16Constant(float f16, bool specConstant = false);
|
||||
#endif
|
||||
|
||||
// Turn the array of constants into a proper spv constant of the requested type.
|
||||
Id makeCompositeConstant(Id type, std::vector<Id>& comps, bool specConst = false);
|
||||
@@ -209,7 +213,7 @@ public:
|
||||
|
||||
// Make the entry-point function. The returned pointer is only valid
|
||||
// for the lifetime of this builder.
|
||||
Function* makeEntrypoint(const char*);
|
||||
Function* makeEntryPoint(const char*);
|
||||
|
||||
// Make a shader-style function, and create its entry block if entry is non-zero.
|
||||
// Return the function, pass back the entry.
|
||||
@@ -466,7 +470,7 @@ public:
|
||||
|
||||
//
|
||||
// the SPIR-V builder maintains a single active chain that
|
||||
// the following methods operated on
|
||||
// the following methods operate on
|
||||
//
|
||||
|
||||
// for external save and restore
|
||||
@@ -551,7 +555,8 @@ public:
|
||||
|
||||
SourceLanguage source;
|
||||
int sourceVersion;
|
||||
std::vector<const char*> extensions;
|
||||
std::set<const char*> extensions;
|
||||
std::vector<const char*> sourceExtensions;
|
||||
AddressingModel addressModel;
|
||||
MemoryModel memoryModel;
|
||||
std::set<spv::Capability> capabilities;
|
||||
|
||||
81
SPIRV/bitutils.h
Normal file
81
SPIRV/bitutils.h
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef LIBSPIRV_UTIL_BITUTILS_H_
|
||||
#define LIBSPIRV_UTIL_BITUTILS_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
namespace spvutils {
|
||||
|
||||
// Performs a bitwise copy of source to the destination type Dest.
|
||||
template <typename Dest, typename Src>
|
||||
Dest BitwiseCast(Src source) {
|
||||
Dest dest;
|
||||
static_assert(sizeof(source) == sizeof(dest),
|
||||
"BitwiseCast: Source and destination must have the same size");
|
||||
std::memcpy(&dest, &source, sizeof(dest));
|
||||
return dest;
|
||||
}
|
||||
|
||||
// SetBits<T, First, Num> returns an integer of type <T> with bits set
|
||||
// for position <First> through <First + Num - 1>, counting from the least
|
||||
// significant bit. In particular when Num == 0, no positions are set to 1.
|
||||
// A static assert will be triggered if First + Num > sizeof(T) * 8, that is,
|
||||
// a bit that will not fit in the underlying type is set.
|
||||
template <typename T, size_t First = 0, size_t Num = 0>
|
||||
struct SetBits {
|
||||
static_assert(First < sizeof(T) * 8,
|
||||
"Tried to set a bit that is shifted too far.");
|
||||
const static T get = (T(1) << First) | SetBits<T, First + 1, Num - 1>::get;
|
||||
};
|
||||
|
||||
template <typename T, size_t Last>
|
||||
struct SetBits<T, Last, 0> {
|
||||
const static T get = T(0);
|
||||
};
|
||||
|
||||
// This is all compile-time so we can put our tests right here.
|
||||
static_assert(SetBits<uint32_t, 0, 0>::get == uint32_t(0x00000000),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint32_t, 0, 1>::get == uint32_t(0x00000001),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint32_t, 31, 1>::get == uint32_t(0x80000000),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint32_t, 1, 2>::get == uint32_t(0x00000006),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint32_t, 30, 2>::get == uint32_t(0xc0000000),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint32_t, 0, 31>::get == uint32_t(0x7FFFFFFF),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint32_t, 0, 32>::get == uint32_t(0xFFFFFFFF),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint32_t, 16, 16>::get == uint32_t(0xFFFF0000),
|
||||
"SetBits failed");
|
||||
|
||||
static_assert(SetBits<uint64_t, 0, 1>::get == uint64_t(0x0000000000000001LL),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint64_t, 63, 1>::get == uint64_t(0x8000000000000000LL),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint64_t, 62, 2>::get == uint64_t(0xc000000000000000LL),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint64_t, 31, 1>::get == uint64_t(0x0000000080000000LL),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint64_t, 16, 16>::get == uint64_t(0x00000000FFFF0000LL),
|
||||
"SetBits failed");
|
||||
|
||||
} // namespace spvutils
|
||||
|
||||
#endif // LIBSPIRV_UTIL_BITUTILS_H_
|
||||
@@ -36,24 +36,33 @@
|
||||
// Disassembler for SPIR-V.
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <iomanip>
|
||||
#include <stack>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
|
||||
namespace spv {
|
||||
// Include C-based headers that don't have a namespace
|
||||
#include "GLSL.std.450.h"
|
||||
}
|
||||
const char* GlslStd450DebugNames[spv::GLSLstd450Count];
|
||||
|
||||
#include "disassemble.h"
|
||||
#include "doc.h"
|
||||
|
||||
namespace spv {
|
||||
extern "C" {
|
||||
// Include C-based headers that don't have a namespace
|
||||
#include "GLSL.std.450.h"
|
||||
#ifdef AMD_EXTENSIONS
|
||||
#include "GLSL.ext.AMD.h"
|
||||
#endif
|
||||
}
|
||||
}
|
||||
const char* GlslStd450DebugNames[spv::GLSLstd450Count];
|
||||
|
||||
namespace spv {
|
||||
|
||||
#ifdef AMD_EXTENSIONS
|
||||
static const char* GLSLextAMDGetDebugNames(const char*, unsigned);
|
||||
#endif
|
||||
|
||||
static void Kill(std::ostream& out, const char* message)
|
||||
{
|
||||
@@ -64,6 +73,9 @@ static void Kill(std::ostream& out, const char* message)
|
||||
// used to identify the extended instruction library imported when printing
|
||||
enum ExtInstSet {
|
||||
GLSL450Inst,
|
||||
#ifdef AMD_EXTENSIONS
|
||||
GLSLextAMDInst,
|
||||
#endif
|
||||
OpenCLExtInst,
|
||||
};
|
||||
|
||||
@@ -205,10 +217,12 @@ void SpirvStream::outputIndent()
|
||||
|
||||
void SpirvStream::formatId(Id id, std::stringstream& idStream)
|
||||
{
|
||||
if (id >= bound)
|
||||
Kill(out, "Bad <id>");
|
||||
|
||||
if (id != 0) {
|
||||
// On instructions with no IDs, this is called with "0", which does not
|
||||
// have to be within ID bounds on null shaders.
|
||||
if (id >= bound)
|
||||
Kill(out, "Bad <id>");
|
||||
|
||||
idStream << id;
|
||||
if (idDescriptor[id].size() > 0)
|
||||
idStream << "(" << idDescriptor[id] << ")";
|
||||
@@ -322,7 +336,7 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
|
||||
idDescriptor[resultId] = (const char*)(&stream[word]);
|
||||
}
|
||||
else {
|
||||
if (idDescriptor[resultId].size() == 0) {
|
||||
if (resultId != 0 && idDescriptor[resultId].size() == 0) {
|
||||
switch (opCode) {
|
||||
case OpTypeInt:
|
||||
idDescriptor[resultId] = "int";
|
||||
@@ -446,14 +460,26 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
|
||||
--numOperands;
|
||||
if (opCode == OpExtInst) {
|
||||
ExtInstSet extInstSet = GLSL450Inst;
|
||||
if (0 == memcmp("OpenCL", (const char*)(idDescriptor[stream[word-2]].c_str()), 6)) {
|
||||
const char* name = idDescriptor[stream[word - 2]].c_str();
|
||||
if (0 == memcmp("OpenCL", name, 6)) {
|
||||
extInstSet = OpenCLExtInst;
|
||||
#ifdef AMD_EXTENSIONS
|
||||
} else if (strcmp(spv::E_SPV_AMD_shader_ballot, name) == 0 ||
|
||||
strcmp(spv::E_SPV_AMD_shader_trinary_minmax, name) == 0 ||
|
||||
strcmp(spv::E_SPV_AMD_shader_explicit_vertex_parameter, name) == 0 ||
|
||||
strcmp(spv::E_SPV_AMD_gcn_shader, name) == 0) {
|
||||
extInstSet = GLSLextAMDInst;
|
||||
#endif
|
||||
}
|
||||
unsigned entrypoint = stream[word - 1];
|
||||
if (extInstSet == GLSL450Inst) {
|
||||
if (entrypoint < GLSLstd450Count) {
|
||||
out << "(" << GlslStd450DebugNames[entrypoint] << ")";
|
||||
}
|
||||
#ifdef AMD_EXTENSIONS
|
||||
} else if (extInstSet == GLSLextAMDInst) {
|
||||
out << "(" << GLSLextAMDGetDebugNames(name, entrypoint) << ")";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -561,6 +587,50 @@ static void GLSLstd450GetDebugNames(const char** names)
|
||||
names[GLSLstd450InterpolateAtOffset] = "InterpolateAtOffset";
|
||||
}
|
||||
|
||||
#ifdef AMD_EXTENSIONS
|
||||
static const char* GLSLextAMDGetDebugNames(const char* name, unsigned entrypoint)
|
||||
{
|
||||
if (strcmp(name, spv::E_SPV_AMD_shader_ballot) == 0) {
|
||||
switch (entrypoint) {
|
||||
case SwizzleInvocationsAMD: return "SwizzleInvocationsAMD";
|
||||
case SwizzleInvocationsMaskedAMD: return "SwizzleInvocationsMaskedAMD";
|
||||
case WriteInvocationAMD: return "WriteInvocationAMD";
|
||||
case MbcntAMD: return "MbcntAMD";
|
||||
default: return "Bad";
|
||||
}
|
||||
} else if (strcmp(name, spv::E_SPV_AMD_shader_trinary_minmax) == 0) {
|
||||
switch (entrypoint) {
|
||||
case FMin3AMD: return "FMin3AMD";
|
||||
case UMin3AMD: return "UMin3AMD";
|
||||
case SMin3AMD: return "SMin3AMD";
|
||||
case FMax3AMD: return "FMax3AMD";
|
||||
case UMax3AMD: return "UMax3AMD";
|
||||
case SMax3AMD: return "SMax3AMD";
|
||||
case FMid3AMD: return "FMid3AMD";
|
||||
case UMid3AMD: return "UMid3AMD";
|
||||
case SMid3AMD: return "SMid3AMD";
|
||||
default: return "Bad";
|
||||
}
|
||||
} else if (strcmp(name, spv::E_SPV_AMD_shader_explicit_vertex_parameter) == 0) {
|
||||
switch (entrypoint) {
|
||||
case InterpolateAtVertexAMD: return "InterpolateAtVertexAMD";
|
||||
default: return "Bad";
|
||||
}
|
||||
}
|
||||
else if (strcmp(name, spv::E_SPV_AMD_gcn_shader) == 0) {
|
||||
switch (entrypoint) {
|
||||
case CubeFaceIndexAMD: return "CubeFaceIndexAMD";
|
||||
case CubeFaceCoordAMD: return "CubeFaceCoordAMD";
|
||||
case TimeAMD: return "TimeAMD";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return "Bad";
|
||||
}
|
||||
#endif
|
||||
|
||||
void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
|
||||
{
|
||||
SpirvStream SpirvStream(out, stream);
|
||||
|
||||
104
SPIRV/doc.cpp
104
SPIRV/doc.cpp
@@ -33,7 +33,7 @@
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//
|
||||
// 1) Programatically fill in instruction/operand information.
|
||||
// 1) Programmatically fill in instruction/operand information.
|
||||
// This can be used for disassembly, printing documentation, etc.
|
||||
//
|
||||
// 2) Print documentation from this parameterization.
|
||||
@@ -41,10 +41,19 @@
|
||||
|
||||
#include "doc.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
namespace spv {
|
||||
extern "C" {
|
||||
// Include C-based headers that don't have a namespace
|
||||
#ifdef AMD_EXTENSIONS
|
||||
#include "GLSL.ext.AMD.h"
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
namespace spv {
|
||||
|
||||
//
|
||||
@@ -243,6 +252,10 @@ const char* DecorationString(int decoration)
|
||||
|
||||
case DecorationCeiling:
|
||||
default: return "Bad";
|
||||
|
||||
#ifdef AMD_EXTENSIONS
|
||||
case 4999: return "ExplicitInterpAMD";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,6 +311,26 @@ const char* BuiltInString(int builtIn)
|
||||
|
||||
case BuiltInCeiling:
|
||||
default: return "Bad";
|
||||
|
||||
case 4416: return "SubgroupEqMaskKHR";
|
||||
case 4417: return "SubgroupGeMaskKHR";
|
||||
case 4418: return "SubgroupGtMaskKHR";
|
||||
case 4419: return "SubgroupLeMaskKHR";
|
||||
case 4420: return "SubgroupLtMaskKHR";
|
||||
|
||||
case 4424: return "BaseVertex";
|
||||
case 4425: return "BaseInstance";
|
||||
case 4426: return "DrawIndex";
|
||||
|
||||
#ifdef AMD_EXTENSIONS
|
||||
case 4992: return "BaryCoordNoPerspAMD";
|
||||
case 4993: return "BaryCoordNoPerspCentroidAMD";
|
||||
case 4994: return "BaryCoordNoPerspSampleAMD";
|
||||
case 4995: return "BaryCoordSmoothAMD";
|
||||
case 4996: return "BaryCoordSmoothCentroidAMD";
|
||||
case 4997: return "BaryCoordSmoothSampleAMD";
|
||||
case 4998: return "BaryCoordPullModelAMD";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -776,6 +809,9 @@ const char* CapabilityString(int info)
|
||||
|
||||
case CapabilityCeiling:
|
||||
default: return "Bad";
|
||||
|
||||
case 4423: return "SubgroupBallotKHR";
|
||||
case 4427: return "DrawParameters";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1107,12 +1143,26 @@ const char* OpcodeString(int op)
|
||||
case OpcodeCeiling:
|
||||
default:
|
||||
return "Bad";
|
||||
|
||||
case 4421: return "OpSubgroupBallotKHR";
|
||||
case 4422: return "OpSubgroupFirstInvocationKHR";
|
||||
|
||||
#ifdef AMD_EXTENSIONS
|
||||
case 5000: return "OpGroupIAddNonUniformAMD";
|
||||
case 5001: return "OpGroupFAddNonUniformAMD";
|
||||
case 5002: return "OpGroupFMinNonUniformAMD";
|
||||
case 5003: return "OpGroupUMinNonUniformAMD";
|
||||
case 5004: return "OpGroupSMinNonUniformAMD";
|
||||
case 5005: return "OpGroupFMaxNonUniformAMD";
|
||||
case 5006: return "OpGroupUMaxNonUniformAMD";
|
||||
case 5007: return "OpGroupSMaxNonUniformAMD";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// The set of objects that hold all the instruction/operand
|
||||
// parameterization information.
|
||||
InstructionParameters InstructionDesc[OpcodeCeiling];
|
||||
InstructionParameters InstructionDesc[OpCodeMask + 1];
|
||||
OperandParameters ExecutionModeOperands[ExecutionModeCeiling];
|
||||
OperandParameters DecorationOperands[DecorationCeiling];
|
||||
|
||||
@@ -2703,6 +2753,52 @@ void Parameterize()
|
||||
InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Num Events'");
|
||||
InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Wait Events'");
|
||||
InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Ret Event'");
|
||||
|
||||
InstructionDesc[OpSubgroupBallotKHR].operands.push(OperandId, "'Predicate'");
|
||||
|
||||
InstructionDesc[OpSubgroupFirstInvocationKHR].operands.push(OperandId, "'Value'");
|
||||
|
||||
#ifdef AMD_EXTENSIONS
|
||||
InstructionDesc[OpGroupIAddNonUniformAMD].capabilities.push_back(CapabilityGroups);
|
||||
InstructionDesc[OpGroupIAddNonUniformAMD].operands.push(OperandScope, "'Execution'");
|
||||
InstructionDesc[OpGroupIAddNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'");
|
||||
InstructionDesc[OpGroupIAddNonUniformAMD].operands.push(OperandId, "'X'");
|
||||
|
||||
InstructionDesc[OpGroupFAddNonUniformAMD].capabilities.push_back(CapabilityGroups);
|
||||
InstructionDesc[OpGroupFAddNonUniformAMD].operands.push(OperandScope, "'Execution'");
|
||||
InstructionDesc[OpGroupFAddNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'");
|
||||
InstructionDesc[OpGroupFAddNonUniformAMD].operands.push(OperandId, "'X'");
|
||||
|
||||
InstructionDesc[OpGroupUMinNonUniformAMD].capabilities.push_back(CapabilityGroups);
|
||||
InstructionDesc[OpGroupUMinNonUniformAMD].operands.push(OperandScope, "'Execution'");
|
||||
InstructionDesc[OpGroupUMinNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'");
|
||||
InstructionDesc[OpGroupUMinNonUniformAMD].operands.push(OperandId, "'X'");
|
||||
|
||||
InstructionDesc[OpGroupSMinNonUniformAMD].capabilities.push_back(CapabilityGroups);
|
||||
InstructionDesc[OpGroupSMinNonUniformAMD].operands.push(OperandScope, "'Execution'");
|
||||
InstructionDesc[OpGroupSMinNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'");
|
||||
InstructionDesc[OpGroupSMinNonUniformAMD].operands.push(OperandId, "X");
|
||||
|
||||
InstructionDesc[OpGroupFMinNonUniformAMD].capabilities.push_back(CapabilityGroups);
|
||||
InstructionDesc[OpGroupFMinNonUniformAMD].operands.push(OperandScope, "'Execution'");
|
||||
InstructionDesc[OpGroupFMinNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'");
|
||||
InstructionDesc[OpGroupFMinNonUniformAMD].operands.push(OperandId, "X");
|
||||
|
||||
InstructionDesc[OpGroupUMaxNonUniformAMD].capabilities.push_back(CapabilityGroups);
|
||||
InstructionDesc[OpGroupUMaxNonUniformAMD].operands.push(OperandScope, "'Execution'");
|
||||
InstructionDesc[OpGroupUMaxNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'");
|
||||
InstructionDesc[OpGroupUMaxNonUniformAMD].operands.push(OperandId, "X");
|
||||
|
||||
InstructionDesc[OpGroupSMaxNonUniformAMD].capabilities.push_back(CapabilityGroups);
|
||||
InstructionDesc[OpGroupSMaxNonUniformAMD].operands.push(OperandScope, "'Execution'");
|
||||
InstructionDesc[OpGroupSMaxNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'");
|
||||
InstructionDesc[OpGroupSMaxNonUniformAMD].operands.push(OperandId, "X");
|
||||
|
||||
InstructionDesc[OpGroupFMaxNonUniformAMD].capabilities.push_back(CapabilityGroups);
|
||||
InstructionDesc[OpGroupFMaxNonUniformAMD].operands.push(OperandScope, "'Execution'");
|
||||
InstructionDesc[OpGroupFMaxNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'");
|
||||
InstructionDesc[OpGroupFMaxNonUniformAMD].operands.push(OperandId, "X");
|
||||
#endif
|
||||
}
|
||||
|
||||
}; // end spv namespace
|
||||
|
||||
@@ -149,7 +149,7 @@ enum OperandClass {
|
||||
OperandMemorySemantics,
|
||||
OperandMemoryAccess,
|
||||
OperandScope,
|
||||
OperandGroupOperation,
|
||||
OperandGroupOperation,
|
||||
OperandKernelEnqueueFlags,
|
||||
OperandKernelProfilingInfo,
|
||||
OperandCapability,
|
||||
|
||||
1078
SPIRV/hex_float.h
Normal file
1078
SPIRV/hex_float.h
Normal file
File diff suppressed because it is too large
Load Diff
1805
SPIRV/spirv.hpp
1805
SPIRV/spirv.hpp
File diff suppressed because it is too large
Load Diff
@@ -64,8 +64,7 @@ class Module;
|
||||
const Id NoResult = 0;
|
||||
const Id NoType = 0;
|
||||
|
||||
const unsigned int BadValue = 0xFFFFFFFF;
|
||||
const Decoration NoPrecision = (Decoration)BadValue;
|
||||
const Decoration NoPrecision = DecorationMax;
|
||||
const MemorySemanticsMask MemorySemanticsAllMemory =
|
||||
(MemorySemanticsMask)(MemorySemanticsSequentiallyConsistentMask |
|
||||
MemorySemanticsUniformMemoryMask |
|
||||
|
||||
Reference in New Issue
Block a user