Parser: Implement extension GL_AMD_gpu_shader_half_float.

- Add built-in types: float16_t, f16vec, f16mat.
- Add support of half float constant: hf, HF.
- Extend built-in floating-point operators: +, -, *, /, ++, --, +=, -=,
  *=, /=, ==, !=, >=, <=, >, <.
- Add support of type conversions: float16_t -> XXX, XXX -> float16_t.
- Add new built-in functions.
This commit is contained in:
Rex Xu
2016-07-29 16:00:05 +08:00
parent b1672fa0de
commit c9e3c3c941
35 changed files with 9765 additions and 4370 deletions

View File

@@ -11,10 +11,12 @@ set(SPVREMAP_SOURCES
doc.cpp)
set(HEADERS
bitutils.h
spirv.hpp
GLSL.std.450.h
GLSL.ext.KHR.h
GlslangToSpv.h
hex_float.h
Logger.h
SpvBuilder.h
spvIR.h
@@ -26,8 +28,9 @@ set(SPVREMAP_HEADERS
doc.h)
if(ENABLE_AMD_EXTENSIONS)
set(HEADERS
GLSL.ext.AMD.h)
list(APPEND
HEADERS
GLSL.ext.AMD.h)
endif(ENABLE_AMD_EXTENSIONS)
add_library(SPIRV STATIC ${SOURCES} ${HEADERS})

View File

@@ -32,7 +32,7 @@ enum Decoration;
enum Op;
static const int GLSLextAMDVersion = 100;
static const int GLSLextAMDRevision = 1;
static const int GLSLextAMDRevision = 2;
// SPV_AMD_shader_ballot
static const char* const E_SPV_AMD_shader_ballot = "SPV_AMD_shader_ballot";
@@ -110,4 +110,7 @@ enum GcnShaderAMD {
GcnShaderCountAMD
};
// SPV_AMD_gpu_shader_half_float
static const char* const E_SPV_AMD_gpu_shader_half_float = "SPV_AMD_gpu_shader_half_float";
#endif // #ifndef GLSLextAMD_H

View File

@@ -1215,6 +1215,10 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
one = builder.makeFloatConstant(1.0F);
else if (node->getBasicType() == glslang::EbtDouble)
one = builder.makeDoubleConstant(1.0);
#ifdef AMD_EXTENSIONS
else if (node->getBasicType() == glslang::EbtFloat16)
one = builder.makeFloat16Constant(1.0F);
#endif
else if (node->getBasicType() == glslang::EbtInt64 || node->getBasicType() == glslang::EbtUint64)
one = builder.makeInt64Constant(1);
else
@@ -1388,6 +1392,17 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
case glslang::EOpConstructDMat4x2:
case glslang::EOpConstructDMat4x3:
case glslang::EOpConstructDMat4x4:
#ifdef AMD_EXTENSIONS
case glslang::EOpConstructF16Mat2x2:
case glslang::EOpConstructF16Mat2x3:
case glslang::EOpConstructF16Mat2x4:
case glslang::EOpConstructF16Mat3x2:
case glslang::EOpConstructF16Mat3x3:
case glslang::EOpConstructF16Mat3x4:
case glslang::EOpConstructF16Mat4x2:
case glslang::EOpConstructF16Mat4x3:
case glslang::EOpConstructF16Mat4x4:
#endif
isMatrix = true;
// fall through
case glslang::EOpConstructFloat:
@@ -1398,6 +1413,12 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
case glslang::EOpConstructDVec2:
case glslang::EOpConstructDVec3:
case glslang::EOpConstructDVec4:
#ifdef AMD_EXTENSIONS
case glslang::EOpConstructFloat16:
case glslang::EOpConstructF16Vec2:
case glslang::EOpConstructF16Vec3:
case glslang::EOpConstructF16Vec4:
#endif
case glslang::EOpConstructBool:
case glslang::EOpConstructBVec2:
case glslang::EOpConstructBVec3:
@@ -1901,7 +1922,6 @@ spv::Id TGlslangToSpvTraverser::createInvertedSwizzle(spv::Decoration precision,
return builder.createRvalueSwizzle(precision, convertGlslangToSpvType(node.getType()), parentResult, swizzle);
}
// Convert a glslang AST swizzle node to a swizzle vector for building SPIR-V.
void TGlslangToSpvTraverser::convertSwizzle(const glslang::TIntermAggregate& node, std::vector<unsigned>& swizzle)
{
@@ -1936,6 +1956,13 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
case glslang::EbtDouble:
spvType = builder.makeFloatType(64);
break;
#ifdef AMD_EXTENSIONS
case glslang::EbtFloat16:
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
builder.addCapability(spv::CapabilityFloat16);
spvType = builder.makeFloatType(16);
break;
#endif
case glslang::EbtBool:
// "transparent" bool doesn't exist in SPIR-V. The GLSL convention is
// a 32-bit int where non-0 means true.
@@ -3040,7 +3067,11 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv
glslang::TBasicType typeProxy, bool reduceComparison)
{
bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64;
#ifdef AMD_EXTENSIONS
bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble || typeProxy == glslang::EbtFloat16;
#else
bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
#endif
bool isBool = typeProxy == glslang::EbtBool;
spv::Op binOp = spv::OpNop;
@@ -3366,7 +3397,11 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv:
int extBuiltins = -1;
int libCall = -1;
bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64;
#ifdef AMD_EXTENSIONS
bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble || typeProxy == glslang::EbtFloat16;
#else
bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
#endif
switch (op) {
case glslang::EOpNegative:
@@ -3550,6 +3585,13 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv:
unaryOp = spv::OpBitcast;
break;
#ifdef AMD_EXTENSIONS
case glslang::EOpPackFloat2x16:
case glslang::EOpUnpackFloat2x16:
unaryOp = spv::OpBitcast;
break;
#endif
case glslang::EOpDPdx:
unaryOp = spv::OpDPdx;
break;
@@ -3746,22 +3788,40 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Dec
zero = makeSmearedConstant(zero, vectorSize);
return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);
#ifdef AMD_EXTENSIONS
case glslang::EOpConvFloat16ToBool:
zero = builder.makeFloat16Constant(0.0F);
zero = makeSmearedConstant(zero, vectorSize);
return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);
#endif
case glslang::EOpConvBoolToFloat:
convOp = spv::OpSelect;
zero = builder.makeFloatConstant(0.0);
one = builder.makeFloatConstant(1.0);
zero = builder.makeFloatConstant(0.0F);
one = builder.makeFloatConstant(1.0F);
break;
case glslang::EOpConvBoolToDouble:
convOp = spv::OpSelect;
zero = builder.makeDoubleConstant(0.0);
one = builder.makeDoubleConstant(1.0);
break;
#ifdef AMD_EXTENSIONS
case glslang::EOpConvBoolToFloat16:
convOp = spv::OpSelect;
zero = builder.makeFloat16Constant(0.0F);
one = builder.makeFloat16Constant(1.0F);
break;
#endif
case glslang::EOpConvBoolToInt:
case glslang::EOpConvBoolToInt64:
zero = (op == glslang::EOpConvBoolToInt64) ? builder.makeInt64Constant(0) : builder.makeIntConstant(0);
one = (op == glslang::EOpConvBoolToInt64) ? builder.makeInt64Constant(1) : builder.makeIntConstant(1);
convOp = spv::OpSelect;
break;
case glslang::EOpConvBoolToUint:
case glslang::EOpConvBoolToUint64:
zero = (op == glslang::EOpConvBoolToUint64) ? builder.makeUint64Constant(0) : builder.makeUintConstant(0);
@@ -3773,6 +3833,10 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Dec
case glslang::EOpConvIntToDouble:
case glslang::EOpConvInt64ToFloat:
case glslang::EOpConvInt64ToDouble:
#ifdef AMD_EXTENSIONS
case glslang::EOpConvIntToFloat16:
case glslang::EOpConvInt64ToFloat16:
#endif
convOp = spv::OpConvertSToF;
break;
@@ -3780,11 +3844,21 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Dec
case glslang::EOpConvUintToDouble:
case glslang::EOpConvUint64ToFloat:
case glslang::EOpConvUint64ToDouble:
#ifdef AMD_EXTENSIONS
case glslang::EOpConvUintToFloat16:
case glslang::EOpConvUint64ToFloat16:
#endif
convOp = spv::OpConvertUToF;
break;
case glslang::EOpConvDoubleToFloat:
case glslang::EOpConvFloatToDouble:
#ifdef AMD_EXTENSIONS
case glslang::EOpConvDoubleToFloat16:
case glslang::EOpConvFloat16ToDouble:
case glslang::EOpConvFloatToFloat16:
case glslang::EOpConvFloat16ToFloat:
#endif
convOp = spv::OpFConvert;
if (builder.isMatrixType(destType))
return createUnaryMatrixOperation(convOp, precision, noContraction, destType, operand, typeProxy);
@@ -3794,6 +3868,10 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Dec
case glslang::EOpConvDoubleToInt:
case glslang::EOpConvFloatToInt64:
case glslang::EOpConvDoubleToInt64:
#ifdef AMD_EXTENSIONS
case glslang::EOpConvFloat16ToInt:
case glslang::EOpConvFloat16ToInt64:
#endif
convOp = spv::OpConvertFToS;
break;
@@ -3818,6 +3896,10 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Dec
case glslang::EOpConvDoubleToUint:
case glslang::EOpConvFloatToUint64:
case glslang::EOpConvDoubleToUint64:
#ifdef AMD_EXTENSIONS
case glslang::EOpConvFloat16ToUint:
case glslang::EOpConvFloat16ToUint64:
#endif
convOp = spv::OpConvertFToU;
break;
@@ -3987,7 +4069,11 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv
spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
{
bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64;
#ifdef AMD_EXTENSIONS
bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble || typeProxy == glslang::EbtFloat16;
#else
bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
#endif
spv::Op opCode = spv::OpNop;
@@ -4185,7 +4271,11 @@ spv::Id TGlslangToSpvTraverser::CreateInvocationsVectorOperation(spv::Op op, spv
spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
{
bool isUnsigned = typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64;
#ifdef AMD_EXTENSIONS
bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble || typeProxy == glslang::EbtFloat16;
#else
bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
#endif
spv::Op opCode = spv::OpNop;
int extBuiltins = -1;
@@ -4715,6 +4805,11 @@ spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glsla
case glslang::EbtDouble:
spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst()));
break;
#ifdef AMD_EXTENSIONS
case glslang::EbtFloat16:
spvConsts.push_back(builder.makeFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
break;
#endif
case glslang::EbtBool:
spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));
break;
@@ -4747,6 +4842,11 @@ spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glsla
case glslang::EbtDouble:
scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst(), specConstant);
break;
#ifdef AMD_EXTENSIONS
case glslang::EbtFloat16:
scalar = builder.makeFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
break;
#endif
case glslang::EbtBool:
scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst(), specConstant);
break;

