Final round for line endings.

This commit is contained in:
John Kessenich 2015-06-26 16:58:36 -06:00
parent b63263267d
commit 140f3df134
19 changed files with 11965 additions and 11965 deletions

View File

@ -1,6 +1,6 @@
This directory contains a Linux binary for the glslang validator. This directory contains a Linux binary for the glslang validator.
Installation: The executable in this directory is self sufficient, and can be Installation: The executable in this directory is self sufficient, and can be
placed where desired; in a test directory, or in a system path, etc. placed where desired; in a test directory, or in a system path, etc.
Usage: Execute glslangValidator with no arguments to get a usage statement. Usage: Execute glslangValidator with no arguments to get a usage statement.

View File

@ -1,6 +1,6 @@
This directory contains a Windows binary for the glslang validator. This directory contains a Windows binary for the glslang validator.
Installation: The executable in this directory is self sufficient, and can be Installation: The executable in this directory is self sufficient, and can be
placed where desired; in a test directory, or in a system path, etc. placed where desired; in a test directory, or in a system path, etc.
Usage: Execute glslangValidator with no arguments to get a usage statement. Usage: Execute glslangValidator with no arguments to get a usage statement.

View File

@ -1,21 +1,21 @@
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)
include_directories(. ../glslang) include_directories(. ../glslang)
if(WIN32) if(WIN32)
include_directories(${include_directories} ../glslang/OSDependent/Windows) include_directories(${include_directories} ../glslang/OSDependent/Windows)
elseif(UNIX) elseif(UNIX)
include_directories(${include_directories} ../glslang/OSDependent/Linux) include_directories(${include_directories} ../glslang/OSDependent/Linux)
else(WIN32) else(WIN32)
message("unknown platform") message("unknown platform")
endif(WIN32) endif(WIN32)
set(SOURCES InitializeDll.cpp InitializeDll.h) set(SOURCES InitializeDll.cpp InitializeDll.h)
add_library(OGLCompiler STATIC ${SOURCES}) add_library(OGLCompiler STATIC ${SOURCES})
if(WIN32) if(WIN32)
source_group("Source" FILES ${SOURCES}) source_group("Source" FILES ${SOURCES})
endif(WIN32) endif(WIN32)
install(TARGETS OGLCompiler install(TARGETS OGLCompiler
ARCHIVE DESTINATION lib) ARCHIVE DESTINATION lib)

View File

@ -1,28 +1,28 @@
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)
include_directories(.. ${CMAKE_CURRENT_BINARY_DIR}) include_directories(.. ${CMAKE_CURRENT_BINARY_DIR})
set(SOURCES set(SOURCES
GlslangToSpv.cpp GlslangToSpv.cpp
SpvBuilder.cpp SpvBuilder.cpp
SPVRemapper.cpp SPVRemapper.cpp
doc.cpp doc.cpp
disassemble.cpp) disassemble.cpp)
set(HEADERS set(HEADERS
spirv.h spirv.h
GlslangToSpv.h GlslangToSpv.h
SpvBuilder.h SpvBuilder.h
SPVRemapper.h SPVRemapper.h
spvIR.h spvIR.h
doc.h doc.h
disassemble.h) disassemble.h)
add_library(SPIRV STATIC ${SOURCES} ${HEADERS}) add_library(SPIRV STATIC ${SOURCES} ${HEADERS})
if(WIN32) if(WIN32)
source_group("Source" FILES ${SOURCES} ${HEADERS}) source_group("Source" FILES ${SOURCES} ${HEADERS})
endif(WIN32) endif(WIN32)
install(TARGETS SPIRV install(TARGETS SPIRV
ARCHIVE DESTINATION lib) ARCHIVE DESTINATION lib)

View File

@ -1,210 +1,210 @@
/* /*
** Copyright (c) 2014-2015 The Khronos Group Inc. ** Copyright (c) 2014-2015 The Khronos Group Inc.
** **
** Permission is hereby granted, free of charge, to any person obtaining a ** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the ** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including ** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish, ** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to ** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to ** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions: ** the following conditions:
** **
** The above copyright notice and this permission notice shall be included ** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials. ** in all copies or substantial portions of the Materials.
** **
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/ */
// //
// Author: John Kessenich, LunarG // Author: John Kessenich, LunarG
// //
namespace GLSL_STD_450 { namespace GLSL_STD_450 {
enum Entrypoints { enum Entrypoints {
Round = 0, Round = 0,
RoundEven = 1, RoundEven = 1,
Trunc = 2, Trunc = 2,
Abs = 3, Abs = 3,
Sign = 4, Sign = 4,
Floor = 5, Floor = 5,
Ceil = 6, Ceil = 6,
Fract = 7, Fract = 7,
Radians = 8, Radians = 8,
Degrees = 9, Degrees = 9,
Sin = 10, Sin = 10,
Cos = 11, Cos = 11,
Tan = 12, Tan = 12,
Asin = 13, Asin = 13,
Acos = 14, Acos = 14,
Atan = 15, Atan = 15,
Sinh = 16, Sinh = 16,
Cosh = 17, Cosh = 17,
Tanh = 18, Tanh = 18,
Asinh = 19, Asinh = 19,
Acosh = 20, Acosh = 20,
Atanh = 21, Atanh = 21,
Atan2 = 22, Atan2 = 22,
Pow = 23, Pow = 23,
Exp = 24, Exp = 24,
Log = 25, Log = 25,
Exp2 = 26, Exp2 = 26,
Log2 = 27, Log2 = 27,
Sqrt = 28, Sqrt = 28,
InverseSqrt = 29, InverseSqrt = 29,
Determinant = 30, Determinant = 30,
MatrixInverse = 31, MatrixInverse = 31,
Modf = 32, // second argument needs the OpVariable = , not an OpLoad Modf = 32, // second argument needs the OpVariable = , not an OpLoad
Min = 33, Min = 33,
Max = 34, Max = 34,
Clamp = 35, Clamp = 35,
Mix = 36, Mix = 36,
Step = 37, Step = 37,
SmoothStep = 38, SmoothStep = 38,
FloatBitsToInt = 39, FloatBitsToInt = 39,
FloatBitsToUint = 40, FloatBitsToUint = 40,
IntBitsToFloat = 41, IntBitsToFloat = 41,
UintBitsToFloat = 42, UintBitsToFloat = 42,
Fma = 43, Fma = 43,
Frexp = 44, Frexp = 44,
Ldexp = 45, Ldexp = 45,
PackSnorm4x8 = 46, PackSnorm4x8 = 46,
PackUnorm4x8 = 47, PackUnorm4x8 = 47,
PackSnorm2x16 = 48, PackSnorm2x16 = 48,
PackUnorm2x16 = 49, PackUnorm2x16 = 49,
PackHalf2x16 = 50, PackHalf2x16 = 50,
PackDouble2x32 = 51, PackDouble2x32 = 51,
UnpackSnorm2x16 = 52, UnpackSnorm2x16 = 52,
UnpackUnorm2x16 = 53, UnpackUnorm2x16 = 53,
UnpackHalf2x16 = 54, UnpackHalf2x16 = 54,
UnpackSnorm4x8 = 55, UnpackSnorm4x8 = 55,
UnpackUnorm4x8 = 56, UnpackUnorm4x8 = 56,
UnpackDouble2x32 = 57, UnpackDouble2x32 = 57,
Length = 58, Length = 58,
Distance = 59, Distance = 59,
Cross = 60, Cross = 60,
Normalize = 61, Normalize = 61,
Ftransform = 62, Ftransform = 62,
FaceForward = 63, FaceForward = 63,
Reflect = 64, Reflect = 64,
Refract = 65, Refract = 65,
UaddCarry = 66, UaddCarry = 66,
UsubBorrow = 67, UsubBorrow = 67,
UmulExtended = 68, UmulExtended = 68,
ImulExtended = 69, ImulExtended = 69,
BitfieldExtract = 70, BitfieldExtract = 70,
BitfieldInsert = 71, BitfieldInsert = 71,
BitfieldReverse = 72, BitfieldReverse = 72,
BitCount = 73, BitCount = 73,
FindLSB = 74, FindLSB = 74,
FindMSB = 75, FindMSB = 75,
InterpolateAtCentroid = 76, InterpolateAtCentroid = 76,
InterpolateAtSample = 77, InterpolateAtSample = 77,
InterpolateAtOffset = 78, InterpolateAtOffset = 78,
Count Count
}; };
inline void GetDebugNames(const char** names) inline void GetDebugNames(const char** names)
{ {
for (int i = 0; i < Count; ++i) for (int i = 0; i < Count; ++i)
names[i] = "Unknown"; names[i] = "Unknown";
names[Round] = "round"; names[Round] = "round";
names[RoundEven] = "roundEven"; names[RoundEven] = "roundEven";
names[Trunc] = "trunc"; names[Trunc] = "trunc";
names[Abs] = "abs"; names[Abs] = "abs";
names[Sign] = "sign"; names[Sign] = "sign";
names[Floor] = "floor"; names[Floor] = "floor";
names[Ceil] = "ceil"; names[Ceil] = "ceil";
names[Fract] = "fract"; names[Fract] = "fract";
names[Radians] = "radians"; names[Radians] = "radians";
names[Degrees] = "degrees"; names[Degrees] = "degrees";
names[Sin] = "sin"; names[Sin] = "sin";
names[Cos] = "cos"; names[Cos] = "cos";
names[Tan] = "tan"; names[Tan] = "tan";
names[Asin] = "asin"; names[Asin] = "asin";
names[Acos] = "acos"; names[Acos] = "acos";
names[Atan] = "atan"; names[Atan] = "atan";
names[Sinh] = "sinh"; names[Sinh] = "sinh";
names[Cosh] = "cosh"; names[Cosh] = "cosh";
names[Tanh] = "tanh"; names[Tanh] = "tanh";
names[Asinh] = "asinh"; names[Asinh] = "asinh";
names[Acosh] = "acosh"; names[Acosh] = "acosh";
names[Atanh] = "atanh"; names[Atanh] = "atanh";
names[Atan2] = "atan2"; names[Atan2] = "atan2";
names[Pow] = "pow"; names[Pow] = "pow";
names[Exp] = "exp"; names[Exp] = "exp";
names[Log] = "log"; names[Log] = "log";
names[Exp2] = "exp2"; names[Exp2] = "exp2";
names[Log2] = "log2"; names[Log2] = "log2";
names[Sqrt] = "sqrt"; names[Sqrt] = "sqrt";
names[InverseSqrt] = "inverseSqrt"; names[InverseSqrt] = "inverseSqrt";
names[Determinant] = "determinant"; names[Determinant] = "determinant";
names[MatrixInverse] = "matrixInverse"; names[MatrixInverse] = "matrixInverse";
names[Modf] = "modf"; names[Modf] = "modf";
names[Min] = "min"; names[Min] = "min";
names[Max] = "max"; names[Max] = "max";
names[Clamp] = "clamp"; names[Clamp] = "clamp";
names[Mix] = "mix"; names[Mix] = "mix";
names[Step] = "step"; names[Step] = "step";
names[SmoothStep] = "smoothStep"; names[SmoothStep] = "smoothStep";
names[FloatBitsToInt] = "floatBitsToInt"; names[FloatBitsToInt] = "floatBitsToInt";
names[FloatBitsToUint] = "floatBitsToUint"; names[FloatBitsToUint] = "floatBitsToUint";
names[IntBitsToFloat] = "intBitsToFloat"; names[IntBitsToFloat] = "intBitsToFloat";
names[UintBitsToFloat] = "uintBitsToFloat"; names[UintBitsToFloat] = "uintBitsToFloat";
names[Fma] = "fma"; names[Fma] = "fma";
names[Frexp] = "frexp"; names[Frexp] = "frexp";
names[Ldexp] = "ldexp"; names[Ldexp] = "ldexp";
names[PackSnorm4x8] = "packSnorm4x8"; names[PackSnorm4x8] = "packSnorm4x8";
names[PackUnorm4x8] = "packUnorm4x8"; names[PackUnorm4x8] = "packUnorm4x8";
names[PackSnorm2x16] = "packSnorm2x16"; names[PackSnorm2x16] = "packSnorm2x16";
names[PackUnorm2x16] = "packUnorm2x16"; names[PackUnorm2x16] = "packUnorm2x16";
names[PackHalf2x16] = "packHalf2x16"; names[PackHalf2x16] = "packHalf2x16";
names[PackDouble2x32] = "packDouble2x32"; names[PackDouble2x32] = "packDouble2x32";
names[UnpackSnorm2x16] = "unpackSnorm2x16"; names[UnpackSnorm2x16] = "unpackSnorm2x16";
names[UnpackUnorm2x16] = "unpackUnorm2x16"; names[UnpackUnorm2x16] = "unpackUnorm2x16";
names[UnpackHalf2x16] = "unpackHalf2x16"; names[UnpackHalf2x16] = "unpackHalf2x16";
names[UnpackSnorm4x8] = "unpackSnorm4x8"; names[UnpackSnorm4x8] = "unpackSnorm4x8";
names[UnpackUnorm4x8] = "unpackUnorm4x8"; names[UnpackUnorm4x8] = "unpackUnorm4x8";
names[UnpackDouble2x32] = "unpackDouble2x32"; names[UnpackDouble2x32] = "unpackDouble2x32";
names[Length] = "length"; names[Length] = "length";
names[Distance] = "distance"; names[Distance] = "distance";
names[Cross] = "cross"; names[Cross] = "cross";
names[Normalize] = "normalize"; names[Normalize] = "normalize";
names[Ftransform] = "ftransform"; names[Ftransform] = "ftransform";
names[FaceForward] = "faceForward"; names[FaceForward] = "faceForward";
names[Reflect] = "reflect"; names[Reflect] = "reflect";
names[Refract] = "refract"; names[Refract] = "refract";
names[UaddCarry] = "uaddCarry"; names[UaddCarry] = "uaddCarry";
names[UsubBorrow] = "usubBorrow"; names[UsubBorrow] = "usubBorrow";
names[UmulExtended] = "umulExtended"; names[UmulExtended] = "umulExtended";
names[ImulExtended] = "imulExtended"; names[ImulExtended] = "imulExtended";
names[BitfieldExtract] = "bitfieldExtract"; names[BitfieldExtract] = "bitfieldExtract";
names[BitfieldInsert] = "bitfieldInsert"; names[BitfieldInsert] = "bitfieldInsert";
names[BitfieldReverse] = "bitfieldReverse"; names[BitfieldReverse] = "bitfieldReverse";
names[BitCount] = "bitCount"; names[BitCount] = "bitCount";
names[FindLSB] = "findLSB"; names[FindLSB] = "findLSB";
names[FindMSB] = "findMSB"; names[FindMSB] = "findMSB";
names[InterpolateAtCentroid] = "interpolateAtCentroid"; names[InterpolateAtCentroid] = "interpolateAtCentroid";
names[InterpolateAtSample] = "interpolateAtSample"; names[InterpolateAtSample] = "interpolateAtSample";
names[InterpolateAtOffset] = "interpolateAtOffset"; names[InterpolateAtOffset] = "interpolateAtOffset";
} }
}; // end namespace GLSL_STD_450 }; // end namespace GLSL_STD_450

File diff suppressed because it is too large Load Diff

View File

@ -1,42 +1,42 @@
// //
//Copyright (C) 2014 LunarG, Inc. //Copyright (C) 2014 LunarG, Inc.
// //
//All rights reserved. //All rights reserved.
// //
//Redistribution and use in source and binary forms, with or without //Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions //modification, are permitted provided that the following conditions
//are met: //are met:
// //
// Redistributions of source code must retain the above copyright // Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer. // notice, this list of conditions and the following disclaimer.
// //
// Redistributions in binary form must reproduce the above // Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following // copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided // disclaimer in the documentation and/or other materials provided
// with the distribution. // with the distribution.
// //
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
// contributors may be used to endorse or promote products derived // contributors may be used to endorse or promote products derived
// from this software without specific prior written permission. // from this software without specific prior written permission.
// //
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//POSSIBILITY OF SUCH DAMAGE. //POSSIBILITY OF SUCH DAMAGE.
#include "../glslang/Include/intermediate.h" #include "../glslang/Include/intermediate.h"
namespace glslang { namespace glslang {
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv); void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv);
void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName); void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName);
}; };

