Home | History | Annotate | Download | only in source
      1 // Copyright (c) 2015-2016 The Khronos Group Inc.
      2 //
      3 // Permission is hereby granted, free of charge, to any person obtaining a
      4 // copy of this software and/or associated documentation files (the
      5 // "Materials"), to deal in the Materials without restriction, including
      6 // without limitation the rights to use, copy, modify, merge, publish,
      7 // distribute, sublicense, and/or sell copies of the Materials, and to
      8 // permit persons to whom the Materials are furnished to do so, subject to
      9 // the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included
     12 // in all copies or substantial portions of the Materials.
     13 //
     14 // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
     15 // KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
     16 // SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
     17 //    https://www.khronos.org/registry/
     18 //
     19 // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     20 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     21 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     22 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
     23 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     24 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     25 // MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
     26 
     27 #include "validate.h"
     28 
     29 #include <functional>
     30 
     31 #include "opcode.h"
     32 #include "val/ValidationState.h"
     33 
     34 using std::function;
     35 using libspirv::ValidationState_t;
     36 
     37 namespace {
     38 // This function takes the opcode of an instruction and returns
     39 // a function object that will return true if the index
     40 // of the operand can be forwarad declared. This function will
     41 // used in the SSA validation stage of the pipeline
     42 function<bool(unsigned)> getCanBeForwardDeclaredFunction(SpvOp opcode) {
     43   function<bool(unsigned index)> out;
     44   switch (opcode) {
     45     case SpvOpExecutionMode:
     46     case SpvOpEntryPoint:
     47     case SpvOpName:
     48     case SpvOpMemberName:
     49     case SpvOpSelectionMerge:
     50     case SpvOpDecorate:
     51     case SpvOpMemberDecorate:
     52     case SpvOpBranch:
     53     case SpvOpLoopMerge:
     54       out = [](unsigned) { return true; };
     55       break;
     56     case SpvOpGroupDecorate:
     57     case SpvOpGroupMemberDecorate:
     58     case SpvOpBranchConditional:
     59     case SpvOpSwitch:
     60       out = [](unsigned index) { return index != 0; };
     61       break;
     62 
     63     case SpvOpFunctionCall:
     64       out = [](unsigned index) { return index == 2; };
     65       break;
     66 
     67     case SpvOpPhi:
     68       out = [](unsigned index) { return index > 1; };
     69       break;
     70 
     71     case SpvOpEnqueueKernel:
     72       out = [](unsigned index) { return index == 8; };
     73       break;
     74 
     75     case SpvOpGetKernelNDrangeSubGroupCount:
     76     case SpvOpGetKernelNDrangeMaxSubGroupSize:
     77       out = [](unsigned index) { return index == 3; };
     78       break;
     79 
     80     case SpvOpGetKernelWorkGroupSize:
     81     case SpvOpGetKernelPreferredWorkGroupSizeMultiple:
     82       out = [](unsigned index) { return index == 2; };
     83       break;
     84 
     85     default:
     86       out = [](unsigned) { return false; };
     87       break;
     88   }
     89   return out;
     90 }
     91 }  // namespace
     92 
     93 namespace libspirv {
     94 
     95 // Performs SSA validation on the IDs of an instruction. The
     96 // can_have_forward_declared_ids  functor should return true if the
     97 // instruction operand's ID can be forward referenced.
     98 //
     99 // TODO(umar): Use dominators to correctly validate SSA. For example, the result
    100 // id from a 'then' block cannot dominate its usage in the 'else' block. This
    101 // is not yet performed by this function.
    102 spv_result_t SsaPass(ValidationState_t& _,
    103                      const spv_parsed_instruction_t* inst) {
    104   auto can_have_forward_declared_ids =
    105       getCanBeForwardDeclaredFunction(static_cast<SpvOp>(inst->opcode));
    106 
    107   for (unsigned i = 0; i < inst->num_operands; i++) {
    108     const spv_parsed_operand_t& operand = inst->operands[i];
    109     const spv_operand_type_t& type = operand.type;
    110     const uint32_t* operand_ptr = inst->words + operand.offset;
    111 
    112     auto ret = SPV_ERROR_INTERNAL;
    113     switch (type) {
    114       case SPV_OPERAND_TYPE_RESULT_ID:
    115         _.RemoveIfForwardDeclared(*operand_ptr);
    116         ret = SPV_SUCCESS;
    117         break;
    118       case SPV_OPERAND_TYPE_ID:
    119       case SPV_OPERAND_TYPE_TYPE_ID:
    120       case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
    121       case SPV_OPERAND_TYPE_SCOPE_ID:
    122         if (_.IsDefinedId(*operand_ptr)) {
    123           ret = SPV_SUCCESS;
    124         } else if (can_have_forward_declared_ids(i)) {
    125           ret = _.ForwardDeclareId(*operand_ptr);
    126         } else {
    127           ret = _.diag(SPV_ERROR_INVALID_ID) << "ID "
    128                                              << _.getIdName(*operand_ptr)
    129                                              << " has not been defined";
    130         }
    131         break;
    132       default:
    133         ret = SPV_SUCCESS;
    134         break;
    135     }
    136     if (SPV_SUCCESS != ret) {
    137       return ret;
    138     }
    139   }
    140   return SPV_SUCCESS;
    141 }
    142 }  // namespace libspirv
    143