| 138 | } |
| 139 | |
| 140 | spv_result_t ValidateGraphEntryPoint(ValidationState_t& _, |
| 141 | const Instruction* inst) { |
| 142 | // Graph must be an OpGraphARM |
| 143 | uint32_t graph = inst->GetOperandAs<uint32_t>(0); |
| 144 | auto graph_inst = _.FindDef(graph); |
| 145 | if (!IsGraph(_, graph)) { |
| 146 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 147 | << spvOpcodeString(inst->opcode()) |
| 148 | << " Graph must be a OpGraphARM but found " |
| 149 | << spvOpcodeString(graph_inst->opcode()) << "."; |
| 150 | } |
| 151 | |
| 152 | // Check number of Interface IDs matches number of I/Os of graph |
| 153 | auto graph_type_inst = _.FindDef(graph_inst->type_id()); |
| 154 | size_t graph_type_num_io = GraphTypeInstNumIO(graph_type_inst); |
| 155 | size_t graph_entry_point_num_interface_id = inst->operands().size() - 2; |
| 156 | if (graph_type_inst->opcode() != spv::Op::OpTypeGraphARM) { |
| 157 | // This is invalid but we want ValidateGraph to report a clear error |
| 158 | // so stop validating the graph entry point instruction |
| 159 | return SPV_SUCCESS; |
| 160 | } |
| 161 | if (graph_type_num_io != graph_entry_point_num_interface_id) { |
| 162 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 163 | << spvOpcodeString(inst->opcode()) << " Interface list contains " |
| 164 | << graph_entry_point_num_interface_id << " IDs but Graph's type " |
| 165 | << _.getIdName(graph_inst->type_id()) << " has " << graph_type_num_io |
| 166 | << " inputs and outputs."; |
| 167 | } |
| 168 | |
| 169 | // Check Interface IDs |
| 170 | for (uint32_t i = 2; i < inst->operands().size(); i++) { |
| 171 | uint32_t interface_id = inst->GetOperandAs<uint32_t>(i); |
| 172 | auto interface_inst = _.FindDef(interface_id); |
| 173 | |
| 174 | // Check interface IDs come from OpVariable |
| 175 | if ((interface_inst->opcode() != spv::Op::OpVariable) || |
| 176 | (interface_inst->GetOperandAs<spv::StorageClass>(2) != |
| 177 | spv::StorageClass::UniformConstant)) { |
| 178 | return _.diag(SPV_ERROR_INVALID_DATA, interface_inst) |
| 179 | << spvOpcodeString(inst->opcode()) << " Interface ID " |
| 180 | << _.getIdName(interface_id) |
| 181 | << " must come from OpVariable with UniformConstant Storage " |
| 182 | "Class."; |
| 183 | } |
| 184 | |
| 185 | // Check type of interface variable matches type of the corresponding graph |
| 186 | // I/O |
| 187 | uint32_t corresponding_graph_io_type = |
| 188 | graph_type_inst->GetOperandAs<uint32_t>(i); |
| 189 | |
| 190 | uint32_t interface_ptr_type = interface_inst->type_id(); |
| 191 | auto interface_ptr_inst = _.FindDef(interface_ptr_type); |
| 192 | auto interface_pointee_type = interface_ptr_inst->GetOperandAs<uint32_t>(2); |
| 193 | if (interface_pointee_type != corresponding_graph_io_type) { |
| 194 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 195 | << spvOpcodeString(inst->opcode()) << " Interface ID type " |
| 196 | << _.getIdName(interface_pointee_type) |
| 197 | << " must match the type of the corresponding graph I/O " |