validation_state.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281
  1. // Copyright (c) 2015-2016 The Khronos Group Inc.
  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. #include "source/val/validation_state.h"
  15. #include <cassert>
  16. #include <stack>
  17. #include <utility>
  18. #include "source/opcode.h"
  19. #include "source/spirv_constant.h"
  20. #include "source/spirv_target_env.h"
  21. #include "source/val/basic_block.h"
  22. #include "source/val/construct.h"
  23. #include "source/val/function.h"
  24. #include "spirv-tools/libspirv.h"
  25. namespace spvtools {
  26. namespace val {
  27. namespace {
  28. bool IsInstructionInLayoutSection(ModuleLayoutSection layout, SpvOp op) {
  29. // See Section 2.4
  30. bool out = false;
  31. // clang-format off
  32. switch (layout) {
  33. case kLayoutCapabilities: out = op == SpvOpCapability; break;
  34. case kLayoutExtensions: out = op == SpvOpExtension; break;
  35. case kLayoutExtInstImport: out = op == SpvOpExtInstImport; break;
  36. case kLayoutMemoryModel: out = op == SpvOpMemoryModel; break;
  37. case kLayoutEntryPoint: out = op == SpvOpEntryPoint; break;
  38. case kLayoutExecutionMode:
  39. out = op == SpvOpExecutionMode || op == SpvOpExecutionModeId;
  40. break;
  41. case kLayoutDebug1:
  42. switch (op) {
  43. case SpvOpSourceContinued:
  44. case SpvOpSource:
  45. case SpvOpSourceExtension:
  46. case SpvOpString:
  47. out = true;
  48. break;
  49. default: break;
  50. }
  51. break;
  52. case kLayoutDebug2:
  53. switch (op) {
  54. case SpvOpName:
  55. case SpvOpMemberName:
  56. out = true;
  57. break;
  58. default: break;
  59. }
  60. break;
  61. case kLayoutDebug3:
  62. // Only OpModuleProcessed is allowed here.
  63. out = (op == SpvOpModuleProcessed);
  64. break;
  65. case kLayoutAnnotations:
  66. switch (op) {
  67. case SpvOpDecorate:
  68. case SpvOpMemberDecorate:
  69. case SpvOpGroupDecorate:
  70. case SpvOpGroupMemberDecorate:
  71. case SpvOpDecorationGroup:
  72. case SpvOpDecorateId:
  73. case SpvOpDecorateStringGOOGLE:
  74. case SpvOpMemberDecorateStringGOOGLE:
  75. out = true;
  76. break;
  77. default: break;
  78. }
  79. break;
  80. case kLayoutTypes:
  81. if (spvOpcodeGeneratesType(op) || spvOpcodeIsConstant(op)) {
  82. out = true;
  83. break;
  84. }
  85. switch (op) {
  86. case SpvOpTypeForwardPointer:
  87. case SpvOpVariable:
  88. case SpvOpLine:
  89. case SpvOpNoLine:
  90. case SpvOpUndef:
  91. out = true;
  92. break;
  93. default: break;
  94. }
  95. break;
  96. case kLayoutFunctionDeclarations:
  97. case kLayoutFunctionDefinitions:
  98. // NOTE: These instructions should NOT be in these layout sections
  99. if (spvOpcodeGeneratesType(op) || spvOpcodeIsConstant(op)) {
  100. out = false;
  101. break;
  102. }
  103. switch (op) {
  104. case SpvOpCapability:
  105. case SpvOpExtension:
  106. case SpvOpExtInstImport:
  107. case SpvOpMemoryModel:
  108. case SpvOpEntryPoint:
  109. case SpvOpExecutionMode:
  110. case SpvOpExecutionModeId:
  111. case SpvOpSourceContinued:
  112. case SpvOpSource:
  113. case SpvOpSourceExtension:
  114. case SpvOpString:
  115. case SpvOpName:
  116. case SpvOpMemberName:
  117. case SpvOpModuleProcessed:
  118. case SpvOpDecorate:
  119. case SpvOpMemberDecorate:
  120. case SpvOpGroupDecorate:
  121. case SpvOpGroupMemberDecorate:
  122. case SpvOpDecorationGroup:
  123. case SpvOpTypeForwardPointer:
  124. out = false;
  125. break;
  126. default:
  127. out = true;
  128. break;
  129. }
  130. }
  131. // clang-format on
  132. return out;
  133. }
  134. // Counts the number of instructions and functions in the file.
  135. spv_result_t CountInstructions(void* user_data,
  136. const spv_parsed_instruction_t* inst) {
  137. ValidationState_t& _ = *(reinterpret_cast<ValidationState_t*>(user_data));
  138. if (inst->opcode == SpvOpFunction) _.increment_total_functions();
  139. _.increment_total_instructions();
  140. return SPV_SUCCESS;
  141. }
  142. spv_result_t setHeader(void* user_data, spv_endianness_t, uint32_t,
  143. uint32_t version, uint32_t generator, uint32_t id_bound,
  144. uint32_t) {
  145. ValidationState_t& vstate =
  146. *(reinterpret_cast<ValidationState_t*>(user_data));
  147. vstate.setIdBound(id_bound);
  148. vstate.setGenerator(generator);
  149. vstate.setVersion(version);
  150. return SPV_SUCCESS;
  151. }
  152. // Add features based on SPIR-V core version number.
  153. void UpdateFeaturesBasedOnSpirvVersion(ValidationState_t::Feature* features,
  154. uint32_t version) {
  155. assert(features);
  156. if (version >= SPV_SPIRV_VERSION_WORD(1, 4)) {
  157. features->select_between_composites = true;
  158. features->copy_memory_permits_two_memory_accesses = true;
  159. features->uconvert_spec_constant_op = true;
  160. features->nonwritable_var_in_function_or_private = true;
  161. }
  162. }
  163. } // namespace
  164. ValidationState_t::ValidationState_t(const spv_const_context ctx,
  165. const spv_const_validator_options opt,
  166. const uint32_t* words,
  167. const size_t num_words,
  168. const uint32_t max_warnings)
  169. : context_(ctx),
  170. options_(opt),
  171. words_(words),
  172. num_words_(num_words),
  173. unresolved_forward_ids_{},
  174. operand_names_{},
  175. current_layout_section_(kLayoutCapabilities),
  176. module_functions_(),
  177. module_capabilities_(),
  178. module_extensions_(),
  179. ordered_instructions_(),
  180. all_definitions_(),
  181. global_vars_(),
  182. local_vars_(),
  183. struct_nesting_depth_(),
  184. struct_has_nested_blockorbufferblock_struct_(),
  185. grammar_(ctx),
  186. addressing_model_(SpvAddressingModelMax),
  187. memory_model_(SpvMemoryModelMax),
  188. pointer_size_and_alignment_(0),
  189. in_function_(false),
  190. num_of_warnings_(0),
  191. max_num_of_warnings_(max_warnings) {
  192. assert(opt && "Validator options may not be Null.");
  193. const auto env = context_->target_env;
  194. if (spvIsVulkanEnv(env)) {
  195. // Vulkan 1.1 includes VK_KHR_relaxed_block_layout in core.
  196. if (env != SPV_ENV_VULKAN_1_0) {
  197. features_.env_relaxed_block_layout = true;
  198. }
  199. }
  200. switch (env) {
  201. case SPV_ENV_WEBGPU_0:
  202. features_.bans_op_undef = true;
  203. break;
  204. default:
  205. break;
  206. }
  207. // Only attempt to count if we have words, otherwise let the other validation
  208. // fail and generate an error.
  209. if (num_words > 0) {
  210. // Count the number of instructions in the binary.
  211. // This parse should not produce any error messages. Hijack the context and
  212. // replace the message consumer so that we do not pollute any state in input
  213. // consumer.
  214. spv_context_t hijacked_context = *ctx;
  215. hijacked_context.consumer = [](spv_message_level_t, const char*,
  216. const spv_position_t&, const char*) {};
  217. spvBinaryParse(&hijacked_context, this, words, num_words, setHeader,
  218. CountInstructions,
  219. /* diagnostic = */ nullptr);
  220. preallocateStorage();
  221. }
  222. UpdateFeaturesBasedOnSpirvVersion(&features_, version_);
  223. friendly_mapper_ = spvtools::MakeUnique<spvtools::FriendlyNameMapper>(
  224. context_, words_, num_words_);
  225. name_mapper_ = friendly_mapper_->GetNameMapper();
  226. }
  227. void ValidationState_t::preallocateStorage() {
  228. ordered_instructions_.reserve(total_instructions_);
  229. module_functions_.reserve(total_functions_);
  230. }
  231. spv_result_t ValidationState_t::ForwardDeclareId(uint32_t id) {
  232. unresolved_forward_ids_.insert(id);
  233. return SPV_SUCCESS;
  234. }
  235. spv_result_t ValidationState_t::RemoveIfForwardDeclared(uint32_t id) {
  236. unresolved_forward_ids_.erase(id);
  237. return SPV_SUCCESS;
  238. }
  239. spv_result_t ValidationState_t::RegisterForwardPointer(uint32_t id) {
  240. forward_pointer_ids_.insert(id);
  241. return SPV_SUCCESS;
  242. }
  243. bool ValidationState_t::IsForwardPointer(uint32_t id) const {
  244. return (forward_pointer_ids_.find(id) != forward_pointer_ids_.end());
  245. }
  246. void ValidationState_t::AssignNameToId(uint32_t id, std::string name) {
  247. operand_names_[id] = name;
  248. }
  249. std::string ValidationState_t::getIdName(uint32_t id) const {
  250. const std::string id_name = name_mapper_(id);
  251. std::stringstream out;
  252. out << id << "[%" << id_name << "]";
  253. return out.str();
  254. }
  255. size_t ValidationState_t::unresolved_forward_id_count() const {
  256. return unresolved_forward_ids_.size();
  257. }
  258. std::vector<uint32_t> ValidationState_t::UnresolvedForwardIds() const {
  259. std::vector<uint32_t> out(std::begin(unresolved_forward_ids_),
  260. std::end(unresolved_forward_ids_));
  261. return out;
  262. }
  263. bool ValidationState_t::IsDefinedId(uint32_t id) const {
  264. return all_definitions_.find(id) != std::end(all_definitions_);
  265. }
  266. const Instruction* ValidationState_t::FindDef(uint32_t id) const {
  267. auto it = all_definitions_.find(id);
  268. if (it == all_definitions_.end()) return nullptr;
  269. return it->second;
  270. }
  271. Instruction* ValidationState_t::FindDef(uint32_t id) {
  272. auto it = all_definitions_.find(id);
  273. if (it == all_definitions_.end()) return nullptr;
  274. return it->second;
  275. }
  276. ModuleLayoutSection ValidationState_t::current_layout_section() const {
  277. return current_layout_section_;
  278. }
  279. void ValidationState_t::ProgressToNextLayoutSectionOrder() {
  280. // Guard against going past the last element(kLayoutFunctionDefinitions)
  281. if (current_layout_section_ <= kLayoutFunctionDefinitions) {
  282. current_layout_section_ =
  283. static_cast<ModuleLayoutSection>(current_layout_section_ + 1);
  284. }
  285. }
  286. bool ValidationState_t::IsOpcodeInCurrentLayoutSection(SpvOp op) {
  287. return IsInstructionInLayoutSection(current_layout_section_, op);
  288. }
  289. DiagnosticStream ValidationState_t::diag(spv_result_t error_code,
  290. const Instruction* inst) {
  291. if (error_code == SPV_WARNING) {
  292. if (num_of_warnings_ == max_num_of_warnings_) {
  293. DiagnosticStream({0, 0, 0}, context_->consumer, "", error_code)
  294. << "Other warnings have been suppressed.\n";
  295. }
  296. if (num_of_warnings_ >= max_num_of_warnings_) {
  297. return DiagnosticStream({0, 0, 0}, nullptr, "", error_code);
  298. }
  299. ++num_of_warnings_;
  300. }
  301. std::string disassembly;
  302. if (inst) disassembly = Disassemble(*inst);
  303. return DiagnosticStream({0, 0, inst ? inst->LineNum() : 0},
  304. context_->consumer, disassembly, error_code);
  305. }
  306. std::vector<Function>& ValidationState_t::functions() {
  307. return module_functions_;
  308. }
  309. Function& ValidationState_t::current_function() {
  310. assert(in_function_body());
  311. return module_functions_.back();
  312. }
  313. const Function& ValidationState_t::current_function() const {
  314. assert(in_function_body());
  315. return module_functions_.back();
  316. }
  317. const Function* ValidationState_t::function(uint32_t id) const {
  318. const auto it = id_to_function_.find(id);
  319. if (it == id_to_function_.end()) return nullptr;
  320. return it->second;
  321. }
  322. Function* ValidationState_t::function(uint32_t id) {
  323. auto it = id_to_function_.find(id);
  324. if (it == id_to_function_.end()) return nullptr;
  325. return it->second;
  326. }
  327. bool ValidationState_t::in_function_body() const { return in_function_; }
  328. bool ValidationState_t::in_block() const {
  329. return module_functions_.empty() == false &&
  330. module_functions_.back().current_block() != nullptr;
  331. }
  332. void ValidationState_t::RegisterCapability(SpvCapability cap) {
  333. // Avoid redundant work. Otherwise the recursion could induce work
  334. // quadrdatic in the capability dependency depth. (Ok, not much, but
  335. // it's something.)
  336. if (module_capabilities_.Contains(cap)) return;
  337. module_capabilities_.Add(cap);
  338. spv_operand_desc desc;
  339. if (SPV_SUCCESS ==
  340. grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, cap, &desc)) {
  341. CapabilitySet(desc->numCapabilities, desc->capabilities)
  342. .ForEach([this](SpvCapability c) { RegisterCapability(c); });
  343. }
  344. switch (cap) {
  345. case SpvCapabilityKernel:
  346. features_.group_ops_reduce_and_scans = true;
  347. break;
  348. case SpvCapabilityInt8:
  349. features_.use_int8_type = true;
  350. features_.declare_int8_type = true;
  351. break;
  352. case SpvCapabilityStorageBuffer8BitAccess:
  353. case SpvCapabilityUniformAndStorageBuffer8BitAccess:
  354. case SpvCapabilityStoragePushConstant8:
  355. features_.declare_int8_type = true;
  356. break;
  357. case SpvCapabilityInt16:
  358. features_.declare_int16_type = true;
  359. break;
  360. case SpvCapabilityFloat16:
  361. case SpvCapabilityFloat16Buffer:
  362. features_.declare_float16_type = true;
  363. break;
  364. case SpvCapabilityStorageUniformBufferBlock16:
  365. case SpvCapabilityStorageUniform16:
  366. case SpvCapabilityStoragePushConstant16:
  367. case SpvCapabilityStorageInputOutput16:
  368. features_.declare_int16_type = true;
  369. features_.declare_float16_type = true;
  370. features_.free_fp_rounding_mode = true;
  371. break;
  372. case SpvCapabilityVariablePointers:
  373. features_.variable_pointers = true;
  374. features_.variable_pointers_storage_buffer = true;
  375. break;
  376. case SpvCapabilityVariablePointersStorageBuffer:
  377. features_.variable_pointers_storage_buffer = true;
  378. break;
  379. default:
  380. break;
  381. }
  382. }
  383. void ValidationState_t::RegisterExtension(Extension ext) {
  384. if (module_extensions_.Contains(ext)) return;
  385. module_extensions_.Add(ext);
  386. switch (ext) {
  387. case kSPV_AMD_gpu_shader_half_float:
  388. case kSPV_AMD_gpu_shader_half_float_fetch:
  389. // SPV_AMD_gpu_shader_half_float enables float16 type.
  390. // https://github.com/KhronosGroup/SPIRV-Tools/issues/1375
  391. features_.declare_float16_type = true;
  392. break;
  393. case kSPV_AMD_gpu_shader_int16:
  394. // This is not yet in the extension, but it's recommended for it.
  395. // See https://github.com/KhronosGroup/glslang/issues/848
  396. features_.uconvert_spec_constant_op = true;
  397. break;
  398. case kSPV_AMD_shader_ballot:
  399. // The grammar doesn't encode the fact that SPV_AMD_shader_ballot
  400. // enables the use of group operations Reduce, InclusiveScan,
  401. // and ExclusiveScan. Enable it manually.
  402. // https://github.com/KhronosGroup/SPIRV-Tools/issues/991
  403. features_.group_ops_reduce_and_scans = true;
  404. break;
  405. default:
  406. break;
  407. }
  408. }
  409. bool ValidationState_t::HasAnyOfCapabilities(
  410. const CapabilitySet& capabilities) const {
  411. return module_capabilities_.HasAnyOf(capabilities);
  412. }
  413. bool ValidationState_t::HasAnyOfExtensions(
  414. const ExtensionSet& extensions) const {
  415. return module_extensions_.HasAnyOf(extensions);
  416. }
  417. void ValidationState_t::set_addressing_model(SpvAddressingModel am) {
  418. addressing_model_ = am;
  419. switch (am) {
  420. case SpvAddressingModelPhysical32:
  421. pointer_size_and_alignment_ = 4;
  422. break;
  423. default:
  424. // fall through
  425. case SpvAddressingModelPhysical64:
  426. case SpvAddressingModelPhysicalStorageBuffer64EXT:
  427. pointer_size_and_alignment_ = 8;
  428. break;
  429. }
  430. }
  431. SpvAddressingModel ValidationState_t::addressing_model() const {
  432. return addressing_model_;
  433. }
  434. void ValidationState_t::set_memory_model(SpvMemoryModel mm) {
  435. memory_model_ = mm;
  436. }
  437. SpvMemoryModel ValidationState_t::memory_model() const { return memory_model_; }
  438. spv_result_t ValidationState_t::RegisterFunction(
  439. uint32_t id, uint32_t ret_type_id, SpvFunctionControlMask function_control,
  440. uint32_t function_type_id) {
  441. assert(in_function_body() == false &&
  442. "RegisterFunction can only be called when parsing the binary outside "
  443. "of another function");
  444. in_function_ = true;
  445. module_functions_.emplace_back(id, ret_type_id, function_control,
  446. function_type_id);
  447. id_to_function_.emplace(id, &current_function());
  448. // TODO(umar): validate function type and type_id
  449. return SPV_SUCCESS;
  450. }
  451. spv_result_t ValidationState_t::RegisterFunctionEnd() {
  452. assert(in_function_body() == true &&
  453. "RegisterFunctionEnd can only be called when parsing the binary "
  454. "inside of another function");
  455. assert(in_block() == false &&
  456. "RegisterFunctionParameter can only be called when parsing the binary "
  457. "ouside of a block");
  458. current_function().RegisterFunctionEnd();
  459. in_function_ = false;
  460. return SPV_SUCCESS;
  461. }
  462. Instruction* ValidationState_t::AddOrderedInstruction(
  463. const spv_parsed_instruction_t* inst) {
  464. ordered_instructions_.emplace_back(inst);
  465. ordered_instructions_.back().SetLineNum(ordered_instructions_.size());
  466. return &ordered_instructions_.back();
  467. }
  468. // Improves diagnostic messages by collecting names of IDs
  469. void ValidationState_t::RegisterDebugInstruction(const Instruction* inst) {
  470. switch (inst->opcode()) {
  471. case SpvOpName: {
  472. const auto target = inst->GetOperandAs<uint32_t>(0);
  473. const auto* str = reinterpret_cast<const char*>(inst->words().data() +
  474. inst->operand(1).offset);
  475. AssignNameToId(target, str);
  476. break;
  477. }
  478. case SpvOpMemberName: {
  479. const auto target = inst->GetOperandAs<uint32_t>(0);
  480. const auto* str = reinterpret_cast<const char*>(inst->words().data() +
  481. inst->operand(2).offset);
  482. AssignNameToId(target, str);
  483. break;
  484. }
  485. case SpvOpSourceContinued:
  486. case SpvOpSource:
  487. case SpvOpSourceExtension:
  488. case SpvOpString:
  489. case SpvOpLine:
  490. case SpvOpNoLine:
  491. default:
  492. break;
  493. }
  494. }
  495. void ValidationState_t::RegisterInstruction(Instruction* inst) {
  496. if (inst->id()) all_definitions_.insert(std::make_pair(inst->id(), inst));
  497. // If the instruction is using an OpTypeSampledImage as an operand, it should
  498. // be recorded. The validator will ensure that all usages of an
  499. // OpTypeSampledImage and its definition are in the same basic block.
  500. for (uint16_t i = 0; i < inst->operands().size(); ++i) {
  501. const spv_parsed_operand_t& operand = inst->operand(i);
  502. if (SPV_OPERAND_TYPE_ID == operand.type) {
  503. const uint32_t operand_word = inst->word(operand.offset);
  504. Instruction* operand_inst = FindDef(operand_word);
  505. if (operand_inst && SpvOpSampledImage == operand_inst->opcode()) {
  506. RegisterSampledImageConsumer(operand_word, inst);
  507. }
  508. }
  509. }
  510. }
  511. std::vector<Instruction*> ValidationState_t::getSampledImageConsumers(
  512. uint32_t sampled_image_id) const {
  513. std::vector<Instruction*> result;
  514. auto iter = sampled_image_consumers_.find(sampled_image_id);
  515. if (iter != sampled_image_consumers_.end()) {
  516. result = iter->second;
  517. }
  518. return result;
  519. }
  520. void ValidationState_t::RegisterSampledImageConsumer(uint32_t sampled_image_id,
  521. Instruction* consumer) {
  522. sampled_image_consumers_[sampled_image_id].push_back(consumer);
  523. }
  524. uint32_t ValidationState_t::getIdBound() const { return id_bound_; }
  525. void ValidationState_t::setIdBound(const uint32_t bound) { id_bound_ = bound; }
  526. bool ValidationState_t::RegisterUniqueTypeDeclaration(const Instruction* inst) {
  527. std::vector<uint32_t> key;
  528. key.push_back(static_cast<uint32_t>(inst->opcode()));
  529. for (size_t index = 0; index < inst->operands().size(); ++index) {
  530. const spv_parsed_operand_t& operand = inst->operand(index);
  531. if (operand.type == SPV_OPERAND_TYPE_RESULT_ID) continue;
  532. const int words_begin = operand.offset;
  533. const int words_end = words_begin + operand.num_words;
  534. assert(words_end <= static_cast<int>(inst->words().size()));
  535. key.insert(key.end(), inst->words().begin() + words_begin,
  536. inst->words().begin() + words_end);
  537. }
  538. return unique_type_declarations_.insert(std::move(key)).second;
  539. }
  540. uint32_t ValidationState_t::GetTypeId(uint32_t id) const {
  541. const Instruction* inst = FindDef(id);
  542. return inst ? inst->type_id() : 0;
  543. }
  544. SpvOp ValidationState_t::GetIdOpcode(uint32_t id) const {
  545. const Instruction* inst = FindDef(id);
  546. return inst ? inst->opcode() : SpvOpNop;
  547. }
  548. uint32_t ValidationState_t::GetComponentType(uint32_t id) const {
  549. const Instruction* inst = FindDef(id);
  550. assert(inst);
  551. switch (inst->opcode()) {
  552. case SpvOpTypeFloat:
  553. case SpvOpTypeInt:
  554. case SpvOpTypeBool:
  555. return id;
  556. case SpvOpTypeVector:
  557. return inst->word(2);
  558. case SpvOpTypeMatrix:
  559. return GetComponentType(inst->word(2));
  560. case SpvOpTypeCooperativeMatrixNV:
  561. return inst->word(2);
  562. default:
  563. break;
  564. }
  565. if (inst->type_id()) return GetComponentType(inst->type_id());
  566. assert(0);
  567. return 0;
  568. }
  569. uint32_t ValidationState_t::GetDimension(uint32_t id) const {
  570. const Instruction* inst = FindDef(id);
  571. assert(inst);
  572. switch (inst->opcode()) {
  573. case SpvOpTypeFloat:
  574. case SpvOpTypeInt:
  575. case SpvOpTypeBool:
  576. return 1;
  577. case SpvOpTypeVector:
  578. case SpvOpTypeMatrix:
  579. return inst->word(3);
  580. case SpvOpTypeCooperativeMatrixNV:
  581. // Actual dimension isn't known, return 0
  582. return 0;
  583. default:
  584. break;
  585. }
  586. if (inst->type_id()) return GetDimension(inst->type_id());
  587. assert(0);
  588. return 0;
  589. }
  590. uint32_t ValidationState_t::GetBitWidth(uint32_t id) const {
  591. const uint32_t component_type_id = GetComponentType(id);
  592. const Instruction* inst = FindDef(component_type_id);
  593. assert(inst);
  594. if (inst->opcode() == SpvOpTypeFloat || inst->opcode() == SpvOpTypeInt)
  595. return inst->word(2);
  596. if (inst->opcode() == SpvOpTypeBool) return 1;
  597. assert(0);
  598. return 0;
  599. }
  600. bool ValidationState_t::IsVoidType(uint32_t id) const {
  601. const Instruction* inst = FindDef(id);
  602. assert(inst);
  603. return inst->opcode() == SpvOpTypeVoid;
  604. }
  605. bool ValidationState_t::IsFloatScalarType(uint32_t id) const {
  606. const Instruction* inst = FindDef(id);
  607. assert(inst);
  608. return inst->opcode() == SpvOpTypeFloat;
  609. }
  610. bool ValidationState_t::IsFloatVectorType(uint32_t id) const {
  611. const Instruction* inst = FindDef(id);
  612. assert(inst);
  613. if (inst->opcode() == SpvOpTypeVector) {
  614. return IsFloatScalarType(GetComponentType(id));
  615. }
  616. return false;
  617. }
  618. bool ValidationState_t::IsFloatScalarOrVectorType(uint32_t id) const {
  619. const Instruction* inst = FindDef(id);
  620. assert(inst);
  621. if (inst->opcode() == SpvOpTypeFloat) {
  622. return true;
  623. }
  624. if (inst->opcode() == SpvOpTypeVector) {
  625. return IsFloatScalarType(GetComponentType(id));
  626. }
  627. return false;
  628. }
  629. bool ValidationState_t::IsIntScalarType(uint32_t id) const {
  630. const Instruction* inst = FindDef(id);
  631. assert(inst);
  632. return inst->opcode() == SpvOpTypeInt;
  633. }
  634. bool ValidationState_t::IsIntVectorType(uint32_t id) const {
  635. const Instruction* inst = FindDef(id);
  636. assert(inst);
  637. if (inst->opcode() == SpvOpTypeVector) {
  638. return IsIntScalarType(GetComponentType(id));
  639. }
  640. return false;
  641. }
  642. bool ValidationState_t::IsIntScalarOrVectorType(uint32_t id) const {
  643. const Instruction* inst = FindDef(id);
  644. assert(inst);
  645. if (inst->opcode() == SpvOpTypeInt) {
  646. return true;
  647. }
  648. if (inst->opcode() == SpvOpTypeVector) {
  649. return IsIntScalarType(GetComponentType(id));
  650. }
  651. return false;
  652. }
  653. bool ValidationState_t::IsUnsignedIntScalarType(uint32_t id) const {
  654. const Instruction* inst = FindDef(id);
  655. assert(inst);
  656. return inst->opcode() == SpvOpTypeInt && inst->word(3) == 0;
  657. }
  658. bool ValidationState_t::IsUnsignedIntVectorType(uint32_t id) const {
  659. const Instruction* inst = FindDef(id);
  660. assert(inst);
  661. if (inst->opcode() == SpvOpTypeVector) {
  662. return IsUnsignedIntScalarType(GetComponentType(id));
  663. }
  664. return false;
  665. }
  666. bool ValidationState_t::IsSignedIntScalarType(uint32_t id) const {
  667. const Instruction* inst = FindDef(id);
  668. assert(inst);
  669. return inst->opcode() == SpvOpTypeInt && inst->word(3) == 1;
  670. }
  671. bool ValidationState_t::IsSignedIntVectorType(uint32_t id) const {
  672. const Instruction* inst = FindDef(id);
  673. assert(inst);
  674. if (inst->opcode() == SpvOpTypeVector) {
  675. return IsSignedIntScalarType(GetComponentType(id));
  676. }
  677. return false;
  678. }
  679. bool ValidationState_t::IsBoolScalarType(uint32_t id) const {
  680. const Instruction* inst = FindDef(id);
  681. assert(inst);
  682. return inst->opcode() == SpvOpTypeBool;
  683. }
  684. bool ValidationState_t::IsBoolVectorType(uint32_t id) const {
  685. const Instruction* inst = FindDef(id);
  686. assert(inst);
  687. if (inst->opcode() == SpvOpTypeVector) {
  688. return IsBoolScalarType(GetComponentType(id));
  689. }
  690. return false;
  691. }
  692. bool ValidationState_t::IsBoolScalarOrVectorType(uint32_t id) const {
  693. const Instruction* inst = FindDef(id);
  694. assert(inst);
  695. if (inst->opcode() == SpvOpTypeBool) {
  696. return true;
  697. }
  698. if (inst->opcode() == SpvOpTypeVector) {
  699. return IsBoolScalarType(GetComponentType(id));
  700. }
  701. return false;
  702. }
  703. bool ValidationState_t::IsFloatMatrixType(uint32_t id) const {
  704. const Instruction* inst = FindDef(id);
  705. assert(inst);
  706. if (inst->opcode() == SpvOpTypeMatrix) {
  707. return IsFloatScalarType(GetComponentType(id));
  708. }
  709. return false;
  710. }
  711. bool ValidationState_t::GetMatrixTypeInfo(uint32_t id, uint32_t* num_rows,
  712. uint32_t* num_cols,
  713. uint32_t* column_type,
  714. uint32_t* component_type) const {
  715. if (!id) return false;
  716. const Instruction* mat_inst = FindDef(id);
  717. assert(mat_inst);
  718. if (mat_inst->opcode() != SpvOpTypeMatrix) return false;
  719. const uint32_t vec_type = mat_inst->word(2);
  720. const Instruction* vec_inst = FindDef(vec_type);
  721. assert(vec_inst);
  722. if (vec_inst->opcode() != SpvOpTypeVector) {
  723. assert(0);
  724. return false;
  725. }
  726. *num_cols = mat_inst->word(3);
  727. *num_rows = vec_inst->word(3);
  728. *column_type = mat_inst->word(2);
  729. *component_type = vec_inst->word(2);
  730. return true;
  731. }
  732. bool ValidationState_t::GetStructMemberTypes(
  733. uint32_t struct_type_id, std::vector<uint32_t>* member_types) const {
  734. member_types->clear();
  735. if (!struct_type_id) return false;
  736. const Instruction* inst = FindDef(struct_type_id);
  737. assert(inst);
  738. if (inst->opcode() != SpvOpTypeStruct) return false;
  739. *member_types =
  740. std::vector<uint32_t>(inst->words().cbegin() + 2, inst->words().cend());
  741. if (member_types->empty()) return false;
  742. return true;
  743. }
  744. bool ValidationState_t::IsPointerType(uint32_t id) const {
  745. const Instruction* inst = FindDef(id);
  746. assert(inst);
  747. return inst->opcode() == SpvOpTypePointer;
  748. }
  749. bool ValidationState_t::GetPointerTypeInfo(uint32_t id, uint32_t* data_type,
  750. uint32_t* storage_class) const {
  751. if (!id) return false;
  752. const Instruction* inst = FindDef(id);
  753. assert(inst);
  754. if (inst->opcode() != SpvOpTypePointer) return false;
  755. *storage_class = inst->word(2);
  756. *data_type = inst->word(3);
  757. return true;
  758. }
  759. bool ValidationState_t::IsCooperativeMatrixType(uint32_t id) const {
  760. const Instruction* inst = FindDef(id);
  761. assert(inst);
  762. return inst->opcode() == SpvOpTypeCooperativeMatrixNV;
  763. }
  764. bool ValidationState_t::IsFloatCooperativeMatrixType(uint32_t id) const {
  765. if (!IsCooperativeMatrixType(id)) return false;
  766. return IsFloatScalarType(FindDef(id)->word(2));
  767. }
  768. bool ValidationState_t::IsIntCooperativeMatrixType(uint32_t id) const {
  769. if (!IsCooperativeMatrixType(id)) return false;
  770. return IsIntScalarType(FindDef(id)->word(2));
  771. }
  772. bool ValidationState_t::IsUnsignedIntCooperativeMatrixType(uint32_t id) const {
  773. if (!IsCooperativeMatrixType(id)) return false;
  774. return IsUnsignedIntScalarType(FindDef(id)->word(2));
  775. }
  776. spv_result_t ValidationState_t::CooperativeMatrixShapesMatch(
  777. const Instruction* inst, uint32_t m1, uint32_t m2) {
  778. const auto m1_type = FindDef(m1);
  779. const auto m2_type = FindDef(m2);
  780. if (m1_type->opcode() != SpvOpTypeCooperativeMatrixNV ||
  781. m2_type->opcode() != SpvOpTypeCooperativeMatrixNV) {
  782. return diag(SPV_ERROR_INVALID_DATA, inst)
  783. << "Expected cooperative matrix types";
  784. }
  785. uint32_t m1_scope_id = m1_type->GetOperandAs<uint32_t>(2);
  786. uint32_t m1_rows_id = m1_type->GetOperandAs<uint32_t>(3);
  787. uint32_t m1_cols_id = m1_type->GetOperandAs<uint32_t>(4);
  788. uint32_t m2_scope_id = m2_type->GetOperandAs<uint32_t>(2);
  789. uint32_t m2_rows_id = m2_type->GetOperandAs<uint32_t>(3);
  790. uint32_t m2_cols_id = m2_type->GetOperandAs<uint32_t>(4);
  791. bool m1_is_int32 = false, m1_is_const_int32 = false, m2_is_int32 = false,
  792. m2_is_const_int32 = false;
  793. uint32_t m1_value = 0, m2_value = 0;
  794. std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
  795. EvalInt32IfConst(m1_scope_id);
  796. std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
  797. EvalInt32IfConst(m2_scope_id);
  798. if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
  799. return diag(SPV_ERROR_INVALID_DATA, inst)
  800. << "Expected scopes of Matrix and Result Type to be "
  801. << "identical";
  802. }
  803. std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
  804. EvalInt32IfConst(m1_rows_id);
  805. std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
  806. EvalInt32IfConst(m2_rows_id);
  807. if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
  808. return diag(SPV_ERROR_INVALID_DATA, inst)
  809. << "Expected rows of Matrix type and Result Type to be "
  810. << "identical";
  811. }
  812. std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
  813. EvalInt32IfConst(m1_cols_id);
  814. std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
  815. EvalInt32IfConst(m2_cols_id);
  816. if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
  817. return diag(SPV_ERROR_INVALID_DATA, inst)
  818. << "Expected columns of Matrix type and Result Type to be "
  819. << "identical";
  820. }
  821. return SPV_SUCCESS;
  822. }
  823. uint32_t ValidationState_t::GetOperandTypeId(const Instruction* inst,
  824. size_t operand_index) const {
  825. return GetTypeId(inst->GetOperandAs<uint32_t>(operand_index));
  826. }
  827. bool ValidationState_t::GetConstantValUint64(uint32_t id, uint64_t* val) const {
  828. const Instruction* inst = FindDef(id);
  829. if (!inst) {
  830. assert(0 && "Instruction not found");
  831. return false;
  832. }
  833. if (inst->opcode() != SpvOpConstant && inst->opcode() != SpvOpSpecConstant)
  834. return false;
  835. if (!IsIntScalarType(inst->type_id())) return false;
  836. if (inst->words().size() == 4) {
  837. *val = inst->word(3);
  838. } else {
  839. assert(inst->words().size() == 5);
  840. *val = inst->word(3);
  841. *val |= uint64_t(inst->word(4)) << 32;
  842. }
  843. return true;
  844. }
  845. std::tuple<bool, bool, uint32_t> ValidationState_t::EvalInt32IfConst(
  846. uint32_t id) const {
  847. const Instruction* const inst = FindDef(id);
  848. assert(inst);
  849. const uint32_t type = inst->type_id();
  850. if (type == 0 || !IsIntScalarType(type) || GetBitWidth(type) != 32) {
  851. return std::make_tuple(false, false, 0);
  852. }
  853. // Spec constant values cannot be evaluated so don't consider constant for
  854. // the purpose of this method.
  855. if (!spvOpcodeIsConstant(inst->opcode()) ||
  856. spvOpcodeIsSpecConstant(inst->opcode())) {
  857. return std::make_tuple(true, false, 0);
  858. }
  859. if (inst->opcode() == SpvOpConstantNull) {
  860. return std::make_tuple(true, true, 0);
  861. }
  862. assert(inst->words().size() == 4);
  863. return std::make_tuple(true, true, inst->word(3));
  864. }
  865. void ValidationState_t::ComputeFunctionToEntryPointMapping() {
  866. for (const uint32_t entry_point : entry_points()) {
  867. std::stack<uint32_t> call_stack;
  868. std::set<uint32_t> visited;
  869. call_stack.push(entry_point);
  870. while (!call_stack.empty()) {
  871. const uint32_t called_func_id = call_stack.top();
  872. call_stack.pop();
  873. if (!visited.insert(called_func_id).second) continue;
  874. function_to_entry_points_[called_func_id].push_back(entry_point);
  875. const Function* called_func = function(called_func_id);
  876. if (called_func) {
  877. // Other checks should error out on this invalid SPIR-V.
  878. for (const uint32_t new_call : called_func->function_call_targets()) {
  879. call_stack.push(new_call);
  880. }
  881. }
  882. }
  883. }
  884. }
  885. void ValidationState_t::ComputeRecursiveEntryPoints() {
  886. for (const Function func : functions()) {
  887. std::stack<uint32_t> call_stack;
  888. std::set<uint32_t> visited;
  889. for (const uint32_t new_call : func.function_call_targets()) {
  890. call_stack.push(new_call);
  891. }
  892. while (!call_stack.empty()) {
  893. const uint32_t called_func_id = call_stack.top();
  894. call_stack.pop();
  895. if (!visited.insert(called_func_id).second) continue;
  896. if (called_func_id == func.id()) {
  897. for (const uint32_t entry_point :
  898. function_to_entry_points_[called_func_id])
  899. recursive_entry_points_.insert(entry_point);
  900. break;
  901. }
  902. const Function* called_func = function(called_func_id);
  903. if (called_func) {
  904. // Other checks should error out on this invalid SPIR-V.
  905. for (const uint32_t new_call : called_func->function_call_targets()) {
  906. call_stack.push(new_call);
  907. }
  908. }
  909. }
  910. }
  911. }
  912. const std::vector<uint32_t>& ValidationState_t::FunctionEntryPoints(
  913. uint32_t func) const {
  914. auto iter = function_to_entry_points_.find(func);
  915. if (iter == function_to_entry_points_.end()) {
  916. return empty_ids_;
  917. } else {
  918. return iter->second;
  919. }
  920. }
  921. std::set<uint32_t> ValidationState_t::EntryPointReferences(uint32_t id) const {
  922. std::set<uint32_t> referenced_entry_points;
  923. const auto inst = FindDef(id);
  924. if (!inst) return referenced_entry_points;
  925. std::vector<const Instruction*> stack;
  926. stack.push_back(inst);
  927. while (!stack.empty()) {
  928. const auto current_inst = stack.back();
  929. stack.pop_back();
  930. if (const auto func = current_inst->function()) {
  931. // Instruction lives in a function, we can stop searching.
  932. const auto function_entry_points = FunctionEntryPoints(func->id());
  933. referenced_entry_points.insert(function_entry_points.begin(),
  934. function_entry_points.end());
  935. } else {
  936. // Instruction is in the global scope, keep searching its uses.
  937. for (auto pair : current_inst->uses()) {
  938. const auto next_inst = pair.first;
  939. stack.push_back(next_inst);
  940. }
  941. }
  942. }
  943. return referenced_entry_points;
  944. }
  945. std::string ValidationState_t::Disassemble(const Instruction& inst) const {
  946. const spv_parsed_instruction_t& c_inst(inst.c_inst());
  947. return Disassemble(c_inst.words, c_inst.num_words);
  948. }
  949. std::string ValidationState_t::Disassemble(const uint32_t* words,
  950. uint16_t num_words) const {
  951. uint32_t disassembly_options = SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
  952. SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES;
  953. return spvInstructionBinaryToText(context()->target_env, words, num_words,
  954. words_, num_words_, disassembly_options);
  955. }
  956. bool ValidationState_t::LogicallyMatch(const Instruction* lhs,
  957. const Instruction* rhs,
  958. bool check_decorations) {
  959. if (lhs->opcode() != rhs->opcode()) {
  960. return false;
  961. }
  962. if (check_decorations) {
  963. const auto& dec_a = id_decorations(lhs->id());
  964. const auto& dec_b = id_decorations(rhs->id());
  965. for (const auto& dec : dec_b) {
  966. if (std::find(dec_a.begin(), dec_a.end(), dec) == dec_a.end()) {
  967. return false;
  968. }
  969. }
  970. }
  971. if (lhs->opcode() == SpvOpTypeArray) {
  972. // Size operands must match.
  973. if (lhs->GetOperandAs<uint32_t>(2u) != rhs->GetOperandAs<uint32_t>(2u)) {
  974. return false;
  975. }
  976. // Elements must match or logically match.
  977. const auto lhs_ele_id = lhs->GetOperandAs<uint32_t>(1u);
  978. const auto rhs_ele_id = rhs->GetOperandAs<uint32_t>(1u);
  979. if (lhs_ele_id == rhs_ele_id) {
  980. return true;
  981. }
  982. const auto lhs_ele = FindDef(lhs_ele_id);
  983. const auto rhs_ele = FindDef(rhs_ele_id);
  984. if (!lhs_ele || !rhs_ele) {
  985. return false;
  986. }
  987. return LogicallyMatch(lhs_ele, rhs_ele, check_decorations);
  988. } else if (lhs->opcode() == SpvOpTypeStruct) {
  989. // Number of elements must match.
  990. if (lhs->operands().size() != rhs->operands().size()) {
  991. return false;
  992. }
  993. for (size_t i = 1u; i < lhs->operands().size(); ++i) {
  994. const auto lhs_ele_id = lhs->GetOperandAs<uint32_t>(i);
  995. const auto rhs_ele_id = rhs->GetOperandAs<uint32_t>(i);
  996. // Elements must match or logically match.
  997. if (lhs_ele_id == rhs_ele_id) {
  998. continue;
  999. }
  1000. const auto lhs_ele = FindDef(lhs_ele_id);
  1001. const auto rhs_ele = FindDef(rhs_ele_id);
  1002. if (!lhs_ele || !rhs_ele) {
  1003. return false;
  1004. }
  1005. if (!LogicallyMatch(lhs_ele, rhs_ele, check_decorations)) {
  1006. return false;
  1007. }
  1008. }
  1009. // All checks passed.
  1010. return true;
  1011. }
  1012. // No other opcodes are acceptable at this point. Arrays and structs are
  1013. // caught above and if they're elements are not arrays or structs they are
  1014. // required to match exactly.
  1015. return false;
  1016. }
  1017. const Instruction* ValidationState_t::TracePointer(
  1018. const Instruction* inst) const {
  1019. auto base_ptr = inst;
  1020. while (base_ptr->opcode() == SpvOpAccessChain ||
  1021. base_ptr->opcode() == SpvOpInBoundsAccessChain ||
  1022. base_ptr->opcode() == SpvOpPtrAccessChain ||
  1023. base_ptr->opcode() == SpvOpInBoundsPtrAccessChain ||
  1024. base_ptr->opcode() == SpvOpCopyObject) {
  1025. base_ptr = FindDef(base_ptr->GetOperandAs<uint32_t>(2u));
  1026. }
  1027. return base_ptr;
  1028. }
  1029. bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type,
  1030. uint32_t width) const {
  1031. if (type != SpvOpTypeInt && type != SpvOpTypeFloat) return false;
  1032. const auto inst = FindDef(id);
  1033. if (!inst) return false;
  1034. if (inst->opcode() == type) {
  1035. return inst->GetOperandAs<uint32_t>(1u) == width;
  1036. }
  1037. switch (inst->opcode()) {
  1038. case SpvOpTypeArray:
  1039. case SpvOpTypeRuntimeArray:
  1040. case SpvOpTypeVector:
  1041. case SpvOpTypeMatrix:
  1042. case SpvOpTypeImage:
  1043. case SpvOpTypeSampledImage:
  1044. case SpvOpTypeCooperativeMatrixNV:
  1045. return ContainsSizedIntOrFloatType(inst->GetOperandAs<uint32_t>(1u), type,
  1046. width);
  1047. case SpvOpTypePointer:
  1048. if (IsForwardPointer(id)) return false;
  1049. return ContainsSizedIntOrFloatType(inst->GetOperandAs<uint32_t>(2u), type,
  1050. width);
  1051. case SpvOpTypeFunction:
  1052. case SpvOpTypeStruct: {
  1053. for (uint32_t i = 1; i < inst->operands().size(); ++i) {
  1054. if (ContainsSizedIntOrFloatType(inst->GetOperandAs<uint32_t>(i), type,
  1055. width))
  1056. return true;
  1057. }
  1058. return false;
  1059. }
  1060. default:
  1061. return false;
  1062. }
  1063. }
  1064. bool ValidationState_t::ContainsLimitedUseIntOrFloatType(uint32_t id) const {
  1065. if ((!HasCapability(SpvCapabilityInt16) &&
  1066. ContainsSizedIntOrFloatType(id, SpvOpTypeInt, 16)) ||
  1067. (!HasCapability(SpvCapabilityInt8) &&
  1068. ContainsSizedIntOrFloatType(id, SpvOpTypeInt, 8)) ||
  1069. (!HasCapability(SpvCapabilityFloat16) &&
  1070. ContainsSizedIntOrFloatType(id, SpvOpTypeFloat, 16))) {
  1071. return true;
  1072. }
  1073. return false;
  1074. }
  1075. } // namespace val
  1076. } // namespace spvtools