File diff suppressed because it is too large Load Diff

View File

@ -1,288 +1,288 @@
// //
//Copyright (C) 2015 LunarG, Inc. //Copyright (C) 2015 LunarG, Inc.
// //
//All rights reserved. //All rights reserved.
// //
//Redistribution and use in source and binary forms, with or without //Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions //modification, are permitted provided that the following conditions
//are met: //are met:
// //
// Redistributions of source code must retain the above copyright // Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer. // notice, this list of conditions and the following disclaimer.
// //
// Redistributions in binary form must reproduce the above // Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following // copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided // disclaimer in the documentation and/or other materials provided
// with the distribution. // with the distribution.
// //
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
// contributors may be used to endorse or promote products derived // contributors may be used to endorse or promote products derived
// from this software without specific prior written permission. // from this software without specific prior written permission.
// //
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//POSSIBILITY OF SUCH DAMAGE. //POSSIBILITY OF SUCH DAMAGE.
// //
#ifndef SPIRVREMAPPER_H #ifndef SPIRVREMAPPER_H
#define SPIRVREMAPPER_H #define SPIRVREMAPPER_H
#include <string> #include <string>
#include <vector> #include <vector>
#include <stdlib.h> #include <stdlib.h>
namespace spv { namespace spv {
// MSVC defines __cplusplus as an older value, even when it supports almost all of 11. // MSVC defines __cplusplus as an older value, even when it supports almost all of 11.
// We handle that here by making our own symbol. // We handle that here by making our own symbol.
#if __cplusplus >= 201103L || _MSC_VER >= 1700 #if __cplusplus >= 201103L || _MSC_VER >= 1700
# define use_cpp11 1 # define use_cpp11 1
#endif #endif
class spirvbin_base_t class spirvbin_base_t
{ {
public: public:
enum Options { enum Options {
NONE = 0, NONE = 0,
STRIP = (1<<0), STRIP = (1<<0),
MAP_TYPES = (1<<1), MAP_TYPES = (1<<1),
MAP_NAMES = (1<<2), MAP_NAMES = (1<<2),
MAP_FUNCS = (1<<3), MAP_FUNCS = (1<<3),
DCE_FUNCS = (1<<4), DCE_FUNCS = (1<<4),
DCE_VARS = (1<<5), DCE_VARS = (1<<5),
DCE_TYPES = (1<<6), DCE_TYPES = (1<<6),
OPT_LOADSTORE = (1<<7), OPT_LOADSTORE = (1<<7),
OPT_FWD_LS = (1<<8), // EXPERIMENTAL: PRODUCES INVALID SCHEMA-0 SPIRV OPT_FWD_LS = (1<<8), // EXPERIMENTAL: PRODUCES INVALID SCHEMA-0 SPIRV
MAP_ALL = (MAP_TYPES | MAP_NAMES | MAP_FUNCS), MAP_ALL = (MAP_TYPES | MAP_NAMES | MAP_FUNCS),
DCE_ALL = (DCE_FUNCS | DCE_VARS | DCE_TYPES), DCE_ALL = (DCE_FUNCS | DCE_VARS | DCE_TYPES),
OPT_ALL = (OPT_LOADSTORE), OPT_ALL = (OPT_LOADSTORE),
ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL), ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL),
DO_EVERYTHING = (STRIP | ALL_BUT_STRIP) DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)
}; };
}; };
} // namespace SPV } // namespace SPV
#if !defined (use_cpp11) #if !defined (use_cpp11)
#include <stdio.h> #include <stdio.h>
namespace spv { namespace spv {
class spirvbin_t : public spirvbin_base_t class spirvbin_t : public spirvbin_base_t
{ {
public: public:
spirvbin_t(int /*verbose = 0*/) { } spirvbin_t(int /*verbose = 0*/) { }
void remap(std::vector<unsigned int>& /*spv*/, unsigned int /*opts = 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"); printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");
exit(5); exit(5);
} }
}; };
} // namespace SPV } // namespace SPV
#else // defined (use_cpp11) #else // defined (use_cpp11)
#include <functional> #include <functional>
#include <cstdint> #include <cstdint>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <map> #include <map>
#include <set> #include <set>
#include <cassert> #include <cassert>
#include "../../glslang/SPIRV/spirv.h" #include "../../glslang/SPIRV/spirv.h"
#include "../../glslang/SPIRV/spvIR.h" #include "../../glslang/SPIRV/spvIR.h"
namespace spv { namespace spv {
// class to hold SPIR-V binary data for remapping, DCE, and debug stripping // class to hold SPIR-V binary data for remapping, DCE, and debug stripping
class spirvbin_t : public spirvbin_base_t class spirvbin_t : public spirvbin_base_t
{ {
public: public:
spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose) { } spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose) { }
// remap on an existing binary in memory // remap on an existing binary in memory
void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = DO_EVERYTHING); void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = DO_EVERYTHING);
// Type for error/log handler functions // Type for error/log handler functions
typedef std::function<void(const std::string&)> errorfn_t; typedef std::function<void(const std::string&)> errorfn_t;
typedef std::function<void(const std::string&)> logfn_t; typedef std::function<void(const std::string&)> logfn_t;
// Register error/log handling functions (can be lambda fn / functor / etc) // Register error/log handling functions (can be lambda fn / functor / etc)
static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; } static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }
static void registerLogHandler(logfn_t handler) { logHandler = handler; } static void registerLogHandler(logfn_t handler) { logHandler = handler; }
protected: protected:
// This can be overridden to provide other message behavior if needed // This can be overridden to provide other message behavior if needed
virtual void msg(int minVerbosity, int indent, const std::string& txt) const; virtual void msg(int minVerbosity, int indent, const std::string& txt) const;
private: private:
// Local to global, or global to local ID map // Local to global, or global to local ID map
typedef std::unordered_map<spv::Id, spv::Id> idmap_t; typedef std::unordered_map<spv::Id, spv::Id> idmap_t;
typedef std::unordered_set<spv::Id> idset_t; typedef std::unordered_set<spv::Id> idset_t;
void remap(std::uint32_t opts = DO_EVERYTHING); void remap(std::uint32_t opts = DO_EVERYTHING);
// Map of names to IDs // Map of names to IDs
typedef std::unordered_map<std::string, spv::Id> namemap_t; typedef std::unordered_map<std::string, spv::Id> namemap_t;
typedef std::uint32_t spirword_t; typedef std::uint32_t spirword_t;
typedef std::pair<unsigned, unsigned> range_t; typedef std::pair<unsigned, unsigned> range_t;
typedef std::function<void(spv::Id&)> idfn_t; typedef std::function<void(spv::Id&)> idfn_t;
typedef std::function<bool(spv::Op, unsigned start)> instfn_t; typedef std::function<bool(spv::Op, unsigned start)> instfn_t;
// Special Values for ID map: // Special Values for ID map:
static const spv::Id unmapped; // unchanged from default value static const spv::Id unmapped; // unchanged from default value
static const spv::Id unused; // unused ID static const spv::Id unused; // unused ID
static const int header_size; // SPIR header = 5 words static const int header_size; // SPIR header = 5 words
class id_iterator_t; class id_iterator_t;
// For mapping type entries between different shaders // For mapping type entries between different shaders
typedef std::vector<spirword_t> typeentry_t; typedef std::vector<spirword_t> typeentry_t;
typedef std::map<spv::Id, typeentry_t> globaltypes_t; typedef std::map<spv::Id, typeentry_t> globaltypes_t;
// A set that preserves position order, and a reverse map // A set that preserves position order, and a reverse map
typedef std::set<int> posmap_t; typedef std::set<int> posmap_t;
typedef std::unordered_map<spv::Id, int> posmap_rev_t; typedef std::unordered_map<spv::Id, int> posmap_rev_t;
// handle error // handle error
void error(const std::string& txt) const { errorHandler(txt); } void error(const std::string& txt) const { errorHandler(txt); }
bool isConstOp(spv::Op opCode) const; bool isConstOp(spv::Op opCode) const;
bool isTypeOp(spv::Op opCode) const; bool isTypeOp(spv::Op opCode) const;
bool isStripOp(spv::Op opCode) const; bool isStripOp(spv::Op opCode) const;
bool isFlowCtrlOpen(spv::Op opCode) const; bool isFlowCtrlOpen(spv::Op opCode) const;
bool isFlowCtrlClose(spv::Op opCode) const; bool isFlowCtrlClose(spv::Op opCode) const;
range_t literalRange(spv::Op opCode) const; range_t literalRange(spv::Op opCode) const;
range_t typeRange(spv::Op opCode) const; range_t typeRange(spv::Op opCode) const;
range_t constRange(spv::Op opCode) const; range_t constRange(spv::Op opCode) const;
spv::Id& asId(unsigned word) { return spv[word]; } spv::Id& asId(unsigned word) { return spv[word]; }
const spv::Id& asId(unsigned word) const { return spv[word]; } const spv::Id& asId(unsigned word) const { return spv[word]; }
spv::Op asOpCode(unsigned word) const { return opOpCode(spv[word]); } spv::Op asOpCode(unsigned word) const { return opOpCode(spv[word]); }
std::uint32_t asOpCodeHash(unsigned word); std::uint32_t asOpCodeHash(unsigned word);
spv::Decoration asDecoration(unsigned word) const { return spv::Decoration(spv[word]); } spv::Decoration asDecoration(unsigned word) const { return spv::Decoration(spv[word]); }
unsigned asWordCount(unsigned word) const { return opWordCount(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)); } spv::Id asTypeConstId(unsigned word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }
unsigned typePos(spv::Id id) const; unsigned typePos(spv::Id id) const;
static unsigned opWordCount(spirword_t data) { return data >> spv::WordCountShift; } static unsigned opWordCount(spirword_t data) { return data >> spv::WordCountShift; }
static spv::Op opOpCode(spirword_t data) { return spv::Op(data & spv::OpCodeMask); } static spv::Op opOpCode(spirword_t data) { return spv::Op(data & spv::OpCodeMask); }
// Header access & set methods // Header access & set methods
spirword_t magic() const { return spv[0]; } // return magic number 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() const { return spv[3]; } // return Id bound from header
spirword_t bound(spirword_t b) { return spv[3] = b; }; spirword_t bound(spirword_t b) { return spv[3] = b; };
spirword_t genmagic() const { return spv[2]; } // generator magic spirword_t genmagic() const { return spv[2]; } // generator magic
spirword_t genmagic(spirword_t m) { return spv[2] = m; } spirword_t genmagic(spirword_t m) { return spv[2] = m; }
spirword_t schemaNum() const { return spv[4]; } // schema number from header spirword_t schemaNum() const { return spv[4]; } // schema number from header
// Mapping fns: get // Mapping fns: get
spv::Id localId(spv::Id id) const { return idMapL[id]; } spv::Id localId(spv::Id id) const { return idMapL[id]; }
// Mapping fns: set // Mapping fns: set
inline spv::Id localId(spv::Id id, spv::Id newId); inline spv::Id localId(spv::Id id, spv::Id newId);
void countIds(spv::Id id); void countIds(spv::Id id);
// Return next unused new local ID. // Return next unused new local ID.
// NOTE: boost::dynamic_bitset would be more efficient due to find_next(), // NOTE: boost::dynamic_bitset would be more efficient due to find_next(),
// which std::vector<bool> doens't have. // which std::vector<bool> doens't have.
inline spv::Id nextUnusedId(spv::Id id); inline spv::Id nextUnusedId(spv::Id id);
void buildLocalMaps(); void buildLocalMaps();
std::string literalString(unsigned word) const; // Return literal as a std::string 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; } int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }
bool isNewIdMapped(spv::Id newId) const { return isMapped(newId); } bool isNewIdMapped(spv::Id newId) const { return isMapped(newId); }
bool isOldIdUnmapped(spv::Id oldId) const { return localId(oldId) == unmapped; } bool isOldIdUnmapped(spv::Id oldId) const { return localId(oldId) == unmapped; }
bool isOldIdUnused(spv::Id oldId) const { return localId(oldId) == unused; } bool isOldIdUnused(spv::Id oldId) const { return localId(oldId) == unused; }
bool isOldIdMapped(spv::Id oldId) const { return !isOldIdUnused(oldId) && !isOldIdUnmapped(oldId); } bool isOldIdMapped(spv::Id oldId) const { return !isOldIdUnused(oldId) && !isOldIdUnmapped(oldId); }
bool isFunction(spv::Id oldId) const { return fnPos.find(oldId) != fnPos.end(); } 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; // bool matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;
// spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const; // spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;
std::uint32_t hashType(unsigned typeStart) const; std::uint32_t hashType(unsigned typeStart) const;
spirvbin_t& process(instfn_t, idfn_t, unsigned begin = 0, unsigned end = 0); spirvbin_t& process(instfn_t, idfn_t, unsigned begin = 0, unsigned end = 0);
int processInstruction(unsigned word, instfn_t, idfn_t); int processInstruction(unsigned word, instfn_t, idfn_t);
void validate() const; void validate() const;
void mapTypeConst(); void mapTypeConst();
void mapFnBodies(); void mapFnBodies();
void optLoadStore(); void optLoadStore();
void dceFuncs(); void dceFuncs();
void dceVars(); void dceVars();
void dceTypes(); void dceTypes();
void mapNames(); void mapNames();
void foldIds(); // fold IDs to smallest space void foldIds(); // fold IDs to smallest space
void forwardLoadStores(); // load store forwarding (EXPERIMENTAL) void forwardLoadStores(); // load store forwarding (EXPERIMENTAL)
void offsetIds(); // create relative offset IDs void offsetIds(); // create relative offset IDs
void applyMap(); // remap per local name map void applyMap(); // remap per local name map
void mapRemainder(); // map any IDs we haven't touched yet void mapRemainder(); // map any IDs we haven't touched yet
void stripDebug(); // strip debug info void stripDebug(); // strip debug info
void strip(); // remove debug symbols void strip(); // remove debug symbols
std::vector<spirword_t> spv; // SPIR words std::vector<spirword_t> spv; // SPIR words
namemap_t nameMap; // ID names from OpName 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 // 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. // boost::dynamic_bitset, but we're trying to avoid a boost dependency.
typedef std::uint64_t bits_t; typedef std::uint64_t bits_t;
std::vector<bits_t> mapped; // which new IDs have been mapped std::vector<bits_t> mapped; // which new IDs have been mapped
static const int mBits = sizeof(bits_t) * 4; static const int mBits = sizeof(bits_t) * 4;
bool isMapped(spv::Id id) const { return id < maxMappedId() && ((mapped[id/mBits] & (1LL<<(id%mBits))) != 0); } 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 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); } void resizeMapped(spv::Id id) { if (id >= maxMappedId()) mapped.resize(id/mBits+1, 0); }
size_t maxMappedId() const { return mapped.size() * mBits; } size_t maxMappedId() const { return mapped.size() * mBits; }
// Add a strip range for a given instruction starting at 'start' // Add a strip range for a given instruction starting at 'start'
// Note: avoiding brace initializers to please older versions os MSVC. // Note: avoiding brace initializers to please older versions os MSVC.
void stripInst(unsigned start) { stripRange.push_back(range_t(start, start + asWordCount(start))); } void stripInst(unsigned start) { stripRange.push_back(range_t(start, start + asWordCount(start))); }
// Function start and end. use unordered_map because we'll have // Function start and end. use unordered_map because we'll have
// many fewer functions than IDs. // many fewer functions than IDs.
std::unordered_map<spv::Id, range_t> fnPos; std::unordered_map<spv::Id, range_t> fnPos;
std::unordered_map<spv::Id, range_t> fnPosDCE; // deleted functions std::unordered_map<spv::Id, range_t> fnPosDCE; // deleted functions
// Which functions are called, anywhere in the module, with a call count // Which functions are called, anywhere in the module, with a call count
std::unordered_map<spv::Id, int> fnCalls; std::unordered_map<spv::Id, int> fnCalls;
posmap_t typeConstPos; // word positions that define types & consts (ordered) posmap_t typeConstPos; // word positions that define types & consts (ordered)
posmap_rev_t typeConstPosR; // reverse map from IDs to positions 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 std::vector<spv::Id> idMapL; // ID {M}ap from {L}ocal to {G}lobal IDs
spv::Id entryPoint; // module entry point spv::Id entryPoint; // module entry point
spv::Id largestNewId; // biggest new ID we have mapped anything to spv::Id largestNewId; // biggest new ID we have mapped anything to
// Sections of the binary to strip, given as [begin,end) // Sections of the binary to strip, given as [begin,end)
std::vector<range_t> stripRange; std::vector<range_t> stripRange;
// processing options: // processing options:
std::uint32_t options; std::uint32_t options;
int verbose; // verbosity level int verbose; // verbosity level
static errorfn_t errorHandler; static errorfn_t errorHandler;
static logfn_t logHandler; static logfn_t logHandler;
}; };
} // namespace SPV } // namespace SPV
#endif // defined (use_cpp11) #endif // defined (use_cpp11)
#endif // SPIRVREMAPPER_H #endif // SPIRVREMAPPER_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,435 +1,435 @@
// //
//Copyright (C) 2014 LunarG, Inc. //Copyright (C) 2014 LunarG, Inc.
// //
//All rights reserved. //All rights reserved.
// //
//Redistribution and use in source and binary forms, with or without //Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions //modification, are permitted provided that the following conditions
//are met: //are met:
// //
// Redistributions of source code must retain the above copyright // Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer. // notice, this list of conditions and the following disclaimer.
// //
// Redistributions in binary form must reproduce the above // Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following // copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided // disclaimer in the documentation and/or other materials provided
// with the distribution. // with the distribution.
// //
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
// contributors may be used to endorse or promote products derived // contributors may be used to endorse or promote products derived
// from this software without specific prior written permission. // from this software without specific prior written permission.
// //
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTAstreamITY AND FITNESS //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTAstreamITY AND FITNESS
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//CAUSED AND ON ANY THEORY OF LIAstreamITY, WHETHER IN CONTRACT, STRICT //CAUSED AND ON ANY THEORY OF LIAstreamITY, WHETHER IN CONTRACT, STRICT
//LIAstreamITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN //LIAstreamITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//POSSIstreamITY OF SUCH DAMAGE. //POSSIstreamITY OF SUCH DAMAGE.
// //
// Author: John Kessenich, LunarG // Author: John Kessenich, LunarG
// //
// //
// Disassembler for SPIR-V. // Disassembler for SPIR-V.
// //
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <iomanip> #include <iomanip>
#include <stack> #include <stack>
#include <sstream> #include <sstream>
#include "GLSL450Lib.h" #include "GLSL450Lib.h"
extern const char* GlslStd450DebugNames[GLSL_STD_450::Count]; extern const char* GlslStd450DebugNames[GLSL_STD_450::Count];
#include "disassemble.h" #include "disassemble.h"
#include "doc.h" #include "doc.h"
namespace spv { namespace spv {
void Kill(std::ostream& out, const char* message) void Kill(std::ostream& out, const char* message)
{ {
out << std::endl << "Disassembly failed: " << message << std::endl; out << std::endl << "Disassembly failed: " << message << std::endl;
exit(1); exit(1);
} }
// Container class for a single instance of a SPIR-V stream, with methods for disassembly. // Container class for a single instance of a SPIR-V stream, with methods for disassembly.
class SpirvStream { class SpirvStream {
public: public:
SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { } SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { }
virtual ~SpirvStream() { } virtual ~SpirvStream() { }
void validate(); void validate();
void processInstructions(); void processInstructions();
protected: protected:
SpirvStream(SpirvStream&); SpirvStream(SpirvStream&);
SpirvStream& operator=(SpirvStream&); SpirvStream& operator=(SpirvStream&);
Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; } Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; }
// Output methods // Output methods
void outputIndent(); void outputIndent();
void formatId(Id id, std::stringstream&); void formatId(Id id, std::stringstream&);
void outputResultId(Id id); void outputResultId(Id id);
void outputTypeId(Id id); void outputTypeId(Id id);
void outputId(Id id); void outputId(Id id);
void disassembleImmediates(int numOperands); void disassembleImmediates(int numOperands);
void disassembleIds(int numOperands); void disassembleIds(int numOperands);
void disassembleString(); void disassembleString();
void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands); void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands);
// Data // Data
std::ostream& out; // where to write the disassembly std::ostream& out; // where to write the disassembly
const std::vector<unsigned int>& stream; // the actual word stream const std::vector<unsigned int>& stream; // the actual word stream
int size; // the size of the word stream int size; // the size of the word stream
int word; // the next word of the stream to read int word; // the next word of the stream to read
// map each <id> to the instruction that created it // map each <id> to the instruction that created it
Id bound; 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<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> std::vector<std::string> idDescriptor; // the best text string known for explaining the <id>
// schema // schema
unsigned int schema; unsigned int schema;
// stack of structured-merge points // stack of structured-merge points
std::stack<Id> nestedControl; std::stack<Id> nestedControl;
Id nextNestedControl; // need a slight delay for when we are nested Id nextNestedControl; // need a slight delay for when we are nested
}; };
void SpirvStream::validate() void SpirvStream::validate()
{ {
size = (int)stream.size(); size = (int)stream.size();
if (size < 4) if (size < 4)
Kill(out, "stream is too short"); Kill(out, "stream is too short");
// Magic number // Magic number
if (stream[word++] != MagicNumber) { if (stream[word++] != MagicNumber) {
out << "Bad magic number"; out << "Bad magic number";
return; return;
} }
// Version // Version
out << "// Module Version " << stream[word++] << std::endl; out << "// Module Version " << stream[word++] << std::endl;
// Generator's magic number // Generator's magic number
out << "// Generated by (magic number): " << std::setbase(16) << stream[word++] << std::setbase(10) << std::endl; out << "// Generated by (magic number): " << std::setbase(16) << stream[word++] << std::setbase(10) << std::endl;
// Result <id> bound // Result <id> bound
bound = stream[word++]; bound = stream[word++];
idInstruction.resize(bound); idInstruction.resize(bound);
idDescriptor.resize(bound); idDescriptor.resize(bound);
out << "// Id's are bound by " << bound << std::endl; out << "// Id's are bound by " << bound << std::endl;
out << std::endl; out << std::endl;
// Reserved schema, must be 0 for now // Reserved schema, must be 0 for now
schema = stream[word++]; schema = stream[word++];
if (schema != 0) if (schema != 0)
Kill(out, "bad schema, must be 0"); Kill(out, "bad schema, must be 0");
} }
// Loop over all the instructions, in order, processing each. // Loop over all the instructions, in order, processing each.
// Boiler plate for each is handled here directly, the rest is dispatched. // Boiler plate for each is handled here directly, the rest is dispatched.
void SpirvStream::processInstructions() void SpirvStream::processInstructions()
{ {
// Instructions // Instructions
while (word < size) { while (word < size) {
int instructionStart = word; int instructionStart = word;
// Instruction wordCount and opcode // Instruction wordCount and opcode
unsigned int firstWord = stream[word]; unsigned int firstWord = stream[word];
unsigned wordCount = firstWord >> WordCountShift; unsigned wordCount = firstWord >> WordCountShift;
Op opCode = (Op)(firstWord & OpCodeMask); Op opCode = (Op)(firstWord & OpCodeMask);
int nextInst = word + wordCount; int nextInst = word + wordCount;
++word; ++word;
// Presence of full instruction // Presence of full instruction
if (nextInst > size) if (nextInst > size)
Kill(out, "stream instruction terminated too early"); Kill(out, "stream instruction terminated too early");
// Base for computing number of operands; will be updated as more is learned // Base for computing number of operands; will be updated as more is learned
unsigned numOperands = wordCount - 1; unsigned numOperands = wordCount - 1;
// Type <id> // Type <id>
Id typeId = 0; Id typeId = 0;
if (InstructionDesc[opCode].hasType()) { if (InstructionDesc[opCode].hasType()) {
typeId = stream[word++]; typeId = stream[word++];
--numOperands; --numOperands;
} }
// Result <id> // Result <id>
Id resultId = 0; Id resultId = 0;
if (InstructionDesc[opCode].hasResult()) { if (InstructionDesc[opCode].hasResult()) {
resultId = stream[word++]; resultId = stream[word++];
--numOperands; --numOperands;
// save instruction for future reference // save instruction for future reference
idInstruction[resultId] = instructionStart; idInstruction[resultId] = instructionStart;
} }
outputResultId(resultId); outputResultId(resultId);
outputTypeId(typeId); outputTypeId(typeId);
outputIndent(); outputIndent();
// Hand off the Op and all its operands // Hand off the Op and all its operands
disassembleInstruction(resultId, typeId, opCode, numOperands); disassembleInstruction(resultId, typeId, opCode, numOperands);
if (word != nextInst) { if (word != nextInst) {
out << " ERROR, incorrect number of operands consumed. At " << word << " instead of " << nextInst << " instruction start was " << instructionStart; out << " ERROR, incorrect number of operands consumed. At " << word << " instead of " << nextInst << " instruction start was " << instructionStart;
word = nextInst; word = nextInst;
} }
out << std::endl; out << std::endl;
} }
} }
void SpirvStream::outputIndent() void SpirvStream::outputIndent()
{ {
for (int i = 0; i < (int)nestedControl.size(); ++i) for (int i = 0; i < (int)nestedControl.size(); ++i)
out << " "; out << " ";
} }
void SpirvStream::formatId(Id id, std::stringstream& idStream) void SpirvStream::formatId(Id id, std::stringstream& idStream)
{ {
if (id >= bound) if (id >= bound)
Kill(out, "Bad <id>"); Kill(out, "Bad <id>");
if (id != 0) { if (id != 0) {
idStream << id; idStream << id;
if (idDescriptor[id].size() > 0) if (idDescriptor[id].size() > 0)
idStream << "(" << idDescriptor[id] << ")"; idStream << "(" << idDescriptor[id] << ")";
} }
} }
void SpirvStream::outputResultId(Id id) void SpirvStream::outputResultId(Id id)
{ {
const int width = 16; const int width = 16;
std::stringstream idStream; std::stringstream idStream;
formatId(id, idStream); formatId(id, idStream);
out << std::setw(width) << std::right << idStream.str(); out << std::setw(width) << std::right << idStream.str();
if (id != 0) if (id != 0)
out << ":"; out << ":";
else else
out << " "; out << " ";
if (nestedControl.size() && id == nestedControl.top()) if (nestedControl.size() && id == nestedControl.top())
nestedControl.pop(); nestedControl.pop();
} }
void SpirvStream::outputTypeId(Id id) void SpirvStream::outputTypeId(Id id)
{ {
const int width = 12; const int width = 12;
std::stringstream idStream; std::stringstream idStream;
formatId(id, idStream); formatId(id, idStream);
out << std::setw(width) << std::right << idStream.str() << " "; out << std::setw(width) << std::right << idStream.str() << " ";
} }
void SpirvStream::outputId(Id id) void SpirvStream::outputId(Id id)
{ {
if (id >= bound) if (id >= bound)
Kill(out, "Bad <id>"); Kill(out, "Bad <id>");
out << id; out << id;
if (idDescriptor[id].size() > 0) if (idDescriptor[id].size() > 0)
out << "(" << idDescriptor[id] << ")"; out << "(" << idDescriptor[id] << ")";
} }
void SpirvStream::disassembleImmediates(int numOperands) void SpirvStream::disassembleImmediates(int numOperands)
{ {
for (int i = 0; i < numOperands; ++i) { for (int i = 0; i < numOperands; ++i) {
out << stream[word++]; out << stream[word++];
if (i < numOperands - 1) if (i < numOperands - 1)
out << " "; out << " ";
} }
} }
void SpirvStream::disassembleIds(int numOperands) void SpirvStream::disassembleIds(int numOperands)
{ {
for (int i = 0; i < numOperands; ++i) { for (int i = 0; i < numOperands; ++i) {
outputId(stream[word++]); outputId(stream[word++]);
if (i < numOperands - 1) if (i < numOperands - 1)
out << " "; out << " ";
} }
} }
void SpirvStream::disassembleString() void SpirvStream::disassembleString()
{ {
out << " \""; out << " \"";
char* wordString; char* wordString;
bool done = false; bool done = false;
do { do {
unsigned int content = stream[word]; unsigned int content = stream[word];
wordString = (char*)&content; wordString = (char*)&content;
for (int charCount = 0; charCount < 4; ++charCount) { for (int charCount = 0; charCount < 4; ++charCount) {
if (*wordString == 0) { if (*wordString == 0) {
done = true; done = true;
break; break;
} }
out << *(wordString++); out << *(wordString++);
} }
++word; ++word;
} while (! done); } while (! done);
out << "\""; out << "\"";
} }
void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands) void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)
{ {
// Process the opcode // Process the opcode
out << (OpcodeString(opCode) + 2); // leave out the "Op" out << (OpcodeString(opCode) + 2); // leave out the "Op"
if (opCode == OpLoopMerge || opCode == OpSelectionMerge) if (opCode == OpLoopMerge || opCode == OpSelectionMerge)
nextNestedControl = stream[word]; nextNestedControl = stream[word];
else if (opCode == OpBranchConditional || opCode == OpSwitch) { else if (opCode == OpBranchConditional || opCode == OpSwitch) {
if (nextNestedControl) { if (nextNestedControl) {
nestedControl.push(nextNestedControl); nestedControl.push(nextNestedControl);
nextNestedControl = 0; nextNestedControl = 0;
} }
} else if (opCode == OpExtInstImport) } else if (opCode == OpExtInstImport)
idDescriptor[resultId] = (char*)(&stream[word]); idDescriptor[resultId] = (char*)(&stream[word]);
else { else {
if (idDescriptor[resultId].size() == 0) { if (idDescriptor[resultId].size() == 0) {
switch (opCode) { switch (opCode) {
case OpTypeInt: case OpTypeInt:
idDescriptor[resultId] = "int"; idDescriptor[resultId] = "int";
break; break;
case OpTypeFloat: case OpTypeFloat:
idDescriptor[resultId] = "float"; idDescriptor[resultId] = "float";
break; break;
case OpTypeBool: case OpTypeBool:
idDescriptor[resultId] = "bool"; idDescriptor[resultId] = "bool";
break; break;
case OpTypeStruct: case OpTypeStruct:
idDescriptor[resultId] = "struct"; idDescriptor[resultId] = "struct";
break; break;
case OpTypePointer: case OpTypePointer:
idDescriptor[resultId] = "ptr"; idDescriptor[resultId] = "ptr";
break; break;
case OpTypeVector: case OpTypeVector:
if (idDescriptor[stream[word]].size() > 0) if (idDescriptor[stream[word]].size() > 0)
idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1); idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);
idDescriptor[resultId].append("vec"); idDescriptor[resultId].append("vec");
switch (stream[word + 1]) { switch (stream[word + 1]) {
case 2: idDescriptor[resultId].append("2"); break; case 2: idDescriptor[resultId].append("2"); break;
case 3: idDescriptor[resultId].append("3"); break; case 3: idDescriptor[resultId].append("3"); break;
case 4: idDescriptor[resultId].append("4"); break; case 4: idDescriptor[resultId].append("4"); break;
case 8: idDescriptor[resultId].append("8"); break; case 8: idDescriptor[resultId].append("8"); break;
case 16: idDescriptor[resultId].append("16"); break; case 16: idDescriptor[resultId].append("16"); break;
case 32: idDescriptor[resultId].append("32"); break; case 32: idDescriptor[resultId].append("32"); break;
default: break; default: break;
} }
break; break;
default: default:
break; break;
} }
} }
} }
// Process the operands. Note, a new context-dependent set could be // Process the operands. Note, a new context-dependent set could be
// swapped in mid-traversal. // swapped in mid-traversal.
// Handle textures specially, so can put out helpful strings. // Handle textures specially, so can put out helpful strings.
if (opCode == OpTypeSampler) { if (opCode == OpTypeSampler) {
disassembleIds(1); disassembleIds(1);
out << " " << DimensionString((Dim)stream[word++]); out << " " << DimensionString((Dim)stream[word++]);
switch (stream[word++]) { switch (stream[word++]) {
case 0: out << " texture"; break; case 0: out << " texture"; break;
case 1: out << " image"; break; case 1: out << " image"; break;
case 2: out << " filter+texture"; break; case 2: out << " filter+texture"; break;
} }
out << (stream[word++] != 0 ? " array" : ""); out << (stream[word++] != 0 ? " array" : "");
out << (stream[word++] != 0 ? " depth" : ""); out << (stream[word++] != 0 ? " depth" : "");
out << (stream[word++] != 0 ? " multi-sampled" : ""); out << (stream[word++] != 0 ? " multi-sampled" : "");
return; return;
} }
// Handle all the parameterized operands // Handle all the parameterized operands
for (int op = 0; op < InstructionDesc[opCode].operands.getNum(); ++op) { for (int op = 0; op < InstructionDesc[opCode].operands.getNum(); ++op) {
out << " "; out << " ";
OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op); OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op);
switch (operandClass) { switch (operandClass) {
case OperandId: case OperandId:
disassembleIds(1); disassembleIds(1);
// Get names for printing "(XXX)" for readability, *after* this id // Get names for printing "(XXX)" for readability, *after* this id
if (opCode == OpName) if (opCode == OpName)
idDescriptor[stream[word - 1]] = (char*)(&stream[word]); idDescriptor[stream[word - 1]] = (char*)(&stream[word]);
break; break;
case OperandOptionalId: case OperandOptionalId:
case OperandVariableIds: case OperandVariableIds:
disassembleIds(numOperands); disassembleIds(numOperands);
return; return;
case OperandVariableLiterals: case OperandVariableLiterals:
if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) || if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) ||
(opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) { (opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) {
out << BuiltInString(stream[word++]); out << BuiltInString(stream[word++]);
--numOperands; --numOperands;
++op; ++op;
} }
disassembleImmediates(numOperands); disassembleImmediates(numOperands);
return; return;
case OperandVariableLiteralId: case OperandVariableLiteralId:
while (numOperands > 0) { while (numOperands > 0) {
out << std::endl; out << std::endl;
outputResultId(0); outputResultId(0);
outputTypeId(0); outputTypeId(0);
outputIndent(); outputIndent();
out << " case "; out << " case ";
disassembleImmediates(1); disassembleImmediates(1);
out << ": "; out << ": ";
disassembleIds(1); disassembleIds(1);
numOperands -= 2; numOperands -= 2;
} }
return; return;
case OperandLiteralNumber: case OperandLiteralNumber:
disassembleImmediates(1); disassembleImmediates(1);
if (opCode == OpExtInst) { if (opCode == OpExtInst) {
unsigned entrypoint = stream[word - 1]; unsigned entrypoint = stream[word - 1];
if (entrypoint < GLSL_STD_450::Count) if (entrypoint < GLSL_STD_450::Count)
out << "(" << GlslStd450DebugNames[entrypoint] << ")"; out << "(" << GlslStd450DebugNames[entrypoint] << ")";
} }
break; break;
case OperandLiteralString: case OperandLiteralString:
disassembleString(); disassembleString();
return; return;
default: default:
assert(operandClass >= OperandSource && operandClass < OperandOpcode); assert(operandClass >= OperandSource && operandClass < OperandOpcode);
if (OperandClassParams[operandClass].bitmask) { if (OperandClassParams[operandClass].bitmask) {
unsigned int mask = stream[word++]; unsigned int mask = stream[word++];
if (mask == 0) if (mask == 0)
out << "None"; out << "None";
else { else {
for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) { for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {
if (mask & (1 << m)) if (mask & (1 << m))
out << OperandClassParams[operandClass].getName(m) << " "; out << OperandClassParams[operandClass].getName(m) << " ";
} }
} }
break; break;
} else } else
out << OperandClassParams[operandClass].getName(stream[word++]); out << OperandClassParams[operandClass].getName(stream[word++]);
break; break;
} }
--numOperands; --numOperands;
} }
return; return;
} }
void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream) void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
{ {
SpirvStream SpirvStream(out, stream); SpirvStream SpirvStream(out, stream);
SpirvStream.validate(); SpirvStream.validate();
SpirvStream.processInstructions(); SpirvStream.processInstructions();
} }
}; // end namespace spv }; // end namespace spv

View File

@ -1,56 +1,56 @@
// //
//Copyright (C) 2014 LunarG, Inc. //Copyright (C) 2014 LunarG, Inc.
// //
//All rights reserved. //All rights reserved.
// //
//Redistribution and use in source and binary forms, with or without //Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions //modification, are permitted provided that the following conditions
//are met: //are met:
// //
// Redistributions of source code must retain the above copyright // Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer. // notice, this list of conditions and the following disclaimer.
// //
// Redistributions in binary form must reproduce the above // Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following // copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided // disclaimer in the documentation and/or other materials provided
// with the distribution. // with the distribution.
// //
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
// contributors may be used to endorse or promote products derived // contributors may be used to endorse or promote products derived
// from this software without specific prior written permission. // from this software without specific prior written permission.
// //
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//POSSIBILITY OF SUCH DAMAGE. //POSSIBILITY OF SUCH DAMAGE.
// //
// Author: John Kessenich, LunarG // Author: John Kessenich, LunarG
// //
// //
// Disassembler for SPIR-V. // Disassembler for SPIR-V.
// //
#pragma once #pragma once
#ifndef disassembler_H #ifndef disassembler_H
#define disassembler_H #define disassembler_H
#include <iostream> #include <iostream>
#include <vector> #include <vector>
namespace spv { namespace spv {
void Disassemble(std::ostream& out, const std::vector<unsigned int>&); void Disassemble(std::ostream& out, const std::vector<unsigned int>&);
}; // end namespace spv }; // end namespace spv
#endif // disassembler_H #endif // disassembler_H

File diff suppressed because it is too large Load Diff

View File

@ -1,256 +1,256 @@
// //
//Copyright (C) 2014 LunarG, Inc. //Copyright (C) 2014 LunarG, Inc.
// //
//All rights reserved. //All rights reserved.
// //
//Redistribution and use in source and binary forms, with or without //Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions //modification, are permitted provided that the following conditions
//are met: //are met:
// //
// Redistributions of source code must retain the above copyright // Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer. // notice, this list of conditions and the following disclaimer.
// //
// Redistributions in binary form must reproduce the above // Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following // copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided // disclaimer in the documentation and/or other materials provided
// with the distribution. // with the distribution.
// //
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
// contributors may be used to endorse or promote products derived // contributors may be used to endorse or promote products derived
// from this software without specific prior written permission. // from this software without specific prior written permission.
// //
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//POSSIBILITY OF SUCH DAMAGE. //POSSIBILITY OF SUCH DAMAGE.
// //
// Author: John Kessenich, LunarG // Author: John Kessenich, LunarG
// //
// //
// Parameterize the SPIR-V enumerants. // Parameterize the SPIR-V enumerants.
// //
#include "spirv.h" #include "spirv.h"
#include <vector> #include <vector>
namespace spv { namespace spv {
// Fill in all the parameters // Fill in all the parameters
void Parameterize(); void Parameterize();
// Return the English names of all the enums. // Return the English names of all the enums.
const char* SourceString(int); const char* SourceString(int);
const char* AddressingString(int); const char* AddressingString(int);
const char* MemoryString(int); const char* MemoryString(int);
const char* ExecutionModelString(int); const char* ExecutionModelString(int);
const char* ExecutionModeString(int); const char* ExecutionModeString(int);
const char* StorageClassString(int); const char* StorageClassString(int);
const char* DecorationString(int); const char* DecorationString(int);
const char* BuiltInString(int); const char* BuiltInString(int);
const char* DimensionString(int); const char* DimensionString(int);
const char* SelectControlString(int); const char* SelectControlString(int);
const char* LoopControlString(int); const char* LoopControlString(int);
const char* FunctionControlString(int); const char* FunctionControlString(int);
const char* SamplerAddressingModeString(int); const char* SamplerAddressingModeString(int);
const char* SamplerFilterModeString(int); const char* SamplerFilterModeString(int);
const char* FPFastMathString(int); const char* FPFastMathString(int);
const char* FPRoundingModeString(int); const char* FPRoundingModeString(int);
const char* LinkageTypeString(int); const char* LinkageTypeString(int);
const char* FuncParamAttrString(int); const char* FuncParamAttrString(int);
const char* AccessQualifierString(int); const char* AccessQualifierString(int);
const char* MemorySemanticsString(int); const char* MemorySemanticsString(int);
const char* MemoryAccessString(int); const char* MemoryAccessString(int);
const char* ExecutionScopeString(int); const char* ExecutionScopeString(int);
const char* GroupOperationString(int); const char* GroupOperationString(int);
const char* KernelEnqueueFlagsString(int); const char* KernelEnqueueFlagsString(int);
const char* KernelProfilingInfoString(int); const char* KernelProfilingInfoString(int);
const char* OpcodeString(int); const char* OpcodeString(int);
// For grouping opcodes into subsections // For grouping opcodes into subsections
enum OpcodeClass { enum OpcodeClass {
OpClassMisc, // default, until opcode is classified OpClassMisc, // default, until opcode is classified
OpClassDebug, OpClassDebug,
OpClassAnnotate, OpClassAnnotate,
OpClassExtension, OpClassExtension,
OpClassMode, OpClassMode,
OpClassType, OpClassType,
OpClassConstant, OpClassConstant,
OpClassMemory, OpClassMemory,
OpClassFunction, OpClassFunction,
OpClassTexture, OpClassTexture,
OpClassConvert, OpClassConvert,
OpClassComposite, OpClassComposite,
OpClassArithmetic, OpClassArithmetic,
OpClassRelationalLogical, OpClassRelationalLogical,
OpClassDerivative, OpClassDerivative,
OpClassFlowControl, OpClassFlowControl,
OpClassAtomic, OpClassAtomic,
OpClassPrimitive, OpClassPrimitive,
OpClassBarrier, OpClassBarrier,
OpClassGroup, OpClassGroup,
OpClassDeviceSideEnqueue, OpClassDeviceSideEnqueue,
OpClassPipe, OpClassPipe,
OpClassCount OpClassCount
}; };
// For parameterizing operands. // For parameterizing operands.
enum OperandClass { enum OperandClass {
OperandNone, OperandNone,
OperandId, OperandId,
OperandOptionalId, OperandOptionalId,
OperandVariableIds, OperandVariableIds,
OperandVariableLiterals, OperandVariableLiterals,
OperandVariableLiteralId, OperandVariableLiteralId,
OperandLiteralNumber, OperandLiteralNumber,
OperandLiteralString, OperandLiteralString,
OperandSource, OperandSource,
OperandExecutionModel, OperandExecutionModel,
OperandAddressing, OperandAddressing,
OperandMemory, OperandMemory,
OperandExecutionMode, OperandExecutionMode,
OperandStorage, OperandStorage,
OperandDimensionality, OperandDimensionality,
OperandSamplerAddressingMode, OperandSamplerAddressingMode,
OperandSamplerFilterMode, OperandSamplerFilterMode,
OperandFPFastMath, OperandFPFastMath,
OperandFPRoundingMode, OperandFPRoundingMode,
OperandLinkageType, OperandLinkageType,
OperandAccessQualifier, OperandAccessQualifier,
OperandFuncParamAttr, OperandFuncParamAttr,
OperandDecoration, OperandDecoration,
OperandBuiltIn, OperandBuiltIn,
OperandSelect, OperandSelect,
OperandLoop, OperandLoop,
OperandFunction, OperandFunction,
OperandMemorySemantics, OperandMemorySemantics,
OperandMemoryAccess, OperandMemoryAccess,
OperandExecutionScope, OperandExecutionScope,
OperandGroupOperation, OperandGroupOperation,
OperandKernelEnqueueFlags, OperandKernelEnqueueFlags,
OperandKernelProfilingInfo, OperandKernelProfilingInfo,
OperandOpcode, OperandOpcode,
OperandCount OperandCount
}; };
// Set of capabilities. Generally, something is assumed to be in core, // Set of capabilities. Generally, something is assumed to be in core,
// if nothing else is said. So, these are used to identify when something // if nothing else is said. So, these are used to identify when something
// requires a specific capability to be declared. // requires a specific capability to be declared.
enum Capability { enum Capability {
CapMatrix, CapMatrix,
CapShader, CapShader,
CapGeom, CapGeom,
CapTess, CapTess,
CapAddr, CapAddr,
CapLink, CapLink,
CapKernel CapKernel
}; };
// Any specific enum can have a set of capabilities that allow it: // Any specific enum can have a set of capabilities that allow it:
typedef std::vector<Capability> EnumCaps; typedef std::vector<Capability> EnumCaps;
// Parameterize a set of operands with their OperandClass(es) and descriptions. // Parameterize a set of operands with their OperandClass(es) and descriptions.
class OperandParameters { class OperandParameters {
public: public:
OperandParameters() { } OperandParameters() { }
void push(OperandClass oc, const char* d) void push(OperandClass oc, const char* d)
{ {
opClass.push_back(oc); opClass.push_back(oc);
desc.push_back(d); desc.push_back(d);
} }
OperandClass getClass(int op) const { return opClass[op]; } OperandClass getClass(int op) const { return opClass[op]; }
const char* getDesc(int op) const { return desc[op]; } const char* getDesc(int op) const { return desc[op]; }
int getNum() const { return (int)opClass.size(); } int getNum() const { return (int)opClass.size(); }
protected: protected:
std::vector<OperandClass> opClass; std::vector<OperandClass> opClass;
std::vector<const char*> desc; std::vector<const char*> desc;
}; };
// Parameterize an enumerant // Parameterize an enumerant
class EnumParameters { class EnumParameters {
public: public:
EnumParameters() : desc(0) { } EnumParameters() : desc(0) { }
EnumCaps caps; EnumCaps caps;
const char* desc; const char* desc;
}; };
// Parameterize a set of enumerants that form an enum // Parameterize a set of enumerants that form an enum
class EnumDefinition : public EnumParameters { class EnumDefinition : public EnumParameters {
public: public:
EnumDefinition() : EnumDefinition() :
ceiling(0), bitmask(false), getName(0), enumParams(0), operandParams(0) { } ceiling(0), bitmask(false), getName(0), enumParams(0), operandParams(0) { }
void set(int ceil, const char* (*name)(int), EnumParameters* ep, bool mask = false) void set(int ceil, const char* (*name)(int), EnumParameters* ep, bool mask = false)
{ {
ceiling = ceil; ceiling = ceil;
getName = name; getName = name;
bitmask = mask; bitmask = mask;
enumParams = ep; enumParams = ep;
} }
void setOperands(OperandParameters* op) { operandParams = op; } void setOperands(OperandParameters* op) { operandParams = op; }
int ceiling; // ceiling of enumerants int ceiling; // ceiling of enumerants
bool bitmask; // true if these enumerants combine into a bitmask 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) const char* (*getName)(int); // a function that returns the name for each enumerant value (or shift)
EnumParameters* enumParams; // parameters for each individual enumerant EnumParameters* enumParams; // parameters for each individual enumerant
OperandParameters* operandParams; // sets of operands OperandParameters* operandParams; // sets of operands
}; };
// Parameterize an instruction's logical format, including its known set of operands, // Parameterize an instruction's logical format, including its known set of operands,
// per OperandParameters above. // per OperandParameters above.
class InstructionParameters { class InstructionParameters {
public: public:
InstructionParameters() : InstructionParameters() :
typePresent(true), // most normal, only exceptions have to be spelled out typePresent(true), // most normal, only exceptions have to be spelled out
resultPresent(true), // most normal, only exceptions have to be spelled out resultPresent(true), // most normal, only exceptions have to be spelled out
opDesc(0), opDesc(0),
opClass(OpClassMisc) opClass(OpClassMisc)
{ } { }
void setResultAndType(bool r, bool t) void setResultAndType(bool r, bool t)
{ {
resultPresent = r; resultPresent = r;
typePresent = t; typePresent = t;
} }
bool hasResult() const { return resultPresent != 0; } bool hasResult() const { return resultPresent != 0; }
bool hasType() const { return typePresent != 0; } bool hasType() const { return typePresent != 0; }
const char* opDesc; const char* opDesc;
EnumCaps capabilities; EnumCaps capabilities;
OpcodeClass opClass; OpcodeClass opClass;
OperandParameters operands; OperandParameters operands;
protected: protected:
int typePresent : 1; int typePresent : 1;
int resultPresent : 1; int resultPresent : 1;
}; };
const int OpcodeCeiling = 267; const int OpcodeCeiling = 267;
// The set of objects that hold all the instruction/operand // The set of objects that hold all the instruction/operand
// parameterization information. // parameterization information.
extern InstructionParameters InstructionDesc[]; extern InstructionParameters InstructionDesc[];
// These hold definitions of the enumerants used for operands // These hold definitions of the enumerants used for operands
extern EnumDefinition OperandClassParams[]; extern EnumDefinition OperandClassParams[];
const char* GetOperandDesc(OperandClass operand); const char* GetOperandDesc(OperandClass operand);
void PrintImmediateRow(int imm, const char* name, const EnumParameters* enumParams, bool caps, bool hex = false); void PrintImmediateRow(int imm, const char* name, const EnumParameters* enumParams, bool caps, bool hex = false);
const char* AccessQualifierString(int attr); const char* AccessQualifierString(int attr);
void PrintOperands(const OperandParameters& operands, int reservedOperands); void PrintOperands(const OperandParameters& operands, int reservedOperands);
}; // end namespace spv }; // end namespace spv

File diff suppressed because it is too large Load Diff

View File

@ -1,369 +1,369 @@
// //
//Copyright (C) 2014 LunarG, Inc. //Copyright (C) 2014 LunarG, Inc.
// //
//All rights reserved. //All rights reserved.
// //
//Redistribution and use in source and binary forms, with or without //Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions //modification, are permitted provided that the following conditions
//are met: //are met:
// //
// Redistributions of source code must retain the above copyright // Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer. // notice, this list of conditions and the following disclaimer.
// //
// Redistributions in binary form must reproduce the above // Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following // copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided // disclaimer in the documentation and/or other materials provided
// with the distribution. // with the distribution.
// //
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
// contributors may be used to endorse or promote products derived // contributors may be used to endorse or promote products derived
// from this software without specific prior written permission. // from this software without specific prior written permission.
// //
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//POSSIBILITY OF SUCH DAMAGE. //POSSIBILITY OF SUCH DAMAGE.
// //
// Author: John Kessenich, LunarG // Author: John Kessenich, LunarG
// //
// SPIRV-IR // SPIRV-IR
// //
// Simple in-memory representation (IR) of SPIRV. Just for holding // Simple in-memory representation (IR) of SPIRV. Just for holding
// Each function's CFG of blocks. Has this hierarchy: // Each function's CFG of blocks. Has this hierarchy:
// - Module, which is a list of // - Module, which is a list of
// - Function, which is a list of // - Function, which is a list of
// - Block, which is a list of // - Block, which is a list of
// - Instruction // - Instruction
// //
#pragma once #pragma once
#ifndef spvIR_H #ifndef spvIR_H
#define spvIR_H #define spvIR_H
#include "spirv.h" #include "spirv.h"
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include <assert.h> #include <assert.h>
namespace spv { namespace spv {
class Function; class Function;
class Module; class Module;
const Id NoResult = 0; const Id NoResult = 0;
const Id NoType = 0; const Id NoType = 0;
const unsigned int BadValue = 0xFFFFFFFF; const unsigned int BadValue = 0xFFFFFFFF;
const Decoration NoPrecision = (Decoration)BadValue; const Decoration NoPrecision = (Decoration)BadValue;
const MemorySemanticsMask MemorySemanticsAllMemory = (MemorySemanticsMask)0x3FF; const MemorySemanticsMask MemorySemanticsAllMemory = (MemorySemanticsMask)0x3FF;
// //
// SPIR-V IR instruction. // SPIR-V IR instruction.
// //
class Instruction { class Instruction {
public: public:
Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode), string(0) { } Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode), string(0) { }
explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), string(0) { } explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), string(0) { }
virtual ~Instruction() virtual ~Instruction()
{ {
delete string; delete string;
} }
void addIdOperand(Id id) { operands.push_back(id); } void addIdOperand(Id id) { operands.push_back(id); }
void addImmediateOperand(unsigned int immediate) { operands.push_back(immediate); } void addImmediateOperand(unsigned int immediate) { operands.push_back(immediate); }
void addStringOperand(const char* str) void addStringOperand(const char* str)
{ {
originalString = str; originalString = str;
string = new std::vector<unsigned int>; string = new std::vector<unsigned int>;
unsigned int word; unsigned int word;
char* wordString = (char*)&word; char* wordString = (char*)&word;
char* wordPtr = wordString; char* wordPtr = wordString;
int charCount = 0; int charCount = 0;
char c; char c;
do { do {
c = *(str++); c = *(str++);
*(wordPtr++) = c; *(wordPtr++) = c;
++charCount; ++charCount;
if (charCount == 4) { if (charCount == 4) {
string->push_back(word); string->push_back(word);
wordPtr = wordString; wordPtr = wordString;
charCount = 0; charCount = 0;
} }
} while (c != 0); } while (c != 0);
// deal with partial last word // deal with partial last word
if (charCount > 0) { if (charCount > 0) {
// pad with 0s // pad with 0s
for (; charCount < 4; ++charCount) for (; charCount < 4; ++charCount)
*(wordPtr++) = 0; *(wordPtr++) = 0;
string->push_back(word); string->push_back(word);
} }
} }
Op getOpCode() const { return opCode; } Op getOpCode() const { return opCode; }
int getNumOperands() const { return (int)operands.size(); } int getNumOperands() const { return (int)operands.size(); }
Id getResultId() const { return resultId; } Id getResultId() const { return resultId; }
Id getTypeId() const { return typeId; } Id getTypeId() const { return typeId; }
Id getIdOperand(int op) const { return operands[op]; } Id getIdOperand(int op) const { return operands[op]; }
unsigned int getImmediateOperand(int op) const { return operands[op]; } unsigned int getImmediateOperand(int op) const { return operands[op]; }
const char* getStringOperand() const { return originalString.c_str(); } const char* getStringOperand() const { return originalString.c_str(); }
// Write out the binary form. // Write out the binary form.
void dump(std::vector<unsigned int>& out) const void dump(std::vector<unsigned int>& out) const
{ {
// Compute the wordCount // Compute the wordCount
unsigned int wordCount = 1; unsigned int wordCount = 1;
if (typeId) if (typeId)
++wordCount; ++wordCount;
if (resultId) if (resultId)
++wordCount; ++wordCount;
wordCount += (unsigned int)operands.size(); wordCount += (unsigned int)operands.size();
if (string) if (string)
wordCount += (unsigned int)string->size(); wordCount += (unsigned int)string->size();
// Write out the beginning of the instruction // Write out the beginning of the instruction
out.push_back(((wordCount) << WordCountShift) | opCode); out.push_back(((wordCount) << WordCountShift) | opCode);
if (typeId) if (typeId)
out.push_back(typeId); out.push_back(typeId);
if (resultId) if (resultId)
out.push_back(resultId); out.push_back(resultId);
// Write out the operands // Write out the operands
for (int op = 0; op < (int)operands.size(); ++op) for (int op = 0; op < (int)operands.size(); ++op)
out.push_back(operands[op]); out.push_back(operands[op]);
if (string) if (string)
for (int op = 0; op < (int)string->size(); ++op) for (int op = 0; op < (int)string->size(); ++op)
out.push_back((*string)[op]); out.push_back((*string)[op]);
} }
protected: protected:
Instruction(const Instruction&); Instruction(const Instruction&);
Id resultId; Id resultId;
Id typeId; Id typeId;
Op opCode; Op opCode;
std::vector<Id> operands; std::vector<Id> operands;
std::vector<unsigned int>* string; // usually non-existent std::vector<unsigned int>* string; // usually non-existent
std::string originalString; // could be optimized away; convenience for getting string operand std::string originalString; // could be optimized away; convenience for getting string operand
}; };
// //
// SPIR-V IR block. // SPIR-V IR block.
// //
class Block { class Block {
public: public:
Block(Id id, Function& parent); Block(Id id, Function& parent);
virtual ~Block() virtual ~Block()
{ {
// TODO: free instructions // TODO: free instructions
} }
Id getId() { return instructions.front()->getResultId(); } Id getId() { return instructions.front()->getResultId(); }
Function& getParent() const { return parent; } Function& getParent() const { return parent; }
void addInstruction(Instruction* inst); void addInstruction(Instruction* inst);
void addPredecessor(Block* pred) { predecessors.push_back(pred); } void addPredecessor(Block* pred) { predecessors.push_back(pred); }
void addLocalVariable(Instruction* inst) { localVariables.push_back(inst); } void addLocalVariable(Instruction* inst) { localVariables.push_back(inst); }
int getNumPredecessors() const { return (int)predecessors.size(); } int getNumPredecessors() const { return (int)predecessors.size(); }
void setUnreachable() { unreachable = true; } void setUnreachable() { unreachable = true; }
bool isUnreachable() const { return unreachable; } bool isUnreachable() const { return unreachable; }
bool isTerminated() const bool isTerminated() const
{ {
switch (instructions.back()->getOpCode()) { switch (instructions.back()->getOpCode()) {
case OpBranch: case OpBranch:
case OpBranchConditional: case OpBranchConditional:
case OpSwitch: case OpSwitch:
case OpKill: case OpKill:
case OpReturn: case OpReturn:
case OpReturnValue: case OpReturnValue:
return true; return true;
default: default:
return false; return false;
} }
} }
void dump(std::vector<unsigned int>& out) const void dump(std::vector<unsigned int>& out) const
{ {
// skip the degenerate unreachable blocks // skip the degenerate unreachable blocks
// TODO: code gen: skip all unreachable blocks (transitive closure) // TODO: code gen: skip all unreachable blocks (transitive closure)
// (but, until that's done safer to keep non-degenerate unreachable blocks, in case others depend on something) // (but, until that's done safer to keep non-degenerate unreachable blocks, in case others depend on something)
if (unreachable && instructions.size() <= 2) if (unreachable && instructions.size() <= 2)
return; return;
instructions[0]->dump(out); instructions[0]->dump(out);
for (int i = 0; i < (int)localVariables.size(); ++i) for (int i = 0; i < (int)localVariables.size(); ++i)
localVariables[i]->dump(out); localVariables[i]->dump(out);
for (int i = 1; i < (int)instructions.size(); ++i) for (int i = 1; i < (int)instructions.size(); ++i)
instructions[i]->dump(out); instructions[i]->dump(out);
} }
protected: protected:
Block(const Block&); Block(const Block&);
Block& operator=(Block&); Block& operator=(Block&);
// To enforce keeping parent and ownership in sync: // To enforce keeping parent and ownership in sync:
friend Function; friend Function;
std::vector<Instruction*> instructions; std::vector<Instruction*> instructions;
std::vector<Block*> predecessors; std::vector<Block*> predecessors;
std::vector<Instruction*> localVariables; std::vector<Instruction*> localVariables;
Function& parent; Function& parent;
// track whether this block is known to be uncreachable (not necessarily // track whether this block is known to be uncreachable (not necessarily
// true for all unreachable blocks, but should be set at least // true for all unreachable blocks, but should be set at least
// for the extraneous ones introduced by the builder). // for the extraneous ones introduced by the builder).
bool unreachable; bool unreachable;
}; };
// //
// SPIR-V IR Function. // SPIR-V IR Function.
// //
class Function { class Function {
public: public:
Function(Id id, Id resultType, Id functionType, Id firstParam, Module& parent); Function(Id id, Id resultType, Id functionType, Id firstParam, Module& parent);
virtual ~Function() virtual ~Function()
{ {
for (int i = 0; i < (int)parameterInstructions.size(); ++i) for (int i = 0; i < (int)parameterInstructions.size(); ++i)
delete parameterInstructions[i]; delete parameterInstructions[i];
for (int i = 0; i < (int)blocks.size(); ++i) for (int i = 0; i < (int)blocks.size(); ++i)
delete blocks[i]; delete blocks[i];
} }
Id getId() const { return functionInstruction.getResultId(); } Id getId() const { return functionInstruction.getResultId(); }
Id getParamId(int p) { return parameterInstructions[p]->getResultId(); } Id getParamId(int p) { return parameterInstructions[p]->getResultId(); }
void addBlock(Block* block) { blocks.push_back(block); } void addBlock(Block* block) { blocks.push_back(block); }
void popBlock(Block*) { blocks.pop_back(); } void popBlock(Block*) { blocks.pop_back(); }
Module& getParent() const { return parent; } Module& getParent() const { return parent; }
Block* getEntryBlock() const { return blocks.front(); } Block* getEntryBlock() const { return blocks.front(); }
Block* getLastBlock() const { return blocks.back(); } Block* getLastBlock() const { return blocks.back(); }
void addLocalVariable(Instruction* inst); void addLocalVariable(Instruction* inst);
Id getReturnType() const { return functionInstruction.getTypeId(); } Id getReturnType() const { return functionInstruction.getTypeId(); }
void dump(std::vector<unsigned int>& out) const void dump(std::vector<unsigned int>& out) const
{ {
// OpFunction // OpFunction
functionInstruction.dump(out); functionInstruction.dump(out);
// OpFunctionParameter // OpFunctionParameter
for (int p = 0; p < (int)parameterInstructions.size(); ++p) for (int p = 0; p < (int)parameterInstructions.size(); ++p)
parameterInstructions[p]->dump(out); parameterInstructions[p]->dump(out);
// Blocks // Blocks
for (int b = 0; b < (int)blocks.size(); ++b) for (int b = 0; b < (int)blocks.size(); ++b)
blocks[b]->dump(out); blocks[b]->dump(out);
Instruction end(0, 0, OpFunctionEnd); Instruction end(0, 0, OpFunctionEnd);
end.dump(out); end.dump(out);
} }
protected: protected:
Function(const Function&); Function(const Function&);
Function& operator=(Function&); Function& operator=(Function&);
Module& parent; Module& parent;
Instruction functionInstruction; Instruction functionInstruction;
std::vector<Instruction*> parameterInstructions; std::vector<Instruction*> parameterInstructions;
std::vector<Block*> blocks; std::vector<Block*> blocks;
}; };
// //
// SPIR-V IR Module. // SPIR-V IR Module.
// //
class Module { class Module {
public: public:
Module() {} Module() {}
virtual ~Module() virtual ~Module()
{ {
// TODO delete things // TODO delete things
} }
void addFunction(Function *fun) { functions.push_back(fun); } void addFunction(Function *fun) { functions.push_back(fun); }
void mapInstruction(Instruction *instruction) void mapInstruction(Instruction *instruction)
{ {
spv::Id resultId = instruction->getResultId(); spv::Id resultId = instruction->getResultId();
// map the instruction's result id // map the instruction's result id
if (resultId >= idToInstruction.size()) if (resultId >= idToInstruction.size())
idToInstruction.resize(resultId + 16); idToInstruction.resize(resultId + 16);
idToInstruction[resultId] = instruction; idToInstruction[resultId] = instruction;
} }
Instruction* getInstruction(Id id) const { return idToInstruction[id]; } Instruction* getInstruction(Id id) const { return idToInstruction[id]; }
spv::Id getTypeId(Id resultId) const { return idToInstruction[resultId]->getTypeId(); } spv::Id getTypeId(Id resultId) const { return idToInstruction[resultId]->getTypeId(); }
StorageClass getStorageClass(Id typeId) const { return (StorageClass)idToInstruction[typeId]->getImmediateOperand(0); } StorageClass getStorageClass(Id typeId) const { return (StorageClass)idToInstruction[typeId]->getImmediateOperand(0); }
void dump(std::vector<unsigned int>& out) const void dump(std::vector<unsigned int>& out) const
{ {
for (int f = 0; f < (int)functions.size(); ++f) for (int f = 0; f < (int)functions.size(); ++f)
functions[f]->dump(out); functions[f]->dump(out);
} }
protected: protected:
Module(const Module&); Module(const Module&);
std::vector<Function*> functions; std::vector<Function*> functions;
// map from result id to instruction having that result id // map from result id to instruction having that result id
std::vector<Instruction*> idToInstruction; std::vector<Instruction*> idToInstruction;
// map from a result id to its type id // map from a result id to its type id
}; };
// //
// Implementation (it's here due to circular type definitions). // Implementation (it's here due to circular type definitions).
// //
// Add both // Add both
// - the OpFunction instruction // - the OpFunction instruction
// - all the OpFunctionParameter instructions // - all the OpFunctionParameter instructions
__inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent) __inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent)
: parent(parent), functionInstruction(id, resultType, OpFunction) : parent(parent), functionInstruction(id, resultType, OpFunction)
{ {
// OpFunction // OpFunction
functionInstruction.addImmediateOperand(FunctionControlMaskNone); functionInstruction.addImmediateOperand(FunctionControlMaskNone);
functionInstruction.addIdOperand(functionType); functionInstruction.addIdOperand(functionType);
parent.mapInstruction(&functionInstruction); parent.mapInstruction(&functionInstruction);
parent.addFunction(this); parent.addFunction(this);
// OpFunctionParameter // OpFunctionParameter
Instruction* typeInst = parent.getInstruction(functionType); Instruction* typeInst = parent.getInstruction(functionType);
int numParams = typeInst->getNumOperands() - 1; int numParams = typeInst->getNumOperands() - 1;
for (int p = 0; p < numParams; ++p) { for (int p = 0; p < numParams; ++p) {
Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), OpFunctionParameter); Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), OpFunctionParameter);
parent.mapInstruction(param); parent.mapInstruction(param);
parameterInstructions.push_back(param); parameterInstructions.push_back(param);
} }
} }
__inline void Function::addLocalVariable(Instruction* inst) __inline void Function::addLocalVariable(Instruction* inst)
{ {
blocks[0]->addLocalVariable(inst); blocks[0]->addLocalVariable(inst);
parent.mapInstruction(inst); parent.mapInstruction(inst);
} }
__inline Block::Block(Id id, Function& parent) : parent(parent), unreachable(false) __inline Block::Block(Id id, Function& parent) : parent(parent), unreachable(false)
{ {
instructions.push_back(new Instruction(id, NoType, OpLabel)); instructions.push_back(new Instruction(id, NoType, OpLabel));
} }
__inline void Block::addInstruction(Instruction* inst) __inline void Block::addInstruction(Instruction* inst)
{ {
instructions.push_back(inst); instructions.push_back(inst);
if (inst->getResultId()) if (inst->getResultId())
parent.getParent().mapInstruction(inst); parent.getParent().mapInstruction(inst);
} }
}; // end spv namespace }; // end spv namespace
#endif // spvIR_H #endif // spvIR_H

View File

@ -1,41 +1,41 @@
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)
include_directories(.) include_directories(.)
if(WIN32) if(WIN32)
include_directories(../glslang/OSDependent/Windows) include_directories(../glslang/OSDependent/Windows)
elseif(UNIX) elseif(UNIX)
include_directories(../glslang/OSDependent/Linux) include_directories(../glslang/OSDependent/Linux)
else(WIN32) else(WIN32)
message("unkown platform") message("unkown platform")
endif(WIN32) endif(WIN32)
set(SOURCES StandAlone.cpp) set(SOURCES StandAlone.cpp)
set(REMAPPER_SOURCES spirv-remap.cpp) set(REMAPPER_SOURCES spirv-remap.cpp)
add_executable(glslangValidator ${SOURCES}) add_executable(glslangValidator ${SOURCES})
add_executable(spirv-remap ${REMAPPER_SOURCES}) add_executable(spirv-remap ${REMAPPER_SOURCES})
set(LIBRARIES set(LIBRARIES
glslang glslang
OGLCompiler OGLCompiler
OSDependent OSDependent
SPIRV) SPIRV)
if(WIN32) if(WIN32)
set(LIBRARIES ${LIBRARIES} psapi) set(LIBRARIES ${LIBRARIES} psapi)
elseif(UNIX) elseif(UNIX)
set(LIBRARIES ${LIBRARIES} pthread) set(LIBRARIES ${LIBRARIES} pthread)
endif(WIN32) endif(WIN32)
target_link_libraries(glslangValidator ${LIBRARIES}) target_link_libraries(glslangValidator ${LIBRARIES})
target_link_libraries(spirv-remap ${LIBRARIES}) target_link_libraries(spirv-remap ${LIBRARIES})
if(WIN32) if(WIN32)
source_group("Source" FILES ${SOURCES}) source_group("Source" FILES ${SOURCES})
endif(WIN32) endif(WIN32)
install(TARGETS glslangValidator install(TARGETS glslangValidator
RUNTIME DESTINATION bin) RUNTIME DESTINATION bin)
install(TARGETS spirv-remap install(TARGETS spirv-remap
RUNTIME DESTINATION bin) RUNTIME DESTINATION bin)

View File

@ -1,337 +1,337 @@
// //
//Copyright (C) 2015 LunarG, Inc. //Copyright (C) 2015 LunarG, Inc.
// //
//All rights reserved. //All rights reserved.
// //
//Redistribution and use in source and binary forms, with or without //Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions //modification, are permitted provided that the following conditions
//are met: //are met:
// //
// Redistributions of source code must retain the above copyright // Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer. // notice, this list of conditions and the following disclaimer.
// //
// Redistributions in binary form must reproduce the above // Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following // copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided // disclaimer in the documentation and/or other materials provided
// with the distribution. // with the distribution.
// //
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
// contributors may be used to endorse or promote products derived // contributors may be used to endorse or promote products derived
// from this software without specific prior written permission. // from this software without specific prior written permission.
// //
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//POSSIBILITY OF SUCH DAMAGE. //POSSIBILITY OF SUCH DAMAGE.
// //
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <cstring> #include <cstring>
#include <stdexcept> #include <stdexcept>
#include "../SPIRV/SPVRemapper.h" #include "../SPIRV/SPVRemapper.h"
namespace { namespace {
typedef unsigned int SpvWord; typedef unsigned int SpvWord;
// Poor man's basename: given a complete path, return file portion. // Poor man's basename: given a complete path, return file portion.
// E.g: // E.g:
// Linux: /foo/bar/test -> test // Linux: /foo/bar/test -> test
// Win: c:\foo\bar\test -> test // Win: c:\foo\bar\test -> test
// It's not very efficient, but that doesn't matter for our minimal-duty use. // It's not very efficient, but that doesn't matter for our minimal-duty use.
// Using boost::filesystem would be better in many ways, but want to avoid that dependency. // Using boost::filesystem would be better in many ways, but want to avoid that dependency.
// OS dependent path separator (avoiding boost::filesystem dependency) // OS dependent path separator (avoiding boost::filesystem dependency)
#if defined(_WIN32) #if defined(_WIN32)
char path_sep_char() { return '\\'; } char path_sep_char() { return '\\'; }
#else #else
char path_sep_char() { return '/'; } char path_sep_char() { return '/'; }
#endif #endif
std::string basename(const std::string filename) std::string basename(const std::string filename)
{ {
const size_t sepLoc = filename.find_last_of(path_sep_char()); const size_t sepLoc = filename.find_last_of(path_sep_char());
return (sepLoc == filename.npos) ? filename : filename.substr(sepLoc+1); return (sepLoc == filename.npos) ? filename : filename.substr(sepLoc+1);
} }
void errHandler(const std::string& str) { void errHandler(const std::string& str) {
std::cout << str << std::endl; std::cout << str << std::endl;
exit(5); exit(5);
} }
void logHandler(const std::string& str) { void logHandler(const std::string& str) {
std::cout << str << std::endl; std::cout << str << std::endl;
} }
// Read word stream from disk // Read word stream from disk
void read(std::vector<SpvWord>& spv, const std::string& inFilename, int verbosity) void read(std::vector<SpvWord>& spv, const std::string& inFilename, int verbosity)
{ {
std::ifstream fp; std::ifstream fp;
if (verbosity > 0) if (verbosity > 0)
logHandler(std::string(" reading: ") + inFilename); logHandler(std::string(" reading: ") + inFilename);
spv.clear(); spv.clear();
fp.open(inFilename, std::fstream::in | std::fstream::binary); fp.open(inFilename, std::fstream::in | std::fstream::binary);
if (fp.fail()) if (fp.fail())
errHandler("error opening file for read: "); errHandler("error opening file for read: ");
// Reserve space (for efficiency, not for correctness) // Reserve space (for efficiency, not for correctness)
fp.seekg(0, fp.end); fp.seekg(0, fp.end);
spv.reserve(size_t(fp.tellg()) / sizeof(SpvWord)); spv.reserve(size_t(fp.tellg()) / sizeof(SpvWord));
fp.seekg(0, fp.beg); fp.seekg(0, fp.beg);
while (!fp.eof()) { while (!fp.eof()) {
SpvWord inWord; SpvWord inWord;
fp.read((char *)&inWord, sizeof(inWord)); fp.read((char *)&inWord, sizeof(inWord));
if (!fp.eof()) { if (!fp.eof()) {
spv.push_back(inWord); spv.push_back(inWord);
if (fp.fail()) if (fp.fail())
errHandler(std::string("error reading file: ") + inFilename); errHandler(std::string("error reading file: ") + inFilename);
} }
} }
} }
void write(std::vector<SpvWord>& spv, const std::string& outFile, int verbosity) void write(std::vector<SpvWord>& spv, const std::string& outFile, int verbosity)
{ {
if (outFile.empty()) if (outFile.empty())
errHandler("missing output filename."); errHandler("missing output filename.");
std::ofstream fp; std::ofstream fp;
if (verbosity > 0) if (verbosity > 0)
logHandler(std::string(" writing: ") + outFile); logHandler(std::string(" writing: ") + outFile);
fp.open(outFile, std::fstream::out | std::fstream::binary); fp.open(outFile, std::fstream::out | std::fstream::binary);
if (fp.fail()) if (fp.fail())
errHandler(std::string("error opening file for write: ") + outFile); errHandler(std::string("error opening file for write: ") + outFile);
for (auto word : spv) { for (auto word : spv) {
fp.write((char *)&word, sizeof(word)); fp.write((char *)&word, sizeof(word));
if (fp.fail()) if (fp.fail())
errHandler(std::string("error writing file: ") + outFile); errHandler(std::string("error writing file: ") + outFile);
} }
// file is closed by destructor // file is closed by destructor
} }
// Print helpful usage message to stdout, and exit // Print helpful usage message to stdout, and exit
void usage(const char* const name, const char* const msg = 0) void usage(const char* const name, const char* const msg = 0)
{ {
if (msg) if (msg)
std::cout << msg << std::endl << std::endl; std::cout << msg << std::endl << std::endl;
std::cout << "Usage: " << std::endl; std::cout << "Usage: " << std::endl;
std::cout << " " << basename(name) std::cout << " " << basename(name)
<< " [-v[v[...]] | --verbose [int]]" << " [-v[v[...]] | --verbose [int]]"
<< " [--map (all|types|names|funcs)]" << " [--map (all|types|names|funcs)]"
<< " [--dce (all|types|funcs)]" << " [--dce (all|types|funcs)]"
<< " [--opt (all|loadstore)]" << " [--opt (all|loadstore)]"
<< " [--strip-all | --strip all | -s]" << " [--strip-all | --strip all | -s]"
<< " [--do-everything]" << " [--do-everything]"
<< " --input | -i file1 [file2...] --output|-o DESTDIR" << " --input | -i file1 [file2...] --output|-o DESTDIR"
<< std::endl; << std::endl;
std::cout << " " << basename(name) << " [--version | -V]" << std::endl; std::cout << " " << basename(name) << " [--version | -V]" << std::endl;
std::cout << " " << basename(name) << " [--help | -?]" << std::endl; std::cout << " " << basename(name) << " [--help | -?]" << std::endl;
exit(5); exit(5);
} }
// grind through each SPIR in turn // grind through each SPIR in turn
void execute(const std::vector<std::string>& inputFile, const std::string& outputDir, void execute(const std::vector<std::string>& inputFile, const std::string& outputDir,
int opts, int verbosity) int opts, int verbosity)
{ {
for (const auto& filename : inputFile) { for (const auto& filename : inputFile) {
std::vector<SpvWord> spv; std::vector<SpvWord> spv;
read(spv, filename, verbosity); read(spv, filename, verbosity);
spv::spirvbin_t(verbosity).remap(spv, opts); spv::spirvbin_t(verbosity).remap(spv, opts);
const std::string outfile = outputDir + path_sep_char() + basename(filename); const std::string outfile = outputDir + path_sep_char() + basename(filename);
write(spv, outfile, verbosity); write(spv, outfile, verbosity);
} }
if (verbosity > 0) if (verbosity > 0)
std::cout << "Done: " << inputFile.size() << " file(s) processed" << std::endl; std::cout << "Done: " << inputFile.size() << " file(s) processed" << std::endl;
} }
// Parse command line options // Parse command line options
void parseCmdLine(int argc, char** argv, std::vector<std::string>& inputFile, void parseCmdLine(int argc, char** argv, std::vector<std::string>& inputFile,
std::string& outputDir, std::string& outputDir,
int& options, int& options,
int& verbosity) int& verbosity)
{ {
if (argc < 2) if (argc < 2)
usage(argv[0]); usage(argv[0]);
verbosity = 0; verbosity = 0;
options = spv::spirvbin_t::NONE; options = spv::spirvbin_t::NONE;
// Parse command line. // Parse command line.
// boost::program_options would be quite a bit nicer, but we don't want to // boost::program_options would be quite a bit nicer, but we don't want to
// introduce a dependency on boost. // introduce a dependency on boost.
for (int a=1; a<argc; ) { for (int a=1; a<argc; ) {
const std::string arg = argv[a]; const std::string arg = argv[a];
if (arg == "--output" || arg == "-o") { if (arg == "--output" || arg == "-o") {
// Output directory // Output directory
if (++a >= argc) if (++a >= argc)
usage(argv[0], "--output requires an argument"); usage(argv[0], "--output requires an argument");
if (!outputDir.empty()) if (!outputDir.empty())
usage(argv[0], "--output can be provided only once"); usage(argv[0], "--output can be provided only once");
outputDir = argv[a++]; outputDir = argv[a++];
// Remove trailing directory separator characters // Remove trailing directory separator characters
while (!outputDir.empty() && outputDir.back() == path_sep_char()) while (!outputDir.empty() && outputDir.back() == path_sep_char())
outputDir.pop_back(); outputDir.pop_back();
} }
else if (arg == "-vv") { verbosity = 2; ++a; } // verbosity shortcuts else if (arg == "-vv") { verbosity = 2; ++a; } // verbosity shortcuts
else if (arg == "-vvv") { verbosity = 3; ++a; } // ... else if (arg == "-vvv") { verbosity = 3; ++a; } // ...
else if (arg == "-vvvv") { verbosity = 4; ++a; } // ... else if (arg == "-vvvv") { verbosity = 4; ++a; } // ...
else if (arg == "-vvvvv") { verbosity = 5; ++a; } // ... else if (arg == "-vvvvv") { verbosity = 5; ++a; } // ...
else if (arg == "--verbose" || arg == "-v") { else if (arg == "--verbose" || arg == "-v") {
++a; ++a;
verbosity = 1; verbosity = 1;
if (a < argc) { if (a < argc) {
try { try {
verbosity = std::stoi(argv[a]); verbosity = std::stoi(argv[a]);
++a; ++a;
} catch (const std::invalid_argument&) { } // ok to have no numeric value } catch (const std::invalid_argument&) { } // ok to have no numeric value
} }
} }
else if (arg == "--version" || arg == "-V") { else if (arg == "--version" || arg == "-V") {
std::cout << basename(argv[0]) << " version 0.97 " << __DATE__ << " " << __TIME__ << std::endl; std::cout << basename(argv[0]) << " version 0.97 " << __DATE__ << " " << __TIME__ << std::endl;
exit(0); exit(0);
} else if (arg == "--input" || arg == "-i") { } else if (arg == "--input" || arg == "-i") {
// Collect input files // Collect input files
for (++a; a < argc && argv[a][0] != '-'; ++a) for (++a; a < argc && argv[a][0] != '-'; ++a)
inputFile.push_back(argv[a]); inputFile.push_back(argv[a]);
} else if (arg == "--do-everything") { } else if (arg == "--do-everything") {
++a; ++a;
options = options | spv::spirvbin_t::DO_EVERYTHING; options = options | spv::spirvbin_t::DO_EVERYTHING;
} else if (arg == "--strip-all" || arg == "-s") { } else if (arg == "--strip-all" || arg == "-s") {
++a; ++a;
options = options | spv::spirvbin_t::STRIP; options = options | spv::spirvbin_t::STRIP;
} else if (arg == "--strip") { } else if (arg == "--strip") {
++a; ++a;
if (strncmp(argv[a], "all", 3) == 0) { if (strncmp(argv[a], "all", 3) == 0) {
options = options | spv::spirvbin_t::STRIP; options = options | spv::spirvbin_t::STRIP;
++a; ++a;
} }
} else if (arg == "--dce") { } else if (arg == "--dce") {
// Parse comma (or colon, etc) separated list of things to dce // Parse comma (or colon, etc) separated list of things to dce
++a; ++a;
for (const char* c = argv[a]; *c; ++c) { for (const char* c = argv[a]; *c; ++c) {
if (strncmp(c, "all", 3) == 0) { if (strncmp(c, "all", 3) == 0) {
options = (options | spv::spirvbin_t::DCE_ALL); options = (options | spv::spirvbin_t::DCE_ALL);
c += 3; c += 3;
} else if (strncmp(c, "*", 1) == 0) { } else if (strncmp(c, "*", 1) == 0) {
options = (options | spv::spirvbin_t::DCE_ALL); options = (options | spv::spirvbin_t::DCE_ALL);
c += 1; c += 1;
} else if (strncmp(c, "funcs", 5) == 0) { } else if (strncmp(c, "funcs", 5) == 0) {
options = (options | spv::spirvbin_t::DCE_FUNCS); options = (options | spv::spirvbin_t::DCE_FUNCS);
c += 5; c += 5;
} else if (strncmp(c, "types", 5) == 0) { } else if (strncmp(c, "types", 5) == 0) {
options = (options | spv::spirvbin_t::DCE_TYPES); options = (options | spv::spirvbin_t::DCE_TYPES);
c += 5; c += 5;
} }
} }
++a; ++a;
} else if (arg == "--map") { } else if (arg == "--map") {
// Parse comma (or colon, etc) separated list of things to map // Parse comma (or colon, etc) separated list of things to map
++a; ++a;
for (const char* c = argv[a]; *c; ++c) { for (const char* c = argv[a]; *c; ++c) {
if (strncmp(c, "all", 3) == 0) { if (strncmp(c, "all", 3) == 0) {
options = (options | spv::spirvbin_t::MAP_ALL); options = (options | spv::spirvbin_t::MAP_ALL);
c += 3; c += 3;
} else if (strncmp(c, "*", 1) == 0) { } else if (strncmp(c, "*", 1) == 0) {
options = (options | spv::spirvbin_t::MAP_ALL); options = (options | spv::spirvbin_t::MAP_ALL);
c += 1; c += 1;
} else if (strncmp(c, "types", 5) == 0) { } else if (strncmp(c, "types", 5) == 0) {
options = (options | spv::spirvbin_t::MAP_TYPES); options = (options | spv::spirvbin_t::MAP_TYPES);
c += 5; c += 5;
} else if (strncmp(c, "names", 5) == 0) { } else if (strncmp(c, "names", 5) == 0) {
options = (options | spv::spirvbin_t::MAP_NAMES); options = (options | spv::spirvbin_t::MAP_NAMES);
c += 5; c += 5;
} else if (strncmp(c, "funcs", 5) == 0) { } else if (strncmp(c, "funcs", 5) == 0) {
options = (options | spv::spirvbin_t::MAP_FUNCS); options = (options | spv::spirvbin_t::MAP_FUNCS);
c += 5; c += 5;
} }
} }
++a; ++a;
} else if (arg == "--opt") { } else if (arg == "--opt") {
++a; ++a;
for (const char* c = argv[a]; *c; ++c) { for (const char* c = argv[a]; *c; ++c) {
if (strncmp(c, "all", 3) == 0) { if (strncmp(c, "all", 3) == 0) {
options = (options | spv::spirvbin_t::OPT_ALL); options = (options | spv::spirvbin_t::OPT_ALL);
c += 3; c += 3;
} else if (strncmp(c, "*", 1) == 0) { } else if (strncmp(c, "*", 1) == 0) {
options = (options | spv::spirvbin_t::OPT_ALL); options = (options | spv::spirvbin_t::OPT_ALL);
c += 1; c += 1;
} else if (strncmp(c, "loadstore", 9) == 0) { } else if (strncmp(c, "loadstore", 9) == 0) {
options = (options | spv::spirvbin_t::OPT_LOADSTORE); options = (options | spv::spirvbin_t::OPT_LOADSTORE);
c += 9; c += 9;
} }
} }
++a; ++a;
} else if (arg == "--help" || arg == "-?") { } else if (arg == "--help" || arg == "-?") {
usage(argv[0]); usage(argv[0]);
} else { } else {
usage(argv[0], "Unknown command line option"); usage(argv[0], "Unknown command line option");
} }
} }
} }
} // namespace } // namespace
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
std::vector<std::string> inputFile; std::vector<std::string> inputFile;
std::string outputDir; std::string outputDir;
int opts; int opts;
int verbosity; int verbosity;
#ifdef use_cpp11 #ifdef use_cpp11
// handle errors by exiting // handle errors by exiting
spv::spirvbin_t::registerErrorHandler(errHandler); spv::spirvbin_t::registerErrorHandler(errHandler);
// Log messages to std::cout // Log messages to std::cout
spv::spirvbin_t::registerLogHandler(logHandler); spv::spirvbin_t::registerLogHandler(logHandler);
#endif #endif
if (argc < 2) if (argc < 2)
usage(argv[0]); usage(argv[0]);
parseCmdLine(argc, argv, inputFile, outputDir, opts, verbosity); parseCmdLine(argc, argv, inputFile, outputDir, opts, verbosity);
if (outputDir.empty()) if (outputDir.empty())
usage(argv[0], "Output directory required"); usage(argv[0], "Output directory required");
std::string errmsg; std::string errmsg;
// Main operations: read, remap, and write. // Main operations: read, remap, and write.
execute(inputFile, outputDir, opts, verbosity); execute(inputFile, outputDir, opts, verbosity);
// If we get here, everything went OK! Nothing more to be done. // If we get here, everything went OK! Nothing more to be done.
} }