glslangValidator: Add straightforward SPIR-V support (non-optimizing, ~3.x functionality).

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@30032 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
John Kessenich 2015-03-03 17:09:43 +00:00
parent 1899e83369
commit 0df0cdeeeb
19 changed files with 6483 additions and 262 deletions

View File

@ -1,6 +0,0 @@
#pragma once
#ifndef Bil_H
#define Bil_H
#endif // Bil_H

View File

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

View File

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

View File

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

View File

@ -1,14 +0,0 @@
namespace GLSL_STD_450 {
enum Entrypoints {
Round,
Count
};
extern const char* Names[Count];
inline void Initialize()
{
}
}; // end namespace GLSL_STD_450

View File

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

View File

@ -16,4 +16,4 @@ endif(WIN32)
add_subdirectory(glslang)
add_subdirectory(OGLCompilersDLL)
add_subdirectory(StandAlone)
add_subdirectory(BIL)
add_subdirectory(SPIRV)

View File

@ -3,20 +3,20 @@ cmake_minimum_required(VERSION 2.8)
include_directories(.. ${CMAKE_CURRENT_BINARY_DIR})
set(SOURCES
GlslangToBil.cpp
BilBuilder.cpp)
GlslangToSpv.cpp
SpvBuilder.cpp)
set(HEADERS
Bil.h
GlslangToBil.h
BilBuilder.h
Bir.h)
spirv.h
GlslangToSpv.h
SpvBuilder.h
SpvIR.h)
add_library(BIL STATIC ${SOURCES} ${HEADERS})
add_library(SPIRV STATIC ${SOURCES} ${HEADERS})
if(WIN32)
source_group("Source" FILES ${SOURCES} ${HEADERS})
endif(WIN32)
install(TARGETS BIL
install(TARGETS SPIRV
ARCHIVE DESTINATION lib)

212
SPIRV/GLSL450Lib.h Normal file
View File

@ -0,0 +1,212 @@
/*
** Copyright (c) 2014-2015 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
//
// Author: John Kessenich, LunarG
//
namespace GLSL_STD_450 {
enum Entrypoints {
Round,
RoundEven,
Trunc,
Abs,
Sign,
Floor,
Ceil,
Fract,
Radians,
Degrees,
Sin,
Cos,
Tan,
Asin,
Acos,
Atan,
Sinh,
Cosh,
Tanh,
Asinh,
Acosh,
Atanh,
Atan2,
Pow,
Exp,
Log,
Exp2,
Log2,
Sqrt,
InverseSqrt,
Determinant,
MatrixInverse,
Modf, // second argument needs the OpVariable, not an OpLoad
Min,
Max,
Clamp,
Mix,
Step,
SmoothStep,
FloatBitsToInt,
FloatBitsToUint,
IntBitsToFloat,
UintBitsToFloat,
Fma,
Frexp,
Ldexp,
PackSnorm4x8,
PackUnorm4x8,
PackSnorm2x16,
PackUnorm2x16,
PackHalf2x16,
PackDouble2x32,
UnpackSnorm2x16,
UnpackUnorm2x16,
UnpackHalf2x16,
UnpackSnorm4x8,
UnpackUnorm4x8,
UnpackDouble2x32,
Length,
Distance,
Cross,
Normalize,
Ftransform,
FaceForward,
Reflect,
Refract,
UaddCarry,
UsubBorrow,
UmulExtended,
ImulExtended,
BitfieldExtract,
BitfieldInsert,
BitfieldReverse,
BitCount,
FindLSB,
FindMSB,
InterpolateAtCentroid,
InterpolateAtSample,
InterpolateAtOffset,
Count
};
inline void GetDebugNames(const char** names)
{
for (int i = 0; i < Count; ++i)
names[i] = "unknown";
names[Round] = "round";
names[RoundEven] = "roundEven";
names[Trunc] = "trunc";
names[Abs] = "abs";
names[Sign] = "sign";
names[Floor] = "floor";
names[Ceil] = "ceil";
names[Fract] = "fract";
names[Radians] = "radians";
names[Degrees] = "degrees";
names[Sin] = "sin";
names[Cos] = "cos";
names[Tan] = "tan";
names[Asin] = "asin";
names[Acos] = "acos";
names[Atan] = "atan";
names[Sinh] = "sinh";
names[Cosh] = "cosh";
names[Tanh] = "tanh";
names[Asinh] = "asinh";
names[Acosh] = "acosh";
names[Atanh] = "atanh";
names[Atan2] = "atan2";
names[Pow] = "pow";
names[Exp] = "exp";
names[Log] = "log";
names[Exp2] = "exp2";
names[Log2] = "log2";
names[Sqrt] = "sqrt";
names[InverseSqrt] = "inverseSqrt";
names[Determinant] = "determinant";
names[MatrixInverse] = "matrixInverse";
names[Modf] = "modf";
names[Min] = "min";
names[Max] = "max";
names[Clamp] = "clamp";
names[Mix] = "mix";
names[Step] = "step";
names[SmoothStep] = "smoothStep";
names[FloatBitsToInt] = "floatBitsToInt";
names[FloatBitsToUint] = "floatBitsToUint";
names[IntBitsToFloat] = "intBitsToFloat";
names[UintBitsToFloat] = "uintBitsToFloat";
names[Fma] = "fma";
names[Frexp] = "frexp";
names[Ldexp] = "ldexp";
names[PackSnorm4x8] = "packSnorm4x8";
names[PackUnorm4x8] = "packUnorm4x8";
names[PackSnorm2x16] = "packSnorm2x16";
names[PackUnorm2x16] = "packUnorm2x16";
names[PackHalf2x16] = "packHalf2x16";
names[PackDouble2x32] = "packDouble2x32";
names[PackHalf2x16] = "packHalf2x16";
names[UnpackSnorm2x16] = "unpackSnorm2x16";
names[UnpackUnorm2x16] = "unpackUnorm2x16";
names[UnpackHalf2x16] = "unpackHalf2x16";
names[UnpackSnorm4x8] = "unpackSnorm4x8";
names[UnpackUnorm4x8] = "unpackUnorm4x8";
names[UnpackDouble2x32] = "unpackDouble2x32";
names[UnpackHalf2x16] = "unpackHalf2x16";
names[Length] = "length";
names[Distance] = "distance";
names[Cross] = "cross";
names[Normalize] = "normalize";
names[Ftransform] = "ftransform";
names[FaceForward] = "faceForward";
names[Reflect] = "reflect";
names[Refract] = "refract";
names[UaddCarry] = "uaddCarry";
names[UsubBorrow] = "usubBorrow";
names[UmulExtended] = "umulExtended";
names[ImulExtended] = "imulExtended";
names[BitfieldExtract] = "bitfieldExtract";
names[BitfieldInsert] = "bitfieldInsert";
names[BitfieldReverse] = "bitfieldReverse";
names[BitCount] = "bitCount";
names[FindLSB] = "findLSB";
names[FindMSB] = "findMSB";
names[InterpolateAtCentroid] = "interpolateAtCentroid";
names[InterpolateAtSample] = "interpolateAtSample";
names[InterpolateAtOffset] = "interpolateAtOffset";
}
}; // end namespace GLSL_STD_450

2589
SPIRV/GlslangToSpv.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -36,8 +36,7 @@
namespace glslang {
void GlslangToBil(const glslang::TIntermediate& intermediate, std::vector<unsigned int> bil);
void OutputBil(const std::vector<unsigned int>& bil, const char* baseName);
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv);
void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName);
};

2011
SPIRV/SpvBuilder.cpp Normal file

File diff suppressed because it is too large Load Diff

519
SPIRV/SpvBuilder.h Normal file
View File

@ -0,0 +1,519 @@
//
//Copyright (C) 2014 LunarG, Inc.
//
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions
//are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//POSSIBILITY OF SUCH DAMAGE.
//
// Author: John Kessenich, LunarG
//
//
// "Builder" is an interface to fully build SPIR-V IR. Allocate one of
// these to build (a thread safe) internal SPIR-V representation (IR),
// and then dump it as a binary stream according to the SPIR-V specification.
//
// A Builder has a 1:1 relationship with a SPIR-V module.
//
#pragma once
#ifndef SpvBuilder_H
#define SpvBuilder_H
#include "spirv.h"
#include "spvIR.h"
#include <algorithm>
#include <stack>
#include <map>
namespace spv {
class Builder {
public:
Builder(unsigned int userNumber);
virtual ~Builder();
static const int maxMatrixSize = 4;
void setSource(spv::SourceLanguage lang, int version)
{
source = lang;
sourceVersion = version;
}
void addSourceExtension(const char* ext) { extensions.push_back(ext); }
Id import(const char*);
void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
{
addressModel = addr;
memoryModel = mem;
}
// To get a new <id> for anything needing a new one.
Id getUniqueId() { return ++uniqueId; }
// To get a set of new <id>s, e.g., for a set of function parameters
Id getUniqueIds(int numIds)
{
Id id = uniqueId + 1;
uniqueId += numIds;
return id;
}
// For creating new types (will return old type if the requested one was already made).
Id makeVoidType();
Id makeBoolType();
Id makePointer(StorageClass, Id type);
Id makeIntegerType(int width, bool hasSign); // generic
Id makeIntType(int width) { return makeIntegerType(width, true); }
Id makeUintType(int width) { return makeIntegerType(width, false); }
Id makeFloatType(int width);
Id makeStructType(std::vector<Id>& members, const char*);
Id makeVectorType(Id component, int size);
Id makeMatrixType(Id component, int cols, int rows);
Id makeArrayType(Id element, unsigned size);
Id makeFunctionType(Id returnType, std::vector<Id>& paramTypes);
enum samplerContent {
samplerContentTexture,
samplerContentImage,
samplerContentTextureFilter
};
Id makeSampler(Id sampledType, Dimensionality, samplerContent, bool arrayed, bool shadow, bool ms);
// For querying about types.
Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
Id getDerefTypeId(Id resultId) const;
OpCode getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
OpCode getTypeClass(Id typeId) const { return getOpCode(typeId); }
OpCode getMostBasicTypeClass(Id typeId) const;
int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
int getNumTypeComponents(Id typeId) const;
Id getScalarTypeId(Id typeId) const;
Id getContainedTypeId(Id typeId) const;
Id getContainedTypeId(Id typeId, int) const;
bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }
bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }
bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); }
bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); }
bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }
bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; }
bool isScalarType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }
bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; }
bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; }
bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; }
bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; }
bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); }
bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
int getTypeNumColumns(Id typeId) const
{
assert(isMatrixType(typeId));
return getNumTypeComponents(typeId);
}
int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
int getTypeNumRows(Id typeId) const
{
assert(isMatrixType(typeId));
return getNumTypeComponents(getContainedTypeId(typeId));
}
int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
Dimensionality getDimensionality(Id resultId) const
{
assert(isSamplerType(getTypeId(resultId)));
return (Dimensionality)module.getInstruction(getTypeId(resultId))->getImmediateOperand(1);
}
bool isArrayedSampler(Id resultId) const
{
assert(isSamplerType(getTypeId(resultId)));
return module.getInstruction(getTypeId(resultId))->getImmediateOperand(3) != 0;
}
// For making new constants (will return old constant if the requested one was already made).
Id makeBoolConstant(bool b);
Id makeIntConstant(Id typeId, unsigned value);
Id makeIntConstant(int i) { return makeIntConstant(makeIntType(32), (unsigned)i); }
Id makeUintConstant(unsigned u) { return makeIntConstant(makeUintType(32), u); }
Id makeFloatConstant(float f);
Id makeDoubleConstant(double d);
// Turn the array of constants into a proper spv constant of the requested type.
Id makeCompositeConstant(Id type, std::vector<Id>& comps);
// Methods for adding information outside the CFG.
void addEntryPoint(ExecutionModel, Function*);
void addExecutionMode(Function*, ExecutionMode mode, int value = -1);
void addName(Id, const char* name);
void addMemberName(Id, int member, const char* name);
void addLine(Id target, Id fileName, int line, int column);
void addDecoration(Id, Decoration, int num = -1);
void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
// At the end of what block do the next create*() instructions go?
void setBuildPoint(Block* bp) { buildPoint = bp; }
Block* getBuildPoint() const { return buildPoint; }
// Make the main function.
Function* makeMain();
// Return from main. Implicit denotes a return at the very end of main.
void makeMainReturn(bool implicit = false) { makeReturn(implicit, 0, true); }
// Close the main function.
void closeMain();
// Make a shader-style function, and create its entry block if entry is non-zero.
// Return the function, pass back the entry.
Function* makeFunctionEntry(Id returnType, const char* name, std::vector<Id>& paramTypes, Block **entry = 0);
// Create a return. Pass whether it is a return form main, and the return
// value (if applicable). In the case of an implicit return, no post-return
// block is inserted.
void makeReturn(bool implicit = false, Id retVal = 0, bool isMain = false);
// Generate all the code needed to finish up a function.
void leaveFunction(bool main);
// Create a discard.
void makeDiscard();
// Create a global or function local or IO variable.
Id createVariable(StorageClass, Id type, const char* name = 0);
// Store into an Id and return the l-value
void createStore(Id rValue, Id lValue);
// Load from an Id and return it
Id createLoad(Id lValue);
// Create an OpAccessChain instruction
Id createAccessChain(StorageClass, Id base, std::vector<Id>& offsets);
// Create an OpCompositeExtract instruction
Id createCompositeExtract(Id composite, Id typeId, unsigned index);
Id createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes);
Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes);
Id createEmptyOp(OpCode);
void createControlBarrier(unsigned executionScope);
void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
Id createUnaryOp(OpCode, Id typeId, Id operand);
Id createBinOp(OpCode, Id typeId, Id operand1, Id operand2);
Id createTriOp(OpCode, Id typeId, Id operand1, Id operand2, Id operand3);
Id createTernaryOp(OpCode, Id typeId, Id operand1, Id operand2, Id operand3);
Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
// Take an rvalue (source) and a set of channels to extract from it to
// make a new rvalue, which is returned.
Id createRvalueSwizzle(Id typeId, Id source, std::vector<unsigned>& channels);
// Take a copy of an lvalue (target) and a source of components, and set the
// source components into the lvalue where the 'channels' say to put them.
// An update version of the target is returned.
// (No true lvalue or stores are used.)
Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels);
// If the value passed in is an instruction and the precision is not EMpNone,
// it gets tagged with the requested precision.
void setPrecision(Id value, Decoration precision)
{
// TODO
}
// Can smear a scalar to a vector for the following forms:
// - promoteScalar(scalar, vector) // smear scalar to width of vector
// - promoteScalar(vector, scalar) // smear scalar to width of vector
// - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
// - promoteScalar(scalar, scalar) // do nothing
// Other forms are not allowed.
//
// Note: One of the arguments will change, with the result coming back that way rather than
// through the return value.
void promoteScalar(Decoration precision, Id& left, Id& right);
// make a value by smearing the scalar to fill the type
Id smearScalar(Decoration precision, Id scalarVal, Id);
// Create a call to a built-in function.
Id createBuiltinCall(Decoration precision, Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);
// List of parameters used to create a texture operation
struct TextureParameters {
Id sampler;
Id coords;
Id bias;
Id lod;
Id Dref;
Id offset;
Id gradX;
Id gradY;
};
// Select the correct texture operation based on all inputs, and emit the correct instruction
Id createTextureCall(Decoration precision, Id resultType, bool proj, const TextureParameters&);
// Emit the OpTextureQuery* instruction that was passed in.
// Figure out the right return value and type, and return it.
Id createTextureQueryCall(OpCode, const TextureParameters&);
Id createSamplePositionCall(Decoration precision, Id, Id);
Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
// Reduction comparision for composites: For equal and not-equal resulting in a scalar.
Id createCompare(Decoration precision, Id, Id, bool /* true if for equal, fales if for not-equal */);
// OpCompositeConstruct
Id createCompositeConstruct(Id typeId, std::vector<Id>& constituents);
// vector or scalar constructor
Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
// matrix constructor
Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
// Helper to use for building nested control flow with if-then-else.
class If {
public:
If(Id condition, Builder& builder);
~If() {}
void makeBeginElse();
void makeEndIf();
private:
Builder& builder;
Id condition;
Function* function;
Block* headerBlock;
Block* thenBlock;
Block* elseBlock;
Block* mergeBlock;
};
// Make a switch statement. A switch has 'numSegments' of pieces of code, not containing
// any case/default labels, all separated by one or more case/default labels. Each possible
// case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this
// number space. How to compute the value is given by 'condition', as in switch(condition).
//
// The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
//
// Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
//
// Returns the right set of basic blocks to start each code segment with, so that the caller's
// recursion stack can hold the memory for it.
//
void makeSwitch(Id condition, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueToSegment, int defaultSegment,
std::vector<Block*>& segmentBB); // return argument
// Add a branch to the innermost switch's merge block.
void addSwitchBreak();
// Move to the next code segment, passing in the return argument in makeSwitch()
void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
// Finish off the innermost switch.
void endSwitch(std::vector<Block*>& segmentBB);
// Start the beginning of a new loop.
void makeNewLoop();
// Add the branch at the end of the loop header, and leave the build position
// in the first block of the body.
// 'condition' is true if should exit the loop
void createLoopHeaderBranch(Id condition);
// Add a back-edge (e.g "continue") for the innermost loop that you're in
void createLoopBackEdge(bool implicit=false);
// Add an exit (e.g. "break") for the innermost loop that you're in
void createLoopExit();
// Close the innermost loop that you're in
void closeLoop();
//
// Access chain design for an R-Value vs. L-Value:
//
// There is a single access chain the builder is building at
// any particular time. Such a chain can be used to either to a load or
// a store, when desired.
//
// Expressions can be r-values, l-values, or both, or only r-values:
// a[b.c].d = .... // l-value
// ... = a[b.c].d; // r-value, that also looks like an l-value
// ++a[b.c].d; // r-value and l-value
// (x + y)[2]; // r-value only, can't possibly be l-value
//
// Computing an r-value means generating code. Hence,
// r-values should only be computed when they are needed, not speculatively.
//
// Computing an l-value means saving away information for later use in the compiler,
// no code is generated until the l-value is later dereferenced. It is okay
// to speculatively generate an l-value, just not okay to speculatively dereference it.
//
// The base of the access chain (the left-most variable or expression
// from which everything is based) can be set either as an l-value
// or as an r-value. Most efficient would be to set an l-value if one
// is available. If an expression was evaluated, the resulting r-value
// can be set as the chain base.
//
// The users of this single access chain can save and restore if they
// want to nest or manage multiple chains.
//
struct AccessChain {
Id base; // for l-values, pointer to the base object, for r-values, the base object
std::vector<Id> indexChain;
Id instr; // the instruction that generates this access chain
std::vector<unsigned> swizzle;
Id component; // a dynamic component index
int swizzleTargetWidth;
Id resultType; // dereferenced type, to be inclusive of swizzles, which can't have a pointer
bool isRValue;
};
//
// the SPIR-V builder maintains a single active chain that
// the following methods operated on
//
// for external save and restore
AccessChain getAccessChain() { return accessChain; }
void setAccessChain(AccessChain newChain) { accessChain = newChain; }
// clear accessChain
void clearAccessChain();
// set new base as an l-value base
void setAccessChainLValue(Id lValue)
{
assert(isPointer(lValue));
accessChain.base = lValue;
}
// set new base value as an r-value
void setAccessChainRValue(Id rValue)
{
accessChain.isRValue = true;
accessChain.base = rValue;
accessChain.resultType = getTypeId(rValue);
}
// push offset onto the end of the chain
void accessChainPush(Id offset, Id newType)
{
accessChain.indexChain.push_back(offset);
accessChain.resultType = newType;
}
// push new swizzle onto the end of any existing swizzle, merging into a single swizzle
void accessChainPushSwizzle(std::vector<unsigned>& swizzle, int width, Id type);
// push a variable component selection onto the access chain; supporting only one, so unsided
void accessChainPushComponent(Id component) { accessChain.component = component; }
// use accessChain and swizzle to store value
void accessChainStore(Id rvalue);
// use accessChain and swizzle to load an r-value
Id accessChainLoad(Decoration precision);
// get the direct pointer for an l-value
Id accessChainGetLValue();
void dump(std::vector<unsigned int>&) const;
protected:
Id findScalarConstant(OpCode typeClass, Id typeId, unsigned value) const;
Id findCompositeConstant(OpCode typeClass, std::vector<Id>& comps) const;
Id collapseAccessChain();
void simplifyAccessChainSwizzle();
void createAndSetNoPredecessorBlock(const char*);
void createBranch(Block* block);
void createMerge(OpCode, Block*, unsigned int control);
void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
void dumpInstructions(std::vector<unsigned int>&, const std::vector<Instruction*>&) const;
SourceLanguage source;
int sourceVersion;
std::vector<const char*> extensions;
AddressingModel addressModel;
MemoryModel memoryModel;
int builderNumber;
Module module;
Block* buildPoint;
Id uniqueId;
Function* mainFunction;
Block* stageExit;
AccessChain accessChain;
// special blocks of instructions for output
std::vector<Instruction*> imports;
std::vector<Instruction*> entryPoints;
std::vector<Instruction*> executionModes;
std::vector<Instruction*> names;
std::vector<Instruction*> lines;
std::vector<Instruction*> decorations;
std::vector<Instruction*> constantsTypesGlobals;
std::vector<Instruction*> externals;
// not output, internally used for quick & dirty canonical (unique) creation
std::vector<Instruction*> groupedConstants[OpConstant]; // all types appear before OpConstant
std::vector<Instruction*> groupedTypes[OpConstant];
// stack of switches
std::stack<Block*> switchMerges;
// Data that needs to be kept in order to properly handle loops.
struct Loop {
Block* header;
Block* merge;
Function* function;
};
// Our loop stack.
std::stack<Loop> loops;
}; // end Builder class
void MissingFunctionality(const char*);
void ValidationError(const char* error);
}; // end spv namespace
#endif // SpvBuilder_H

