Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Johannes van Waveren
2016-10-21 17:21:46 +09:00
484 changed files with 101726 additions and 19867 deletions

View File

@@ -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
View 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
View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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
View 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_

View File

@@ -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);

View File

@@ -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

View File

@@ -149,7 +149,7 @@ enum OperandClass {
OperandMemorySemantics,
OperandMemoryAccess,
OperandScope,
OperandGroupOperation,
OperandGroupOperation,
OperandKernelEnqueueFlags,
OperandKernelProfilingInfo,
OperandCapability,

1078
SPIRV/hex_float.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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 |