Adding a subset of the glslang repo dealing with spirv.
The main repo is a mess.
This commit is contained in:
parent
ecd257b34c
commit
ea959b52fd
|
@ -165,6 +165,7 @@ solution("xenia")
|
||||||
include("third_party/capstone.lua")
|
include("third_party/capstone.lua")
|
||||||
include("third_party/gflags.lua")
|
include("third_party/gflags.lua")
|
||||||
include("third_party/glew.lua")
|
include("third_party/glew.lua")
|
||||||
|
include("third_party/glslang-spirv.lua")
|
||||||
include("third_party/imgui.lua")
|
include("third_party/imgui.lua")
|
||||||
include("third_party/libav.lua")
|
include("third_party/libav.lua")
|
||||||
include("third_party/snappy.lua")
|
include("third_party/snappy.lua")
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
group("third_party")
|
||||||
|
project("glslang-spirv")
|
||||||
|
uuid("1cc8f45e-91e2-4daf-a55e-666bf8b5e6b2")
|
||||||
|
kind("StaticLib")
|
||||||
|
language("C++")
|
||||||
|
links({
|
||||||
|
})
|
||||||
|
defines({
|
||||||
|
"_LIB",
|
||||||
|
})
|
||||||
|
includedirs({
|
||||||
|
})
|
||||||
|
files({
|
||||||
|
"glslang-spirv/disassemble.cpp",
|
||||||
|
"glslang-spirv/disassemble.h",
|
||||||
|
"glslang-spirv/doc.cpp",
|
||||||
|
"glslang-spirv/doc.h",
|
||||||
|
"glslang-spirv/GLSL.std.450.h",
|
||||||
|
-- Disabled until required.
|
||||||
|
-- "glslang-spirv/GlslangToSpv.cpp",
|
||||||
|
-- "glslang-spirv/GlslangToSpv.h",
|
||||||
|
"glslang-spirv/InReadableOrder.cpp",
|
||||||
|
"glslang-spirv/spirv.hpp",
|
||||||
|
"glslang-spirv/SpvBuilder.cpp",
|
||||||
|
"glslang-spirv/SpvBuilder.h",
|
||||||
|
"glslang-spirv/spvIR.h",
|
||||||
|
"glslang-spirv/SPVRemapper.cpp",
|
||||||
|
"glslang-spirv/SPVRemapper.h",
|
||||||
|
})
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
** 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 GLSLstd450_H
|
||||||
|
#define GLSLstd450_H
|
||||||
|
|
||||||
|
static const int GLSLstd450Version = 100;
|
||||||
|
static const int GLSLstd450Revision = 1;
|
||||||
|
|
||||||
|
enum GLSLstd450 {
|
||||||
|
GLSLstd450Bad = 0, // Don't use
|
||||||
|
|
||||||
|
GLSLstd450Round = 1,
|
||||||
|
GLSLstd450RoundEven = 2,
|
||||||
|
GLSLstd450Trunc = 3,
|
||||||
|
GLSLstd450FAbs = 4,
|
||||||
|
GLSLstd450SAbs = 5,
|
||||||
|
GLSLstd450FSign = 6,
|
||||||
|
GLSLstd450SSign = 7,
|
||||||
|
GLSLstd450Floor = 8,
|
||||||
|
GLSLstd450Ceil = 9,
|
||||||
|
GLSLstd450Fract = 10,
|
||||||
|
|
||||||
|
GLSLstd450Radians = 11,
|
||||||
|
GLSLstd450Degrees = 12,
|
||||||
|
GLSLstd450Sin = 13,
|
||||||
|
GLSLstd450Cos = 14,
|
||||||
|
GLSLstd450Tan = 15,
|
||||||
|
GLSLstd450Asin = 16,
|
||||||
|
GLSLstd450Acos = 17,
|
||||||
|
GLSLstd450Atan = 18,
|
||||||
|
GLSLstd450Sinh = 19,
|
||||||
|
GLSLstd450Cosh = 20,
|
||||||
|
GLSLstd450Tanh = 21,
|
||||||
|
GLSLstd450Asinh = 22,
|
||||||
|
GLSLstd450Acosh = 23,
|
||||||
|
GLSLstd450Atanh = 24,
|
||||||
|
GLSLstd450Atan2 = 25,
|
||||||
|
|
||||||
|
GLSLstd450Pow = 26,
|
||||||
|
GLSLstd450Exp = 27,
|
||||||
|
GLSLstd450Log = 28,
|
||||||
|
GLSLstd450Exp2 = 29,
|
||||||
|
GLSLstd450Log2 = 30,
|
||||||
|
GLSLstd450Sqrt = 31,
|
||||||
|
GLSLstd450InverseSqrt = 32,
|
||||||
|
|
||||||
|
GLSLstd450Determinant = 33,
|
||||||
|
GLSLstd450MatrixInverse = 34,
|
||||||
|
|
||||||
|
GLSLstd450Modf = 35, // second operand needs an OpVariable to write to
|
||||||
|
GLSLstd450ModfStruct = 36, // no OpVariable operand
|
||||||
|
GLSLstd450FMin = 37,
|
||||||
|
GLSLstd450UMin = 38,
|
||||||
|
GLSLstd450SMin = 39,
|
||||||
|
GLSLstd450FMax = 40,
|
||||||
|
GLSLstd450UMax = 41,
|
||||||
|
GLSLstd450SMax = 42,
|
||||||
|
GLSLstd450FClamp = 43,
|
||||||
|
GLSLstd450UClamp = 44,
|
||||||
|
GLSLstd450SClamp = 45,
|
||||||
|
GLSLstd450FMix = 46,
|
||||||
|
GLSLstd450IMix = 47, // Reserved
|
||||||
|
GLSLstd450Step = 48,
|
||||||
|
GLSLstd450SmoothStep = 49,
|
||||||
|
|
||||||
|
GLSLstd450Fma = 50,
|
||||||
|
GLSLstd450Frexp = 51, // second operand needs an OpVariable to write to
|
||||||
|
GLSLstd450FrexpStruct = 52, // no OpVariable operand
|
||||||
|
GLSLstd450Ldexp = 53,
|
||||||
|
|
||||||
|
GLSLstd450PackSnorm4x8 = 54,
|
||||||
|
GLSLstd450PackUnorm4x8 = 55,
|
||||||
|
GLSLstd450PackSnorm2x16 = 56,
|
||||||
|
GLSLstd450PackUnorm2x16 = 57,
|
||||||
|
GLSLstd450PackHalf2x16 = 58,
|
||||||
|
GLSLstd450PackDouble2x32 = 59,
|
||||||
|
GLSLstd450UnpackSnorm2x16 = 60,
|
||||||
|
GLSLstd450UnpackUnorm2x16 = 61,
|
||||||
|
GLSLstd450UnpackHalf2x16 = 62,
|
||||||
|
GLSLstd450UnpackSnorm4x8 = 63,
|
||||||
|
GLSLstd450UnpackUnorm4x8 = 64,
|
||||||
|
GLSLstd450UnpackDouble2x32 = 65,
|
||||||
|
|
||||||
|
GLSLstd450Length = 66,
|
||||||
|
GLSLstd450Distance = 67,
|
||||||
|
GLSLstd450Cross = 68,
|
||||||
|
GLSLstd450Normalize = 69,
|
||||||
|
GLSLstd450FaceForward = 70,
|
||||||
|
GLSLstd450Reflect = 71,
|
||||||
|
GLSLstd450Refract = 72,
|
||||||
|
|
||||||
|
GLSLstd450FindILsb = 73,
|
||||||
|
GLSLstd450FindSMsb = 74,
|
||||||
|
GLSLstd450FindUMsb = 75,
|
||||||
|
|
||||||
|
GLSLstd450InterpolateAtCentroid = 76,
|
||||||
|
GLSLstd450InterpolateAtSample = 77,
|
||||||
|
GLSLstd450InterpolateAtOffset = 78,
|
||||||
|
|
||||||
|
GLSLstd450NMin = 79,
|
||||||
|
GLSLstd450NMax = 80,
|
||||||
|
GLSLstd450NClamp = 81,
|
||||||
|
|
||||||
|
GLSLstd450Count
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // #ifndef GLSLstd450_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,43 @@
|
||||||
|
//
|
||||||
|
//Copyright (C) 2014 LunarG, Inc.
|
||||||
|
//
|
||||||
|
//All rights reserved.
|
||||||
|
//
|
||||||
|
//Redistribution and use in source and binary forms, with or without
|
||||||
|
//modification, are permitted provided that the following conditions
|
||||||
|
//are met:
|
||||||
|
//
|
||||||
|
// Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following
|
||||||
|
// disclaimer in the documentation and/or other materials provided
|
||||||
|
// with the distribution.
|
||||||
|
//
|
||||||
|
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived
|
||||||
|
// from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
//POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include "../glslang/Include/intermediate.h"
|
||||||
|
|
||||||
|
namespace glslang {
|
||||||
|
|
||||||
|
void GetSpirvVersion(std::string&);
|
||||||
|
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv);
|
||||||
|
void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName);
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,116 @@
|
||||||
|
//
|
||||||
|
//Copyright (C) 2016 Google, Inc.
|
||||||
|
//
|
||||||
|
//All rights reserved.
|
||||||
|
//
|
||||||
|
//Redistribution and use in source and binary forms, with or without
|
||||||
|
//modification, are permitted provided that the following conditions
|
||||||
|
//are met:
|
||||||
|
//
|
||||||
|
// Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following
|
||||||
|
// disclaimer in the documentation and/or other materials provided
|
||||||
|
// with the distribution.
|
||||||
|
//
|
||||||
|
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived
|
||||||
|
// from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
//POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
//
|
||||||
|
// Author: Dejan Mircevski, Google
|
||||||
|
//
|
||||||
|
|
||||||
|
// The SPIR-V spec requires code blocks to appear in an order satisfying the
|
||||||
|
// dominator-tree direction (ie, dominator before the dominated). This is,
|
||||||
|
// actually, easy to achieve: any pre-order CFG traversal algorithm will do it.
|
||||||
|
// Because such algorithms visit a block only after traversing some path to it
|
||||||
|
// from the root, they necessarily visit the block's idom first.
|
||||||
|
//
|
||||||
|
// But not every graph-traversal algorithm outputs blocks in an order that
|
||||||
|
// appears logical to human readers. The problem is that unrelated branches may
|
||||||
|
// be interspersed with each other, and merge blocks may come before some of the
|
||||||
|
// branches being merged.
|
||||||
|
//
|
||||||
|
// A good, human-readable order of blocks may be achieved by performing
|
||||||
|
// depth-first search but delaying merge nodes until after all their branches
|
||||||
|
// have been visited. This is implemented below by the inReadableOrder()
|
||||||
|
// function.
|
||||||
|
|
||||||
|
#include "spvIR.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
using spv::Block;
|
||||||
|
using spv::Id;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Traverses CFG in a readable order, invoking a pre-set callback on each block.
|
||||||
|
// Use by calling visit() on the root block.
|
||||||
|
class ReadableOrderTraverser {
|
||||||
|
public:
|
||||||
|
explicit ReadableOrderTraverser(std::function<void(Block*)> callback) : callback_(callback) {}
|
||||||
|
// Visits the block if it hasn't been visited already and isn't currently
|
||||||
|
// being delayed. Invokes callback(block), then descends into its
|
||||||
|
// successors. Delays merge-block and continue-block processing until all
|
||||||
|
// the branches have been completed.
|
||||||
|
void visit(Block* block)
|
||||||
|
{
|
||||||
|
assert(block);
|
||||||
|
if (visited_[block] || delayed_[block])
|
||||||
|
return;
|
||||||
|
callback_(block);
|
||||||
|
visited_[block] = true;
|
||||||
|
Block* mergeBlock = nullptr;
|
||||||
|
Block* continueBlock = nullptr;
|
||||||
|
auto mergeInst = block->getMergeInstruction();
|
||||||
|
if (mergeInst) {
|
||||||
|
Id mergeId = mergeInst->getIdOperand(0);
|
||||||
|
mergeBlock = block->getParent().getParent().getInstruction(mergeId)->getBlock();
|
||||||
|
delayed_[mergeBlock] = true;
|
||||||
|
if (mergeInst->getOpCode() == spv::OpLoopMerge) {
|
||||||
|
Id continueId = mergeInst->getIdOperand(1);
|
||||||
|
continueBlock =
|
||||||
|
block->getParent().getParent().getInstruction(continueId)->getBlock();
|
||||||
|
delayed_[continueBlock] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto succ : block->getSuccessors())
|
||||||
|
visit(succ);
|
||||||
|
if (continueBlock) {
|
||||||
|
delayed_[continueBlock] = false;
|
||||||
|
visit(continueBlock);
|
||||||
|
}
|
||||||
|
if (mergeBlock) {
|
||||||
|
delayed_[mergeBlock] = false;
|
||||||
|
visit(mergeBlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<void(Block*)> callback_;
|
||||||
|
// Whether a block has already been visited or is being delayed.
|
||||||
|
std::unordered_map<Block *, bool> visited_, delayed_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void spv::inReadableOrder(Block* root, std::function<void(Block*)> callback)
|
||||||
|
{
|
||||||
|
ReadableOrderTraverser(callback).visit(root);
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,288 @@
|
||||||
|
//
|
||||||
|
//Copyright (C) 2015 LunarG, Inc.
|
||||||
|
//
|
||||||
|
//All rights reserved.
|
||||||
|
//
|
||||||
|
//Redistribution and use in source and binary forms, with or without
|
||||||
|
//modification, are permitted provided that the following conditions
|
||||||
|
//are met:
|
||||||
|
//
|
||||||
|
// Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following
|
||||||
|
// disclaimer in the documentation and/or other materials provided
|
||||||
|
// with the distribution.
|
||||||
|
//
|
||||||
|
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived
|
||||||
|
// from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
//POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SPIRVREMAPPER_H
|
||||||
|
#define SPIRVREMAPPER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
namespace spv {
|
||||||
|
|
||||||
|
// MSVC defines __cplusplus as an older value, even when it supports almost all of 11.
|
||||||
|
// We handle that here by making our own symbol.
|
||||||
|
#if __cplusplus >= 201103L || _MSC_VER >= 1700
|
||||||
|
# define use_cpp11 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class spirvbin_base_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Options {
|
||||||
|
NONE = 0,
|
||||||
|
STRIP = (1<<0),
|
||||||
|
MAP_TYPES = (1<<1),
|
||||||
|
MAP_NAMES = (1<<2),
|
||||||
|
MAP_FUNCS = (1<<3),
|
||||||
|
DCE_FUNCS = (1<<4),
|
||||||
|
DCE_VARS = (1<<5),
|
||||||
|
DCE_TYPES = (1<<6),
|
||||||
|
OPT_LOADSTORE = (1<<7),
|
||||||
|
OPT_FWD_LS = (1<<8), // EXPERIMENTAL: PRODUCES INVALID SCHEMA-0 SPIRV
|
||||||
|
MAP_ALL = (MAP_TYPES | MAP_NAMES | MAP_FUNCS),
|
||||||
|
DCE_ALL = (DCE_FUNCS | DCE_VARS | DCE_TYPES),
|
||||||
|
OPT_ALL = (OPT_LOADSTORE),
|
||||||
|
|
||||||
|
ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL),
|
||||||
|
DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace SPV
|
||||||
|
|
||||||
|
#if !defined (use_cpp11)
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
namespace spv {
|
||||||
|
class spirvbin_t : public spirvbin_base_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
spirvbin_t(int /*verbose = 0*/) { }
|
||||||
|
|
||||||
|
void remap(std::vector<unsigned int>& /*spv*/, unsigned int /*opts = 0*/)
|
||||||
|
{
|
||||||
|
printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");
|
||||||
|
exit(5);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace SPV
|
||||||
|
|
||||||
|
#else // defined (use_cpp11)
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "spirv.hpp"
|
||||||
|
#include "spvIR.h"
|
||||||
|
|
||||||
|
namespace spv {
|
||||||
|
|
||||||
|
// class to hold SPIR-V binary data for remapping, DCE, and debug stripping
|
||||||
|
class spirvbin_t : public spirvbin_base_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose) { }
|
||||||
|
|
||||||
|
// remap on an existing binary in memory
|
||||||
|
void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = DO_EVERYTHING);
|
||||||
|
|
||||||
|
// Type for error/log handler functions
|
||||||
|
typedef std::function<void(const std::string&)> errorfn_t;
|
||||||
|
typedef std::function<void(const std::string&)> logfn_t;
|
||||||
|
|
||||||
|
// Register error/log handling functions (can be lambda fn / functor / etc)
|
||||||
|
static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }
|
||||||
|
static void registerLogHandler(logfn_t handler) { logHandler = handler; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// This can be overridden to provide other message behavior if needed
|
||||||
|
virtual void msg(int minVerbosity, int indent, const std::string& txt) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Local to global, or global to local ID map
|
||||||
|
typedef std::unordered_map<spv::Id, spv::Id> idmap_t;
|
||||||
|
typedef std::unordered_set<spv::Id> idset_t;
|
||||||
|
typedef std::unordered_map<spv::Id, int> blockmap_t;
|
||||||
|
|
||||||
|
void remap(std::uint32_t opts = DO_EVERYTHING);
|
||||||
|
|
||||||
|
// Map of names to IDs
|
||||||
|
typedef std::unordered_map<std::string, spv::Id> namemap_t;
|
||||||
|
|
||||||
|
typedef std::uint32_t spirword_t;
|
||||||
|
|
||||||
|
typedef std::pair<unsigned, unsigned> range_t;
|
||||||
|
typedef std::function<void(spv::Id&)> idfn_t;
|
||||||
|
typedef std::function<bool(spv::Op, unsigned start)> instfn_t;
|
||||||
|
|
||||||
|
// Special Values for ID map:
|
||||||
|
static const spv::Id unmapped; // unchanged from default value
|
||||||
|
static const spv::Id unused; // unused ID
|
||||||
|
static const int header_size; // SPIR header = 5 words
|
||||||
|
|
||||||
|
class id_iterator_t;
|
||||||
|
|
||||||
|
// For mapping type entries between different shaders
|
||||||
|
typedef std::vector<spirword_t> typeentry_t;
|
||||||
|
typedef std::map<spv::Id, typeentry_t> globaltypes_t;
|
||||||
|
|
||||||
|
// A set that preserves position order, and a reverse map
|
||||||
|
typedef std::set<int> posmap_t;
|
||||||
|
typedef std::unordered_map<spv::Id, int> posmap_rev_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;
|
||||||
|
|
||||||
|
spv::Id& asId(unsigned word) { return spv[word]; }
|
||||||
|
const spv::Id& asId(unsigned word) const { return spv[word]; }
|
||||||
|
spv::Op asOpCode(unsigned word) const { return opOpCode(spv[word]); }
|
||||||
|
std::uint32_t asOpCodeHash(unsigned word);
|
||||||
|
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;
|
||||||
|
|
||||||
|
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
|
||||||
|
spirword_t bound() const { return spv[3]; } // return Id bound from header
|
||||||
|
spirword_t bound(spirword_t b) { return spv[3] = b; };
|
||||||
|
spirword_t genmagic() const { return spv[2]; } // generator magic
|
||||||
|
spirword_t genmagic(spirword_t m) { return spv[2] = m; }
|
||||||
|
spirword_t schemaNum() const { return spv[4]; } // schema number from header
|
||||||
|
|
||||||
|
// Mapping fns: get
|
||||||
|
spv::Id localId(spv::Id id) const { return idMapL[id]; }
|
||||||
|
|
||||||
|
// Mapping fns: set
|
||||||
|
inline spv::Id localId(spv::Id id, spv::Id newId);
|
||||||
|
void countIds(spv::Id id);
|
||||||
|
|
||||||
|
// Return next unused new local ID.
|
||||||
|
// NOTE: boost::dynamic_bitset would be more efficient due to find_next(),
|
||||||
|
// which std::vector<bool> doens't have.
|
||||||
|
inline spv::Id nextUnusedId(spv::Id id);
|
||||||
|
|
||||||
|
void buildLocalMaps();
|
||||||
|
std::string literalString(unsigned word) const; // Return literal as a std::string
|
||||||
|
int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }
|
||||||
|
|
||||||
|
bool isNewIdMapped(spv::Id newId) const { return isMapped(newId); }
|
||||||
|
bool isOldIdUnmapped(spv::Id oldId) const { return localId(oldId) == unmapped; }
|
||||||
|
bool isOldIdUnused(spv::Id oldId) const { return localId(oldId) == unused; }
|
||||||
|
bool isOldIdMapped(spv::Id oldId) const { return !isOldIdUnused(oldId) && !isOldIdUnmapped(oldId); }
|
||||||
|
bool isFunction(spv::Id oldId) const { return fnPos.find(oldId) != fnPos.end(); }
|
||||||
|
|
||||||
|
// bool matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;
|
||||||
|
// spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;
|
||||||
|
std::uint32_t hashType(unsigned typeStart) const;
|
||||||
|
|
||||||
|
spirvbin_t& process(instfn_t, idfn_t, unsigned begin = 0, unsigned end = 0);
|
||||||
|
int processInstruction(unsigned word, instfn_t, idfn_t);
|
||||||
|
|
||||||
|
void validate() const;
|
||||||
|
void mapTypeConst();
|
||||||
|
void mapFnBodies();
|
||||||
|
void optLoadStore();
|
||||||
|
void dceFuncs();
|
||||||
|
void dceVars();
|
||||||
|
void dceTypes();
|
||||||
|
void mapNames();
|
||||||
|
void foldIds(); // fold IDs to smallest space
|
||||||
|
void forwardLoadStores(); // load store forwarding (EXPERIMENTAL)
|
||||||
|
void offsetIds(); // create relative offset IDs
|
||||||
|
|
||||||
|
void applyMap(); // remap per local name map
|
||||||
|
void mapRemainder(); // map any IDs we haven't touched yet
|
||||||
|
void stripDebug(); // strip debug info
|
||||||
|
void strip(); // remove debug symbols
|
||||||
|
|
||||||
|
std::vector<spirword_t> spv; // SPIR words
|
||||||
|
|
||||||
|
namemap_t nameMap; // ID names from OpName
|
||||||
|
|
||||||
|
// Since we want to also do binary ops, we can't use std::vector<bool>. we could use
|
||||||
|
// boost::dynamic_bitset, but we're trying to avoid a boost dependency.
|
||||||
|
typedef std::uint64_t bits_t;
|
||||||
|
std::vector<bits_t> mapped; // which new IDs have been mapped
|
||||||
|
static const int mBits = sizeof(bits_t) * 4;
|
||||||
|
|
||||||
|
bool isMapped(spv::Id id) const { return id < maxMappedId() && ((mapped[id/mBits] & (1LL<<(id%mBits))) != 0); }
|
||||||
|
void setMapped(spv::Id id) { resizeMapped(id); mapped[id/mBits] |= (1LL<<(id%mBits)); }
|
||||||
|
void resizeMapped(spv::Id id) { if (id >= maxMappedId()) mapped.resize(id/mBits+1, 0); }
|
||||||
|
size_t maxMappedId() const { return mapped.size() * mBits; }
|
||||||
|
|
||||||
|
// Add a strip range for a given instruction starting at 'start'
|
||||||
|
// Note: avoiding brace initializers to please older versions os MSVC.
|
||||||
|
void stripInst(unsigned start) { stripRange.push_back(range_t(start, start + asWordCount(start))); }
|
||||||
|
|
||||||
|
// Function start and end. use unordered_map because we'll have
|
||||||
|
// many fewer functions than IDs.
|
||||||
|
std::unordered_map<spv::Id, range_t> fnPos;
|
||||||
|
std::unordered_map<spv::Id, range_t> fnPosDCE; // deleted functions
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
std::vector<spv::Id> idMapL; // ID {M}ap from {L}ocal to {G}lobal IDs
|
||||||
|
|
||||||
|
spv::Id entryPoint; // module entry point
|
||||||
|
spv::Id largestNewId; // biggest new ID we have mapped anything to
|
||||||
|
|
||||||
|
// Sections of the binary to strip, given as [begin,end)
|
||||||
|
std::vector<range_t> stripRange;
|
||||||
|
|
||||||
|
// processing options:
|
||||||
|
std::uint32_t options;
|
||||||
|
int verbose; // verbosity level
|
||||||
|
|
||||||
|
static errorfn_t errorHandler;
|
||||||
|
static logfn_t logHandler;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace SPV
|
||||||
|
|
||||||
|
#endif // defined (use_cpp11)
|
||||||
|
#endif // SPIRVREMAPPER_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,576 @@
|
||||||
|
//
|
||||||
|
//Copyright (C) 2014-2015 LunarG, Inc.
|
||||||
|
//Copyright (C) 2015-2016 Google, Inc.
|
||||||
|
//
|
||||||
|
//All rights reserved.
|
||||||
|
//
|
||||||
|
//Redistribution and use in source and binary forms, with or without
|
||||||
|
//modification, are permitted provided that the following conditions
|
||||||
|
//are met:
|
||||||
|
//
|
||||||
|
// Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following
|
||||||
|
// disclaimer in the documentation and/or other materials provided
|
||||||
|
// with the distribution.
|
||||||
|
//
|
||||||
|
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived
|
||||||
|
// from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
//POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
//
|
||||||
|
// Author: John Kessenich, LunarG
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// "Builder" is an interface to fully build SPIR-V IR. Allocate one of
|
||||||
|
// these to build (a thread safe) internal SPIR-V representation (IR),
|
||||||
|
// and then dump it as a binary stream according to the SPIR-V specification.
|
||||||
|
//
|
||||||
|
// A Builder has a 1:1 relationship with a SPIR-V module.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef SpvBuilder_H
|
||||||
|
#define SpvBuilder_H
|
||||||
|
|
||||||
|
#include "spirv.hpp"
|
||||||
|
#include "spvIR.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
#include <stack>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace spv {
|
||||||
|
|
||||||
|
class Builder {
|
||||||
|
public:
|
||||||
|
Builder(unsigned int userNumber);
|
||||||
|
virtual ~Builder();
|
||||||
|
|
||||||
|
static const int maxMatrixSize = 4;
|
||||||
|
|
||||||
|
void setSource(spv::SourceLanguage lang, int version)
|
||||||
|
{
|
||||||
|
source = lang;
|
||||||
|
sourceVersion = version;
|
||||||
|
}
|
||||||
|
void addSourceExtension(const char* ext) { extensions.push_back(ext); }
|
||||||
|
Id import(const char*);
|
||||||
|
void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
|
||||||
|
{
|
||||||
|
addressModel = addr;
|
||||||
|
memoryModel = mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addCapability(spv::Capability cap) { capabilities.insert(cap); }
|
||||||
|
|
||||||
|
// To get a new <id> for anything needing a new one.
|
||||||
|
Id getUniqueId() { return ++uniqueId; }
|
||||||
|
|
||||||
|
// To get a set of new <id>s, e.g., for a set of function parameters
|
||||||
|
Id getUniqueIds(int numIds)
|
||||||
|
{
|
||||||
|
Id id = uniqueId + 1;
|
||||||
|
uniqueId += numIds;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For creating new types (will return old type if the requested one was already made).
|
||||||
|
Id makeVoidType();
|
||||||
|
Id makeBoolType();
|
||||||
|
Id makePointer(StorageClass, Id type);
|
||||||
|
Id makeIntegerType(int width, bool hasSign); // generic
|
||||||
|
Id makeIntType(int width) { return makeIntegerType(width, true); }
|
||||||
|
Id makeUintType(int width) { return makeIntegerType(width, false); }
|
||||||
|
Id makeFloatType(int width);
|
||||||
|
Id makeStructType(const std::vector<Id>& members, const char*);
|
||||||
|
Id makeStructResultType(Id type0, Id type1);
|
||||||
|
Id makeVectorType(Id component, int size);
|
||||||
|
Id makeMatrixType(Id component, int cols, int rows);
|
||||||
|
Id makeArrayType(Id element, Id sizeId, int stride); // 0 stride means no stride decoration
|
||||||
|
Id makeRuntimeArray(Id element);
|
||||||
|
Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);
|
||||||
|
Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
|
||||||
|
Id makeSamplerType();
|
||||||
|
Id makeSampledImageType(Id imageType);
|
||||||
|
|
||||||
|
// For querying about types.
|
||||||
|
Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
|
||||||
|
Id getDerefTypeId(Id resultId) const;
|
||||||
|
Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
|
||||||
|
Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
|
||||||
|
Op getMostBasicTypeClass(Id typeId) const;
|
||||||
|
int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
|
||||||
|
int getNumTypeConstituents(Id typeId) const;
|
||||||
|
int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }
|
||||||
|
Id getScalarTypeId(Id typeId) const;
|
||||||
|
Id getContainedTypeId(Id typeId) const;
|
||||||
|
Id getContainedTypeId(Id typeId, int) const;
|
||||||
|
StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
|
||||||
|
ImageFormat getImageTypeFormat(Id typeId) const { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); }
|
||||||
|
|
||||||
|
bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }
|
||||||
|
bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }
|
||||||
|
bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); }
|
||||||
|
bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); }
|
||||||
|
bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }
|
||||||
|
bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); }
|
||||||
|
|
||||||
|
bool isBoolType(Id typeId) const { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); }
|
||||||
|
bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; }
|
||||||
|
bool isScalarType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }
|
||||||
|
bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; }
|
||||||
|
bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; }
|
||||||
|
bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; }
|
||||||
|
bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; }
|
||||||
|
bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); }
|
||||||
|
bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; }
|
||||||
|
bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
|
||||||
|
bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
|
||||||
|
|
||||||
|
bool isConstantOpCode(Op opcode) const;
|
||||||
|
bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
|
||||||
|
bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
|
||||||
|
unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
|
||||||
|
StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
|
||||||
|
|
||||||
|
int getTypeNumColumns(Id typeId) const
|
||||||
|
{
|
||||||
|
assert(isMatrixType(typeId));
|
||||||
|
return getNumTypeConstituents(typeId);
|
||||||
|
}
|
||||||
|
int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
|
||||||
|
int getTypeNumRows(Id typeId) const
|
||||||
|
{
|
||||||
|
assert(isMatrixType(typeId));
|
||||||
|
return getNumTypeComponents(getContainedTypeId(typeId));
|
||||||
|
}
|
||||||
|
int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
|
||||||
|
|
||||||
|
Dim getTypeDimensionality(Id typeId) const
|
||||||
|
{
|
||||||
|
assert(isImageType(typeId));
|
||||||
|
return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
|
||||||
|
}
|
||||||
|
Id getImageType(Id resultId) const
|
||||||
|
{
|
||||||
|
Id typeId = getTypeId(resultId);
|
||||||
|
assert(isImageType(typeId) || isSampledImageType(typeId));
|
||||||
|
return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
|
||||||
|
}
|
||||||
|
bool isArrayedImageType(Id typeId) const
|
||||||
|
{
|
||||||
|
assert(isImageType(typeId));
|
||||||
|
return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For making new constants (will return old constant if the requested one was already made).
|
||||||
|
Id makeBoolConstant(bool b, bool specConstant = false);
|
||||||
|
Id makeIntConstant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); }
|
||||||
|
Id makeUintConstant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(32), u, specConstant); }
|
||||||
|
Id makeFloatConstant(float f, bool specConstant = false);
|
||||||
|
Id makeDoubleConstant(double d, bool specConstant = false);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Methods for adding information outside the CFG.
|
||||||
|
Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);
|
||||||
|
void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
|
||||||
|
void addName(Id, const char* name);
|
||||||
|
void addMemberName(Id, int member, const char* name);
|
||||||
|
void addLine(Id target, Id fileName, int line, int column);
|
||||||
|
void addDecoration(Id, Decoration, int num = -1);
|
||||||
|
void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
|
||||||
|
|
||||||
|
// At the end of what block do the next create*() instructions go?
|
||||||
|
void setBuildPoint(Block* bp) { buildPoint = bp; }
|
||||||
|
Block* getBuildPoint() const { return buildPoint; }
|
||||||
|
|
||||||
|
// Make the main function. The returned pointer is only valid
|
||||||
|
// for the lifetime of this builder.
|
||||||
|
Function* makeMain();
|
||||||
|
|
||||||
|
// Make a shader-style function, and create its entry block if entry is non-zero.
|
||||||
|
// Return the function, pass back the entry.
|
||||||
|
// The returned pointer is only valid for the lifetime of this builder.
|
||||||
|
Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, const std::vector<Id>& paramTypes,
|
||||||
|
const std::vector<Decoration>& precisions, Block **entry = 0);
|
||||||
|
|
||||||
|
// Create a return. An 'implicit' return is one not appearing in the source
|
||||||
|
// code. In the case of an implicit return, no post-return block is inserted.
|
||||||
|
void makeReturn(bool implicit, Id retVal = 0);
|
||||||
|
|
||||||
|
// Generate all the code needed to finish up a function.
|
||||||
|
void leaveFunction();
|
||||||
|
|
||||||
|
// Create a discard.
|
||||||
|
void makeDiscard();
|
||||||
|
|
||||||
|
// Create a global or function local or IO variable.
|
||||||
|
Id createVariable(StorageClass, Id type, const char* name = 0);
|
||||||
|
|
||||||
|
// Create an intermediate with an undefined value.
|
||||||
|
Id createUndefined(Id type);
|
||||||
|
|
||||||
|
// Store into an Id and return the l-value
|
||||||
|
void createStore(Id rValue, Id lValue);
|
||||||
|
|
||||||
|
// Load from an Id and return it
|
||||||
|
Id createLoad(Id lValue);
|
||||||
|
|
||||||
|
// Create an OpAccessChain instruction
|
||||||
|
Id createAccessChain(StorageClass, Id base, std::vector<Id>& offsets);
|
||||||
|
|
||||||
|
// Create an OpArrayLength instruction
|
||||||
|
Id createArrayLength(Id base, unsigned int member);
|
||||||
|
|
||||||
|
// Create an OpCompositeExtract instruction
|
||||||
|
Id createCompositeExtract(Id composite, Id typeId, unsigned index);
|
||||||
|
Id createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes);
|
||||||
|
Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
|
||||||
|
Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes);
|
||||||
|
|
||||||
|
Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
|
||||||
|
Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
|
||||||
|
|
||||||
|
void createNoResultOp(Op);
|
||||||
|
void createNoResultOp(Op, Id operand);
|
||||||
|
void createNoResultOp(Op, const std::vector<Id>& operands);
|
||||||
|
void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
|
||||||
|
void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
|
||||||
|
Id createUnaryOp(Op, Id typeId, Id operand);
|
||||||
|
Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
|
||||||
|
Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
|
||||||
|
Id createOp(Op, Id typeId, const std::vector<Id>& operands);
|
||||||
|
Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
|
||||||
|
|
||||||
|
// Take an rvalue (source) and a set of channels to extract from it to
|
||||||
|
// make a new rvalue, which is returned.
|
||||||
|
Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, std::vector<unsigned>& channels);
|
||||||
|
|
||||||
|
// Take a copy of an lvalue (target) and a source of components, and set the
|
||||||
|
// source components into the lvalue where the 'channels' say to put them.
|
||||||
|
// An updated version of the target is returned.
|
||||||
|
// (No true lvalue or stores are used.)
|
||||||
|
Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels);
|
||||||
|
|
||||||
|
// If both the id and precision are valid, the id
|
||||||
|
// gets tagged with the requested precision.
|
||||||
|
// The passed in id is always the returned id, to simplify use patterns.
|
||||||
|
Id setPrecision(Id id, Decoration precision)
|
||||||
|
{
|
||||||
|
if (precision != NoPrecision && id != NoResult)
|
||||||
|
addDecoration(id, precision);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can smear a scalar to a vector for the following forms:
|
||||||
|
// - promoteScalar(scalar, vector) // smear scalar to width of vector
|
||||||
|
// - promoteScalar(vector, scalar) // smear scalar to width of vector
|
||||||
|
// - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
|
||||||
|
// - promoteScalar(scalar, scalar) // do nothing
|
||||||
|
// Other forms are not allowed.
|
||||||
|
//
|
||||||
|
// Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'.
|
||||||
|
// The type of the created vector is a vector of components of the same type as the scalar.
|
||||||
|
//
|
||||||
|
// Note: One of the arguments will change, with the result coming back that way rather than
|
||||||
|
// through the return value.
|
||||||
|
void promoteScalar(Decoration precision, Id& left, Id& right);
|
||||||
|
|
||||||
|
// Make a value by smearing the scalar to fill the type.
|
||||||
|
// vectorType should be the correct type for making a vector of scalarVal.
|
||||||
|
// (No conversions are done.)
|
||||||
|
Id smearScalar(Decoration precision, Id scalarVal, Id vectorType);
|
||||||
|
|
||||||
|
// Create a call to a built-in function.
|
||||||
|
Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);
|
||||||
|
|
||||||
|
// List of parameters used to create a texture operation
|
||||||
|
struct TextureParameters {
|
||||||
|
Id sampler;
|
||||||
|
Id coords;
|
||||||
|
Id bias;
|
||||||
|
Id lod;
|
||||||
|
Id Dref;
|
||||||
|
Id offset;
|
||||||
|
Id offsets;
|
||||||
|
Id gradX;
|
||||||
|
Id gradY;
|
||||||
|
Id sample;
|
||||||
|
Id comp;
|
||||||
|
Id texelOut;
|
||||||
|
Id lodClamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Select the correct texture operation based on all inputs, and emit the correct instruction
|
||||||
|
Id createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, bool noImplicit, const TextureParameters&);
|
||||||
|
|
||||||
|
// Emit the OpTextureQuery* instruction that was passed in.
|
||||||
|
// Figure out the right return value and type, and return it.
|
||||||
|
Id createTextureQueryCall(Op, const TextureParameters&);
|
||||||
|
|
||||||
|
Id createSamplePositionCall(Decoration precision, Id, Id);
|
||||||
|
|
||||||
|
Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
|
||||||
|
Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
|
||||||
|
|
||||||
|
// Reduction comparison for composites: For equal and not-equal resulting in a scalar.
|
||||||
|
Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */);
|
||||||
|
|
||||||
|
// OpCompositeConstruct
|
||||||
|
Id createCompositeConstruct(Id typeId, std::vector<Id>& constituents);
|
||||||
|
|
||||||
|
// vector or scalar constructor
|
||||||
|
Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
|
||||||
|
|
||||||
|
// matrix constructor
|
||||||
|
Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
|
||||||
|
|
||||||
|
// Helper to use for building nested control flow with if-then-else.
|
||||||
|
class If {
|
||||||
|
public:
|
||||||
|
If(Id condition, Builder& builder);
|
||||||
|
~If() {}
|
||||||
|
|
||||||
|
void makeBeginElse();
|
||||||
|
void makeEndIf();
|
||||||
|
|
||||||
|
private:
|
||||||
|
If(const If&);
|
||||||
|
If& operator=(If&);
|
||||||
|
|
||||||
|
Builder& builder;
|
||||||
|
Id condition;
|
||||||
|
Function* function;
|
||||||
|
Block* headerBlock;
|
||||||
|
Block* thenBlock;
|
||||||
|
Block* elseBlock;
|
||||||
|
Block* mergeBlock;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make a switch statement. A switch has 'numSegments' of pieces of code, not containing
|
||||||
|
// any case/default labels, all separated by one or more case/default labels. Each possible
|
||||||
|
// case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this
|
||||||
|
// number space. How to compute the value is given by 'condition', as in switch(condition).
|
||||||
|
//
|
||||||
|
// The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
|
||||||
|
//
|
||||||
|
// Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
|
||||||
|
//
|
||||||
|
// Returns the right set of basic blocks to start each code segment with, so that the caller's
|
||||||
|
// recursion stack can hold the memory for it.
|
||||||
|
//
|
||||||
|
void makeSwitch(Id condition, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueToSegment, int defaultSegment,
|
||||||
|
std::vector<Block*>& segmentBB); // return argument
|
||||||
|
|
||||||
|
// Add a branch to the innermost switch's merge block.
|
||||||
|
void addSwitchBreak();
|
||||||
|
|
||||||
|
// Move to the next code segment, passing in the return argument in makeSwitch()
|
||||||
|
void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
|
||||||
|
|
||||||
|
// Finish off the innermost switch.
|
||||||
|
void endSwitch(std::vector<Block*>& segmentBB);
|
||||||
|
|
||||||
|
struct LoopBlocks {
|
||||||
|
Block &head, &body, &merge, &continue_target;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start a new loop and prepare the builder to generate code for it. Until
|
||||||
|
// closeLoop() is called for this loop, createLoopContinue() and
|
||||||
|
// createLoopExit() will target its corresponding blocks.
|
||||||
|
LoopBlocks& makeNewLoop();
|
||||||
|
|
||||||
|
// Create a new block in the function containing the build point. Memory is
|
||||||
|
// owned by the function object.
|
||||||
|
Block& makeNewBlock();
|
||||||
|
|
||||||
|
// Add a branch to the continue_target of the current (innermost) loop.
|
||||||
|
void createLoopContinue();
|
||||||
|
|
||||||
|
// Add an exit (e.g. "break") from the innermost loop that we're currently
|
||||||
|
// in.
|
||||||
|
void createLoopExit();
|
||||||
|
|
||||||
|
// Close the innermost loop that you're in
|
||||||
|
void closeLoop();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Access chain design for an R-Value vs. L-Value:
|
||||||
|
//
|
||||||
|
// There is a single access chain the builder is building at
|
||||||
|
// any particular time. Such a chain can be used to either to a load or
|
||||||
|
// a store, when desired.
|
||||||
|
//
|
||||||
|
// Expressions can be r-values, l-values, or both, or only r-values:
|
||||||
|
// a[b.c].d = .... // l-value
|
||||||
|
// ... = a[b.c].d; // r-value, that also looks like an l-value
|
||||||
|
// ++a[b.c].d; // r-value and l-value
|
||||||
|
// (x + y)[2]; // r-value only, can't possibly be l-value
|
||||||
|
//
|
||||||
|
// Computing an r-value means generating code. Hence,
|
||||||
|
// r-values should only be computed when they are needed, not speculatively.
|
||||||
|
//
|
||||||
|
// Computing an l-value means saving away information for later use in the compiler,
|
||||||
|
// no code is generated until the l-value is later dereferenced. It is okay
|
||||||
|
// to speculatively generate an l-value, just not okay to speculatively dereference it.
|
||||||
|
//
|
||||||
|
// The base of the access chain (the left-most variable or expression
|
||||||
|
// from which everything is based) can be set either as an l-value
|
||||||
|
// or as an r-value. Most efficient would be to set an l-value if one
|
||||||
|
// is available. If an expression was evaluated, the resulting r-value
|
||||||
|
// can be set as the chain base.
|
||||||
|
//
|
||||||
|
// The users of this single access chain can save and restore if they
|
||||||
|
// want to nest or manage multiple chains.
|
||||||
|
//
|
||||||
|
|
||||||
|
struct AccessChain {
|
||||||
|
Id base; // for l-values, pointer to the base object, for r-values, the base object
|
||||||
|
std::vector<Id> indexChain;
|
||||||
|
Id instr; // cache the instruction that generates this access chain
|
||||||
|
std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number
|
||||||
|
Id component; // a dynamic component index, can coexist with a swizzle, done after the swizzle, NoResult if not present
|
||||||
|
Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied; NoType unless a swizzle or component is present
|
||||||
|
bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// the SPIR-V builder maintains a single active chain that
|
||||||
|
// the following methods operated on
|
||||||
|
//
|
||||||
|
|
||||||
|
// for external save and restore
|
||||||
|
AccessChain getAccessChain() { return accessChain; }
|
||||||
|
void setAccessChain(AccessChain newChain) { accessChain = newChain; }
|
||||||
|
|
||||||
|
// clear accessChain
|
||||||
|
void clearAccessChain();
|
||||||
|
|
||||||
|
// set new base as an l-value base
|
||||||
|
void setAccessChainLValue(Id lValue)
|
||||||
|
{
|
||||||
|
assert(isPointer(lValue));
|
||||||
|
accessChain.base = lValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set new base value as an r-value
|
||||||
|
void setAccessChainRValue(Id rValue)
|
||||||
|
{
|
||||||
|
accessChain.isRValue = true;
|
||||||
|
accessChain.base = rValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// push offset onto the end of the chain
|
||||||
|
void accessChainPush(Id offset)
|
||||||
|
{
|
||||||
|
accessChain.indexChain.push_back(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// push new swizzle onto the end of any existing swizzle, merging into a single swizzle
|
||||||
|
void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType);
|
||||||
|
|
||||||
|
// push a variable component selection onto the access chain; supporting only one, so unsided
|
||||||
|
void accessChainPushComponent(Id component, Id preSwizzleBaseType)
|
||||||
|
{
|
||||||
|
accessChain.component = component;
|
||||||
|
if (accessChain.preSwizzleBaseType == NoType)
|
||||||
|
accessChain.preSwizzleBaseType = preSwizzleBaseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use accessChain and swizzle to store value
|
||||||
|
void accessChainStore(Id rvalue);
|
||||||
|
|
||||||
|
// use accessChain and swizzle to load an r-value
|
||||||
|
Id accessChainLoad(Decoration precision, Id ResultType);
|
||||||
|
|
||||||
|
// get the direct pointer for an l-value
|
||||||
|
Id accessChainGetLValue();
|
||||||
|
|
||||||
|
// Get the inferred SPIR-V type of the result of the current access chain,
|
||||||
|
// based on the type of the base and the chain of dereferences.
|
||||||
|
Id accessChainGetInferredType();
|
||||||
|
|
||||||
|
void dump(std::vector<unsigned int>&) const;
|
||||||
|
|
||||||
|
void createBranch(Block* block);
|
||||||
|
void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
|
||||||
|
void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
|
||||||
|
Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const;
|
||||||
|
Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const;
|
||||||
|
Id findCompositeConstant(Op typeClass, std::vector<Id>& comps) const;
|
||||||
|
Id collapseAccessChain();
|
||||||
|
void transferAccessChainSwizzle(bool dynamic);
|
||||||
|
void simplifyAccessChainSwizzle();
|
||||||
|
void createAndSetNoPredecessorBlock(const char*);
|
||||||
|
void createSelectionMerge(Block* mergeBlock, unsigned int control);
|
||||||
|
void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
|
||||||
|
|
||||||
|
SourceLanguage source;
|
||||||
|
int sourceVersion;
|
||||||
|
std::vector<const char*> extensions;
|
||||||
|
AddressingModel addressModel;
|
||||||
|
MemoryModel memoryModel;
|
||||||
|
std::set<spv::Capability> capabilities;
|
||||||
|
int builderNumber;
|
||||||
|
Module module;
|
||||||
|
Block* buildPoint;
|
||||||
|
Id uniqueId;
|
||||||
|
Function* mainFunction;
|
||||||
|
AccessChain accessChain;
|
||||||
|
|
||||||
|
// special blocks of instructions for output
|
||||||
|
std::vector<std::unique_ptr<Instruction> > imports;
|
||||||
|
std::vector<std::unique_ptr<Instruction> > entryPoints;
|
||||||
|
std::vector<std::unique_ptr<Instruction> > executionModes;
|
||||||
|
std::vector<std::unique_ptr<Instruction> > names;
|
||||||
|
std::vector<std::unique_ptr<Instruction> > lines;
|
||||||
|
std::vector<std::unique_ptr<Instruction> > decorations;
|
||||||
|
std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals;
|
||||||
|
std::vector<std::unique_ptr<Instruction> > externals;
|
||||||
|
std::vector<std::unique_ptr<Function> > functions;
|
||||||
|
|
||||||
|
// not output, internally used for quick & dirty canonical (unique) creation
|
||||||
|
std::vector<Instruction*> groupedConstants[OpConstant]; // all types appear before OpConstant
|
||||||
|
std::vector<Instruction*> groupedTypes[OpConstant];
|
||||||
|
|
||||||
|
// stack of switches
|
||||||
|
std::stack<Block*> switchMerges;
|
||||||
|
|
||||||
|
// Our loop stack.
|
||||||
|
std::stack<LoopBlocks> loops;
|
||||||
|
}; // end Builder class
|
||||||
|
|
||||||
|
// Use for non-fatal notes about what's not complete
|
||||||
|
void TbdFunctionality(const char*);
|
||||||
|
|
||||||
|
// Use for fatal missing functionality
|
||||||
|
void MissingFunctionality(const char*);
|
||||||
|
|
||||||
|
}; // end spv namespace
|
||||||
|
|
||||||
|
#endif // SpvBuilder_H
|
|
@ -0,0 +1,576 @@
|
||||||
|
//
|
||||||
|
//Copyright (C) 2014-2015 LunarG, Inc.
|
||||||
|
//
|
||||||
|
//All rights reserved.
|
||||||
|
//
|
||||||
|
//Redistribution and use in source and binary forms, with or without
|
||||||
|
//modification, are permitted provided that the following conditions
|
||||||
|
//are met:
|
||||||
|
//
|
||||||
|
// Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following
|
||||||
|
// disclaimer in the documentation and/or other materials provided
|
||||||
|
// with the distribution.
|
||||||
|
//
|
||||||
|
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived
|
||||||
|
// from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
//POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
//
|
||||||
|
// Author: John Kessenich, LunarG
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Disassembler for SPIR-V.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#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 {
|
||||||
|
|
||||||
|
void Kill(std::ostream& out, const char* message)
|
||||||
|
{
|
||||||
|
out << std::endl << "Disassembly failed: " << message << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// used to identify the extended instruction library imported when printing
|
||||||
|
enum ExtInstSet {
|
||||||
|
GLSL450Inst,
|
||||||
|
OpenCLExtInst,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Container class for a single instance of a SPIR-V stream, with methods for disassembly.
|
||||||
|
class SpirvStream {
|
||||||
|
public:
|
||||||
|
SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { }
|
||||||
|
virtual ~SpirvStream() { }
|
||||||
|
|
||||||
|
void validate();
|
||||||
|
void processInstructions();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SpirvStream(const SpirvStream&);
|
||||||
|
SpirvStream& operator=(const SpirvStream&);
|
||||||
|
Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; }
|
||||||
|
|
||||||
|
// Output methods
|
||||||
|
void outputIndent();
|
||||||
|
void formatId(Id id, std::stringstream&);
|
||||||
|
void outputResultId(Id id);
|
||||||
|
void outputTypeId(Id id);
|
||||||
|
void outputId(Id id);
|
||||||
|
void outputMask(OperandClass operandClass, unsigned mask);
|
||||||
|
void disassembleImmediates(int numOperands);
|
||||||
|
void disassembleIds(int numOperands);
|
||||||
|
int disassembleString();
|
||||||
|
void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands);
|
||||||
|
|
||||||
|
// Data
|
||||||
|
std::ostream& out; // where to write the disassembly
|
||||||
|
const std::vector<unsigned int>& stream; // the actual word stream
|
||||||
|
int size; // the size of the word stream
|
||||||
|
int word; // the next word of the stream to read
|
||||||
|
|
||||||
|
// map each <id> to the instruction that created it
|
||||||
|
Id bound;
|
||||||
|
std::vector<unsigned int> idInstruction; // the word offset into the stream where the instruction for result [id] starts; 0 if not yet seen (forward reference or function parameter)
|
||||||
|
|
||||||
|
std::vector<std::string> idDescriptor; // the best text string known for explaining the <id>
|
||||||
|
|
||||||
|
// schema
|
||||||
|
unsigned int schema;
|
||||||
|
|
||||||
|
// stack of structured-merge points
|
||||||
|
std::stack<Id> nestedControl;
|
||||||
|
Id nextNestedControl; // need a slight delay for when we are nested
|
||||||
|
};
|
||||||
|
|
||||||
|
void SpirvStream::validate()
|
||||||
|
{
|
||||||
|
size = (int)stream.size();
|
||||||
|
if (size < 4)
|
||||||
|
Kill(out, "stream is too short");
|
||||||
|
|
||||||
|
// Magic number
|
||||||
|
if (stream[word++] != MagicNumber) {
|
||||||
|
out << "Bad magic number";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version
|
||||||
|
out << "// Module Version " << std::hex << stream[word++] << std::endl;
|
||||||
|
|
||||||
|
// Generator's magic number
|
||||||
|
out << "// Generated by (magic number): " << std::hex << stream[word++] << std::dec << std::endl;
|
||||||
|
|
||||||
|
// Result <id> bound
|
||||||
|
bound = stream[word++];
|
||||||
|
idInstruction.resize(bound);
|
||||||
|
idDescriptor.resize(bound);
|
||||||
|
out << "// Id's are bound by " << bound << std::endl;
|
||||||
|
out << std::endl;
|
||||||
|
|
||||||
|
// Reserved schema, must be 0 for now
|
||||||
|
schema = stream[word++];
|
||||||
|
if (schema != 0)
|
||||||
|
Kill(out, "bad schema, must be 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop over all the instructions, in order, processing each.
|
||||||
|
// Boiler plate for each is handled here directly, the rest is dispatched.
|
||||||
|
void SpirvStream::processInstructions()
|
||||||
|
{
|
||||||
|
// Instructions
|
||||||
|
while (word < size) {
|
||||||
|
int instructionStart = word;
|
||||||
|
|
||||||
|
// Instruction wordCount and opcode
|
||||||
|
unsigned int firstWord = stream[word];
|
||||||
|
unsigned wordCount = firstWord >> WordCountShift;
|
||||||
|
Op opCode = (Op)(firstWord & OpCodeMask);
|
||||||
|
int nextInst = word + wordCount;
|
||||||
|
++word;
|
||||||
|
|
||||||
|
// Presence of full instruction
|
||||||
|
if (nextInst > size)
|
||||||
|
Kill(out, "stream instruction terminated too early");
|
||||||
|
|
||||||
|
// Base for computing number of operands; will be updated as more is learned
|
||||||
|
unsigned numOperands = wordCount - 1;
|
||||||
|
|
||||||
|
// Type <id>
|
||||||
|
Id typeId = 0;
|
||||||
|
if (InstructionDesc[opCode].hasType()) {
|
||||||
|
typeId = stream[word++];
|
||||||
|
--numOperands;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result <id>
|
||||||
|
Id resultId = 0;
|
||||||
|
if (InstructionDesc[opCode].hasResult()) {
|
||||||
|
resultId = stream[word++];
|
||||||
|
--numOperands;
|
||||||
|
|
||||||
|
// save instruction for future reference
|
||||||
|
idInstruction[resultId] = instructionStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
outputResultId(resultId);
|
||||||
|
outputTypeId(typeId);
|
||||||
|
outputIndent();
|
||||||
|
|
||||||
|
// Hand off the Op and all its operands
|
||||||
|
disassembleInstruction(resultId, typeId, opCode, numOperands);
|
||||||
|
if (word != nextInst) {
|
||||||
|
out << " ERROR, incorrect number of operands consumed. At " << word << " instead of " << nextInst << " instruction start was " << instructionStart;
|
||||||
|
word = nextInst;
|
||||||
|
}
|
||||||
|
out << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvStream::outputIndent()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (int)nestedControl.size(); ++i)
|
||||||
|
out << " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvStream::formatId(Id id, std::stringstream& idStream)
|
||||||
|
{
|
||||||
|
if (id >= bound)
|
||||||
|
Kill(out, "Bad <id>");
|
||||||
|
|
||||||
|
if (id != 0) {
|
||||||
|
idStream << id;
|
||||||
|
if (idDescriptor[id].size() > 0)
|
||||||
|
idStream << "(" << idDescriptor[id] << ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvStream::outputResultId(Id id)
|
||||||
|
{
|
||||||
|
const int width = 16;
|
||||||
|
std::stringstream idStream;
|
||||||
|
formatId(id, idStream);
|
||||||
|
out << std::setw(width) << std::right << idStream.str();
|
||||||
|
if (id != 0)
|
||||||
|
out << ":";
|
||||||
|
else
|
||||||
|
out << " ";
|
||||||
|
|
||||||
|
if (nestedControl.size() && id == nestedControl.top())
|
||||||
|
nestedControl.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvStream::outputTypeId(Id id)
|
||||||
|
{
|
||||||
|
const int width = 12;
|
||||||
|
std::stringstream idStream;
|
||||||
|
formatId(id, idStream);
|
||||||
|
out << std::setw(width) << std::right << idStream.str() << " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvStream::outputId(Id id)
|
||||||
|
{
|
||||||
|
if (id >= bound)
|
||||||
|
Kill(out, "Bad <id>");
|
||||||
|
|
||||||
|
out << id;
|
||||||
|
if (idDescriptor[id].size() > 0)
|
||||||
|
out << "(" << idDescriptor[id] << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvStream::outputMask(OperandClass operandClass, unsigned mask)
|
||||||
|
{
|
||||||
|
if (mask == 0)
|
||||||
|
out << "None";
|
||||||
|
else {
|
||||||
|
for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {
|
||||||
|
if (mask & (1 << m))
|
||||||
|
out << OperandClassParams[operandClass].getName(m) << " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvStream::disassembleImmediates(int numOperands)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < numOperands; ++i) {
|
||||||
|
out << stream[word++];
|
||||||
|
if (i < numOperands - 1)
|
||||||
|
out << " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvStream::disassembleIds(int numOperands)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < numOperands; ++i) {
|
||||||
|
outputId(stream[word++]);
|
||||||
|
if (i < numOperands - 1)
|
||||||
|
out << " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the number of operands consumed by the string
|
||||||
|
int SpirvStream::disassembleString()
|
||||||
|
{
|
||||||
|
int startWord = word;
|
||||||
|
|
||||||
|
out << " \"";
|
||||||
|
|
||||||
|
const char* wordString;
|
||||||
|
bool done = false;
|
||||||
|
do {
|
||||||
|
unsigned int content = stream[word];
|
||||||
|
wordString = (const char*)&content;
|
||||||
|
for (int charCount = 0; charCount < 4; ++charCount) {
|
||||||
|
if (*wordString == 0) {
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out << *(wordString++);
|
||||||
|
}
|
||||||
|
++word;
|
||||||
|
} while (! done);
|
||||||
|
|
||||||
|
out << "\"";
|
||||||
|
|
||||||
|
return word - startWord;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)
|
||||||
|
{
|
||||||
|
// Process the opcode
|
||||||
|
|
||||||
|
out << (OpcodeString(opCode) + 2); // leave out the "Op"
|
||||||
|
|
||||||
|
if (opCode == OpLoopMerge || opCode == OpSelectionMerge)
|
||||||
|
nextNestedControl = stream[word];
|
||||||
|
else if (opCode == OpBranchConditional || opCode == OpSwitch) {
|
||||||
|
if (nextNestedControl) {
|
||||||
|
nestedControl.push(nextNestedControl);
|
||||||
|
nextNestedControl = 0;
|
||||||
|
}
|
||||||
|
} else if (opCode == OpExtInstImport) {
|
||||||
|
idDescriptor[resultId] = (const char*)(&stream[word]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (idDescriptor[resultId].size() == 0) {
|
||||||
|
switch (opCode) {
|
||||||
|
case OpTypeInt:
|
||||||
|
idDescriptor[resultId] = "int";
|
||||||
|
break;
|
||||||
|
case OpTypeFloat:
|
||||||
|
idDescriptor[resultId] = "float";
|
||||||
|
break;
|
||||||
|
case OpTypeBool:
|
||||||
|
idDescriptor[resultId] = "bool";
|
||||||
|
break;
|
||||||
|
case OpTypeStruct:
|
||||||
|
idDescriptor[resultId] = "struct";
|
||||||
|
break;
|
||||||
|
case OpTypePointer:
|
||||||
|
idDescriptor[resultId] = "ptr";
|
||||||
|
break;
|
||||||
|
case OpTypeVector:
|
||||||
|
if (idDescriptor[stream[word]].size() > 0)
|
||||||
|
idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);
|
||||||
|
idDescriptor[resultId].append("vec");
|
||||||
|
switch (stream[word + 1]) {
|
||||||
|
case 2: idDescriptor[resultId].append("2"); break;
|
||||||
|
case 3: idDescriptor[resultId].append("3"); break;
|
||||||
|
case 4: idDescriptor[resultId].append("4"); break;
|
||||||
|
case 8: idDescriptor[resultId].append("8"); break;
|
||||||
|
case 16: idDescriptor[resultId].append("16"); break;
|
||||||
|
case 32: idDescriptor[resultId].append("32"); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the operands. Note, a new context-dependent set could be
|
||||||
|
// swapped in mid-traversal.
|
||||||
|
|
||||||
|
// Handle images specially, so can put out helpful strings.
|
||||||
|
if (opCode == OpTypeImage) {
|
||||||
|
out << " ";
|
||||||
|
disassembleIds(1);
|
||||||
|
out << " " << DimensionString((Dim)stream[word++]);
|
||||||
|
out << (stream[word++] != 0 ? " depth" : "");
|
||||||
|
out << (stream[word++] != 0 ? " array" : "");
|
||||||
|
out << (stream[word++] != 0 ? " multi-sampled" : "");
|
||||||
|
switch (stream[word++]) {
|
||||||
|
case 0: out << " runtime"; break;
|
||||||
|
case 1: out << " sampled"; break;
|
||||||
|
case 2: out << " nonsampled"; break;
|
||||||
|
}
|
||||||
|
out << " format:" << ImageFormatString((ImageFormat)stream[word++]);
|
||||||
|
|
||||||
|
if (numOperands == 8) {
|
||||||
|
out << " " << AccessQualifierString(stream[word++]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle all the parameterized operands
|
||||||
|
for (int op = 0; op < InstructionDesc[opCode].operands.getNum() && numOperands > 0; ++op) {
|
||||||
|
out << " ";
|
||||||
|
OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op);
|
||||||
|
switch (operandClass) {
|
||||||
|
case OperandId:
|
||||||
|
case OperandScope:
|
||||||
|
case OperandMemorySemantics:
|
||||||
|
disassembleIds(1);
|
||||||
|
--numOperands;
|
||||||
|
// Get names for printing "(XXX)" for readability, *after* this id
|
||||||
|
if (opCode == OpName)
|
||||||
|
idDescriptor[stream[word - 1]] = (const char*)(&stream[word]);
|
||||||
|
break;
|
||||||
|
case OperandVariableIds:
|
||||||
|
disassembleIds(numOperands);
|
||||||
|
return;
|
||||||
|
case OperandImageOperands:
|
||||||
|
outputMask(OperandImageOperands, stream[word++]);
|
||||||
|
--numOperands;
|
||||||
|
disassembleIds(numOperands);
|
||||||
|
return;
|
||||||
|
case OperandOptionalLiteral:
|
||||||
|
case OperandVariableLiterals:
|
||||||
|
if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) ||
|
||||||
|
(opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) {
|
||||||
|
out << BuiltInString(stream[word++]);
|
||||||
|
--numOperands;
|
||||||
|
++op;
|
||||||
|
}
|
||||||
|
disassembleImmediates(numOperands);
|
||||||
|
return;
|
||||||
|
case OperandVariableIdLiteral:
|
||||||
|
while (numOperands > 0) {
|
||||||
|
out << std::endl;
|
||||||
|
outputResultId(0);
|
||||||
|
outputTypeId(0);
|
||||||
|
outputIndent();
|
||||||
|
out << " Type ";
|
||||||
|
disassembleIds(1);
|
||||||
|
out << ", member ";
|
||||||
|
disassembleImmediates(1);
|
||||||
|
numOperands -= 2;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case OperandVariableLiteralId:
|
||||||
|
while (numOperands > 0) {
|
||||||
|
out << std::endl;
|
||||||
|
outputResultId(0);
|
||||||
|
outputTypeId(0);
|
||||||
|
outputIndent();
|
||||||
|
out << " case ";
|
||||||
|
disassembleImmediates(1);
|
||||||
|
out << ": ";
|
||||||
|
disassembleIds(1);
|
||||||
|
numOperands -= 2;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case OperandLiteralNumber:
|
||||||
|
disassembleImmediates(1);
|
||||||
|
--numOperands;
|
||||||
|
if (opCode == OpExtInst) {
|
||||||
|
ExtInstSet extInstSet = GLSL450Inst;
|
||||||
|
if (0 == memcmp("OpenCL", (const char*)(idDescriptor[stream[word-2]].c_str()), 6)) {
|
||||||
|
extInstSet = OpenCLExtInst;
|
||||||
|
}
|
||||||
|
unsigned entrypoint = stream[word - 1];
|
||||||
|
if (extInstSet == GLSL450Inst) {
|
||||||
|
if (entrypoint < GLSLstd450Count) {
|
||||||
|
out << "(" << GlslStd450DebugNames[entrypoint] << ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OperandOptionalLiteralString:
|
||||||
|
case OperandLiteralString:
|
||||||
|
numOperands -= disassembleString();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(operandClass >= OperandSource && operandClass < OperandOpcode);
|
||||||
|
|
||||||
|
if (OperandClassParams[operandClass].bitmask)
|
||||||
|
outputMask(operandClass, stream[word++]);
|
||||||
|
else
|
||||||
|
out << OperandClassParams[operandClass].getName(stream[word++]);
|
||||||
|
--numOperands;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLSLstd450GetDebugNames(const char** names)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < GLSLstd450Count; ++i)
|
||||||
|
names[i] = "Unknown";
|
||||||
|
|
||||||
|
names[GLSLstd450Round] = "Round";
|
||||||
|
names[GLSLstd450RoundEven] = "RoundEven";
|
||||||
|
names[GLSLstd450Trunc] = "Trunc";
|
||||||
|
names[GLSLstd450FAbs] = "FAbs";
|
||||||
|
names[GLSLstd450SAbs] = "SAbs";
|
||||||
|
names[GLSLstd450FSign] = "FSign";
|
||||||
|
names[GLSLstd450SSign] = "SSign";
|
||||||
|
names[GLSLstd450Floor] = "Floor";
|
||||||
|
names[GLSLstd450Ceil] = "Ceil";
|
||||||
|
names[GLSLstd450Fract] = "Fract";
|
||||||
|
names[GLSLstd450Radians] = "Radians";
|
||||||
|
names[GLSLstd450Degrees] = "Degrees";
|
||||||
|
names[GLSLstd450Sin] = "Sin";
|
||||||
|
names[GLSLstd450Cos] = "Cos";
|
||||||
|
names[GLSLstd450Tan] = "Tan";
|
||||||
|
names[GLSLstd450Asin] = "Asin";
|
||||||
|
names[GLSLstd450Acos] = "Acos";
|
||||||
|
names[GLSLstd450Atan] = "Atan";
|
||||||
|
names[GLSLstd450Sinh] = "Sinh";
|
||||||
|
names[GLSLstd450Cosh] = "Cosh";
|
||||||
|
names[GLSLstd450Tanh] = "Tanh";
|
||||||
|
names[GLSLstd450Asinh] = "Asinh";
|
||||||
|
names[GLSLstd450Acosh] = "Acosh";
|
||||||
|
names[GLSLstd450Atanh] = "Atanh";
|
||||||
|
names[GLSLstd450Atan2] = "Atan2";
|
||||||
|
names[GLSLstd450Pow] = "Pow";
|
||||||
|
names[GLSLstd450Exp] = "Exp";
|
||||||
|
names[GLSLstd450Log] = "Log";
|
||||||
|
names[GLSLstd450Exp2] = "Exp2";
|
||||||
|
names[GLSLstd450Log2] = "Log2";
|
||||||
|
names[GLSLstd450Sqrt] = "Sqrt";
|
||||||
|
names[GLSLstd450InverseSqrt] = "InverseSqrt";
|
||||||
|
names[GLSLstd450Determinant] = "Determinant";
|
||||||
|
names[GLSLstd450MatrixInverse] = "MatrixInverse";
|
||||||
|
names[GLSLstd450Modf] = "Modf";
|
||||||
|
names[GLSLstd450ModfStruct] = "ModfStruct";
|
||||||
|
names[GLSLstd450FMin] = "FMin";
|
||||||
|
names[GLSLstd450SMin] = "SMin";
|
||||||
|
names[GLSLstd450UMin] = "UMin";
|
||||||
|
names[GLSLstd450FMax] = "FMax";
|
||||||
|
names[GLSLstd450SMax] = "SMax";
|
||||||
|
names[GLSLstd450UMax] = "UMax";
|
||||||
|
names[GLSLstd450FClamp] = "FClamp";
|
||||||
|
names[GLSLstd450SClamp] = "SClamp";
|
||||||
|
names[GLSLstd450UClamp] = "UClamp";
|
||||||
|
names[GLSLstd450FMix] = "FMix";
|
||||||
|
names[GLSLstd450Step] = "Step";
|
||||||
|
names[GLSLstd450SmoothStep] = "SmoothStep";
|
||||||
|
names[GLSLstd450Fma] = "Fma";
|
||||||
|
names[GLSLstd450Frexp] = "Frexp";
|
||||||
|
names[GLSLstd450FrexpStruct] = "FrexpStruct";
|
||||||
|
names[GLSLstd450Ldexp] = "Ldexp";
|
||||||
|
names[GLSLstd450PackSnorm4x8] = "PackSnorm4x8";
|
||||||
|
names[GLSLstd450PackUnorm4x8] = "PackUnorm4x8";
|
||||||
|
names[GLSLstd450PackSnorm2x16] = "PackSnorm2x16";
|
||||||
|
names[GLSLstd450PackUnorm2x16] = "PackUnorm2x16";
|
||||||
|
names[GLSLstd450PackHalf2x16] = "PackHalf2x16";
|
||||||
|
names[GLSLstd450PackDouble2x32] = "PackDouble2x32";
|
||||||
|
names[GLSLstd450UnpackSnorm2x16] = "UnpackSnorm2x16";
|
||||||
|
names[GLSLstd450UnpackUnorm2x16] = "UnpackUnorm2x16";
|
||||||
|
names[GLSLstd450UnpackHalf2x16] = "UnpackHalf2x16";
|
||||||
|
names[GLSLstd450UnpackSnorm4x8] = "UnpackSnorm4x8";
|
||||||
|
names[GLSLstd450UnpackUnorm4x8] = "UnpackUnorm4x8";
|
||||||
|
names[GLSLstd450UnpackDouble2x32] = "UnpackDouble2x32";
|
||||||
|
names[GLSLstd450Length] = "Length";
|
||||||
|
names[GLSLstd450Distance] = "Distance";
|
||||||
|
names[GLSLstd450Cross] = "Cross";
|
||||||
|
names[GLSLstd450Normalize] = "Normalize";
|
||||||
|
names[GLSLstd450FaceForward] = "FaceForward";
|
||||||
|
names[GLSLstd450Reflect] = "Reflect";
|
||||||
|
names[GLSLstd450Refract] = "Refract";
|
||||||
|
names[GLSLstd450FindILsb] = "FindILsb";
|
||||||
|
names[GLSLstd450FindSMsb] = "FindSMsb";
|
||||||
|
names[GLSLstd450FindUMsb] = "FindUMsb";
|
||||||
|
names[GLSLstd450InterpolateAtCentroid] = "InterpolateAtCentroid";
|
||||||
|
names[GLSLstd450InterpolateAtSample] = "InterpolateAtSample";
|
||||||
|
names[GLSLstd450InterpolateAtOffset] = "InterpolateAtOffset";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
|
||||||
|
{
|
||||||
|
SpirvStream SpirvStream(out, stream);
|
||||||
|
GLSLstd450GetDebugNames(GlslStd450DebugNames);
|
||||||
|
SpirvStream.validate();
|
||||||
|
SpirvStream.processInstructions();
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // end namespace spv
|
|
@ -0,0 +1,56 @@
|
||||||
|
//
|
||||||
|
//Copyright (C) 2014-2015 LunarG, Inc.
|
||||||
|
//
|
||||||
|
//All rights reserved.
|
||||||
|
//
|
||||||
|
//Redistribution and use in source and binary forms, with or without
|
||||||
|
//modification, are permitted provided that the following conditions
|
||||||
|
//are met:
|
||||||
|
//
|
||||||
|
// Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following
|
||||||
|
// disclaimer in the documentation and/or other materials provided
|
||||||
|
// with the distribution.
|
||||||
|
//
|
||||||
|
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived
|
||||||
|
// from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
//POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
//
|
||||||
|
// Author: John Kessenich, LunarG
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Disassembler for SPIR-V.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef disassembler_H
|
||||||
|
#define disassembler_H
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace spv {
|
||||||
|
|
||||||
|
void Disassemble(std::ostream& out, const std::vector<unsigned int>&);
|
||||||
|
|
||||||
|
}; // end namespace spv
|
||||||
|
|
||||||
|
#endif // disassembler_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,261 @@
|
||||||
|
//
|
||||||
|
//Copyright (C) 2014-2015 LunarG, Inc.
|
||||||
|
//
|
||||||
|
//All rights reserved.
|
||||||
|
//
|
||||||
|
//Redistribution and use in source and binary forms, with or without
|
||||||
|
//modification, are permitted provided that the following conditions
|
||||||
|
//are met:
|
||||||
|
//
|
||||||
|
// Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following
|
||||||
|
// disclaimer in the documentation and/or other materials provided
|
||||||
|
// with the distribution.
|
||||||
|
//
|
||||||
|
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived
|
||||||
|
// from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
//POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
//
|
||||||
|
// Author: John Kessenich, LunarG
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Parameterize the SPIR-V enumerants.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "spirv.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace spv {
|
||||||
|
|
||||||
|
// Fill in all the parameters
|
||||||
|
void Parameterize();
|
||||||
|
|
||||||
|
// Return the English names of all the enums.
|
||||||
|
const char* SourceString(int);
|
||||||
|
const char* AddressingString(int);
|
||||||
|
const char* MemoryString(int);
|
||||||
|
const char* ExecutionModelString(int);
|
||||||
|
const char* ExecutionModeString(int);
|
||||||
|
const char* StorageClassString(int);
|
||||||
|
const char* DecorationString(int);
|
||||||
|
const char* BuiltInString(int);
|
||||||
|
const char* DimensionString(int);
|
||||||
|
const char* SelectControlString(int);
|
||||||
|
const char* LoopControlString(int);
|
||||||
|
const char* FunctionControlString(int);
|
||||||
|
const char* SamplerAddressingModeString(int);
|
||||||
|
const char* SamplerFilterModeString(int);
|
||||||
|
const char* ImageFormatString(int);
|
||||||
|
const char* ImageChannelOrderString(int);
|
||||||
|
const char* ImageChannelTypeString(int);
|
||||||
|
const char* ImageOperands(int);
|
||||||
|
const char* FPFastMathString(int);
|
||||||
|
const char* FPRoundingModeString(int);
|
||||||
|
const char* LinkageTypeString(int);
|
||||||
|
const char* FuncParamAttrString(int);
|
||||||
|
const char* AccessQualifierString(int);
|
||||||
|
const char* MemorySemanticsString(int);
|
||||||
|
const char* MemoryAccessString(int);
|
||||||
|
const char* ExecutionScopeString(int);
|
||||||
|
const char* GroupOperationString(int);
|
||||||
|
const char* KernelEnqueueFlagsString(int);
|
||||||
|
const char* KernelProfilingInfoString(int);
|
||||||
|
const char* CapabilityString(int);
|
||||||
|
const char* OpcodeString(int);
|
||||||
|
|
||||||
|
// For grouping opcodes into subsections
|
||||||
|
enum OpcodeClass {
|
||||||
|
OpClassMisc,
|
||||||
|
OpClassDebug,
|
||||||
|
OpClassAnnotate,
|
||||||
|
OpClassExtension,
|
||||||
|
OpClassMode,
|
||||||
|
OpClassType,
|
||||||
|
OpClassConstant,
|
||||||
|
OpClassMemory,
|
||||||
|
OpClassFunction,
|
||||||
|
OpClassImage,
|
||||||
|
OpClassConvert,
|
||||||
|
OpClassComposite,
|
||||||
|
OpClassArithmetic,
|
||||||
|
OpClassBit,
|
||||||
|
OpClassRelationalLogical,
|
||||||
|
OpClassDerivative,
|
||||||
|
OpClassFlowControl,
|
||||||
|
OpClassAtomic,
|
||||||
|
OpClassPrimitive,
|
||||||
|
OpClassBarrier,
|
||||||
|
OpClassGroup,
|
||||||
|
OpClassDeviceSideEnqueue,
|
||||||
|
OpClassPipe,
|
||||||
|
|
||||||
|
OpClassCount,
|
||||||
|
OpClassMissing // all instructions start out as missing
|
||||||
|
};
|
||||||
|
|
||||||
|
// For parameterizing operands.
|
||||||
|
enum OperandClass {
|
||||||
|
OperandNone,
|
||||||
|
OperandId,
|
||||||
|
OperandVariableIds,
|
||||||
|
OperandOptionalLiteral,
|
||||||
|
OperandOptionalLiteralString,
|
||||||
|
OperandVariableLiterals,
|
||||||
|
OperandVariableIdLiteral,
|
||||||
|
OperandVariableLiteralId,
|
||||||
|
OperandLiteralNumber,
|
||||||
|
OperandLiteralString,
|
||||||
|
OperandSource,
|
||||||
|
OperandExecutionModel,
|
||||||
|
OperandAddressing,
|
||||||
|
OperandMemory,
|
||||||
|
OperandExecutionMode,
|
||||||
|
OperandStorage,
|
||||||
|
OperandDimensionality,
|
||||||
|
OperandSamplerAddressingMode,
|
||||||
|
OperandSamplerFilterMode,
|
||||||
|
OperandSamplerImageFormat,
|
||||||
|
OperandImageChannelOrder,
|
||||||
|
OperandImageChannelDataType,
|
||||||
|
OperandImageOperands,
|
||||||
|
OperandFPFastMath,
|
||||||
|
OperandFPRoundingMode,
|
||||||
|
OperandLinkageType,
|
||||||
|
OperandAccessQualifier,
|
||||||
|
OperandFuncParamAttr,
|
||||||
|
OperandDecoration,
|
||||||
|
OperandBuiltIn,
|
||||||
|
OperandSelect,
|
||||||
|
OperandLoop,
|
||||||
|
OperandFunction,
|
||||||
|
OperandMemorySemantics,
|
||||||
|
OperandMemoryAccess,
|
||||||
|
OperandScope,
|
||||||
|
OperandGroupOperation,
|
||||||
|
OperandKernelEnqueueFlags,
|
||||||
|
OperandKernelProfilingInfo,
|
||||||
|
OperandCapability,
|
||||||
|
|
||||||
|
OperandOpcode,
|
||||||
|
|
||||||
|
OperandCount
|
||||||
|
};
|
||||||
|
|
||||||
|
// Any specific enum can have a set of capabilities that allow it:
|
||||||
|
typedef std::vector<Capability> EnumCaps;
|
||||||
|
|
||||||
|
// Parameterize a set of operands with their OperandClass(es) and descriptions.
|
||||||
|
class OperandParameters {
|
||||||
|
public:
|
||||||
|
OperandParameters() { }
|
||||||
|
void push(OperandClass oc, const char* d, bool opt = false)
|
||||||
|
{
|
||||||
|
opClass.push_back(oc);
|
||||||
|
desc.push_back(d);
|
||||||
|
optional.push_back(opt);
|
||||||
|
}
|
||||||
|
void setOptional();
|
||||||
|
OperandClass getClass(int op) const { return opClass[op]; }
|
||||||
|
const char* getDesc(int op) const { return desc[op]; }
|
||||||
|
bool isOptional(int op) const { return optional[op]; }
|
||||||
|
int getNum() const { return (int)opClass.size(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<OperandClass> opClass;
|
||||||
|
std::vector<const char*> desc;
|
||||||
|
std::vector<bool> optional;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parameterize an enumerant
|
||||||
|
class EnumParameters {
|
||||||
|
public:
|
||||||
|
EnumParameters() : desc(0) { }
|
||||||
|
EnumCaps caps;
|
||||||
|
const char* desc;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parameterize a set of enumerants that form an enum
|
||||||
|
class EnumDefinition : public EnumParameters {
|
||||||
|
public:
|
||||||
|
EnumDefinition() :
|
||||||
|
ceiling(0), bitmask(false), getName(0), enumParams(0), operandParams(0) { }
|
||||||
|
void set(int ceil, const char* (*name)(int), EnumParameters* ep, bool mask = false)
|
||||||
|
{
|
||||||
|
ceiling = ceil;
|
||||||
|
getName = name;
|
||||||
|
bitmask = mask;
|
||||||
|
enumParams = ep;
|
||||||
|
}
|
||||||
|
void setOperands(OperandParameters* op) { operandParams = op; }
|
||||||
|
int ceiling; // ceiling of enumerants
|
||||||
|
bool bitmask; // true if these enumerants combine into a bitmask
|
||||||
|
const char* (*getName)(int); // a function that returns the name for each enumerant value (or shift)
|
||||||
|
EnumParameters* enumParams; // parameters for each individual enumerant
|
||||||
|
OperandParameters* operandParams; // sets of operands
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parameterize an instruction's logical format, including its known set of operands,
|
||||||
|
// per OperandParameters above.
|
||||||
|
class InstructionParameters {
|
||||||
|
public:
|
||||||
|
InstructionParameters() :
|
||||||
|
opDesc("TBD"),
|
||||||
|
opClass(OpClassMissing),
|
||||||
|
typePresent(true), // most normal, only exceptions have to be spelled out
|
||||||
|
resultPresent(true) // most normal, only exceptions have to be spelled out
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void setResultAndType(bool r, bool t)
|
||||||
|
{
|
||||||
|
resultPresent = r;
|
||||||
|
typePresent = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasResult() const { return resultPresent != 0; }
|
||||||
|
bool hasType() const { return typePresent != 0; }
|
||||||
|
|
||||||
|
const char* opDesc;
|
||||||
|
EnumCaps capabilities;
|
||||||
|
OpcodeClass opClass;
|
||||||
|
OperandParameters operands;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int typePresent : 1;
|
||||||
|
int resultPresent : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const int OpcodeCeiling = 321;
|
||||||
|
|
||||||
|
// The set of objects that hold all the instruction/operand
|
||||||
|
// parameterization information.
|
||||||
|
extern InstructionParameters InstructionDesc[];
|
||||||
|
|
||||||
|
// These hold definitions of the enumerants used for operands
|
||||||
|
extern EnumDefinition OperandClassParams[];
|
||||||
|
|
||||||
|
const char* GetOperandDesc(OperandClass operand);
|
||||||
|
void PrintImmediateRow(int imm, const char* name, const EnumParameters* enumParams, bool caps, bool hex = false);
|
||||||
|
const char* AccessQualifierString(int attr);
|
||||||
|
|
||||||
|
void PrintOperands(const OperandParameters& operands, int reservedOperands);
|
||||||
|
|
||||||
|
}; // end namespace spv
|
|
@ -0,0 +1,879 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// This header is automatically generated by the same tool that creates
|
||||||
|
// the Binary Section of the SPIR-V specification.
|
||||||
|
|
||||||
|
// Enumeration tokens for SPIR-V, in various styles:
|
||||||
|
// C, C++, C++11, JSON, Lua, Python
|
||||||
|
//
|
||||||
|
// - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL
|
||||||
|
// - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL
|
||||||
|
// - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL
|
||||||
|
// - Lua will use tables, e.g.: spv.SourceLanguage.GLSL
|
||||||
|
// - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']
|
||||||
|
//
|
||||||
|
// Some tokens act like mask values, which can be OR'd together,
|
||||||
|
// while others are mutually exclusive. The mask-like ones have
|
||||||
|
// "Mask" in their name, and a parallel enum that has the shift
|
||||||
|
// amount (1 << x) for each corresponding enumerant.
|
||||||
|
|
||||||
|
#ifndef spirv_HPP
|
||||||
|
#define spirv_HPP
|
||||||
|
|
||||||
|
namespace spv {
|
||||||
|
|
||||||
|
typedef unsigned int Id;
|
||||||
|
|
||||||
|
#define SPV_VERSION 0x10000
|
||||||
|
#define SPV_REVISION 3
|
||||||
|
|
||||||
|
static const unsigned int MagicNumber = 0x07230203;
|
||||||
|
static const unsigned int Version = 0x00010000;
|
||||||
|
static const unsigned int Revision = 3;
|
||||||
|
static const unsigned int OpCodeMask = 0xffff;
|
||||||
|
static const unsigned int WordCountShift = 16;
|
||||||
|
|
||||||
|
enum SourceLanguage {
|
||||||
|
SourceLanguageUnknown = 0,
|
||||||
|
SourceLanguageESSL = 1,
|
||||||
|
SourceLanguageGLSL = 2,
|
||||||
|
SourceLanguageOpenCL_C = 3,
|
||||||
|
SourceLanguageOpenCL_CPP = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ExecutionModel {
|
||||||
|
ExecutionModelVertex = 0,
|
||||||
|
ExecutionModelTessellationControl = 1,
|
||||||
|
ExecutionModelTessellationEvaluation = 2,
|
||||||
|
ExecutionModelGeometry = 3,
|
||||||
|
ExecutionModelFragment = 4,
|
||||||
|
ExecutionModelGLCompute = 5,
|
||||||
|
ExecutionModelKernel = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum AddressingModel {
|
||||||
|
AddressingModelLogical = 0,
|
||||||
|
AddressingModelPhysical32 = 1,
|
||||||
|
AddressingModelPhysical64 = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MemoryModel {
|
||||||
|
MemoryModelSimple = 0,
|
||||||
|
MemoryModelGLSL450 = 1,
|
||||||
|
MemoryModelOpenCL = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ExecutionMode {
|
||||||
|
ExecutionModeInvocations = 0,
|
||||||
|
ExecutionModeSpacingEqual = 1,
|
||||||
|
ExecutionModeSpacingFractionalEven = 2,
|
||||||
|
ExecutionModeSpacingFractionalOdd = 3,
|
||||||
|
ExecutionModeVertexOrderCw = 4,
|
||||||
|
ExecutionModeVertexOrderCcw = 5,
|
||||||
|
ExecutionModePixelCenterInteger = 6,
|
||||||
|
ExecutionModeOriginUpperLeft = 7,
|
||||||
|
ExecutionModeOriginLowerLeft = 8,
|
||||||
|
ExecutionModeEarlyFragmentTests = 9,
|
||||||
|
ExecutionModePointMode = 10,
|
||||||
|
ExecutionModeXfb = 11,
|
||||||
|
ExecutionModeDepthReplacing = 12,
|
||||||
|
ExecutionModeDepthGreater = 14,
|
||||||
|
ExecutionModeDepthLess = 15,
|
||||||
|
ExecutionModeDepthUnchanged = 16,
|
||||||
|
ExecutionModeLocalSize = 17,
|
||||||
|
ExecutionModeLocalSizeHint = 18,
|
||||||
|
ExecutionModeInputPoints = 19,
|
||||||
|
ExecutionModeInputLines = 20,
|
||||||
|
ExecutionModeInputLinesAdjacency = 21,
|
||||||
|
ExecutionModeTriangles = 22,
|
||||||
|
ExecutionModeInputTrianglesAdjacency = 23,
|
||||||
|
ExecutionModeQuads = 24,
|
||||||
|
ExecutionModeIsolines = 25,
|
||||||
|
ExecutionModeOutputVertices = 26,
|
||||||
|
ExecutionModeOutputPoints = 27,
|
||||||
|
ExecutionModeOutputLineStrip = 28,
|
||||||
|
ExecutionModeOutputTriangleStrip = 29,
|
||||||
|
ExecutionModeVecTypeHint = 30,
|
||||||
|
ExecutionModeContractionOff = 31,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum StorageClass {
|
||||||
|
StorageClassUniformConstant = 0,
|
||||||
|
StorageClassInput = 1,
|
||||||
|
StorageClassUniform = 2,
|
||||||
|
StorageClassOutput = 3,
|
||||||
|
StorageClassWorkgroup = 4,
|
||||||
|
StorageClassCrossWorkgroup = 5,
|
||||||
|
StorageClassPrivate = 6,
|
||||||
|
StorageClassFunction = 7,
|
||||||
|
StorageClassGeneric = 8,
|
||||||
|
StorageClassPushConstant = 9,
|
||||||
|
StorageClassAtomicCounter = 10,
|
||||||
|
StorageClassImage = 11,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Dim {
|
||||||
|
Dim1D = 0,
|
||||||
|
Dim2D = 1,
|
||||||
|
Dim3D = 2,
|
||||||
|
DimCube = 3,
|
||||||
|
DimRect = 4,
|
||||||
|
DimBuffer = 5,
|
||||||
|
DimSubpassData = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SamplerAddressingMode {
|
||||||
|
SamplerAddressingModeNone = 0,
|
||||||
|
SamplerAddressingModeClampToEdge = 1,
|
||||||
|
SamplerAddressingModeClamp = 2,
|
||||||
|
SamplerAddressingModeRepeat = 3,
|
||||||
|
SamplerAddressingModeRepeatMirrored = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SamplerFilterMode {
|
||||||
|
SamplerFilterModeNearest = 0,
|
||||||
|
SamplerFilterModeLinear = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ImageFormat {
|
||||||
|
ImageFormatUnknown = 0,
|
||||||
|
ImageFormatRgba32f = 1,
|
||||||
|
ImageFormatRgba16f = 2,
|
||||||
|
ImageFormatR32f = 3,
|
||||||
|
ImageFormatRgba8 = 4,
|
||||||
|
ImageFormatRgba8Snorm = 5,
|
||||||
|
ImageFormatRg32f = 6,
|
||||||
|
ImageFormatRg16f = 7,
|
||||||
|
ImageFormatR11fG11fB10f = 8,
|
||||||
|
ImageFormatR16f = 9,
|
||||||
|
ImageFormatRgba16 = 10,
|
||||||
|
ImageFormatRgb10A2 = 11,
|
||||||
|
ImageFormatRg16 = 12,
|
||||||
|
ImageFormatRg8 = 13,
|
||||||
|
ImageFormatR16 = 14,
|
||||||
|
ImageFormatR8 = 15,
|
||||||
|
ImageFormatRgba16Snorm = 16,
|
||||||
|
ImageFormatRg16Snorm = 17,
|
||||||
|
ImageFormatRg8Snorm = 18,
|
||||||
|
ImageFormatR16Snorm = 19,
|
||||||
|
ImageFormatR8Snorm = 20,
|
||||||
|
ImageFormatRgba32i = 21,
|
||||||
|
ImageFormatRgba16i = 22,
|
||||||
|
ImageFormatRgba8i = 23,
|
||||||
|
ImageFormatR32i = 24,
|
||||||
|
ImageFormatRg32i = 25,
|
||||||
|
ImageFormatRg16i = 26,
|
||||||
|
ImageFormatRg8i = 27,
|
||||||
|
ImageFormatR16i = 28,
|
||||||
|
ImageFormatR8i = 29,
|
||||||
|
ImageFormatRgba32ui = 30,
|
||||||
|
ImageFormatRgba16ui = 31,
|
||||||
|
ImageFormatRgba8ui = 32,
|
||||||
|
ImageFormatR32ui = 33,
|
||||||
|
ImageFormatRgb10a2ui = 34,
|
||||||
|
ImageFormatRg32ui = 35,
|
||||||
|
ImageFormatRg16ui = 36,
|
||||||
|
ImageFormatRg8ui = 37,
|
||||||
|
ImageFormatR16ui = 38,
|
||||||
|
ImageFormatR8ui = 39,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ImageChannelOrder {
|
||||||
|
ImageChannelOrderR = 0,
|
||||||
|
ImageChannelOrderA = 1,
|
||||||
|
ImageChannelOrderRG = 2,
|
||||||
|
ImageChannelOrderRA = 3,
|
||||||
|
ImageChannelOrderRGB = 4,
|
||||||
|
ImageChannelOrderRGBA = 5,
|
||||||
|
ImageChannelOrderBGRA = 6,
|
||||||
|
ImageChannelOrderARGB = 7,
|
||||||
|
ImageChannelOrderIntensity = 8,
|
||||||
|
ImageChannelOrderLuminance = 9,
|
||||||
|
ImageChannelOrderRx = 10,
|
||||||
|
ImageChannelOrderRGx = 11,
|
||||||
|
ImageChannelOrderRGBx = 12,
|
||||||
|
ImageChannelOrderDepth = 13,
|
||||||
|
ImageChannelOrderDepthStencil = 14,
|
||||||
|
ImageChannelOrdersRGB = 15,
|
||||||
|
ImageChannelOrdersRGBx = 16,
|
||||||
|
ImageChannelOrdersRGBA = 17,
|
||||||
|
ImageChannelOrdersBGRA = 18,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ImageChannelDataType {
|
||||||
|
ImageChannelDataTypeSnormInt8 = 0,
|
||||||
|
ImageChannelDataTypeSnormInt16 = 1,
|
||||||
|
ImageChannelDataTypeUnormInt8 = 2,
|
||||||
|
ImageChannelDataTypeUnormInt16 = 3,
|
||||||
|
ImageChannelDataTypeUnormShort565 = 4,
|
||||||
|
ImageChannelDataTypeUnormShort555 = 5,
|
||||||
|
ImageChannelDataTypeUnormInt101010 = 6,
|
||||||
|
ImageChannelDataTypeSignedInt8 = 7,
|
||||||
|
ImageChannelDataTypeSignedInt16 = 8,
|
||||||
|
ImageChannelDataTypeSignedInt32 = 9,
|
||||||
|
ImageChannelDataTypeUnsignedInt8 = 10,
|
||||||
|
ImageChannelDataTypeUnsignedInt16 = 11,
|
||||||
|
ImageChannelDataTypeUnsignedInt32 = 12,
|
||||||
|
ImageChannelDataTypeHalfFloat = 13,
|
||||||
|
ImageChannelDataTypeFloat = 14,
|
||||||
|
ImageChannelDataTypeUnormInt24 = 15,
|
||||||
|
ImageChannelDataTypeUnormInt101010_2 = 16,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ImageOperandsShift {
|
||||||
|
ImageOperandsBiasShift = 0,
|
||||||
|
ImageOperandsLodShift = 1,
|
||||||
|
ImageOperandsGradShift = 2,
|
||||||
|
ImageOperandsConstOffsetShift = 3,
|
||||||
|
ImageOperandsOffsetShift = 4,
|
||||||
|
ImageOperandsConstOffsetsShift = 5,
|
||||||
|
ImageOperandsSampleShift = 6,
|
||||||
|
ImageOperandsMinLodShift = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ImageOperandsMask {
|
||||||
|
ImageOperandsMaskNone = 0,
|
||||||
|
ImageOperandsBiasMask = 0x00000001,
|
||||||
|
ImageOperandsLodMask = 0x00000002,
|
||||||
|
ImageOperandsGradMask = 0x00000004,
|
||||||
|
ImageOperandsConstOffsetMask = 0x00000008,
|
||||||
|
ImageOperandsOffsetMask = 0x00000010,
|
||||||
|
ImageOperandsConstOffsetsMask = 0x00000020,
|
||||||
|
ImageOperandsSampleMask = 0x00000040,
|
||||||
|
ImageOperandsMinLodMask = 0x00000080,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FPFastMathModeShift {
|
||||||
|
FPFastMathModeNotNaNShift = 0,
|
||||||
|
FPFastMathModeNotInfShift = 1,
|
||||||
|
FPFastMathModeNSZShift = 2,
|
||||||
|
FPFastMathModeAllowRecipShift = 3,
|
||||||
|
FPFastMathModeFastShift = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FPFastMathModeMask {
|
||||||
|
FPFastMathModeMaskNone = 0,
|
||||||
|
FPFastMathModeNotNaNMask = 0x00000001,
|
||||||
|
FPFastMathModeNotInfMask = 0x00000002,
|
||||||
|
FPFastMathModeNSZMask = 0x00000004,
|
||||||
|
FPFastMathModeAllowRecipMask = 0x00000008,
|
||||||
|
FPFastMathModeFastMask = 0x00000010,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FPRoundingMode {
|
||||||
|
FPRoundingModeRTE = 0,
|
||||||
|
FPRoundingModeRTZ = 1,
|
||||||
|
FPRoundingModeRTP = 2,
|
||||||
|
FPRoundingModeRTN = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum LinkageType {
|
||||||
|
LinkageTypeExport = 0,
|
||||||
|
LinkageTypeImport = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum AccessQualifier {
|
||||||
|
AccessQualifierReadOnly = 0,
|
||||||
|
AccessQualifierWriteOnly = 1,
|
||||||
|
AccessQualifierReadWrite = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FunctionParameterAttribute {
|
||||||
|
FunctionParameterAttributeZext = 0,
|
||||||
|
FunctionParameterAttributeSext = 1,
|
||||||
|
FunctionParameterAttributeByVal = 2,
|
||||||
|
FunctionParameterAttributeSret = 3,
|
||||||
|
FunctionParameterAttributeNoAlias = 4,
|
||||||
|
FunctionParameterAttributeNoCapture = 5,
|
||||||
|
FunctionParameterAttributeNoWrite = 6,
|
||||||
|
FunctionParameterAttributeNoReadWrite = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Decoration {
|
||||||
|
DecorationRelaxedPrecision = 0,
|
||||||
|
DecorationSpecId = 1,
|
||||||
|
DecorationBlock = 2,
|
||||||
|
DecorationBufferBlock = 3,
|
||||||
|
DecorationRowMajor = 4,
|
||||||
|
DecorationColMajor = 5,
|
||||||
|
DecorationArrayStride = 6,
|
||||||
|
DecorationMatrixStride = 7,
|
||||||
|
DecorationGLSLShared = 8,
|
||||||
|
DecorationGLSLPacked = 9,
|
||||||
|
DecorationCPacked = 10,
|
||||||
|
DecorationBuiltIn = 11,
|
||||||
|
DecorationNoPerspective = 13,
|
||||||
|
DecorationFlat = 14,
|
||||||
|
DecorationPatch = 15,
|
||||||
|
DecorationCentroid = 16,
|
||||||
|
DecorationSample = 17,
|
||||||
|
DecorationInvariant = 18,
|
||||||
|
DecorationRestrict = 19,
|
||||||
|
DecorationAliased = 20,
|
||||||
|
DecorationVolatile = 21,
|
||||||
|
DecorationConstant = 22,
|
||||||
|
DecorationCoherent = 23,
|
||||||
|
DecorationNonWritable = 24,
|
||||||
|
DecorationNonReadable = 25,
|
||||||
|
DecorationUniform = 26,
|
||||||
|
DecorationSaturatedConversion = 28,
|
||||||
|
DecorationStream = 29,
|
||||||
|
DecorationLocation = 30,
|
||||||
|
DecorationComponent = 31,
|
||||||
|
DecorationIndex = 32,
|
||||||
|
DecorationBinding = 33,
|
||||||
|
DecorationDescriptorSet = 34,
|
||||||
|
DecorationOffset = 35,
|
||||||
|
DecorationXfbBuffer = 36,
|
||||||
|
DecorationXfbStride = 37,
|
||||||
|
DecorationFuncParamAttr = 38,
|
||||||
|
DecorationFPRoundingMode = 39,
|
||||||
|
DecorationFPFastMathMode = 40,
|
||||||
|
DecorationLinkageAttributes = 41,
|
||||||
|
DecorationNoContraction = 42,
|
||||||
|
DecorationInputAttachmentIndex = 43,
|
||||||
|
DecorationAlignment = 44,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BuiltIn {
|
||||||
|
BuiltInPosition = 0,
|
||||||
|
BuiltInPointSize = 1,
|
||||||
|
BuiltInClipDistance = 3,
|
||||||
|
BuiltInCullDistance = 4,
|
||||||
|
BuiltInVertexId = 5,
|
||||||
|
BuiltInInstanceId = 6,
|
||||||
|
BuiltInPrimitiveId = 7,
|
||||||
|
BuiltInInvocationId = 8,
|
||||||
|
BuiltInLayer = 9,
|
||||||
|
BuiltInViewportIndex = 10,
|
||||||
|
BuiltInTessLevelOuter = 11,
|
||||||
|
BuiltInTessLevelInner = 12,
|
||||||
|
BuiltInTessCoord = 13,
|
||||||
|
BuiltInPatchVertices = 14,
|
||||||
|
BuiltInFragCoord = 15,
|
||||||
|
BuiltInPointCoord = 16,
|
||||||
|
BuiltInFrontFacing = 17,
|
||||||
|
BuiltInSampleId = 18,
|
||||||
|
BuiltInSamplePosition = 19,
|
||||||
|
BuiltInSampleMask = 20,
|
||||||
|
BuiltInFragDepth = 22,
|
||||||
|
BuiltInHelperInvocation = 23,
|
||||||
|
BuiltInNumWorkgroups = 24,
|
||||||
|
BuiltInWorkgroupSize = 25,
|
||||||
|
BuiltInWorkgroupId = 26,
|
||||||
|
BuiltInLocalInvocationId = 27,
|
||||||
|
BuiltInGlobalInvocationId = 28,
|
||||||
|
BuiltInLocalInvocationIndex = 29,
|
||||||
|
BuiltInWorkDim = 30,
|
||||||
|
BuiltInGlobalSize = 31,
|
||||||
|
BuiltInEnqueuedWorkgroupSize = 32,
|
||||||
|
BuiltInGlobalOffset = 33,
|
||||||
|
BuiltInGlobalLinearId = 34,
|
||||||
|
BuiltInSubgroupSize = 36,
|
||||||
|
BuiltInSubgroupMaxSize = 37,
|
||||||
|
BuiltInNumSubgroups = 38,
|
||||||
|
BuiltInNumEnqueuedSubgroups = 39,
|
||||||
|
BuiltInSubgroupId = 40,
|
||||||
|
BuiltInSubgroupLocalInvocationId = 41,
|
||||||
|
BuiltInVertexIndex = 42,
|
||||||
|
BuiltInInstanceIndex = 43,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SelectionControlShift {
|
||||||
|
SelectionControlFlattenShift = 0,
|
||||||
|
SelectionControlDontFlattenShift = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SelectionControlMask {
|
||||||
|
SelectionControlMaskNone = 0,
|
||||||
|
SelectionControlFlattenMask = 0x00000001,
|
||||||
|
SelectionControlDontFlattenMask = 0x00000002,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum LoopControlShift {
|
||||||
|
LoopControlUnrollShift = 0,
|
||||||
|
LoopControlDontUnrollShift = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum LoopControlMask {
|
||||||
|
LoopControlMaskNone = 0,
|
||||||
|
LoopControlUnrollMask = 0x00000001,
|
||||||
|
LoopControlDontUnrollMask = 0x00000002,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FunctionControlShift {
|
||||||
|
FunctionControlInlineShift = 0,
|
||||||
|
FunctionControlDontInlineShift = 1,
|
||||||
|
FunctionControlPureShift = 2,
|
||||||
|
FunctionControlConstShift = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FunctionControlMask {
|
||||||
|
FunctionControlMaskNone = 0,
|
||||||
|
FunctionControlInlineMask = 0x00000001,
|
||||||
|
FunctionControlDontInlineMask = 0x00000002,
|
||||||
|
FunctionControlPureMask = 0x00000004,
|
||||||
|
FunctionControlConstMask = 0x00000008,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MemorySemanticsShift {
|
||||||
|
MemorySemanticsAcquireShift = 1,
|
||||||
|
MemorySemanticsReleaseShift = 2,
|
||||||
|
MemorySemanticsAcquireReleaseShift = 3,
|
||||||
|
MemorySemanticsSequentiallyConsistentShift = 4,
|
||||||
|
MemorySemanticsUniformMemoryShift = 6,
|
||||||
|
MemorySemanticsSubgroupMemoryShift = 7,
|
||||||
|
MemorySemanticsWorkgroupMemoryShift = 8,
|
||||||
|
MemorySemanticsCrossWorkgroupMemoryShift = 9,
|
||||||
|
MemorySemanticsAtomicCounterMemoryShift = 10,
|
||||||
|
MemorySemanticsImageMemoryShift = 11,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MemorySemanticsMask {
|
||||||
|
MemorySemanticsMaskNone = 0,
|
||||||
|
MemorySemanticsAcquireMask = 0x00000002,
|
||||||
|
MemorySemanticsReleaseMask = 0x00000004,
|
||||||
|
MemorySemanticsAcquireReleaseMask = 0x00000008,
|
||||||
|
MemorySemanticsSequentiallyConsistentMask = 0x00000010,
|
||||||
|
MemorySemanticsUniformMemoryMask = 0x00000040,
|
||||||
|
MemorySemanticsSubgroupMemoryMask = 0x00000080,
|
||||||
|
MemorySemanticsWorkgroupMemoryMask = 0x00000100,
|
||||||
|
MemorySemanticsCrossWorkgroupMemoryMask = 0x00000200,
|
||||||
|
MemorySemanticsAtomicCounterMemoryMask = 0x00000400,
|
||||||
|
MemorySemanticsImageMemoryMask = 0x00000800,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MemoryAccessShift {
|
||||||
|
MemoryAccessVolatileShift = 0,
|
||||||
|
MemoryAccessAlignedShift = 1,
|
||||||
|
MemoryAccessNontemporalShift = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MemoryAccessMask {
|
||||||
|
MemoryAccessMaskNone = 0,
|
||||||
|
MemoryAccessVolatileMask = 0x00000001,
|
||||||
|
MemoryAccessAlignedMask = 0x00000002,
|
||||||
|
MemoryAccessNontemporalMask = 0x00000004,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Scope {
|
||||||
|
ScopeCrossDevice = 0,
|
||||||
|
ScopeDevice = 1,
|
||||||
|
ScopeWorkgroup = 2,
|
||||||
|
ScopeSubgroup = 3,
|
||||||
|
ScopeInvocation = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum GroupOperation {
|
||||||
|
GroupOperationReduce = 0,
|
||||||
|
GroupOperationInclusiveScan = 1,
|
||||||
|
GroupOperationExclusiveScan = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum KernelEnqueueFlags {
|
||||||
|
KernelEnqueueFlagsNoWait = 0,
|
||||||
|
KernelEnqueueFlagsWaitKernel = 1,
|
||||||
|
KernelEnqueueFlagsWaitWorkGroup = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum KernelProfilingInfoShift {
|
||||||
|
KernelProfilingInfoCmdExecTimeShift = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum KernelProfilingInfoMask {
|
||||||
|
KernelProfilingInfoMaskNone = 0,
|
||||||
|
KernelProfilingInfoCmdExecTimeMask = 0x00000001,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Capability {
|
||||||
|
CapabilityMatrix = 0,
|
||||||
|
CapabilityShader = 1,
|
||||||
|
CapabilityGeometry = 2,
|
||||||
|
CapabilityTessellation = 3,
|
||||||
|
CapabilityAddresses = 4,
|
||||||
|
CapabilityLinkage = 5,
|
||||||
|
CapabilityKernel = 6,
|
||||||
|
CapabilityVector16 = 7,
|
||||||
|
CapabilityFloat16Buffer = 8,
|
||||||
|
CapabilityFloat16 = 9,
|
||||||
|
CapabilityFloat64 = 10,
|
||||||
|
CapabilityInt64 = 11,
|
||||||
|
CapabilityInt64Atomics = 12,
|
||||||
|
CapabilityImageBasic = 13,
|
||||||
|
CapabilityImageReadWrite = 14,
|
||||||
|
CapabilityImageMipmap = 15,
|
||||||
|
CapabilityPipes = 17,
|
||||||
|
CapabilityGroups = 18,
|
||||||
|
CapabilityDeviceEnqueue = 19,
|
||||||
|
CapabilityLiteralSampler = 20,
|
||||||
|
CapabilityAtomicStorage = 21,
|
||||||
|
CapabilityInt16 = 22,
|
||||||
|
CapabilityTessellationPointSize = 23,
|
||||||
|
CapabilityGeometryPointSize = 24,
|
||||||
|
CapabilityImageGatherExtended = 25,
|
||||||
|
CapabilityStorageImageMultisample = 27,
|
||||||
|
CapabilityUniformBufferArrayDynamicIndexing = 28,
|
||||||
|
CapabilitySampledImageArrayDynamicIndexing = 29,
|
||||||
|
CapabilityStorageBufferArrayDynamicIndexing = 30,
|
||||||
|
CapabilityStorageImageArrayDynamicIndexing = 31,
|
||||||
|
CapabilityClipDistance = 32,
|
||||||
|
CapabilityCullDistance = 33,
|
||||||
|
CapabilityImageCubeArray = 34,
|
||||||
|
CapabilitySampleRateShading = 35,
|
||||||
|
CapabilityImageRect = 36,
|
||||||
|
CapabilitySampledRect = 37,
|
||||||
|
CapabilityGenericPointer = 38,
|
||||||
|
CapabilityInt8 = 39,
|
||||||
|
CapabilityInputAttachment = 40,
|
||||||
|
CapabilitySparseResidency = 41,
|
||||||
|
CapabilityMinLod = 42,
|
||||||
|
CapabilitySampled1D = 43,
|
||||||
|
CapabilityImage1D = 44,
|
||||||
|
CapabilitySampledCubeArray = 45,
|
||||||
|
CapabilitySampledBuffer = 46,
|
||||||
|
CapabilityImageBuffer = 47,
|
||||||
|
CapabilityImageMSArray = 48,
|
||||||
|
CapabilityStorageImageExtendedFormats = 49,
|
||||||
|
CapabilityImageQuery = 50,
|
||||||
|
CapabilityDerivativeControl = 51,
|
||||||
|
CapabilityInterpolationFunction = 52,
|
||||||
|
CapabilityTransformFeedback = 53,
|
||||||
|
CapabilityGeometryStreams = 54,
|
||||||
|
CapabilityStorageImageReadWithoutFormat = 55,
|
||||||
|
CapabilityStorageImageWriteWithoutFormat = 56,
|
||||||
|
CapabilityMultiViewport = 57,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Op {
|
||||||
|
OpNop = 0,
|
||||||
|
OpUndef = 1,
|
||||||
|
OpSourceContinued = 2,
|
||||||
|
OpSource = 3,
|
||||||
|
OpSourceExtension = 4,
|
||||||
|
OpName = 5,
|
||||||
|
OpMemberName = 6,
|
||||||
|
OpString = 7,
|
||||||
|
OpLine = 8,
|
||||||
|
OpExtension = 10,
|
||||||
|
OpExtInstImport = 11,
|
||||||
|
OpExtInst = 12,
|
||||||
|
OpMemoryModel = 14,
|
||||||
|
OpEntryPoint = 15,
|
||||||
|
OpExecutionMode = 16,
|
||||||
|
OpCapability = 17,
|
||||||
|
OpTypeVoid = 19,
|
||||||
|
OpTypeBool = 20,
|
||||||
|
OpTypeInt = 21,
|
||||||
|
OpTypeFloat = 22,
|
||||||
|
OpTypeVector = 23,
|
||||||
|
OpTypeMatrix = 24,
|
||||||
|
OpTypeImage = 25,
|
||||||
|
OpTypeSampler = 26,
|
||||||
|
OpTypeSampledImage = 27,
|
||||||
|
OpTypeArray = 28,
|
||||||
|
OpTypeRuntimeArray = 29,
|
||||||
|
OpTypeStruct = 30,
|
||||||
|
OpTypeOpaque = 31,
|
||||||
|
OpTypePointer = 32,
|
||||||
|
OpTypeFunction = 33,
|
||||||
|
OpTypeEvent = 34,
|
||||||
|
OpTypeDeviceEvent = 35,
|
||||||
|
OpTypeReserveId = 36,
|
||||||
|
OpTypeQueue = 37,
|
||||||
|
OpTypePipe = 38,
|
||||||
|
OpTypeForwardPointer = 39,
|
||||||
|
OpConstantTrue = 41,
|
||||||
|
OpConstantFalse = 42,
|
||||||
|
OpConstant = 43,
|
||||||
|
OpConstantComposite = 44,
|
||||||
|
OpConstantSampler = 45,
|
||||||
|
OpConstantNull = 46,
|
||||||
|
OpSpecConstantTrue = 48,
|
||||||
|
OpSpecConstantFalse = 49,
|
||||||
|
OpSpecConstant = 50,
|
||||||
|
OpSpecConstantComposite = 51,
|
||||||
|
OpSpecConstantOp = 52,
|
||||||
|
OpFunction = 54,
|
||||||
|
OpFunctionParameter = 55,
|
||||||
|
OpFunctionEnd = 56,
|
||||||
|
OpFunctionCall = 57,
|
||||||
|
OpVariable = 59,
|
||||||
|
OpImageTexelPointer = 60,
|
||||||
|
OpLoad = 61,
|
||||||
|
OpStore = 62,
|
||||||
|
OpCopyMemory = 63,
|
||||||
|
OpCopyMemorySized = 64,
|
||||||
|
OpAccessChain = 65,
|
||||||
|
OpInBoundsAccessChain = 66,
|
||||||
|
OpPtrAccessChain = 67,
|
||||||
|
OpArrayLength = 68,
|
||||||
|
OpGenericPtrMemSemantics = 69,
|
||||||
|
OpInBoundsPtrAccessChain = 70,
|
||||||
|
OpDecorate = 71,
|
||||||
|
OpMemberDecorate = 72,
|
||||||
|
OpDecorationGroup = 73,
|
||||||
|
OpGroupDecorate = 74,
|
||||||
|
OpGroupMemberDecorate = 75,
|
||||||
|
OpVectorExtractDynamic = 77,
|
||||||
|
OpVectorInsertDynamic = 78,
|
||||||
|
OpVectorShuffle = 79,
|
||||||
|
OpCompositeConstruct = 80,
|
||||||
|
OpCompositeExtract = 81,
|
||||||
|
OpCompositeInsert = 82,
|
||||||
|
OpCopyObject = 83,
|
||||||
|
OpTranspose = 84,
|
||||||
|
OpSampledImage = 86,
|
||||||
|
OpImageSampleImplicitLod = 87,
|
||||||
|
OpImageSampleExplicitLod = 88,
|
||||||
|
OpImageSampleDrefImplicitLod = 89,
|
||||||
|
OpImageSampleDrefExplicitLod = 90,
|
||||||
|
OpImageSampleProjImplicitLod = 91,
|
||||||
|
OpImageSampleProjExplicitLod = 92,
|
||||||
|
OpImageSampleProjDrefImplicitLod = 93,
|
||||||
|
OpImageSampleProjDrefExplicitLod = 94,
|
||||||
|
OpImageFetch = 95,
|
||||||
|
OpImageGather = 96,
|
||||||
|
OpImageDrefGather = 97,
|
||||||
|
OpImageRead = 98,
|
||||||
|
OpImageWrite = 99,
|
||||||
|
OpImage = 100,
|
||||||
|
OpImageQueryFormat = 101,
|
||||||
|
OpImageQueryOrder = 102,
|
||||||
|
OpImageQuerySizeLod = 103,
|
||||||
|
OpImageQuerySize = 104,
|
||||||
|
OpImageQueryLod = 105,
|
||||||
|
OpImageQueryLevels = 106,
|
||||||
|
OpImageQuerySamples = 107,
|
||||||
|
OpConvertFToU = 109,
|
||||||
|
OpConvertFToS = 110,
|
||||||
|
OpConvertSToF = 111,
|
||||||
|
OpConvertUToF = 112,
|
||||||
|
OpUConvert = 113,
|
||||||
|
OpSConvert = 114,
|
||||||
|
OpFConvert = 115,
|
||||||
|
OpQuantizeToF16 = 116,
|
||||||
|
OpConvertPtrToU = 117,
|
||||||
|
OpSatConvertSToU = 118,
|
||||||
|
OpSatConvertUToS = 119,
|
||||||
|
OpConvertUToPtr = 120,
|
||||||
|
OpPtrCastToGeneric = 121,
|
||||||
|
OpGenericCastToPtr = 122,
|
||||||
|
OpGenericCastToPtrExplicit = 123,
|
||||||
|
OpBitcast = 124,
|
||||||
|
OpSNegate = 126,
|
||||||
|
OpFNegate = 127,
|
||||||
|
OpIAdd = 128,
|
||||||
|
OpFAdd = 129,
|
||||||
|
OpISub = 130,
|
||||||
|
OpFSub = 131,
|
||||||
|
OpIMul = 132,
|
||||||
|
OpFMul = 133,
|
||||||
|
OpUDiv = 134,
|
||||||
|
OpSDiv = 135,
|
||||||
|
OpFDiv = 136,
|
||||||
|
OpUMod = 137,
|
||||||
|
OpSRem = 138,
|
||||||
|
OpSMod = 139,
|
||||||
|
OpFRem = 140,
|
||||||
|
OpFMod = 141,
|
||||||
|
OpVectorTimesScalar = 142,
|
||||||
|
OpMatrixTimesScalar = 143,
|
||||||
|
OpVectorTimesMatrix = 144,
|
||||||
|
OpMatrixTimesVector = 145,
|
||||||
|
OpMatrixTimesMatrix = 146,
|
||||||
|
OpOuterProduct = 147,
|
||||||
|
OpDot = 148,
|
||||||
|
OpIAddCarry = 149,
|
||||||
|
OpISubBorrow = 150,
|
||||||
|
OpUMulExtended = 151,
|
||||||
|
OpSMulExtended = 152,
|
||||||
|
OpAny = 154,
|
||||||
|
OpAll = 155,
|
||||||
|
OpIsNan = 156,
|
||||||
|
OpIsInf = 157,
|
||||||
|
OpIsFinite = 158,
|
||||||
|
OpIsNormal = 159,
|
||||||
|
OpSignBitSet = 160,
|
||||||
|
OpLessOrGreater = 161,
|
||||||
|
OpOrdered = 162,
|
||||||
|
OpUnordered = 163,
|
||||||
|
OpLogicalEqual = 164,
|
||||||
|
OpLogicalNotEqual = 165,
|
||||||
|
OpLogicalOr = 166,
|
||||||
|
OpLogicalAnd = 167,
|
||||||
|
OpLogicalNot = 168,
|
||||||
|
OpSelect = 169,
|
||||||
|
OpIEqual = 170,
|
||||||
|
OpINotEqual = 171,
|
||||||
|
OpUGreaterThan = 172,
|
||||||
|
OpSGreaterThan = 173,
|
||||||
|
OpUGreaterThanEqual = 174,
|
||||||
|
OpSGreaterThanEqual = 175,
|
||||||
|
OpULessThan = 176,
|
||||||
|
OpSLessThan = 177,
|
||||||
|
OpULessThanEqual = 178,
|
||||||
|
OpSLessThanEqual = 179,
|
||||||
|
OpFOrdEqual = 180,
|
||||||
|
OpFUnordEqual = 181,
|
||||||
|
OpFOrdNotEqual = 182,
|
||||||
|
OpFUnordNotEqual = 183,
|
||||||
|
OpFOrdLessThan = 184,
|
||||||
|
OpFUnordLessThan = 185,
|
||||||
|
OpFOrdGreaterThan = 186,
|
||||||
|
OpFUnordGreaterThan = 187,
|
||||||
|
OpFOrdLessThanEqual = 188,
|
||||||
|
OpFUnordLessThanEqual = 189,
|
||||||
|
OpFOrdGreaterThanEqual = 190,
|
||||||
|
OpFUnordGreaterThanEqual = 191,
|
||||||
|
OpShiftRightLogical = 194,
|
||||||
|
OpShiftRightArithmetic = 195,
|
||||||
|
OpShiftLeftLogical = 196,
|
||||||
|
OpBitwiseOr = 197,
|
||||||
|
OpBitwiseXor = 198,
|
||||||
|
OpBitwiseAnd = 199,
|
||||||
|
OpNot = 200,
|
||||||
|
OpBitFieldInsert = 201,
|
||||||
|
OpBitFieldSExtract = 202,
|
||||||
|
OpBitFieldUExtract = 203,
|
||||||
|
OpBitReverse = 204,
|
||||||
|
OpBitCount = 205,
|
||||||
|
OpDPdx = 207,
|
||||||
|
OpDPdy = 208,
|
||||||
|
OpFwidth = 209,
|
||||||
|
OpDPdxFine = 210,
|
||||||
|
OpDPdyFine = 211,
|
||||||
|
OpFwidthFine = 212,
|
||||||
|
OpDPdxCoarse = 213,
|
||||||
|
OpDPdyCoarse = 214,
|
||||||
|
OpFwidthCoarse = 215,
|
||||||
|
OpEmitVertex = 218,
|
||||||
|
OpEndPrimitive = 219,
|
||||||
|
OpEmitStreamVertex = 220,
|
||||||
|
OpEndStreamPrimitive = 221,
|
||||||
|
OpControlBarrier = 224,
|
||||||
|
OpMemoryBarrier = 225,
|
||||||
|
OpAtomicLoad = 227,
|
||||||
|
OpAtomicStore = 228,
|
||||||
|
OpAtomicExchange = 229,
|
||||||
|
OpAtomicCompareExchange = 230,
|
||||||
|
OpAtomicCompareExchangeWeak = 231,
|
||||||
|
OpAtomicIIncrement = 232,
|
||||||
|
OpAtomicIDecrement = 233,
|
||||||
|
OpAtomicIAdd = 234,
|
||||||
|
OpAtomicISub = 235,
|
||||||
|
OpAtomicSMin = 236,
|
||||||
|
OpAtomicUMin = 237,
|
||||||
|
OpAtomicSMax = 238,
|
||||||
|
OpAtomicUMax = 239,
|
||||||
|
OpAtomicAnd = 240,
|
||||||
|
OpAtomicOr = 241,
|
||||||
|
OpAtomicXor = 242,
|
||||||
|
OpPhi = 245,
|
||||||
|
OpLoopMerge = 246,
|
||||||
|
OpSelectionMerge = 247,
|
||||||
|
OpLabel = 248,
|
||||||
|
OpBranch = 249,
|
||||||
|
OpBranchConditional = 250,
|
||||||
|
OpSwitch = 251,
|
||||||
|
OpKill = 252,
|
||||||
|
OpReturn = 253,
|
||||||
|
OpReturnValue = 254,
|
||||||
|
OpUnreachable = 255,
|
||||||
|
OpLifetimeStart = 256,
|
||||||
|
OpLifetimeStop = 257,
|
||||||
|
OpGroupAsyncCopy = 259,
|
||||||
|
OpGroupWaitEvents = 260,
|
||||||
|
OpGroupAll = 261,
|
||||||
|
OpGroupAny = 262,
|
||||||
|
OpGroupBroadcast = 263,
|
||||||
|
OpGroupIAdd = 264,
|
||||||
|
OpGroupFAdd = 265,
|
||||||
|
OpGroupFMin = 266,
|
||||||
|
OpGroupUMin = 267,
|
||||||
|
OpGroupSMin = 268,
|
||||||
|
OpGroupFMax = 269,
|
||||||
|
OpGroupUMax = 270,
|
||||||
|
OpGroupSMax = 271,
|
||||||
|
OpReadPipe = 274,
|
||||||
|
OpWritePipe = 275,
|
||||||
|
OpReservedReadPipe = 276,
|
||||||
|
OpReservedWritePipe = 277,
|
||||||
|
OpReserveReadPipePackets = 278,
|
||||||
|
OpReserveWritePipePackets = 279,
|
||||||
|
OpCommitReadPipe = 280,
|
||||||
|
OpCommitWritePipe = 281,
|
||||||
|
OpIsValidReserveId = 282,
|
||||||
|
OpGetNumPipePackets = 283,
|
||||||
|
OpGetMaxPipePackets = 284,
|
||||||
|
OpGroupReserveReadPipePackets = 285,
|
||||||
|
OpGroupReserveWritePipePackets = 286,
|
||||||
|
OpGroupCommitReadPipe = 287,
|
||||||
|
OpGroupCommitWritePipe = 288,
|
||||||
|
OpEnqueueMarker = 291,
|
||||||
|
OpEnqueueKernel = 292,
|
||||||
|
OpGetKernelNDrangeSubGroupCount = 293,
|
||||||
|
OpGetKernelNDrangeMaxSubGroupSize = 294,
|
||||||
|
OpGetKernelWorkGroupSize = 295,
|
||||||
|
OpGetKernelPreferredWorkGroupSizeMultiple = 296,
|
||||||
|
OpRetainEvent = 297,
|
||||||
|
OpReleaseEvent = 298,
|
||||||
|
OpCreateUserEvent = 299,
|
||||||
|
OpIsValidEvent = 300,
|
||||||
|
OpSetUserEventStatus = 301,
|
||||||
|
OpCaptureEventProfilingInfo = 302,
|
||||||
|
OpGetDefaultQueue = 303,
|
||||||
|
OpBuildNDRange = 304,
|
||||||
|
OpImageSparseSampleImplicitLod = 305,
|
||||||
|
OpImageSparseSampleExplicitLod = 306,
|
||||||
|
OpImageSparseSampleDrefImplicitLod = 307,
|
||||||
|
OpImageSparseSampleDrefExplicitLod = 308,
|
||||||
|
OpImageSparseSampleProjImplicitLod = 309,
|
||||||
|
OpImageSparseSampleProjExplicitLod = 310,
|
||||||
|
OpImageSparseSampleProjDrefImplicitLod = 311,
|
||||||
|
OpImageSparseSampleProjDrefExplicitLod = 312,
|
||||||
|
OpImageSparseFetch = 313,
|
||||||
|
OpImageSparseGather = 314,
|
||||||
|
OpImageSparseDrefGather = 315,
|
||||||
|
OpImageSparseTexelsResident = 316,
|
||||||
|
OpNoLine = 317,
|
||||||
|
OpAtomicFlagTestAndSet = 318,
|
||||||
|
OpAtomicFlagClear = 319,
|
||||||
|
OpImageSparseRead = 320,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Overload operator| for mask bit combining
|
||||||
|
|
||||||
|
inline ImageOperandsMask operator|(ImageOperandsMask a, ImageOperandsMask b) { return ImageOperandsMask(unsigned(a) | unsigned(b)); }
|
||||||
|
inline FPFastMathModeMask operator|(FPFastMathModeMask a, FPFastMathModeMask b) { return FPFastMathModeMask(unsigned(a) | unsigned(b)); }
|
||||||
|
inline SelectionControlMask operator|(SelectionControlMask a, SelectionControlMask b) { return SelectionControlMask(unsigned(a) | unsigned(b)); }
|
||||||
|
inline LoopControlMask operator|(LoopControlMask a, LoopControlMask b) { return LoopControlMask(unsigned(a) | unsigned(b)); }
|
||||||
|
inline FunctionControlMask operator|(FunctionControlMask a, FunctionControlMask b) { return FunctionControlMask(unsigned(a) | unsigned(b)); }
|
||||||
|
inline MemorySemanticsMask operator|(MemorySemanticsMask a, MemorySemanticsMask b) { return MemorySemanticsMask(unsigned(a) | unsigned(b)); }
|
||||||
|
inline MemoryAccessMask operator|(MemoryAccessMask a, MemoryAccessMask b) { return MemoryAccessMask(unsigned(a) | unsigned(b)); }
|
||||||
|
inline KernelProfilingInfoMask operator|(KernelProfilingInfoMask a, KernelProfilingInfoMask b) { return KernelProfilingInfoMask(unsigned(a) | unsigned(b)); }
|
||||||
|
|
||||||
|
} // end namespace spv
|
||||||
|
|
||||||
|
#endif // #ifndef spirv_HPP
|
|
@ -0,0 +1,403 @@
|
||||||
|
//
|
||||||
|
//Copyright (C) 2014 LunarG, Inc.
|
||||||
|
//
|
||||||
|
//All rights reserved.
|
||||||
|
//
|
||||||
|
//Redistribution and use in source and binary forms, with or without
|
||||||
|
//modification, are permitted provided that the following conditions
|
||||||
|
//are met:
|
||||||
|
//
|
||||||
|
// Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following
|
||||||
|
// disclaimer in the documentation and/or other materials provided
|
||||||
|
// with the distribution.
|
||||||
|
//
|
||||||
|
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived
|
||||||
|
// from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
//POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
//
|
||||||
|
// Author: John Kessenich, LunarG
|
||||||
|
//
|
||||||
|
|
||||||
|
// SPIRV-IR
|
||||||
|
//
|
||||||
|
// Simple in-memory representation (IR) of SPIRV. Just for holding
|
||||||
|
// Each function's CFG of blocks. Has this hierarchy:
|
||||||
|
// - Module, which is a list of
|
||||||
|
// - Function, which is a list of
|
||||||
|
// - Block, which is a list of
|
||||||
|
// - Instruction
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef spvIR_H
|
||||||
|
#define spvIR_H
|
||||||
|
|
||||||
|
#include "spirv.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace spv {
|
||||||
|
|
||||||
|
class Block;
|
||||||
|
class Function;
|
||||||
|
class Module;
|
||||||
|
|
||||||
|
const Id NoResult = 0;
|
||||||
|
const Id NoType = 0;
|
||||||
|
|
||||||
|
const unsigned int BadValue = 0xFFFFFFFF;
|
||||||
|
const Decoration NoPrecision = (Decoration)BadValue;
|
||||||
|
const MemorySemanticsMask MemorySemanticsAllMemory =
|
||||||
|
(MemorySemanticsMask)(MemorySemanticsAcquireMask |
|
||||||
|
MemorySemanticsReleaseMask |
|
||||||
|
MemorySemanticsAcquireReleaseMask |
|
||||||
|
MemorySemanticsSequentiallyConsistentMask |
|
||||||
|
MemorySemanticsUniformMemoryMask |
|
||||||
|
MemorySemanticsSubgroupMemoryMask |
|
||||||
|
MemorySemanticsWorkgroupMemoryMask |
|
||||||
|
MemorySemanticsCrossWorkgroupMemoryMask |
|
||||||
|
MemorySemanticsAtomicCounterMemoryMask |
|
||||||
|
MemorySemanticsImageMemoryMask);
|
||||||
|
|
||||||
|
//
|
||||||
|
// SPIR-V IR instruction.
|
||||||
|
//
|
||||||
|
|
||||||
|
class Instruction {
|
||||||
|
public:
|
||||||
|
Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode), block(nullptr) { }
|
||||||
|
explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), block(nullptr) { }
|
||||||
|
virtual ~Instruction() {}
|
||||||
|
void addIdOperand(Id id) { operands.push_back(id); }
|
||||||
|
void addImmediateOperand(unsigned int immediate) { operands.push_back(immediate); }
|
||||||
|
void addStringOperand(const char* str)
|
||||||
|
{
|
||||||
|
originalString = str;
|
||||||
|
unsigned int word;
|
||||||
|
char* wordString = (char*)&word;
|
||||||
|
char* wordPtr = wordString;
|
||||||
|
int charCount = 0;
|
||||||
|
char c;
|
||||||
|
do {
|
||||||
|
c = *(str++);
|
||||||
|
*(wordPtr++) = c;
|
||||||
|
++charCount;
|
||||||
|
if (charCount == 4) {
|
||||||
|
addImmediateOperand(word);
|
||||||
|
wordPtr = wordString;
|
||||||
|
charCount = 0;
|
||||||
|
}
|
||||||
|
} while (c != 0);
|
||||||
|
|
||||||
|
// deal with partial last word
|
||||||
|
if (charCount > 0) {
|
||||||
|
// pad with 0s
|
||||||
|
for (; charCount < 4; ++charCount)
|
||||||
|
*(wordPtr++) = 0;
|
||||||
|
addImmediateOperand(word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void setBlock(Block* b) { block = b; }
|
||||||
|
Block* getBlock() const { return block; }
|
||||||
|
Op getOpCode() const { return opCode; }
|
||||||
|
int getNumOperands() const { return (int)operands.size(); }
|
||||||
|
Id getResultId() const { return resultId; }
|
||||||
|
Id getTypeId() const { return typeId; }
|
||||||
|
Id getIdOperand(int op) const { return operands[op]; }
|
||||||
|
unsigned int getImmediateOperand(int op) const { return operands[op]; }
|
||||||
|
const char* getStringOperand() const { return originalString.c_str(); }
|
||||||
|
|
||||||
|
// Write out the binary form.
|
||||||
|
void dump(std::vector<unsigned int>& out) const
|
||||||
|
{
|
||||||
|
// Compute the wordCount
|
||||||
|
unsigned int wordCount = 1;
|
||||||
|
if (typeId)
|
||||||
|
++wordCount;
|
||||||
|
if (resultId)
|
||||||
|
++wordCount;
|
||||||
|
wordCount += (unsigned int)operands.size();
|
||||||
|
|
||||||
|
// Write out the beginning of the instruction
|
||||||
|
out.push_back(((wordCount) << WordCountShift) | opCode);
|
||||||
|
if (typeId)
|
||||||
|
out.push_back(typeId);
|
||||||
|
if (resultId)
|
||||||
|
out.push_back(resultId);
|
||||||
|
|
||||||
|
// Write out the operands
|
||||||
|
for (int op = 0; op < (int)operands.size(); ++op)
|
||||||
|
out.push_back(operands[op]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Instruction(const Instruction&);
|
||||||
|
Id resultId;
|
||||||
|
Id typeId;
|
||||||
|
Op opCode;
|
||||||
|
std::vector<Id> operands;
|
||||||
|
std::string originalString; // could be optimized away; convenience for getting string operand
|
||||||
|
Block* block;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// SPIR-V IR block.
|
||||||
|
//
|
||||||
|
|
||||||
|
class Block {
|
||||||
|
public:
|
||||||
|
Block(Id id, Function& parent);
|
||||||
|
virtual ~Block()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Id getId() { return instructions.front()->getResultId(); }
|
||||||
|
|
||||||
|
Function& getParent() const { return parent; }
|
||||||
|
void addInstruction(std::unique_ptr<Instruction> inst);
|
||||||
|
void addPredecessor(Block* pred) { predecessors.push_back(pred); pred->successors.push_back(this);}
|
||||||
|
void addLocalVariable(std::unique_ptr<Instruction> inst) { localVariables.push_back(std::move(inst)); }
|
||||||
|
const std::vector<Block*>& getPredecessors() const { return predecessors; }
|
||||||
|
const std::vector<Block*>& getSuccessors() const { return successors; }
|
||||||
|
void setUnreachable() { unreachable = true; }
|
||||||
|
bool isUnreachable() const { return unreachable; }
|
||||||
|
// Returns the block's merge instruction, if one exists (otherwise null).
|
||||||
|
const Instruction* getMergeInstruction() const {
|
||||||
|
if (instructions.size() < 2) return nullptr;
|
||||||
|
const Instruction* nextToLast = (instructions.cend() - 2)->get();
|
||||||
|
switch (nextToLast->getOpCode()) {
|
||||||
|
case OpSelectionMerge:
|
||||||
|
case OpLoopMerge:
|
||||||
|
return nextToLast;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isTerminated() const
|
||||||
|
{
|
||||||
|
switch (instructions.back()->getOpCode()) {
|
||||||
|
case OpBranch:
|
||||||
|
case OpBranchConditional:
|
||||||
|
case OpSwitch:
|
||||||
|
case OpKill:
|
||||||
|
case OpReturn:
|
||||||
|
case OpReturnValue:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump(std::vector<unsigned int>& out) const
|
||||||
|
{
|
||||||
|
instructions[0]->dump(out);
|
||||||
|
for (int i = 0; i < (int)localVariables.size(); ++i)
|
||||||
|
localVariables[i]->dump(out);
|
||||||
|
for (int i = 1; i < (int)instructions.size(); ++i)
|
||||||
|
instructions[i]->dump(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Block(const Block&);
|
||||||
|
Block& operator=(Block&);
|
||||||
|
|
||||||
|
// To enforce keeping parent and ownership in sync:
|
||||||
|
friend Function;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<Instruction> > instructions;
|
||||||
|
std::vector<Block*> predecessors, successors;
|
||||||
|
std::vector<std::unique_ptr<Instruction> > localVariables;
|
||||||
|
Function& parent;
|
||||||
|
|
||||||
|
// track whether this block is known to be uncreachable (not necessarily
|
||||||
|
// true for all unreachable blocks, but should be set at least
|
||||||
|
// for the extraneous ones introduced by the builder).
|
||||||
|
bool unreachable;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Traverses the control-flow graph rooted at root in an order suited for
|
||||||
|
// readable code generation. Invokes callback at every node in the traversal
|
||||||
|
// order.
|
||||||
|
void inReadableOrder(Block* root, std::function<void(Block*)> callback);
|
||||||
|
|
||||||
|
//
|
||||||
|
// SPIR-V IR Function.
|
||||||
|
//
|
||||||
|
|
||||||
|
class Function {
|
||||||
|
public:
|
||||||
|
Function(Id id, Id resultType, Id functionType, Id firstParam, Module& parent);
|
||||||
|
virtual ~Function()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (int)parameterInstructions.size(); ++i)
|
||||||
|
delete parameterInstructions[i];
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)blocks.size(); ++i)
|
||||||
|
delete blocks[i];
|
||||||
|
}
|
||||||
|
Id getId() const { return functionInstruction.getResultId(); }
|
||||||
|
Id getParamId(int p) { return parameterInstructions[p]->getResultId(); }
|
||||||
|
|
||||||
|
void addBlock(Block* block) { blocks.push_back(block); }
|
||||||
|
void removeBlock(Block* block)
|
||||||
|
{
|
||||||
|
auto found = find(blocks.begin(), blocks.end(), block);
|
||||||
|
assert(found != blocks.end());
|
||||||
|
blocks.erase(found);
|
||||||
|
delete block;
|
||||||
|
}
|
||||||
|
|
||||||
|
Module& getParent() const { return parent; }
|
||||||
|
Block* getEntryBlock() const { return blocks.front(); }
|
||||||
|
Block* getLastBlock() const { return blocks.back(); }
|
||||||
|
void addLocalVariable(std::unique_ptr<Instruction> inst);
|
||||||
|
Id getReturnType() const { return functionInstruction.getTypeId(); }
|
||||||
|
void dump(std::vector<unsigned int>& out) const
|
||||||
|
{
|
||||||
|
// OpFunction
|
||||||
|
functionInstruction.dump(out);
|
||||||
|
|
||||||
|
// OpFunctionParameter
|
||||||
|
for (int p = 0; p < (int)parameterInstructions.size(); ++p)
|
||||||
|
parameterInstructions[p]->dump(out);
|
||||||
|
|
||||||
|
// Blocks
|
||||||
|
inReadableOrder(blocks[0], [&out](const Block* b) { b->dump(out); });
|
||||||
|
Instruction end(0, 0, OpFunctionEnd);
|
||||||
|
end.dump(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Function(const Function&);
|
||||||
|
Function& operator=(Function&);
|
||||||
|
|
||||||
|
Module& parent;
|
||||||
|
Instruction functionInstruction;
|
||||||
|
std::vector<Instruction*> parameterInstructions;
|
||||||
|
std::vector<Block*> blocks;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// SPIR-V IR Module.
|
||||||
|
//
|
||||||
|
|
||||||
|
class Module {
|
||||||
|
public:
|
||||||
|
Module() {}
|
||||||
|
virtual ~Module()
|
||||||
|
{
|
||||||
|
// TODO delete things
|
||||||
|
}
|
||||||
|
|
||||||
|
void addFunction(Function *fun) { functions.push_back(fun); }
|
||||||
|
|
||||||
|
void mapInstruction(Instruction *instruction)
|
||||||
|
{
|
||||||
|
spv::Id resultId = instruction->getResultId();
|
||||||
|
// map the instruction's result id
|
||||||
|
if (resultId >= idToInstruction.size())
|
||||||
|
idToInstruction.resize(resultId + 16);
|
||||||
|
idToInstruction[resultId] = instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction* getInstruction(Id id) const { return idToInstruction[id]; }
|
||||||
|
spv::Id getTypeId(Id resultId) const { return idToInstruction[resultId]->getTypeId(); }
|
||||||
|
StorageClass getStorageClass(Id typeId) const
|
||||||
|
{
|
||||||
|
assert(idToInstruction[typeId]->getOpCode() == spv::OpTypePointer);
|
||||||
|
return (StorageClass)idToInstruction[typeId]->getImmediateOperand(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump(std::vector<unsigned int>& out) const
|
||||||
|
{
|
||||||
|
for (int f = 0; f < (int)functions.size(); ++f)
|
||||||
|
functions[f]->dump(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Module(const Module&);
|
||||||
|
std::vector<Function*> functions;
|
||||||
|
|
||||||
|
// map from result id to instruction having that result id
|
||||||
|
std::vector<Instruction*> idToInstruction;
|
||||||
|
|
||||||
|
// map from a result id to its type id
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Implementation (it's here due to circular type definitions).
|
||||||
|
//
|
||||||
|
|
||||||
|
// Add both
|
||||||
|
// - the OpFunction instruction
|
||||||
|
// - all the OpFunctionParameter instructions
|
||||||
|
__inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent)
|
||||||
|
: parent(parent), functionInstruction(id, resultType, OpFunction)
|
||||||
|
{
|
||||||
|
// OpFunction
|
||||||
|
functionInstruction.addImmediateOperand(FunctionControlMaskNone);
|
||||||
|
functionInstruction.addIdOperand(functionType);
|
||||||
|
parent.mapInstruction(&functionInstruction);
|
||||||
|
parent.addFunction(this);
|
||||||
|
|
||||||
|
// OpFunctionParameter
|
||||||
|
Instruction* typeInst = parent.getInstruction(functionType);
|
||||||
|
int numParams = typeInst->getNumOperands() - 1;
|
||||||
|
for (int p = 0; p < numParams; ++p) {
|
||||||
|
Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), OpFunctionParameter);
|
||||||
|
parent.mapInstruction(param);
|
||||||
|
parameterInstructions.push_back(param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__inline void Function::addLocalVariable(std::unique_ptr<Instruction> inst)
|
||||||
|
{
|
||||||
|
Instruction* raw_instruction = inst.get();
|
||||||
|
blocks[0]->addLocalVariable(std::move(inst));
|
||||||
|
parent.mapInstruction(raw_instruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
__inline Block::Block(Id id, Function& parent) : parent(parent), unreachable(false)
|
||||||
|
{
|
||||||
|
instructions.push_back(std::unique_ptr<Instruction>(new Instruction(id, NoType, OpLabel)));
|
||||||
|
instructions.back()->setBlock(this);
|
||||||
|
parent.getParent().mapInstruction(instructions.back().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
__inline void Block::addInstruction(std::unique_ptr<Instruction> inst)
|
||||||
|
{
|
||||||
|
Instruction* raw_instruction = inst.get();
|
||||||
|
instructions.push_back(std::move(inst));
|
||||||
|
raw_instruction->setBlock(this);
|
||||||
|
if (raw_instruction->getResultId())
|
||||||
|
parent.getParent().mapInstruction(raw_instruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // end spv namespace
|
||||||
|
|
||||||
|
#endif // spvIR_H
|
Loading…
Reference in New Issue