mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-22 03:30:06 +00:00
Add support for SPV_KHR_float_controls2 (#5543)
* Test asm/dis for SPV_KHR_float_controls2 * SPV_KHR_float_controls2 validation --------- Co-authored-by: David Neto <dneto@google.com>
This commit is contained in:
parent
de3d5acc04
commit
ef2f432364
@ -141,6 +141,10 @@ spv_result_t ValidateEntryPoints(ValidationState_t& _) {
|
||||
}
|
||||
}
|
||||
|
||||
if (auto error = ValidateFloatControls2(_)) {
|
||||
return error;
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,18 @@ spv_result_t ValidateAdjacency(ValidationState_t& _);
|
||||
/// @return SPV_SUCCESS if no errors are found.
|
||||
spv_result_t ValidateInterfaces(ValidationState_t& _);
|
||||
|
||||
/// @brief Validates entry point call tree requirements of
|
||||
/// SPV_KHR_float_controls2
|
||||
///
|
||||
/// Checks that no entry point using FPFastMathDefault uses:
|
||||
/// * FPFastMathMode Fast
|
||||
/// * NoContraction
|
||||
///
|
||||
/// @param[in] _ the validation state of the module
|
||||
///
|
||||
/// @return SPV_SUCCESS if no errors are found.
|
||||
spv_result_t ValidateFloatControls2(ValidationState_t& _);
|
||||
|
||||
/// @brief Validates memory instructions
|
||||
///
|
||||
/// @param[in] _ the validation state of the module
|
||||
|
@ -267,6 +267,34 @@ spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) {
|
||||
}
|
||||
}
|
||||
|
||||
if (decoration == spv::Decoration::FPFastMathMode) {
|
||||
if (_.HasDecoration(target_id, spv::Decoration::NoContraction)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "FPFastMathMode and NoContraction cannot decorate the same "
|
||||
"target";
|
||||
}
|
||||
auto mask = inst->GetOperandAs<spv::FPFastMathModeMask>(2);
|
||||
if ((mask & spv::FPFastMathModeMask::AllowTransform) !=
|
||||
spv::FPFastMathModeMask::MaskNone &&
|
||||
((mask & (spv::FPFastMathModeMask::AllowContract |
|
||||
spv::FPFastMathModeMask::AllowReassoc)) !=
|
||||
(spv::FPFastMathModeMask::AllowContract |
|
||||
spv::FPFastMathModeMask::AllowReassoc))) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "AllowReassoc and AllowContract must be specified when "
|
||||
"AllowTransform is specified";
|
||||
}
|
||||
}
|
||||
|
||||
// This is checked from both sides since we register decorations as we go.
|
||||
if (decoration == spv::Decoration::NoContraction) {
|
||||
if (_.HasDecoration(target_id, spv::Decoration::FPFastMathMode)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "FPFastMathMode and NoContraction cannot decorate the same "
|
||||
"target";
|
||||
}
|
||||
}
|
||||
|
||||
if (DecorationTakesIdParameters(decoration)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "Decorations taking ID parameters may not be used with "
|
||||
|
@ -470,7 +470,8 @@ spv_result_t InstructionPass(ValidationState_t& _, const Instruction* inst) {
|
||||
}
|
||||
_.set_addressing_model(inst->GetOperandAs<spv::AddressingModel>(0));
|
||||
_.set_memory_model(inst->GetOperandAs<spv::MemoryModel>(1));
|
||||
} else if (opcode == spv::Op::OpExecutionMode) {
|
||||
} else if (opcode == spv::Op::OpExecutionMode ||
|
||||
opcode == spv::Op::OpExecutionModeId) {
|
||||
const uint32_t entry_point = inst->word(1);
|
||||
_.RegisterExecutionModeForEntryPoint(entry_point,
|
||||
spv::ExecutionMode(inst->word(2)));
|
||||
|
@ -340,29 +340,92 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
|
||||
|
||||
const auto mode = inst->GetOperandAs<spv::ExecutionMode>(1);
|
||||
if (inst->opcode() == spv::Op::OpExecutionModeId) {
|
||||
bool valid_mode = false;
|
||||
switch (mode) {
|
||||
case spv::ExecutionMode::SubgroupsPerWorkgroupId:
|
||||
case spv::ExecutionMode::LocalSizeHintId:
|
||||
case spv::ExecutionMode::LocalSizeId:
|
||||
case spv::ExecutionMode::FPFastMathDefault:
|
||||
valid_mode = true;
|
||||
break;
|
||||
default:
|
||||
valid_mode = false;
|
||||
break;
|
||||
}
|
||||
if (!valid_mode) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpExecutionModeId is only valid when the Mode operand is an "
|
||||
"execution mode that takes Extra Operands that are id "
|
||||
"operands.";
|
||||
}
|
||||
|
||||
size_t operand_count = inst->operands().size();
|
||||
for (size_t i = 2; i < operand_count; ++i) {
|
||||
const auto operand_id = inst->GetOperandAs<uint32_t>(2);
|
||||
const auto operand_id = inst->GetOperandAs<uint32_t>(i);
|
||||
const auto* operand_inst = _.FindDef(operand_id);
|
||||
if (mode == spv::ExecutionMode::SubgroupsPerWorkgroupId ||
|
||||
mode == spv::ExecutionMode::LocalSizeHintId ||
|
||||
mode == spv::ExecutionMode::LocalSizeId) {
|
||||
if (!spvOpcodeIsConstant(operand_inst->opcode())) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "For OpExecutionModeId all Extra Operand ids must be "
|
||||
"constant "
|
||||
"instructions.";
|
||||
}
|
||||
} else {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "OpExecutionModeId is only valid when the Mode operand is an "
|
||||
"execution mode that takes Extra Operands that are id "
|
||||
"operands.";
|
||||
switch (mode) {
|
||||
case spv::ExecutionMode::SubgroupsPerWorkgroupId:
|
||||
case spv::ExecutionMode::LocalSizeHintId:
|
||||
case spv::ExecutionMode::LocalSizeId:
|
||||
if (!spvOpcodeIsConstant(operand_inst->opcode())) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "For OpExecutionModeId all Extra Operand ids must be "
|
||||
"constant instructions.";
|
||||
}
|
||||
break;
|
||||
case spv::ExecutionMode::FPFastMathDefault:
|
||||
if (i == 2) {
|
||||
if (!_.IsFloatScalarType(operand_id)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The Target Type operand must be a floating-point "
|
||||
"scalar type";
|
||||
}
|
||||
} else {
|
||||
bool is_int32 = false;
|
||||
bool is_const = false;
|
||||
uint32_t value = 0;
|
||||
std::tie(is_int32, is_const, value) =
|
||||
_.EvalInt32IfConst(operand_id);
|
||||
if (is_int32 && is_const) {
|
||||
// Valid values include up to 0x00040000 (AllowTransform).
|
||||
uint32_t invalid_mask = 0xfff80000;
|
||||
if ((invalid_mask & value) != 0) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The Fast Math Default operand is an invalid bitmask "
|
||||
"value";
|
||||
}
|
||||
if (value &
|
||||
static_cast<uint32_t>(spv::FPFastMathModeMask::Fast)) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The Fast Math Default operand must not include Fast";
|
||||
}
|
||||
const auto reassoc_contract =
|
||||
spv::FPFastMathModeMask::AllowContract |
|
||||
spv::FPFastMathModeMask::AllowReassoc;
|
||||
if ((value & static_cast<uint32_t>(
|
||||
spv::FPFastMathModeMask::AllowTransform)) != 0 &&
|
||||
((value & static_cast<uint32_t>(reassoc_contract)) !=
|
||||
static_cast<uint32_t>(reassoc_contract))) {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The Fast Math Default operand must include "
|
||||
"AllowContract and AllowReassoc when AllowTransform "
|
||||
"is specified";
|
||||
}
|
||||
} else {
|
||||
return _.diag(SPV_ERROR_INVALID_ID, inst)
|
||||
<< "The Fast Math Default operand must be a "
|
||||
"non-specialization constant";
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (mode == spv::ExecutionMode::SubgroupsPerWorkgroupId ||
|
||||
mode == spv::ExecutionMode::LocalSizeHintId ||
|
||||
mode == spv::ExecutionMode::LocalSizeId) {
|
||||
mode == spv::ExecutionMode::LocalSizeId ||
|
||||
mode == spv::ExecutionMode::FPFastMathDefault) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "OpExecutionMode is only valid when the Mode operand is an "
|
||||
"execution mode that takes no Extra Operands, or takes Extra "
|
||||
@ -579,6 +642,20 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
|
||||
break;
|
||||
}
|
||||
|
||||
if (mode == spv::ExecutionMode::FPFastMathDefault) {
|
||||
const auto* modes = _.GetExecutionModes(entry_point_id);
|
||||
if (modes && modes->count(spv::ExecutionMode::ContractionOff)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "FPFastMathDefault and ContractionOff execution modes cannot "
|
||||
"be applied to the same entry point";
|
||||
}
|
||||
if (modes && modes->count(spv::ExecutionMode::SignedZeroInfNanPreserve)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "FPFastMathDefault and SignedZeroInfNanPreserve execution "
|
||||
"modes cannot be applied to the same entry point";
|
||||
}
|
||||
}
|
||||
|
||||
if (spvIsVulkanEnv(_.context()->target_env)) {
|
||||
if (mode == spv::ExecutionMode::OriginLowerLeft) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
@ -636,6 +713,70 @@ spv_result_t ValidateMemoryModel(ValidationState_t& _,
|
||||
|
||||
} // namespace
|
||||
|
||||
spv_result_t ValidateFloatControls2(ValidationState_t& _) {
|
||||
std::unordered_set<uint32_t> fp_fast_math_default_entry_points;
|
||||
for (auto entry_point : _.entry_points()) {
|
||||
const auto* exec_modes = _.GetExecutionModes(entry_point);
|
||||
if (exec_modes &&
|
||||
exec_modes->count(spv::ExecutionMode::FPFastMathDefault)) {
|
||||
fp_fast_math_default_entry_points.insert(entry_point);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<const Instruction*, spv::Decoration>> worklist;
|
||||
for (const auto& inst : _.ordered_instructions()) {
|
||||
if (inst.opcode() != spv::Op::OpDecorate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto decoration = inst.GetOperandAs<spv::Decoration>(1);
|
||||
const auto target_id = inst.GetOperandAs<uint32_t>(0);
|
||||
const auto target = _.FindDef(target_id);
|
||||
if (decoration == spv::Decoration::NoContraction) {
|
||||
worklist.push_back(std::make_pair(target, decoration));
|
||||
} else if (decoration == spv::Decoration::FPFastMathMode) {
|
||||
auto mask = inst.GetOperandAs<spv::FPFastMathModeMask>(2);
|
||||
if ((mask & spv::FPFastMathModeMask::Fast) !=
|
||||
spv::FPFastMathModeMask::MaskNone) {
|
||||
worklist.push_back(std::make_pair(target, decoration));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_set<const Instruction*> visited;
|
||||
while (!worklist.empty()) {
|
||||
const auto inst = worklist.back().first;
|
||||
const auto decoration = worklist.back().second;
|
||||
worklist.pop_back();
|
||||
|
||||
if (!visited.insert(inst).second) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto function = inst->function();
|
||||
if (function) {
|
||||
const auto& entry_points = _.FunctionEntryPoints(function->id());
|
||||
for (auto entry_point : entry_points) {
|
||||
if (fp_fast_math_default_entry_points.count(entry_point)) {
|
||||
const std::string dec = decoration == spv::Decoration::NoContraction
|
||||
? "NoContraction"
|
||||
: "FPFastMathMode Fast";
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< dec
|
||||
<< " cannot be used by an entry point with the "
|
||||
"FPFastMathDefault execution mode";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const auto& pair : inst->uses()) {
|
||||
worklist.push_back(std::make_pair(pair.first, decoration));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ModeSettingPass(ValidationState_t& _, const Instruction* inst) {
|
||||
switch (inst->opcode()) {
|
||||
case spv::Op::OpEntryPoint:
|
||||
|
@ -21,6 +21,9 @@
|
||||
#include "source/assembly_grammar.h"
|
||||
#include "source/enum_set.h"
|
||||
#include "source/operand.h"
|
||||
#include "source/spirv_target_env.h"
|
||||
#include "source/table.h"
|
||||
#include "spirv-tools/libspirv.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
@ -58,15 +61,17 @@ struct EnumCapabilityCase {
|
||||
uint32_t value;
|
||||
CapabilitySet expected_capabilities;
|
||||
};
|
||||
// Emits an EnumCapabilityCase to the ostream, returning the ostream.
|
||||
inline std::ostream& operator<<(std::ostream& out,
|
||||
const EnumCapabilityCase& ecc) {
|
||||
out << "EnumCapabilityCase{ " << spvOperandTypeStr(ecc.type) << "("
|
||||
<< unsigned(ecc.type) << "), " << ecc.value << ", "
|
||||
<< ecc.expected_capabilities << "}";
|
||||
|
||||
// Emits an EnumCapabilityCase to the given output stream. This is used
|
||||
// to emit failure cases when they occur, which helps debug tests.
|
||||
inline std::ostream& operator<<(std::ostream& out, EnumCapabilityCase e) {
|
||||
out << "{" << spvOperandTypeStr(e.type) << " " << e.value << " "
|
||||
<< e.expected_capabilities << " }";
|
||||
return out;
|
||||
}
|
||||
|
||||
using EnvEnumCapabilityCase = std::tuple<spv_target_env, EnumCapabilityCase>;
|
||||
|
||||
// Test fixture for testing EnumCapabilityCases.
|
||||
using EnumCapabilityTest =
|
||||
TestWithParam<std::tuple<spv_target_env, EnumCapabilityCase>>;
|
||||
|
@ -1264,5 +1264,41 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
{1, (uint32_t)spv::ExecutionMode::MaximallyReconvergesKHR})},
|
||||
})));
|
||||
|
||||
// SPV_KHR_float_controls2
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SPV_KHR_float_controls2, ExtensionRoundTripTest,
|
||||
Combine(
|
||||
Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_0,
|
||||
SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_3),
|
||||
ValuesIn(std::vector<AssemblyCase>{
|
||||
{"OpExtension \"SPV_KHR_float_controls2\"\n",
|
||||
MakeInstruction(spv::Op::OpExtension,
|
||||
MakeVector("SPV_KHR_float_controls2"))},
|
||||
{"OpCapability FloatControls2\n",
|
||||
MakeInstruction(spv::Op::OpCapability,
|
||||
{(uint32_t)spv::Capability::FloatControls2})},
|
||||
{"OpExecutionMode %1 FPFastMathDefault %2 %3\n",
|
||||
// The operands are: target type, flags constant
|
||||
MakeInstruction(
|
||||
spv::Op::OpExecutionMode,
|
||||
{1, (uint32_t)spv::ExecutionMode::FPFastMathDefault, 2, 3})},
|
||||
{"OpDecorate %1 FPFastMathMode AllowContract\n",
|
||||
MakeInstruction(
|
||||
spv::Op::OpDecorate,
|
||||
{1, (uint32_t)spv::Decoration::FPFastMathMode,
|
||||
(uint32_t)spv::FPFastMathModeMask::AllowContract})},
|
||||
{"OpDecorate %1 FPFastMathMode AllowReassoc\n",
|
||||
MakeInstruction(
|
||||
spv::Op::OpDecorate,
|
||||
{1, (uint32_t)spv::Decoration::FPFastMathMode,
|
||||
(uint32_t)spv::FPFastMathModeMask::AllowReassoc})},
|
||||
{"OpDecorate %1 FPFastMathMode AllowTransform\n",
|
||||
MakeInstruction(
|
||||
spv::Op::OpDecorate,
|
||||
{1, (uint32_t)spv::Decoration::FPFastMathMode,
|
||||
(uint32_t)spv::FPFastMathModeMask::AllowTransform})},
|
||||
})));
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
|
@ -65,6 +65,171 @@ OpDecorate %var BuiltIn WorkgroupSize
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(DecorationTest, FPFastMathModeInvalidMask) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %add FPFastMathMode !524288
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%undef = OpUndef %float
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%add = OpFAdd %float %undef %undef
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(text);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Invalid floating-point fast math mode operand"));
|
||||
}
|
||||
|
||||
TEST_F(DecorationTest, FPFastMathModeAllowTransformMissingAllowContract) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %add FPFastMathMode AllowTransform|AllowReassoc
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%undef = OpUndef %float
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%add = OpFAdd %float %undef %undef
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(text);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("AllowReassoc and AllowContract must be specified when "
|
||||
"AllowTransform is specified"));
|
||||
}
|
||||
|
||||
TEST_F(DecorationTest, FPFastMathModeAllowTransformMissingAllowReassoc) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %add FPFastMathMode AllowTransform|AllowContract
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%undef = OpUndef %float
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%add = OpFAdd %float %undef %undef
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(text);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("AllowReassoc and AllowContract must be specified when "
|
||||
"AllowTransform is specified"));
|
||||
}
|
||||
|
||||
TEST_F(DecorationTest, FPFastMathModeAllowTransformMissingContractAndReassoc) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %add FPFastMathMode AllowTransform
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%undef = OpUndef %float
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%add = OpFAdd %float %undef %undef
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(text);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("AllowReassoc and AllowContract must be specified when "
|
||||
"AllowTransform is specified"));
|
||||
}
|
||||
|
||||
TEST_F(DecorationTest, FPFastMathModeAndNoContraction) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %add FPFastMathMode None
|
||||
OpDecorate %add NoContraction
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%undef = OpUndef %float
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%add = OpFAdd %float %undef %undef
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(text);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"FPFastMathMode and NoContraction cannot decorate the same target"));
|
||||
}
|
||||
|
||||
TEST_F(DecorationTest, FPFastMathModeAndNoContraction2) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %add NoContraction
|
||||
OpDecorate %add FPFastMathMode None
|
||||
%void = OpTypeVoid
|
||||
%float = OpTypeFloat 32
|
||||
%undef = OpUndef %float
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%add = OpFAdd %float %undef %undef
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(text);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"FPFastMathMode and NoContraction cannot decorate the same target"));
|
||||
}
|
||||
|
||||
using MemberOnlyDecorations = spvtest::ValidateBase<std::string>;
|
||||
|
||||
TEST_P(MemberOnlyDecorations, MemberDecoration) {
|
||||
|
@ -1328,6 +1328,552 @@ OpFunctionEnd
|
||||
"SPV_KHR_maximal_reconvergence "));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultNotExecutionModeId) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpExecutionMode %main FPFastMathDefault %int_0 %int_0
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("OpExecutionMode is only valid when the Mode operand "
|
||||
"is an execution mode that takes no Extra Operands, or "
|
||||
"takes Extra Operands that are not id operands"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultNotAType) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpExecutionModeId %main FPFastMathDefault %int_0 %int_0
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"The Target Type operand must be a floating-point scalar type"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultNotAFloatType) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpExecutionModeId %main FPFastMathDefault %int %int_0
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"The Target Type operand must be a floating-point scalar type"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultNotAFloatScalarType) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpExecutionModeId %main FPFastMathDefault %float2 %int_0
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpConstant %int 0
|
||||
%float = OpTypeFloat 32
|
||||
%float2 = OpTypeVector %float 2
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"The Target Type operand must be a floating-point scalar type"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultSpecConstant) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpExecutionModeId %main FPFastMathDefault %float %int_0
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%int_0 = OpSpecConstant %int 0
|
||||
%float = OpTypeFloat 32
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("The Fast Math Default operand must be a "
|
||||
"non-specialization constant"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultInvalidMask) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpExecutionModeId %main FPFastMathDefault %float %constant
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%constant = OpConstant %int 524288
|
||||
%float = OpTypeFloat 32
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("The Fast Math Default operand is an invalid bitmask value"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultContainsFast) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpExecutionModeId %main FPFastMathDefault %float %constant
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%constant = OpConstant %int 16
|
||||
%float = OpTypeFloat 32
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("The Fast Math Default operand must not include Fast"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultAllowTransformMissingAllowReassoc) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpExecutionModeId %main FPFastMathDefault %float %constant
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%constant = OpConstant %int 327680
|
||||
%float = OpTypeFloat 32
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("The Fast Math Default operand must include AllowContract and "
|
||||
"AllowReassoc when AllowTransform is specified"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultAllowTransformMissingAllowContract) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpExecutionModeId %main FPFastMathDefault %float %constant
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%constant = OpConstant %int 393216
|
||||
%float = OpTypeFloat 32
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("The Fast Math Default operand must include AllowContract and "
|
||||
"AllowReassoc when AllowTransform is specified"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultAllowTransformMissingContractAndReassoc) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpExecutionModeId %main FPFastMathDefault %float %constant
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%constant = OpConstant %int 262144
|
||||
%float = OpTypeFloat 32
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("The Fast Math Default operand must include AllowContract and "
|
||||
"AllowReassoc when AllowTransform is specified"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultSignedZeroInfNanPreserve) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpCapability SignedZeroInfNanPreserve
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpExtension "SPV_KHR_float_controls"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpExecutionModeId %main FPFastMathDefault %float %constant
|
||||
OpExecutionMode %main SignedZeroInfNanPreserve 32
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%constant = OpConstant %int 0
|
||||
%float = OpTypeFloat 32
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
||||
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("FPFastMathDefault and SignedZeroInfNanPreserve execution "
|
||||
"modes cannot be applied to the same entry point"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultConractionOff) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Kernel
|
||||
OpCapability Addresses
|
||||
OpCapability FloatControls2
|
||||
OpCapability SignedZeroInfNanPreserve
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpExtension "SPV_KHR_float_controls"
|
||||
OpMemoryModel Physical64 OpenCL
|
||||
OpEntryPoint Kernel %main "main"
|
||||
OpExecutionModeId %main FPFastMathDefault %float %constant
|
||||
OpExecutionMode %main ContractionOff
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%constant = OpConstant %int 0
|
||||
%float = OpTypeFloat 32
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
||||
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("FPFastMathDefault and ContractionOff execution modes "
|
||||
"cannot be applied to the same entry point"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultNoContractionNotInCallTree) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionModeId %main FPFastMathDefault %float %constant
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %add NoContraction
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%constant = OpConstant %int 0
|
||||
%float = OpTypeFloat 32
|
||||
%zero = OpConstant %float 0
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%func = OpFunction %void None %void_fn
|
||||
%func_entry = OpLabel
|
||||
%add = OpFAdd %float %zero %zero
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultNoContractionInCallTree) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionModeId %main FPFastMathDefault %float %constant
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %add NoContraction
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%constant = OpConstant %int 0
|
||||
%float = OpTypeFloat 32
|
||||
%zero = OpConstant %float 0
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%call = OpFunctionCall %void %func
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%func = OpFunction %void None %void_fn
|
||||
%func_entry = OpLabel
|
||||
%add = OpFAdd %float %zero %zero
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
||||
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("NoContraction cannot be used by an entry point with "
|
||||
"the FPFastMathDefault execution mode"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultNoContractionInCallTree2) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Kernel
|
||||
OpCapability Addresses
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Physical64 OpenCL
|
||||
OpEntryPoint Kernel %main "main"
|
||||
OpExecutionModeId %main FPFastMathDefault %float %constant
|
||||
OpDecorate %const NoContraction
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%constant = OpConstant %int 0
|
||||
%float = OpTypeFloat 32
|
||||
%zero = OpConstant %float 0
|
||||
%const = OpSpecConstantOp %float FAdd %zero %zero
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%call = OpFunctionCall %void %func
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%func = OpFunction %void None %void_fn
|
||||
%func_entry = OpLabel
|
||||
%add = OpFAdd %float %const %zero
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
||||
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("NoContraction cannot be used by an entry point with "
|
||||
"the FPFastMathDefault execution mode"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultFastMathFastNotInCallTree) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionModeId %main FPFastMathDefault %float %constant
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %add FPFastMathMode Fast
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%constant = OpConstant %int 0
|
||||
%float = OpTypeFloat 32
|
||||
%zero = OpConstant %float 0
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%func = OpFunction %void None %void_fn
|
||||
%func_entry = OpLabel
|
||||
%add = OpFAdd %float %zero %zero
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultFastMathFastInCallTree) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %main "main"
|
||||
OpExecutionModeId %main FPFastMathDefault %float %constant
|
||||
OpExecutionMode %main LocalSize 1 1 1
|
||||
OpDecorate %add FPFastMathMode Fast
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%constant = OpConstant %int 0
|
||||
%float = OpTypeFloat 32
|
||||
%zero = OpConstant %float 0
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%call = OpFunctionCall %void %func
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%func = OpFunction %void None %void_fn
|
||||
%func_entry = OpLabel
|
||||
%add = OpFAdd %float %zero %zero
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
||||
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("FPFastMathMode Fast cannot be used by an entry point "
|
||||
"with the FPFastMathDefault execution mode"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateMode, FPFastMathDefaultFastMathFastInCallTree2) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Kernel
|
||||
OpCapability Addresses
|
||||
OpCapability FloatControls2
|
||||
OpExtension "SPV_KHR_float_controls2"
|
||||
OpMemoryModel Physical64 OpenCL
|
||||
OpEntryPoint Kernel %main "main"
|
||||
OpExecutionModeId %main FPFastMathDefault %float %constant
|
||||
OpDecorate %const FPFastMathMode Fast
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%constant = OpConstant %int 0
|
||||
%float = OpTypeFloat 32
|
||||
%zero = OpConstant %float 0
|
||||
%const = OpSpecConstantOp %float FAdd %zero %zero
|
||||
%void_fn = OpTypeFunction %void
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
%call = OpFunctionCall %void %func
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%func = OpFunction %void None %void_fn
|
||||
%func_entry = OpLabel
|
||||
%add = OpFAdd %float %const %zero
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
||||
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("FPFastMathMode Fast cannot be used by an entry point "
|
||||
"with the FPFastMathDefault execution mode"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
Loading…
Reference in New Issue
Block a user