[spirv] Use extension for fp16 in GLSL extended instruction set. (#2151)

This commit is contained in:
Ehsan 2019-05-01 12:33:22 -04:00 коммит произвёл GitHub
Родитель 9a0f7160e5
Коммит 6e8df18886
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 119 добавлений и 31 удалений

Просмотреть файл

@ -68,7 +68,8 @@ public:
static bool isSubpassInput(const SpirvType *); static bool isSubpassInput(const SpirvType *);
static bool isSubpassInputMS(const SpirvType *); static bool isSubpassInputMS(const SpirvType *);
static bool isResourceType(const SpirvType *); static bool isResourceType(const SpirvType *);
static bool isOrContains16BitType(const SpirvType *); template <class T, unsigned int Bitwidth = 0>
static bool isOrContainsType(const SpirvType *);
protected: protected:
SpirvType(Kind k, llvm::StringRef name = "") : kind(k), debugName(name) {} SpirvType(Kind k, llvm::StringRef name = "") : kind(k), debugName(name) {}
@ -525,6 +526,44 @@ private:
llvm::SmallVector<QualType, 8> paramTypes; llvm::SmallVector<QualType, 8> paramTypes;
}; };
//
// Function Definition for templated functions
//
template <class T, unsigned int Bitwidth>
bool SpirvType::isOrContainsType(const SpirvType *type) {
if (isa<T>(type)) {
if (Bitwidth == 0)
// No specific bitwidth was asked for.
return true;
else
// We want to make sure it is a numberical type of a specific bitwidth.
return isa<NumericalType>(type) &&
llvm::cast<NumericalType>(type)->getBitwidth() == Bitwidth;
}
if (const auto *vecType = dyn_cast<VectorType>(type))
return isOrContainsType<T, Bitwidth>(vecType->getElementType());
if (const auto *matType = dyn_cast<MatrixType>(type))
return isOrContainsType<T, Bitwidth>(matType->getElementType());
if (const auto *arrType = dyn_cast<ArrayType>(type))
return isOrContainsType<T, Bitwidth>(arrType->getElementType());
if (const auto *pointerType = dyn_cast<SpirvPointerType>(type))
return isOrContainsType<T, Bitwidth>(pointerType->getPointeeType());
if (const auto *raType = dyn_cast<RuntimeArrayType>(type))
return isOrContainsType<T, Bitwidth>(raType->getElementType());
if (const auto *imgType = dyn_cast<ImageType>(type))
return isOrContainsType<T, Bitwidth>(imgType->getSampledType());
if (const auto *sampledImageType = dyn_cast<SampledImageType>(type))
return isOrContainsType<T, Bitwidth>(sampledImageType->getImageType());
if (const auto *structType = dyn_cast<StructType>(type))
for (auto &field : structType->getFields())
if (isOrContainsType<T, Bitwidth>(field.type))
return true;
return false;
}
} // end namespace spirv } // end namespace spirv
} // end namespace clang } // end namespace clang

Просмотреть файл

