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