case SpvCapabilityStorageInputOutput16:
features_.declare_int16_type = true;
features_.declare_float16_type = true;
+ features_.free_fp_rounding_mode = true;
default:
break;
}
public:
// Features that can optionally be turned on by a capability.
struct Feature {
- bool declare_int16_type = false; // Allow OpTypeInt with 16 bit width?
- bool declare_float16_type = false; // Allow OpTypeFloat with 16 bit width?
+ bool declare_int16_type = false; // Allow OpTypeInt with 16 bit width?
+ bool declare_float16_type = false; // Allow OpTypeFloat with 16 bit width?
+ bool free_fp_rounding_mode = false; // Allow the FPRoundingMode decoration
+ // and its vaules to be used without
+ // requiring any capability
};
ValidationState_t(const spv_const_context context,
/// Returns the memory model of this module, or Simple if uninitialized.
SpvMemoryModel memory_model() const;
- AssemblyGrammar& grammar() { return grammar_; }
+ const AssemblyGrammar& grammar() const { return grammar_; }
/// Registers the instruction
void RegisterInstruction(const spv_parsed_instruction_t& inst);
}
// Returns an operand's required capabilities.
-CapabilitySet RequiredCapabilities(const AssemblyGrammar& grammar,
+CapabilitySet RequiredCapabilities(const ValidationState_t& state,
spv_operand_type_t type, uint32_t operand) {
// Mere mention of PointSize, ClipDistance, or CullDistance in a Builtin
// decoration does not require the associated capability. The use of such
default:
break;
}
+ } else if (type == SPV_OPERAND_TYPE_FP_ROUNDING_MODE) {
+ // Allow all FP rounding modes if requested
+ if (state.features().free_fp_rounding_mode) {
+ return CapabilitySet();
+ }
}
spv_operand_desc operand_desc;
- if (SPV_SUCCESS == grammar.lookupOperand(type, operand, &operand_desc)) {
- return operand_desc->capabilities;
+ const auto ret = state.grammar().lookupOperand(type, operand, &operand_desc);
+ if (ret == SPV_SUCCESS) {
+ CapabilitySet result = operand_desc->capabilities;
+
+ // Allow FPRoundingMode decoration if requested
+ if (state.features().free_fp_rounding_mode &&
+ type == SPV_OPERAND_TYPE_DECORATION &&
+ operand_desc->value == SpvDecorationFPRoundingMode) {
+ return CapabilitySet();
+ }
+ return result;
}
return CapabilitySet();
// Check for required capabilities for each bit position of the mask.
for (uint32_t mask_bit = 0x80000000; mask_bit; mask_bit >>= 1) {
if (word & mask_bit) {
- const auto caps =
- RequiredCapabilities(_.grammar(), operand.type, mask_bit);
+ const auto caps = RequiredCapabilities(_, operand.type, mask_bit);
if (!_.HasAnyOf(caps)) {
return CapabilityError(_, i + 1, opcode,
ToString(caps, _.grammar()));
// https://github.com/KhronosGroup/SPIRV-Tools/issues/248
} else {
// Check the operand word as a whole.
- const auto caps = RequiredCapabilities(_.grammar(), operand.type, word);
+ const auto caps = RequiredCapabilities(_, operand.type, word);
if (!_.HasAnyOf(caps)) {
return CapabilityError(_, i + 1, opcode, ToString(caps, _.grammar()));
}
case SpvOpImageSparseSampleProjExplicitLod:
case SpvOpImageSparseSampleProjDrefImplicitLod:
case SpvOpImageSparseSampleProjDrefExplicitLod:
- return _.diag(SPV_ERROR_INVALID_VALUE)
- << spvOpcodeString(opcode)
- << " is reserved for future use.";
+ return _.diag(SPV_ERROR_INVALID_VALUE) << spvOpcodeString(opcode)
+ << " is reserved for future use.";
default:
return SPV_SUCCESS;
}
OpCapability Float64
OpMemoryModel Logical GLSL450
)";
+
string invalid_comp_error = "Illegal number of components";
string missing_cap_error = "requires the Vector16 capability";
string missing_int8_cap_error = "requires the Int8 capability";
}
TEST_F(ValidateData, storage_uniform_buffer_block_16_good) {
- string str =
- HeaderWith("StorageUniformBufferBlock16") + "%2 = OpTypeInt 16 1 %3 = OpTypeFloat 16";
+ string str = HeaderWith("StorageUniformBufferBlock16") +
+ "%2 = OpTypeInt 16 1 %3 = OpTypeFloat 16";
CompileSuccessfully(str.c_str());
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
+TEST_F(ValidateData, ext_16bit_storage_caps_allow_free_fp_rounding_mode) {
+ for (const char* cap : {"StorageUniform16", "StorageUniformBufferBlock16",
+ "StoragePushConstant16", "StorageInputOutput16"}) {
+ for (const char* mode : {"RTE", "RTZ", "RTP", "RTN"}) {
+ string str = string(R"(
+ OpCapability Shader
+ OpCapability Linkage
+ OpCapability )") +
+ cap + R"(
+ OpMemoryModel Logical GLSL450
+ OpDecorate %2 FPRoundingMode )" +
+ mode + R"(
+ %1 = OpTypeFloat 32
+ %2 = OpConstant %1 1.25
+ )";
+ CompileSuccessfully(str.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+ }
+ }
+}
+
+TEST_F(ValidateData, default_disallow_free_fp_rounding_mode) {
+ string str = R"(
+ OpCapability Shader
+ OpCapability Linkage
+ OpMemoryModel Logical GLSL450
+ OpDecorate %2 FPRoundingMode RTZ
+ %1 = OpTypeFloat 32
+ %2 = OpConstant %1 1.25
+ )";
+ CompileSuccessfully(str.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Operand 2 of Decorate requires one of these "
+ "capabilities: Kernel"));
+}
+
} // anonymous namespace