@ -64,7 +64,6 @@ void CapabilityVisitor::addCapabilityForType(const SpirvType *type,
case 16: { case 16: {
// Usage of a 16-bit float type. // Usage of a 16-bit float type.
addCapability(spv::Capability::Float16); addCapability(spv::Capability::Float16);
addExtension(Extension::AMD_gpu_shader_half_float, "16-bit float", loc);
// Usage of a 16-bit float type as stage I/O. // Usage of a 16-bit float type as stage I/O.
if (sc == spv::StorageClass::Input || sc == spv::StorageClass::Output) { if (sc == spv::StorageClass::Input || sc == spv::StorageClass::Output) {
@ -180,7 +179,7 @@ void CapabilityVisitor::addCapabilityForType(const SpirvType *type,
} }
// Struct type // Struct type
else if (const auto *structType = dyn_cast<StructType>(type)) { else if (const auto *structType = dyn_cast<StructType>(type)) {
if (SpirvType::isOrContains16BitType(structType)) { if (SpirvType::isOrContainsType<NumericalType, 16>(structType)) {
addExtension(Extension::KHR_16bit_storage, "16-bit types in resource", addExtension(Extension::KHR_16bit_storage, "16-bit types in resource",
loc); loc);
if (sc == spv::StorageClass::PushConstant) { if (sc == spv::StorageClass::PushConstant) {
@ -504,5 +503,47 @@ bool CapabilityVisitor::visit(SpirvExecutionMode *execMode) {
return true; return true;
} }
bool CapabilityVisitor::visit(SpirvExtInst *instr) {
// OpExtInst using the GLSL extended instruction allows only 32-bit types by
// default. The AMD_gpu_shader_half_float extension adds support for 16-bit
// floating-point component types for the following instructions described in
// the GLSL.std.450 extended instruction set:
// Acos, Acosh, Asin, Asinh, Atan2, Atanh, Atan, Cos, Cosh, Degrees, Exp,
// Exp2, InterpolateAtCentroid, InterpolateAtSample, InterpolateAtOffset, Log,
// Log2, Pow, Radians, Sin, Sinh, Tan, Tanh
if (SpirvType::isOrContainsType<FloatType, 16>(instr->getResultType()))
switch (instr->getInstruction()) {
case GLSLstd450::GLSLstd450Acos:
case GLSLstd450::GLSLstd450Acosh:
case GLSLstd450::GLSLstd450Asin:
case GLSLstd450::GLSLstd450Asinh:
case GLSLstd450::GLSLstd450Atan2:
case GLSLstd450::GLSLstd450Atanh:
case GLSLstd450::GLSLstd450Atan:
case GLSLstd450::GLSLstd450Cos:
case GLSLstd450::GLSLstd450Cosh:
case GLSLstd450::GLSLstd450Degrees:
case GLSLstd450::GLSLstd450Exp:
case GLSLstd450::GLSLstd450Exp2:
case GLSLstd450::GLSLstd450InterpolateAtCentroid:
case GLSLstd450::GLSLstd450InterpolateAtSample:
case GLSLstd450::GLSLstd450InterpolateAtOffset:
case GLSLstd450::GLSLstd450Log:
case GLSLstd450::GLSLstd450Log2:
case GLSLstd450::GLSLstd450Pow:
case GLSLstd450::GLSLstd450Radians:
case GLSLstd450::GLSLstd450Sin:
case GLSLstd450::GLSLstd450Sinh:
case GLSLstd450::GLSLstd450Tan:
case GLSLstd450::GLSLstd450Tanh:
addExtension(Extension::AMD_gpu_shader_half_float, "16-bit float",
instr->getSourceLocation());
default:
break;
}
return visitInstruction(instr);
}
} // end namespace spirv } // end namespace spirv
} // end namespace clang } // end namespace clang

Просмотреть файл

@ -32,6 +32,7 @@ public:
bool visit(SpirvImageQuery *); bool visit(SpirvImageQuery *);
bool visit(SpirvImageOp *); bool visit(SpirvImageOp *);
bool visit(SpirvImageSparseTexelsResident *); bool visit(SpirvImageSparseTexelsResident *);
bool visit(SpirvExtInst *);
/// The "sink" visit function for all instructions. /// The "sink" visit function for all instructions.
/// ///

Просмотреть файл

@ -102,33 +102,6 @@ bool SpirvType::isResourceType(const SpirvType *type) {
return false; return false;
} }
bool SpirvType::isOrContains16BitType(const SpirvType *type) {
if (const auto *numericType = dyn_cast<NumericalType>(type))
if (numericType->getBitwidth() == 16)
return true;
if (const auto *vecType = dyn_cast<VectorType>(type))
return isOrContains16BitType(vecType->getElementType());
if (const auto *matType = dyn_cast<MatrixType>(type))
return isOrContains16BitType(matType->getElementType());
if (const auto *arrType = dyn_cast<ArrayType>(type))
return isOrContains16BitType(arrType->getElementType());
if (const auto *pointerType = dyn_cast<SpirvPointerType>(type))
return isOrContains16BitType(pointerType->getPointeeType());
if (const auto *raType = dyn_cast<RuntimeArrayType>(type))
return isOrContains16BitType(raType->getElementType());
if (const auto *imgType = dyn_cast<ImageType>(type))
return isOrContains16BitType(imgType->getSampledType());
if (const auto *sampledImageType = dyn_cast<SampledImageType>(type))
return isOrContains16BitType(sampledImageType->getImageType());
if (const auto *structType = dyn_cast<StructType>(type))
for (auto &field : structType->getFields())
if (isOrContains16BitType(field.type))
return true;
return false;
}
MatrixType::MatrixType(const VectorType *vecType, uint32_t vecCount) MatrixType::MatrixType(const VectorType *vecType, uint32_t vecCount)
: SpirvType(TK_Matrix), vectorType(vecType), vectorCount(vecCount) {} : SpirvType(TK_Matrix), vectorType(vecType), vectorCount(vecCount) {}

Просмотреть файл

@ -17,7 +17,6 @@
// CHECK: OpCapability Float16 // CHECK: OpCapability Float16
// CHECK: OpCapability Int16 // CHECK: OpCapability Int16
// CHECK: OpExtension "SPV_AMD_gpu_shader_half_float"
// CHECK-NOT: OpDecorate %c_half RelaxedPrecision // CHECK-NOT: OpDecorate %c_half RelaxedPrecision
// CHECK-NOT: OpDecorate %c_min10float RelaxedPrecision // CHECK-NOT: OpDecorate %c_min10float RelaxedPrecision

Просмотреть файл

@ -0,0 +1,11 @@
// Run: %dxc -T ps_6_2 -E main -enable-16bit-types
// The GLSL extended instruction set may only use 16-bit floats if AMD_gpu_shader_half_float extension is used.
// CHECK: OpCapability Float16
// CHECK: OpExtension "SPV_AMD_gpu_shader_half_float"
// CHECK: OpExtInstImport "GLSL.std.450"
void main() {
float16_t4 a;
float16_t4 result = atan(a);
}

Просмотреть файл

@ -0,0 +1,11 @@
// Run: %dxc -T ps_6_2 -E main -enable-16bit-types -fspv-extension=KHR
// The command line option instructs the compiler to only use core Vulkan features and KHR extensions,
// and prevents the compiler from using vendor-specific extensions.
// CHECK: 10:23: error: SPIR-V extension 'SPV_AMD_gpu_shader_half_float' required for 16-bit float but not permitted to use
void main() {
float16_t4 a;
float16_t4 result = atan(a);
}

Просмотреть файл

@ -1862,6 +1862,19 @@ TEST_F(FileTest, CapabilityUnique) { runFileTest("capability.unique.hlsl"); }
// For extension uniqueness // For extension uniqueness
TEST_F(FileTest, ExtensionUnique) { runFileTest("extension.unique.hlsl"); } TEST_F(FileTest, ExtensionUnique) { runFileTest("extension.unique.hlsl"); }
// For vendor-specific extensions
TEST_F(FileTest, VendorSpecificExtensionAllowed) {
// The SPV_AMD_gpu_shader_half_float extension adds support for 16-bit
// floating-point component types for a number of instructions in the
// GLSL.std.450 extended instruction set.
runFileTest("extension.GLSLstd450-fp16.allowed.hlsl");
}
TEST_F(FileTest, VendorSpecificExtensionNotAllowed) {
// Command line options can entirely prevent the compiler from using
// vendor-specific extensions.
runFileTest("extension.GLSLstd450-fp16.not-allowed.hlsl", Expect::Failure);
}
// For RelaxedPrecision decorations // For RelaxedPrecision decorations
TEST_F(FileTest, DecorationRelaxedPrecisionBasic) { TEST_F(FileTest, DecorationRelaxedPrecisionBasic) {
runFileTest("decoration.relaxed-precision.basic.hlsl"); runFileTest("decoration.relaxed-precision.basic.hlsl");