Home | History | Annotate | Download | only in val
      1 // Copyright (c) 2018 Google LLC.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 // Validates correctness of barrier SPIR-V instructions.
     16 
     17 #include "source/val/validate.h"
     18 
     19 #include <string>
     20 
     21 #include "source/diagnostic.h"
     22 #include "source/opcode.h"
     23 #include "source/spirv_constant.h"
     24 #include "source/spirv_target_env.h"
     25 #include "source/util/bitutils.h"
     26 #include "source/val/instruction.h"
     27 #include "source/val/validate_memory_semantics.h"
     28 #include "source/val/validate_scopes.h"
     29 #include "source/val/validation_state.h"
     30 
     31 namespace spvtools {
     32 namespace val {
     33 
     34 // Validates correctness of barrier instructions.
     35 spv_result_t BarriersPass(ValidationState_t& _, const Instruction* inst) {
     36   const SpvOp opcode = inst->opcode();
     37   const uint32_t result_type = inst->type_id();
     38 
     39   switch (opcode) {
     40     case SpvOpControlBarrier: {
     41       if (spvVersionForTargetEnv(_.context()->target_env) <
     42           SPV_SPIRV_VERSION_WORD(1, 3)) {
     43         _.function(inst->function()->id())
     44             ->RegisterExecutionModelLimitation(
     45                 [](SpvExecutionModel model, std::string* message) {
     46                   if (model != SpvExecutionModelTessellationControl &&
     47                       model != SpvExecutionModelGLCompute &&
     48                       model != SpvExecutionModelKernel &&
     49                       model != SpvExecutionModelTaskNV &&
     50                       model != SpvExecutionModelMeshNV) {
     51                     if (message) {
     52                       *message =
     53                           "OpControlBarrier requires one of the following "
     54                           "Execution "
     55                           "Models: TessellationControl, GLCompute or Kernel";
     56                     }
     57                     return false;
     58                   }
     59                   return true;
     60                 });
     61       }
     62 
     63       const uint32_t execution_scope = inst->word(1);
     64       const uint32_t memory_scope = inst->word(2);
     65 
     66       if (auto error = ValidateExecutionScope(_, inst, execution_scope)) {
     67         return error;
     68       }
     69 
     70       if (auto error = ValidateMemoryScope(_, inst, memory_scope)) {
     71         return error;
     72       }
     73 
     74       if (auto error = ValidateMemorySemantics(_, inst, 2)) {
     75         return error;
     76       }
     77       break;
     78     }
     79 
     80     case SpvOpMemoryBarrier: {
     81       const uint32_t memory_scope = inst->word(1);
     82 
     83       if (auto error = ValidateMemoryScope(_, inst, memory_scope)) {
     84         return error;
     85       }
     86 
     87       if (auto error = ValidateMemorySemantics(_, inst, 1)) {
     88         return error;
     89       }
     90       break;
     91     }
     92 
     93     case SpvOpNamedBarrierInitialize: {
     94       if (_.GetIdOpcode(result_type) != SpvOpTypeNamedBarrier) {
     95         return _.diag(SPV_ERROR_INVALID_DATA, inst)
     96                << spvOpcodeString(opcode)
     97                << ": expected Result Type to be OpTypeNamedBarrier";
     98       }
     99 
    100       const uint32_t subgroup_count_type = _.GetOperandTypeId(inst, 2);
    101       if (!_.IsIntScalarType(subgroup_count_type) ||
    102           _.GetBitWidth(subgroup_count_type) != 32) {
    103         return _.diag(SPV_ERROR_INVALID_DATA, inst)
    104                << spvOpcodeString(opcode)
    105                << ": expected Subgroup Count to be a 32-bit int";
    106       }
    107       break;
    108     }
    109 
    110     case SpvOpMemoryNamedBarrier: {
    111       const uint32_t named_barrier_type = _.GetOperandTypeId(inst, 0);
    112       if (_.GetIdOpcode(named_barrier_type) != SpvOpTypeNamedBarrier) {
    113         return _.diag(SPV_ERROR_INVALID_DATA, inst)
    114                << spvOpcodeString(opcode)
    115                << ": expected Named Barrier to be of type OpTypeNamedBarrier";
    116       }
    117 
    118       const uint32_t memory_scope = inst->word(2);
    119 
    120       if (auto error = ValidateMemoryScope(_, inst, memory_scope)) {
    121         return error;
    122       }
    123 
    124       if (auto error = ValidateMemorySemantics(_, inst, 2)) {
    125         return error;
    126       }
    127       break;
    128     }
    129 
    130     default:
    131       break;
    132   }
    133 
    134   return SPV_SUCCESS;
    135 }
    136 
    137 }  // namespace val
    138 }  // namespace spvtools
    139