Allow using FPRoundingMode when see VK_KHR_16bit_storage
authorLei Zhang <antiagainst@google.com>
Wed, 1 Mar 2017 20:51:44 +0000 (15:51 -0500)
committerDavid Neto <dneto@google.com>
Wed, 1 Mar 2017 23:25:28 +0000 (18:25 -0500)
According to the extension, FPRoundingMode should be allowed to
use without requiring Kernel capability when VK_KHR_16bit_storage
is enabled.

source/val/validation_state.cpp
source/val/validation_state.h
source/validate_instruction.cpp
test/val/val_data_test.cpp

index 7a9c591..db3ceb8 100644 (file)
@@ -298,6 +298,7 @@ void ValidationState_t::RegisterCapability(SpvCapability cap) {
     case SpvCapabilityStorageInputOutput16:
       features_.declare_int16_type = true;
       features_.declare_float16_type = true;
+      features_.free_fp_rounding_mode = true;
     default:
       break;
   }
index 686685e..30a1b2d 100644 (file)
@@ -57,8 +57,11 @@ class ValidationState_t {
  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,
@@ -202,7 +205,7 @@ class ValidationState_t {
   /// 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);
index 4d1ff78..d3b448c 100644 (file)
@@ -63,7 +63,7 @@ spv_result_t CapabilityError(ValidationState_t& _, int which_operand,
 }
 
 // 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
@@ -79,11 +79,25 @@ CapabilitySet RequiredCapabilities(const AssemblyGrammar& grammar,
       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();
@@ -110,8 +124,7 @@ spv_result_t CapCheck(ValidationState_t& _,
       // 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()));
@@ -124,7 +137,7 @@ spv_result_t CapCheck(ValidationState_t& _,
       // 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()));
       }
@@ -142,9 +155,8 @@ spv_result_t ReservedCheck(ValidationState_t& _,
     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;
   }
index f756e3a..ddc0dca 100644 (file)
@@ -92,6 +92,7 @@ string header_with_float64 = R"(
      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";
@@ -230,8 +231,8 @@ TEST_F(ValidateData, int16_good) {
 }
 
 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());
 }
@@ -540,4 +541,41 @@ OpTypeForwardPointer %_ptr_Generic_struct_A Generic
   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