View File

@@ -46,6 +46,10 @@
#include "SpvBuilder.h"
#ifdef AMD_EXTENSIONS
#include "hex_float.h"
#endif
#ifndef _WIN32
#include <cstdio>
#endif
@@ -785,6 +789,36 @@ Id Builder::makeDoubleConstant(double d, bool specConstant)
return c->getResultId();
}
#ifdef AMD_EXTENSIONS
Id Builder::makeFloat16Constant(float f16, bool specConstant)
{
Op opcode = specConstant ? OpSpecConstant : OpConstant;
Id typeId = makeFloatType(16);
spvutils::HexFloat<spvutils::FloatProxy<float>> fVal(f16);
spvutils::HexFloat<spvutils::FloatProxy<spvutils::Float16>> f16Val(0);
fVal.castTo(f16Val, spvutils::round_direction::kToZero);
unsigned value = f16Val.value().getAsFloat().get_value();
// See if we already made it. Applies only to regular constants, because specialization constants
// must remain distinct for the purpose of applying a SpecId decoration.
if (!specConstant) {
Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
if (existing)
return existing;
}
Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
c->addImmediateOperand(value);
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
groupedConstants[OpTypeFloat].push_back(c);
module.mapInstruction(c);
return c->getResultId();
}
#endif
Id Builder::findCompositeConstant(Op typeClass, std::vector<Id>& comps) const
{
Instruction* constant = 0;

View File

@@ -191,6 +191,9 @@ public:
Id makeUint64Constant(unsigned long long u, bool specConstant = false) { return makeInt64Constant(makeUintType(64), u, specConstant); }
Id makeFloatConstant(float f, bool specConstant = false);
Id makeDoubleConstant(double d, bool specConstant = false);
#ifdef AMD_EXTENSIONS
Id makeFloat16Constant(float f16, bool specConstant = false);
#endif
// Turn the array of constants into a proper spv constant of the requested type.
Id makeCompositeConstant(Id type, std::vector<Id>& comps, bool specConst = false);

81
SPIRV/bitutils.h Normal file
View File

@@ -0,0 +1,81 @@
// Copyright (c) 2015-2016 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef LIBSPIRV_UTIL_BITUTILS_H_
#define LIBSPIRV_UTIL_BITUTILS_H_
#include <cstdint>
#include <cstring>
namespace spvutils {
// Performs a bitwise copy of source to the destination type Dest.
template <typename Dest, typename Src>
Dest BitwiseCast(Src source) {
Dest dest;
static_assert(sizeof(source) == sizeof(dest),
"BitwiseCast: Source and destination must have the same size");
std::memcpy(&dest, &source, sizeof(dest));
return dest;
}
// SetBits<T, First, Num> returns an integer of type <T> with bits set
// for position <First> through <First + Num - 1>, counting from the least
// significant bit. In particular when Num == 0, no positions are set to 1.
// A static assert will be triggered if First + Num > sizeof(T) * 8, that is,
// a bit that will not fit in the underlying type is set.
template <typename T, size_t First = 0, size_t Num = 0>
struct SetBits {
static_assert(First < sizeof(T) * 8,
"Tried to set a bit that is shifted too far.");
const static T get = (T(1) << First) | SetBits<T, First + 1, Num - 1>::get;
};
template <typename T, size_t Last>
struct SetBits<T, Last, 0> {
const static T get = T(0);
};
// This is all compile-time so we can put our tests right here.
static_assert(SetBits<uint32_t, 0, 0>::get == uint32_t(0x00000000),
"SetBits failed");
static_assert(SetBits<uint32_t, 0, 1>::get == uint32_t(0x00000001),
"SetBits failed");
static_assert(SetBits<uint32_t, 31, 1>::get == uint32_t(0x80000000),
"SetBits failed");
static_assert(SetBits<uint32_t, 1, 2>::get == uint32_t(0x00000006),
"SetBits failed");
static_assert(SetBits<uint32_t, 30, 2>::get == uint32_t(0xc0000000),
"SetBits failed");
static_assert(SetBits<uint32_t, 0, 31>::get == uint32_t(0x7FFFFFFF),
"SetBits failed");
static_assert(SetBits<uint32_t, 0, 32>::get == uint32_t(0xFFFFFFFF),
"SetBits failed");
static_assert(SetBits<uint32_t, 16, 16>::get == uint32_t(0xFFFF0000),
"SetBits failed");
static_assert(SetBits<uint64_t, 0, 1>::get == uint64_t(0x0000000000000001LL),
"SetBits failed");
static_assert(SetBits<uint64_t, 63, 1>::get == uint64_t(0x8000000000000000LL),
"SetBits failed");
static_assert(SetBits<uint64_t, 62, 2>::get == uint64_t(0xc000000000000000LL),
"SetBits failed");
static_assert(SetBits<uint64_t, 31, 1>::get == uint64_t(0x0000000080000000LL),
"SetBits failed");
static_assert(SetBits<uint64_t, 16, 16>::get == uint64_t(0x00000000FFFF0000LL),
"SetBits failed");
} // namespace spvutils
#endif // LIBSPIRV_UTIL_BITUTILS_H_

1076
SPIRV/hex_float.h Normal file

File diff suppressed because it is too large Load Diff