762
SPIRV/spirv.h Normal file
View File

@ -0,0 +1,762 @@
/*
** Copyright (c) 2014-2015 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
//
// Enumeration tokens for SPIR V.
//
#pragma once
#ifndef spirv_H
#define spirv_H
#ifdef __cplusplus
namespace spv{
#endif
const int MagicNumber = 0x07230203;
const int Version = 99;
typedef unsigned int Id;
const Id NoResult = 0;
const Id NoType = 0;
const unsigned int OpCodeMask = 0xFFFF;
const unsigned int WordCountShift = 16;
// Set of capabilities. Generally, something is assumed to be in core,
// if nothing else is said. So, these are used to identify when something
// requires a specific capability to be declared.
enum Capability {
CapMatrix,
CapShader,
CapGeom,
CapTess,
CapAddr,
CapLink,
CapKernel
};
// What language is the source code in? Note the OpSource instruction has a separate
// operand for the version number, this is just the language name. The GLSL
// compatibility profile will be indicated by using an OpSourceExtension string.
enum SourceLanguage {
LangUnknown,
LangESSL,
LangGLSL,
LangOpenCL,
LangCount // guard for validation, "default:" statements, etc.
};
// Used per entry point to communicate the "stage" or other model of
// execution used by that entry point.
// See OpEntryPoint.
enum ExecutionModel {
ModelVertex,
ModelTessellationControl,
ModelTessellationEvaluation,
ModelGeometry,
ModelFragment,
ModelGLCompute,
ModelKernel,
ModelCount // guard for validation, "default:" statements, etc.
};
// Used as an argument to OpMemoryModel
enum AddressingModel {
AddressingLogical,
AddressingPhysical32,
AddressingPhysical64,
AddressingCount // guard for validation, "default:" statements, etc.
};
// Used as an argment to OpMemoryModel
enum MemoryModel {
MemorySimple,
MemoryGLSL450,
MemoryOCL12,
MemoryOCL20,
MemoryOCL21,
MemoryCount // guard for validation, "default:" statements, etc.
};
// Used per entry point to communicate modes related to input, output, and execution.
// See OpExecutionMode.
enum ExecutionMode {
ExecutionInvocations,
ExecutionSpacingEqual,
ExecutionSpacingFractionalEven,
ExecutionSpacingFractionalOdd,
ExecutionVertexOrderCw,
ExecutionVertexOrderCcw,
ExecutionPixelCenterInteger,
ExecutionOriginUpperLeft,
ExecutionEarlyFragmentTests,
ExecutionPointMode,
ExecutionXfb,
ExecutionDepthReplacing,
ExecutionDepthAny,
ExecutionDepthGreater,
ExecutionDepthLess,
ExecutionDepthUnchanged,
ExecutionLocalSize,
ExecutionLocalSizeHint,
ExecutionInputPoints,
ExecutionInputLines,
ExecutionInputLinesAdjacency,
ExecutionInputTriangles,
ExecutionInputTrianglesAdjacency,
ExecutionInputQuads,
ExecutionInputIsolines,
ExecutionOutputVertices,
ExecutionOutputPoints,
ExecutionOutputLineStrip,
ExecutionOutputTriangleStrip,
ExecutionVecTypeHint,
ExecutionContractionOff,
ExecutionModeCount // guard for validation, "default:" statements, etc.
};
enum StorageClass {
StorageConstantUniform,
StorageInput,
StorageUniform,
StorageOutput,
StorageWorkgroupLocal,
StorageWorkgroupGlobal,
StoragePrivateGlobal,
StorageFunction,
StorageGeneric,
StoragePrivate,
StorageAtomicCounter,
StorageCount // guard for validation, "default:" statements, etc.
};
// Dimensionalities currently used for sampling.
// See TypeSampler in TypeClass.
enum Dimensionality {
Dim1D,
Dim2D,
Dim3D,
DimCube,
DimRect,
DimBuffer,
DimCount // guard for validation, "default:" statements, etc.
};
// Sampler addressing mode.
enum SamplerAddressingMode {
SamplerAddressingNone = 0,
SamplerAddressingClampToEdge = 2,
SamplerAddressingClamp = 4,
SamplerAddressingRepeat = 6,
SamplerAddressingRepeatMirrored = 8,
SamplerAddressingModeLast,
};
// Sampler filter mode.
enum SamplerFilterMode {
SamplerFilterNearest = 0x10,
SamplerFilterLinear = 0x20,
SamplerFilterModeLast,
};
// FP Fast Math Mode.
enum FPFastMath {
FPFastMathNNan = 0, // assume parameters and result are not NaN.
FPFastMathNInf = 0x02, // assume parameters and result are not +/- Inf.
FPFastMathNSZ = 0x04, // treat the sign of a zero parameter or result as insignificant.
FPFastMathARcp = 0x08, // allow the usage of reciprocal rather than perform a division.
FPFastMathFast = 0x10, // allow Algebraic transformations according to real number associative and distibutive algebra. This flag implies all the others.
FPFastMathLast,
};
// FP Fast Math Mode.
enum FPRoundingMode {
FPRoundRTE, // round to nearest even.
FPRoundRTZ, // round towards zero.
FPRoundRTP, // round towards positive infinity.
FPRoundRTN, // round towards negative infinity.
FPRoundLast,
};
// Global identifier linkage types (by default the linkage type of global identifiers is private. This means that they are only accessible to objects inside the module.)
enum LinkageType {
LinkageExport, // accessible by objects in other modules as well.
LinkageImport, // a forward declaration to a global identifier that exists in another module.
LinkageLast,
};
// Access Qualifiers for OpenCL pipes and images
enum AccessQualifier {
AccessQualReadOnly,
AccessQualWriteOnly,
AccessQualReadWrite,
AccessQualLast,
};
// Function argument attributes
enum FunctionParameterAttribute {
FuncParamAttrZext, // value should be zero extended if needed
FuncParamAttrSext, // value should be sign extended if needed
FuncParamAttrByval, // only valid for pointer parameters (not for ret value), this indicates that the pointer parameter should really be passed by value to the function.
FuncParamAttrSret, // indicates that the pointer parameter specifies the address of a structure that is the return value of the function in the source program. only applicable to the first parameter
FuncParamAttrNoAlias,
FuncParamAttrNoCapture,
FuncParamAttrSVM,
FuncParamAttrNoWrite,
FuncParamAttrNoReadWrite,
FuncParamAttrLast, // guard for validation, "default:" statements, etc.
};
// Extra forms of "qualification" to add as needed. See OpDecorate.
enum Decoration {
// For legacy ES precision qualifiers; newer language
// designs can use the "num-bits" feature in TypeClass.
// The precision qualifiers may be decorated on type <id>s or instruction <id>s.
DecPrecisionLow,
DecPrecisionMedium,
DecPrecisionHigh,
DecBlock, // basic in/out/uniform block, applied only to types of TypeStruct
DecBufferBlock, // shader storage buffer block
DecRowMajor,
DecColMajor,
DecGLSLShared,
DecGLSLStd140,
DecGLSLStd430,
DecGLSLPacked,
DecSmooth,
DecNoperspective,
DecFlat,
DecPatch,
DecCentroid,
DecSample,
DecInvariant,
DecRestrict,
DecAliased,
DecVolatile,
DecConstant,
DecCoherent,
DecNonwritable,
DecNonreadable,
DecUniform,
DecNoStaticUse,
DecCPacked,
DecFPSaturatedConv,
// these all take one additional operand
DecStream,
DecLocation,
DecComponent,
DecIndex,
DecBinding,
DecDescriptorSet,
DecOffset,
DecAlignment,
DecXfbBuffer,
DecStride,
DecBuiltIn,
DecFuncParamAttr,
DecFPRoundingMode,
DecFPFastMathMode,
DecLinkageType,
DecSpecId,
DecCount // guard for validation, "default:" statements, etc.
};
enum BuiltIn {
BuiltInPosition,
BuiltInPointSize,
BuiltInClipVertex,
BuiltInClipDistance,
BuiltInCullDistance,
BuiltInVertexId,
BuiltInInstanceId,
BuiltInPrimitiveId,
BuiltInInvocationId,
BuiltInLayer,
BuiltInViewportIndex,
BuiltInTessLevelOuter,
BuiltInTessLevelInner,
BuiltInTessCoord,
BuiltInPatchVertices,
BuiltInFragCoord,
BuiltInPointCoord,
BuiltInFrontFacing,
BuiltInSampleId,
BuiltInSamplePosition,
BuiltInSampleMask,
BuiltInFragColor,
BuiltInFragDepth,
BuiltInHelperInvocation,
// OpenGL compute stage, OpenCL work item built-ins
BuiltInNumWorkgroups, // number of work-groups that will execute a kernel
BuiltInWorkgroupSize, // OpenCL number of local work-items
BuiltInWorkgroupId, // OpenCL work group id
BuiltInLocalInvocationId, // OpenCL local work item id (decorates a vector3 i32/i64)
BuiltInGlobalInvocationId, // OpenCL global work item id (decorates a vector3 i32/i64)
BuiltInLocalInvocationIndex, // not in use in OpenCL
BuiltInWorkDim, // OpenCL number of dimensions in use (decorates a scalar i32/i64)
BuiltInGlobalSize, // OpenCL number of global work items, per dimension (decorates a vector3 i32/i64)
BuiltInEnqueuedWorkgroupSize, // OpenCL 2.0 only, get local size
BuiltInGlobalOffset, // OpenCL offset values specified global_work_offset
BuiltInGlobalLinearId, // OpenCL 2.0 only, work items 1-dimensional global ID.
BuiltInWorkgroupLinearId, // OpenCL 2.0 only work items 1-dimensional local ID.
// OpenCL 2.0 subgroups
BuiltInSubgroupSize, // Returns the number of work-items in the subgroup
BuiltInSubgroupMaxSize, // Returns the maximum size of a subgroup within the dispatch
BuiltInNumSubgroups, // Returns the maximum size of a subgroup within the dispatch
BuiltInNumEnqueuedSubgroups, // Returns the maximum size of a subgroup within the dispatch
BuiltInSubgroupId, //
BuiltInSubgroupLocalInvocationId, // Returns the unique work-item ID within the current subgroup
BuiltInCount // guard for validation, "default:" statements, etc.
};
enum SelectControl {
SelectControlNone,
SelectControlFlatten,
SelectControlDontFlatten,
SelectControlCount, // guard for validation, "default:" statements, etc.
};
enum LoopControl {
LoopControlNone,
LoopControlUnroll,
LoopControlDontUnroll,
LoopControlCount,
};
enum FunctionControlMask {
FunctionControlNone = 0x0,
FunctionControlInline = 0x1,
FunctionControlDontInline = 0x2,
FunctionControlPure = 0x4,
FunctionControlConst = 0x8,
FunctionControlCount = 4,
};
enum MemorySemanticsMask {
MemorySemanticsRelaxed = 0x0001,
MemorySemanticsSequentiallyConsistent = 0x0002,
MemorySemanticsAcquire = 0x0004,
MemorySemanticsRelease = 0x0008,
MemorySemanticsUniform = 0x0010,
MemorySemanticsSubgroup = 0x0020,
MemorySemanticsWorkgroupLocal = 0x0040,
MemorySemanticsWorkgroupGlobal = 0x0080,
MemorySemanticsAtomicCounter = 0x0100,
MemorySemanticsImage = 0x0200,
MemorySemanticsAllMemory = 0x03FF,
MemorySemanticsCount = 10
};
enum MemoryAccessMask {
MemoryAccessVolatile = 0x0001,
MemoryAccessAligned = 0x0002,
MemoryAccessCount = 2
};
enum ExecutionScope {
ExecutionScopeCrossDevice,
ExecutionScopeDevice,
ExecutionScopeWorkgroup,
ExecutionScopeSubgroup,
ExecutionScopeCount // guard for validation, "default:" statements, etc.
};
enum GroupOperation {
GroupOpReduce,
GroupOpInclusiveScan,
GroupOpExclusiveScan,
GroupOpCount
};
enum KernelEnqueueFlags {
EnqFlagNoWait,
EnqFlagWaitKernel,
EnqFlagWaitWaitWorgGroup,
EnqFlagCount
};
enum KernelProfilingInfo {
ProfInfoCmdExecTime = 0x01,
ProfilingInfoCount = 1
};
enum OpCode {
OpNop = 0, // Not used.
OpSource,
OpSourceExtension,
OpExtension,
OpExtInstImport,
OpMemoryModel,
OpEntryPoint,
OpExecutionMode,
OpTypeVoid,
OpTypeBool,
OpTypeInt,
OpTypeFloat,
OpTypeVector,
OpTypeMatrix,
OpTypeSampler,
OpTypeFilter,
OpTypeArray,
OpTypeRuntimeArray,
OpTypeStruct,
OpTypeOpaque,
OpTypePointer,
OpTypeFunction,
OpTypeEvent,
OpTypeDeviceEvent,
OpTypeReserveId,
OpTypeQueue,
OpTypePipe,
OpConstantTrue,
OpConstantFalse,
OpConstant,
OpConstantComposite,
OpConstantSampler,
OpConstantNullPointer,
OpConstantNullObject,
OpSpecConstantTrue,
OpSpecConstantFalse,
OpSpecConstant,
OpSpecConstantComposite,
OpVariable,
OpVariableArray,
OpFunction,
OpFunctionParameter,
OpFunctionEnd,
OpFunctionCall,
OpExtInst,
OpUndef,
OpLoad,
OpStore,
OpPhi,
OpDecorationGroup,
OpDecorate,
OpMemberDecorate,
OpGroupDecorate,
OpGroupMemberDecorate,
OpName,
OpMemberName,
OpString,
OpLine,
OpVectorExtractDynamic,
OpVectorInsertDynamic,
OpVectorShuffle,
OpCompositeConstruct,
OpCompositeExtract,
OpCompositeInsert,
OpCopyObject,
OpCopyMemory,
OpCopyMemorySized,
OpSampler,
OpTextureSample,
OpTextureSampleDref,
OpTextureSampleLod,
OpTextureSampleProj,
OpTextureSampleGrad,
OpTextureSampleOffset,
OpTextureSampleProjLod,
OpTextureSampleProjGrad,
OpTextureSampleLodOffset,
OpTextureSampleProjOffset,
OpTextureSampleGradOffset,
OpTextureSampleProjLodOffset,
OpTextureSampleProjGradOffset,
OpTextureFetchTexel,
OpTextureFetchTexelOffset,
OpTextureFetchSample,
OpTextureFetchBuffer,
OpTextureGather,
OpTextureGatherOffset,
OpTextureGatherOffsets,
OpTextureQuerySizeLod,
OpTextureQuerySize,
OpTextureQueryLod,
OpTextureQueryLevels,
OpTextureQuerySamples,
OpAccessChain,
OpInBoundsAccessChain,
OpSNegate,
OpFNegate,
OpNot,
OpAny,
OpAll,
OpConvertFToU,
OpConvertFToS,
OpConvertSToF,
OpConvertUToF,
OpUConvert,
OpSConvert,
OpFConvert,
OpConvertPtrToU,
OpConvertUToPtr,
OpPtrCastToGeneric, // cast a pointer storage class to be in storage generic
OpGenericCastToPtr, // cast a pointer in the generic storage class generic to another storage class
OpBitcast,
OpTranspose,
OpIsNan,
OpIsInf,
OpIsFinite,
OpIsNormal,
OpSignBitSet,
OpLessOrGreater,
OpOrdered,
OpUnordered,
OpArrayLength,
OpIAdd,
OpFAdd,
OpISub,
OpFSub,
OpIMul,
OpFMul,
OpUDiv,
OpSDiv,
OpFDiv,
OpUMod,
OpSRem,
OpSMod,
OpFRem,
OpFMod,
OpVectorTimesScalar,
OpMatrixTimesScalar,
OpVectorTimesMatrix,
OpMatrixTimesVector,
OpMatrixTimesMatrix,
OpOuterProduct,
OpDot,
OpShiftRightLogical,
OpShiftRightArithmetic,
OpShiftLeftLogical,
OpLogicalOr,
OpLogicalXor,
OpLogicalAnd,
OpBitwiseOr,
OpBitwiseXor,
OpBitwiseAnd,
OpSelect,
OpIEqual,
OpFOrdEqual,
OpFUnordEqual,
OpINotEqual,
OpFOrdNotEqual,
OpFUnordNotEqual,
OpULessThan,
OpSLessThan,
OpFOrdLessThan,
OpFUnordLessThan,
OpUGreaterThan,
OpSGreaterThan,
OpFOrdGreaterThan,
OpFUnordGreaterThan,
OpULessThanEqual,
OpSLessThanEqual,
OpFOrdLessThanEqual,
OpFUnordLessThanEqual,
OpUGreaterThanEqual,
OpSGreaterThanEqual,
OpFOrdGreaterThanEqual,
OpFUnordGreaterThanEqual,
OpDPdx,
OpDPdy,
OpFwidth,
OpDPdxFine,
OpDPdyFine,
OpFwidthFine,
OpDPdxCoarse,
OpDPdyCoarse,
OpFwidthCoarse,
OpEmitVertex,
OpEndPrimitive,
OpEmitStreamVertex,
OpEndStreamPrimitive,
OpControlBarrier,
OpMemoryBarrier,
OpImagePointer,
OpAtomicInit,
OpAtomicLoad,
OpAtomicStore,
OpAtomicExchange,
OpAtomicCompareExchange,
OpAtomicCompareExchangeWeak,
OpAtomicIIncrement,
OpAtomicIDecrement,
OpAtomicIAdd,
OpAtomicISub,
OpAtomicUMin,
OpAtomicUMax,
OpAtomicAnd,
OpAtomicOr,
OpAtomicXor,
OpLoopMerge,
OpSelectionMerge,
OpLabel,
OpBranch,
OpBranchConditional,
OpSwitch,
OpKill,
OpReturn,
OpReturnValue,
OpUnreachable,
OpLifetimeStart,
OpLifetimeStop,
OpCompileFlag,
OpAsyncGroupCopy,
OpWaitGroupEvents,
OpGroupAll,
OpGroupAny,
OpGroupBroadcast,
OpGroupIAdd,
OpGroupFAdd,
OpGroupFMin,
OpGroupUMin,
OpGroupSMin,
OpGroupFMax,
OpGroupUMax,
OpGroupSMax,
OpGenericCastToPtrExplicit,
OpGenericPtrMemSemantics,
OpReadPipe,
OpWritePipe,
OpReservedReadPipe,
OpReservedWritePipe,
OpReserveReadPipePackets,
OpReserveWritePipePackets,
OpCommitReadPipe,
OpCommitWritePipe,
OpIsValidReserveId,
OpGetNumPipePackets,
OpGetMaxPipePackets,
OpGroupReserveReadPipePackets,
OpGroupReserveWritePipePackets,
OpGroupCommitReadPipe,
OpGroupCommitWritePipe,
OpEnqueueMarker,
OpEnqueueKernel,
OpGetKernelNDrangeSubGroupCount,
OpGetKernelNDrangeMaxSubGroupSize,
OpGetKernelWorkGroupSize,
OpGetKernelPreferredWorkGroupSizeMultiple,
OpRetainEvent,
OpReleaseEvent,
OpCreateUserEvent,
OpIsValidEvent,
OpSetUserEventStatus,
OpCaptureEventProfilingInfo,
OpGetDefaultQueue,
OpBuildNDRange,
OpCount // guard for validation, "default:" statements, etc.
};
#ifdef __cplusplus
}; // end namespace spv
#endif
#endif // spirv_H

348
SPIRV/spvIR.h Normal file
View File

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

View File

@ -17,7 +17,7 @@ set(LIBRARIES
glslang
OGLCompiler
OSDependent
BIL)
SPIRV)
if(WIN32)
set(LIBRARIES ${LIBRARIES} psapi)

View File

@ -40,8 +40,8 @@
#include "Worklist.h"
#include "./../glslang/Include/ShHandle.h"
#include "./../glslang/Public/ShaderLang.h"
#include "../BIL/GlslangToBil.h"
#include "../BIL/GLSL450Lib.h"
#include "../SPIRV/GlslangToSpv.h"
#include "../SPIRV/GLSL450Lib.h"
#include <string.h>
#include <stdlib.h>
#include <math.h>
@ -66,7 +66,7 @@ enum TOptions {
EOptionDumpReflection = 0x100,
EOptionSuppressWarnings = 0x200,
EOptionDumpVersions = 0x400,
EOptionBil = 0x800,
EOptionSpv = 0x800,
EOptionDefaultDesktop = 0x1000,
};
@ -479,8 +479,8 @@ bool ProcessArguments(int argc, char* argv[])
Work[argc] = 0;
if (argv[0][0] == '-') {
switch (argv[0][1]) {
case 'b':
Options |= EOptionBil;
case 'V':
Options |= EOptionSpv;
Options |= EOptionLinkProgram;
break;
case 'c':
@ -634,14 +634,14 @@ void CompileAndLinkShaders()
program.dumpReflection();
}
if (Options & EOptionBil) {
if (Options & EOptionSpv) {
if (CompileFailed || LinkFailed)
printf("Bil is not generated for failed compile or link\n");
printf("SPIRV is not generated for failed compile or link\n");
else {
for (int stage = 0; stage < EShLangCount; ++stage) {
if (program.getIntermediate((EShLanguage)stage)) {
std::vector<unsigned int> bil;
glslang::GlslangToBil(*program.getIntermediate((EShLanguage)stage), bil);
std::vector<unsigned int> spirv;
glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv);
const char* name;
switch (stage) {
case EShLangVertex: name = "vert"; break;
@ -652,7 +652,7 @@ void CompileAndLinkShaders()
case EShLangCompute: name = "comp"; break;
default: name = "unknown"; break;
}
glslang::OutputBil(bil, name);
glslang::OutputSpv(spirv, name);
}
}
}
@ -839,7 +839,7 @@ void usage()
{
printf("Usage: glslangValidator [option]... [file]...\n"
"\n"
"Where: each 'file' ends in\n"
"Where: each 'file' ends in .<stage>, where <stage> is one of\n"
" .conf to provide an optional config file that replaces the default configuration\n"
" (see -c option below for generating a template)\n"
" .vert for a vertex shader\n"
@ -853,7 +853,7 @@ void usage()
"\n"
"To get other information, use one of the following options:\n"
"(Each option must be specified separately, but can go anywhere in the command line.)\n"
" -b create BIL in file <stage>.bil\n"
" -V create SPIR-V in file <stage>.spv\n"
" -c configuration dump; use to create default configuration file (redirect to a .conf file)\n"
" -d default to desktop (#version 110) when there is no version in the shader (default is ES version 100)\n"
" -i intermediate tree (glslang AST) is printed out\n"

View File

@ -482,6 +482,7 @@ public:
layoutLocation = layoutLocationEnd;
layoutComponent = layoutComponentEnd;
layoutSet = layoutSetEnd;
layoutBinding = layoutBindingEnd;
layoutIndex = layoutIndexEnd;
@ -513,6 +514,9 @@ public:
unsigned int layoutComponent : 3;
static const unsigned int layoutComponentEnd = 4;
unsigned int layoutSet : 7;
static const unsigned int layoutSetEnd = 0x3F;
unsigned int layoutBinding : 8;
static const unsigned int layoutBindingEnd = 0xFF;
@ -575,6 +579,10 @@ public:
{
return layoutIndex != layoutIndexEnd;
}
bool hasSet() const
{
return layoutSet != layoutSetEnd;
}
bool hasBinding() const
{
return layoutBinding != layoutBindingEnd;
@ -1201,6 +1209,8 @@ public:
if (qualifier.hasIndex())
p += snprintf(p, end - p, "index=%d ", qualifier.layoutIndex);
}
if (qualifier.hasSet())
p += snprintf(p, end - p, "set=%d ", qualifier.layoutSet);
if (qualifier.hasBinding())
p += snprintf(p, end - p, "binding=%d ", qualifier.layoutBinding);
if (qualifier.hasStream())

View File

@ -3312,6 +3312,12 @@ void TParseContext::setLayoutQualifier(TSourceLoc loc, TPublicType& publicType,
else
publicType.qualifier.layoutLocation = value;
return;
} else if (id == "set") {
if ((unsigned int)value >= TQualifier::layoutSetEnd)
error(loc, "set is too large", id.c_str(), "");
else
publicType.qualifier.layoutSet = value;
return;
} else if (id == "binding") {
profileRequires(loc, ~EEsProfile, 420, GL_ARB_shading_language_420pack, "binding");
profileRequires(loc, EEsProfile, 310, 0, "binding");
@ -3476,6 +3482,8 @@ void TParseContext::mergeObjectLayoutQualifiers(TSourceLoc loc, TQualifier& dst,
if (src.hasOffset())
dst.layoutOffset = src.layoutOffset;
if (src.hasSet())
dst.layoutSet = src.layoutSet;
if (src.layoutBinding != TQualifier::layoutBindingEnd)
dst.layoutBinding = src.layoutBinding;