validate_interfaces.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  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. #include <algorithm>
  15. #include <vector>
  16. #include "source/diagnostic.h"
  17. #include "source/spirv_constant.h"
  18. #include "source/spirv_target_env.h"
  19. #include "source/val/function.h"
  20. #include "source/val/instruction.h"
  21. #include "source/val/validate.h"
  22. #include "source/val/validation_state.h"
  23. namespace spvtools {
  24. namespace val {
  25. namespace {
  26. // Limit the number of checked locations to 4096. Multiplied by 4 to represent
  27. // all the components. This limit is set to be well beyond practical use cases.
  28. const uint32_t kMaxLocations = 4096 * 4;
  29. // Returns true if \c inst is an input or output variable.
  30. bool is_interface_variable(const Instruction* inst, bool is_spv_1_4) {
  31. if (is_spv_1_4) {
  32. // Starting in SPIR-V 1.4, all global variables are interface variables.
  33. return inst->opcode() == spv::Op::OpVariable &&
  34. inst->GetOperandAs<spv::StorageClass>(2u) !=
  35. spv::StorageClass::Function;
  36. } else {
  37. return inst->opcode() == spv::Op::OpVariable &&
  38. (inst->GetOperandAs<spv::StorageClass>(2u) ==
  39. spv::StorageClass::Input ||
  40. inst->GetOperandAs<spv::StorageClass>(2u) ==
  41. spv::StorageClass::Output);
  42. }
  43. }
  44. // Checks that \c var is listed as an interface in all the entry points that use
  45. // it.
  46. spv_result_t check_interface_variable(ValidationState_t& _,
  47. const Instruction* var) {
  48. std::vector<const Function*> functions;
  49. std::vector<const Instruction*> uses;
  50. for (auto use : var->uses()) {
  51. uses.push_back(use.first);
  52. }
  53. for (uint32_t i = 0; i < uses.size(); ++i) {
  54. const auto user = uses[i];
  55. if (const Function* func = user->function()) {
  56. functions.push_back(func);
  57. } else {
  58. // In the rare case that the variable is used by another instruction in
  59. // the global scope, continue searching for an instruction used in a
  60. // function.
  61. for (auto use : user->uses()) {
  62. uses.push_back(use.first);
  63. }
  64. }
  65. }
  66. std::sort(functions.begin(), functions.end(),
  67. [](const Function* lhs, const Function* rhs) {
  68. return lhs->id() < rhs->id();
  69. });
  70. functions.erase(std::unique(functions.begin(), functions.end()),
  71. functions.end());
  72. std::vector<uint32_t> entry_points;
  73. for (const auto func : functions) {
  74. for (auto id : _.FunctionEntryPoints(func->id())) {
  75. entry_points.push_back(id);
  76. }
  77. }
  78. std::sort(entry_points.begin(), entry_points.end());
  79. entry_points.erase(std::unique(entry_points.begin(), entry_points.end()),
  80. entry_points.end());
  81. for (auto id : entry_points) {
  82. for (const auto& desc : _.entry_point_descriptions(id)) {
  83. bool found = false;
  84. for (auto interface : desc.interfaces) {
  85. if (var->id() == interface) {
  86. found = true;
  87. break;
  88. }
  89. }
  90. if (!found) {
  91. return _.diag(SPV_ERROR_INVALID_ID, var)
  92. << "Interface variable id <" << var->id()
  93. << "> is used by entry point '" << desc.name << "' id <" << id
  94. << ">, but is not listed as an interface";
  95. }
  96. }
  97. }
  98. return SPV_SUCCESS;
  99. }
  100. // This function assumes a base location has been determined already. As such
  101. // any further location decorations are invalid.
  102. // TODO: if this code turns out to be slow, there is an opportunity to cache
  103. // the result for a given type id.
  104. spv_result_t NumConsumedLocations(ValidationState_t& _, const Instruction* type,
  105. uint32_t* num_locations) {
  106. *num_locations = 0;
  107. switch (type->opcode()) {
  108. case spv::Op::OpTypeInt:
  109. case spv::Op::OpTypeFloat:
  110. // Scalars always consume a single location.
  111. *num_locations = 1;
  112. break;
  113. case spv::Op::OpTypeVector:
  114. // 3- and 4-component 64-bit vectors consume two locations.
  115. if ((_.ContainsSizedIntOrFloatType(type->id(), spv::Op::OpTypeInt, 64) ||
  116. _.ContainsSizedIntOrFloatType(type->id(), spv::Op::OpTypeFloat,
  117. 64)) &&
  118. (type->GetOperandAs<uint32_t>(2) > 2)) {
  119. *num_locations = 2;
  120. } else {
  121. *num_locations = 1;
  122. }
  123. break;
  124. case spv::Op::OpTypeMatrix:
  125. // Matrices consume locations equal to the underlying vector type for
  126. // each column.
  127. NumConsumedLocations(_, _.FindDef(type->GetOperandAs<uint32_t>(1)),
  128. num_locations);
  129. *num_locations *= type->GetOperandAs<uint32_t>(2);
  130. break;
  131. case spv::Op::OpTypeArray: {
  132. // Arrays consume locations equal to the underlying type times the number
  133. // of elements in the vector.
  134. NumConsumedLocations(_, _.FindDef(type->GetOperandAs<uint32_t>(1)),
  135. num_locations);
  136. bool is_int = false;
  137. bool is_const = false;
  138. uint32_t value = 0;
  139. // Attempt to evaluate the number of array elements.
  140. std::tie(is_int, is_const, value) =
  141. _.EvalInt32IfConst(type->GetOperandAs<uint32_t>(2));
  142. if (is_int && is_const) *num_locations *= value;
  143. break;
  144. }
  145. case spv::Op::OpTypeStruct: {
  146. // Members cannot have location decorations at this point.
  147. if (_.HasDecoration(type->id(), spv::Decoration::Location)) {
  148. return _.diag(SPV_ERROR_INVALID_DATA, type)
  149. << _.VkErrorID(4918) << "Members cannot be assigned a location";
  150. }
  151. // Structs consume locations equal to the sum of the locations consumed
  152. // by the members.
  153. for (uint32_t i = 1; i < type->operands().size(); ++i) {
  154. uint32_t member_locations = 0;
  155. if (auto error = NumConsumedLocations(
  156. _, _.FindDef(type->GetOperandAs<uint32_t>(i)),
  157. &member_locations)) {
  158. return error;
  159. }
  160. *num_locations += member_locations;
  161. }
  162. break;
  163. }
  164. default:
  165. break;
  166. }
  167. return SPV_SUCCESS;
  168. }
  169. // Returns the number of components consumed by types that support a component
  170. // decoration.
  171. uint32_t NumConsumedComponents(ValidationState_t& _, const Instruction* type) {
  172. uint32_t num_components = 0;
  173. switch (type->opcode()) {
  174. case spv::Op::OpTypeInt:
  175. case spv::Op::OpTypeFloat:
  176. // 64-bit types consume two components.
  177. if (type->GetOperandAs<uint32_t>(1) == 64) {
  178. num_components = 2;
  179. } else {
  180. num_components = 1;
  181. }
  182. break;
  183. case spv::Op::OpTypeVector:
  184. // Vectors consume components equal to the underlying type's consumption
  185. // times the number of elements in the vector. Note that 3- and 4-element
  186. // vectors cannot have a component decoration (i.e. assumed to be zero).
  187. num_components =
  188. NumConsumedComponents(_, _.FindDef(type->GetOperandAs<uint32_t>(1)));
  189. num_components *= type->GetOperandAs<uint32_t>(2);
  190. break;
  191. case spv::Op::OpTypeArray:
  192. // Skip the array.
  193. return NumConsumedComponents(_,
  194. _.FindDef(type->GetOperandAs<uint32_t>(1)));
  195. default:
  196. // This is an error that is validated elsewhere.
  197. break;
  198. }
  199. return num_components;
  200. }
  201. // Populates |locations| (and/or |output_index1_locations|) with the use
  202. // location and component coordinates for |variable|. Indices are calculated as
  203. // 4 * location + component.
  204. spv_result_t GetLocationsForVariable(
  205. ValidationState_t& _, const Instruction* entry_point,
  206. const Instruction* variable, std::unordered_set<uint32_t>* locations,
  207. std::unordered_set<uint32_t>* output_index1_locations) {
  208. const bool is_fragment = entry_point->GetOperandAs<spv::ExecutionModel>(0) ==
  209. spv::ExecutionModel::Fragment;
  210. const bool is_output =
  211. variable->GetOperandAs<spv::StorageClass>(2) == spv::StorageClass::Output;
  212. auto ptr_type_id = variable->GetOperandAs<uint32_t>(0);
  213. auto ptr_type = _.FindDef(ptr_type_id);
  214. auto type_id = ptr_type->GetOperandAs<uint32_t>(2);
  215. auto type = _.FindDef(type_id);
  216. // Check for Location, Component and Index decorations on the variable. The
  217. // validator allows duplicate decorations if the location/component/index are
  218. // equal. Also track Patch and PerTaskNV decorations.
  219. bool has_location = false;
  220. uint32_t location = 0;
  221. bool has_component = false;
  222. uint32_t component = 0;
  223. bool has_index = false;
  224. uint32_t index = 0;
  225. bool has_patch = false;
  226. bool has_per_task_nv = false;
  227. bool has_per_vertex_khr = false;
  228. for (auto& dec : _.id_decorations(variable->id())) {
  229. if (dec.dec_type() == spv::Decoration::Location) {
  230. if (has_location && dec.params()[0] != location) {
  231. return _.diag(SPV_ERROR_INVALID_DATA, variable)
  232. << "Variable has conflicting location decorations";
  233. }
  234. has_location = true;
  235. location = dec.params()[0];
  236. } else if (dec.dec_type() == spv::Decoration::Component) {
  237. if (has_component && dec.params()[0] != component) {
  238. return _.diag(SPV_ERROR_INVALID_DATA, variable)
  239. << "Variable has conflicting component decorations";
  240. }
  241. has_component = true;
  242. component = dec.params()[0];
  243. } else if (dec.dec_type() == spv::Decoration::Index) {
  244. if (!is_output || !is_fragment) {
  245. return _.diag(SPV_ERROR_INVALID_DATA, variable)
  246. << "Index can only be applied to Fragment output variables";
  247. }
  248. if (has_index && dec.params()[0] != index) {
  249. return _.diag(SPV_ERROR_INVALID_DATA, variable)
  250. << "Variable has conflicting index decorations";
  251. }
  252. has_index = true;
  253. index = dec.params()[0];
  254. } else if (dec.dec_type() == spv::Decoration::BuiltIn) {
  255. // Don't check built-ins.
  256. return SPV_SUCCESS;
  257. } else if (dec.dec_type() == spv::Decoration::Patch) {
  258. has_patch = true;
  259. } else if (dec.dec_type() == spv::Decoration::PerTaskNV) {
  260. has_per_task_nv = true;
  261. } else if (dec.dec_type() == spv::Decoration::PerVertexKHR) {
  262. if (!is_fragment) {
  263. return _.diag(SPV_ERROR_INVALID_DATA, variable)
  264. << _.VkErrorID(6777)
  265. << "PerVertexKHR can only be applied to Fragment Execution "
  266. "Models";
  267. }
  268. if (type->opcode() != spv::Op::OpTypeArray &&
  269. type->opcode() != spv::Op::OpTypeRuntimeArray) {
  270. return _.diag(SPV_ERROR_INVALID_DATA, variable)
  271. << _.VkErrorID(6778)
  272. << "PerVertexKHR must be declared as arrays";
  273. }
  274. has_per_vertex_khr = true;
  275. }
  276. }
  277. // Vulkan 14.1.3: Tessellation control and mesh per-vertex outputs and
  278. // tessellation control, evaluation and geometry per-vertex inputs have a
  279. // layer of arraying that is not included in interface matching.
  280. bool is_arrayed = false;
  281. switch (entry_point->GetOperandAs<spv::ExecutionModel>(0)) {
  282. case spv::ExecutionModel::TessellationControl:
  283. if (!has_patch) {
  284. is_arrayed = true;
  285. }
  286. break;
  287. case spv::ExecutionModel::TessellationEvaluation:
  288. if (!is_output && !has_patch) {
  289. is_arrayed = true;
  290. }
  291. break;
  292. case spv::ExecutionModel::Geometry:
  293. if (!is_output) {
  294. is_arrayed = true;
  295. }
  296. break;
  297. case spv::ExecutionModel::Fragment:
  298. if (!is_output && has_per_vertex_khr) {
  299. is_arrayed = true;
  300. }
  301. break;
  302. case spv::ExecutionModel::MeshNV:
  303. if (is_output && !has_per_task_nv) {
  304. is_arrayed = true;
  305. }
  306. break;
  307. default:
  308. break;
  309. }
  310. // Unpack arrayness.
  311. if (is_arrayed && (type->opcode() == spv::Op::OpTypeArray ||
  312. type->opcode() == spv::Op::OpTypeRuntimeArray)) {
  313. type_id = type->GetOperandAs<uint32_t>(1);
  314. type = _.FindDef(type_id);
  315. }
  316. if (type->opcode() == spv::Op::OpTypeStruct) {
  317. // Don't check built-ins.
  318. if (_.HasDecoration(type_id, spv::Decoration::BuiltIn)) return SPV_SUCCESS;
  319. }
  320. // Only block-decorated structs don't need a location on the variable.
  321. const bool is_block = _.HasDecoration(type_id, spv::Decoration::Block);
  322. if (!has_location && !is_block) {
  323. const auto vuid = (type->opcode() == spv::Op::OpTypeStruct) ? 4917 : 4916;
  324. return _.diag(SPV_ERROR_INVALID_DATA, variable)
  325. << _.VkErrorID(vuid) << "Variable must be decorated with a location";
  326. }
  327. const std::string storage_class = is_output ? "output" : "input";
  328. if (has_location) {
  329. auto sub_type = type;
  330. bool is_int = false;
  331. bool is_const = false;
  332. uint32_t array_size = 1;
  333. // If the variable is still arrayed, mark the locations/components per
  334. // index.
  335. if (type->opcode() == spv::Op::OpTypeArray) {
  336. // Determine the array size if possible and get the element type.
  337. std::tie(is_int, is_const, array_size) =
  338. _.EvalInt32IfConst(type->GetOperandAs<uint32_t>(2));
  339. if (!is_int || !is_const) array_size = 1;
  340. auto sub_type_id = type->GetOperandAs<uint32_t>(1);
  341. sub_type = _.FindDef(sub_type_id);
  342. }
  343. for (uint32_t array_idx = 0; array_idx < array_size; ++array_idx) {
  344. uint32_t num_locations = 0;
  345. if (auto error = NumConsumedLocations(_, sub_type, &num_locations))
  346. return error;
  347. uint32_t num_components = NumConsumedComponents(_, sub_type);
  348. uint32_t array_location = location + (num_locations * array_idx);
  349. uint32_t start = array_location * 4;
  350. if (kMaxLocations <= start) {
  351. // Too many locations, give up.
  352. break;
  353. }
  354. uint32_t end = (array_location + num_locations) * 4;
  355. if (num_components != 0) {
  356. start += component;
  357. end = array_location * 4 + component + num_components;
  358. }
  359. auto locs = locations;
  360. if (has_index && index == 1) locs = output_index1_locations;
  361. for (uint32_t i = start; i < end; ++i) {
  362. if (!locs->insert(i).second) {
  363. return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
  364. << "Entry-point has conflicting " << storage_class
  365. << " location assignment at location " << i / 4
  366. << ", component " << i % 4;
  367. }
  368. }
  369. }
  370. } else {
  371. // For Block-decorated structs with no location assigned to the variable,
  372. // each member of the block must be assigned a location. Also record any
  373. // member component assignments. The validator allows duplicate decorations
  374. // if they agree on the location/component.
  375. std::unordered_map<uint32_t, uint32_t> member_locations;
  376. std::unordered_map<uint32_t, uint32_t> member_components;
  377. for (auto& dec : _.id_decorations(type_id)) {
  378. if (dec.dec_type() == spv::Decoration::Location) {
  379. auto where = member_locations.find(dec.struct_member_index());
  380. if (where == member_locations.end()) {
  381. member_locations[dec.struct_member_index()] = dec.params()[0];
  382. } else if (where->second != dec.params()[0]) {
  383. return _.diag(SPV_ERROR_INVALID_DATA, type)
  384. << "Member index " << dec.struct_member_index()
  385. << " has conflicting location assignments";
  386. }
  387. } else if (dec.dec_type() == spv::Decoration::Component) {
  388. auto where = member_components.find(dec.struct_member_index());
  389. if (where == member_components.end()) {
  390. member_components[dec.struct_member_index()] = dec.params()[0];
  391. } else if (where->second != dec.params()[0]) {
  392. return _.diag(SPV_ERROR_INVALID_DATA, type)
  393. << "Member index " << dec.struct_member_index()
  394. << " has conflicting component assignments";
  395. }
  396. }
  397. }
  398. for (uint32_t i = 1; i < type->operands().size(); ++i) {
  399. auto where = member_locations.find(i - 1);
  400. if (where == member_locations.end()) {
  401. return _.diag(SPV_ERROR_INVALID_DATA, type)
  402. << _.VkErrorID(4919) << "Member index " << i - 1
  403. << " is missing a location assignment";
  404. }
  405. location = where->second;
  406. auto member = _.FindDef(type->GetOperandAs<uint32_t>(i));
  407. uint32_t num_locations = 0;
  408. if (auto error = NumConsumedLocations(_, member, &num_locations))
  409. return error;
  410. // If the component is not specified, it is assumed to be zero.
  411. uint32_t num_components = NumConsumedComponents(_, member);
  412. component = 0;
  413. if (member_components.count(i - 1)) {
  414. component = member_components[i - 1];
  415. }
  416. uint32_t start = location * 4;
  417. if (kMaxLocations <= start) {
  418. // Too many locations, give up.
  419. continue;
  420. }
  421. if (member->opcode() == spv::Op::OpTypeArray && num_components >= 1 &&
  422. num_components < 4) {
  423. // When an array has an element that takes less than a location in
  424. // size, calculate the used locations in a strided manner.
  425. for (uint32_t l = location; l < num_locations + location; ++l) {
  426. for (uint32_t c = component; c < component + num_components; ++c) {
  427. uint32_t check = 4 * l + c;
  428. if (!locations->insert(check).second) {
  429. return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
  430. << "Entry-point has conflicting " << storage_class
  431. << " location assignment at location " << l
  432. << ", component " << c;
  433. }
  434. }
  435. }
  436. } else {
  437. // TODO: There is a hole here is the member is an array of 3- or
  438. // 4-element vectors of 64-bit types.
  439. uint32_t end = (location + num_locations) * 4;
  440. if (num_components != 0) {
  441. start += component;
  442. end = location * 4 + component + num_components;
  443. }
  444. for (uint32_t l = start; l < end; ++l) {
  445. if (!locations->insert(l).second) {
  446. return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
  447. << "Entry-point has conflicting " << storage_class
  448. << " location assignment at location " << l / 4
  449. << ", component " << l % 4;
  450. }
  451. }
  452. }
  453. }
  454. }
  455. return SPV_SUCCESS;
  456. }
  457. spv_result_t ValidateLocations(ValidationState_t& _,
  458. const Instruction* entry_point) {
  459. // According to Vulkan 14.1 only the following execution models have
  460. // locations assigned.
  461. // TODO(dneto): SPV_NV_ray_tracing also uses locations on interface variables,
  462. // in other shader stages. Similarly, the *provisional* version of
  463. // SPV_KHR_ray_tracing did as well, but not the final version.
  464. switch (entry_point->GetOperandAs<spv::ExecutionModel>(0)) {
  465. case spv::ExecutionModel::Vertex:
  466. case spv::ExecutionModel::TessellationControl:
  467. case spv::ExecutionModel::TessellationEvaluation:
  468. case spv::ExecutionModel::Geometry:
  469. case spv::ExecutionModel::Fragment:
  470. break;
  471. default:
  472. return SPV_SUCCESS;
  473. }
  474. // Locations are stored as a combined location and component values.
  475. std::unordered_set<uint32_t> input_locations;
  476. std::unordered_set<uint32_t> output_locations_index0;
  477. std::unordered_set<uint32_t> output_locations_index1;
  478. std::unordered_set<uint32_t> seen;
  479. for (uint32_t i = 3; i < entry_point->operands().size(); ++i) {
  480. auto interface_id = entry_point->GetOperandAs<uint32_t>(i);
  481. auto interface_var = _.FindDef(interface_id);
  482. auto storage_class = interface_var->GetOperandAs<spv::StorageClass>(2);
  483. if (storage_class != spv::StorageClass::Input &&
  484. storage_class != spv::StorageClass::Output) {
  485. continue;
  486. }
  487. if (!seen.insert(interface_id).second) {
  488. // Pre-1.4 an interface variable could be listed multiple times in an
  489. // entry point. Validation for 1.4 or later is done elsewhere.
  490. continue;
  491. }
  492. auto locations = (storage_class == spv::StorageClass::Input)
  493. ? &input_locations
  494. : &output_locations_index0;
  495. if (auto error = GetLocationsForVariable(
  496. _, entry_point, interface_var, locations, &output_locations_index1))
  497. return error;
  498. }
  499. return SPV_SUCCESS;
  500. }
  501. } // namespace
  502. spv_result_t ValidateInterfaces(ValidationState_t& _) {
  503. bool is_spv_1_4 = _.version() >= SPV_SPIRV_VERSION_WORD(1, 4);
  504. for (auto& inst : _.ordered_instructions()) {
  505. if (is_interface_variable(&inst, is_spv_1_4)) {
  506. if (auto error = check_interface_variable(_, &inst)) {
  507. return error;
  508. }
  509. }
  510. }
  511. if (spvIsVulkanEnv(_.context()->target_env)) {
  512. for (auto& inst : _.ordered_instructions()) {
  513. if (inst.opcode() == spv::Op::OpEntryPoint) {
  514. if (auto error = ValidateLocations(_, &inst)) {
  515. return error;
  516. }
  517. }
  518. if (inst.opcode() == spv::Op::OpTypeVoid) break;
  519. }
  520. }
  521. return SPV_SUCCESS;
  522. }
  523. } // namespace val
  524. } // namespace spvtools