validate_decorations.cpp 71 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699
  1. // Copyright (c) 2017 Google 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 <algorithm>
  15. #include <cassert>
  16. #include <string>
  17. #include <tuple>
  18. #include <unordered_map>
  19. #include <unordered_set>
  20. #include <utility>
  21. #include <vector>
  22. #include "source/diagnostic.h"
  23. #include "source/opcode.h"
  24. #include "source/spirv_constant.h"
  25. #include "source/spirv_target_env.h"
  26. #include "source/spirv_validator_options.h"
  27. #include "source/val/validate_scopes.h"
  28. #include "source/val/validation_state.h"
  29. namespace spvtools {
  30. namespace val {
  31. namespace {
  32. // Distinguish between row and column major matrix layouts.
  33. enum MatrixLayout { kRowMajor, kColumnMajor };
  34. // A functor for hashing a pair of integers.
  35. struct PairHash {
  36. std::size_t operator()(const std::pair<uint32_t, uint32_t> pair) const {
  37. const uint32_t a = pair.first;
  38. const uint32_t b = pair.second;
  39. const uint32_t rotated_b = (b >> 2) | ((b & 3) << 30);
  40. return a ^ rotated_b;
  41. }
  42. };
  43. // A functor for hashing decoration types.
  44. struct SpvDecorationHash {
  45. std::size_t operator()(SpvDecoration dec) const {
  46. return static_cast<std::size_t>(dec);
  47. }
  48. };
  49. // Struct member layout attributes that are inherited through arrays.
  50. struct LayoutConstraints {
  51. explicit LayoutConstraints(
  52. MatrixLayout the_majorness = MatrixLayout::kColumnMajor,
  53. uint32_t stride = 0)
  54. : majorness(the_majorness), matrix_stride(stride) {}
  55. MatrixLayout majorness;
  56. uint32_t matrix_stride;
  57. };
  58. // A type for mapping (struct id, member id) to layout constraints.
  59. using MemberConstraints = std::unordered_map<std::pair<uint32_t, uint32_t>,
  60. LayoutConstraints, PairHash>;
  61. // Returns the array stride of the given array type.
  62. uint32_t GetArrayStride(uint32_t array_id, ValidationState_t& vstate) {
  63. for (auto& decoration : vstate.id_decorations(array_id)) {
  64. if (SpvDecorationArrayStride == decoration.dec_type()) {
  65. return decoration.params()[0];
  66. }
  67. }
  68. return 0;
  69. }
  70. // Returns true if the given variable has a BuiltIn decoration.
  71. bool isBuiltInVar(uint32_t var_id, ValidationState_t& vstate) {
  72. const auto& decorations = vstate.id_decorations(var_id);
  73. return std::any_of(
  74. decorations.begin(), decorations.end(),
  75. [](const Decoration& d) { return SpvDecorationBuiltIn == d.dec_type(); });
  76. }
  77. // Returns true if the given structure type has any members with BuiltIn
  78. // decoration.
  79. bool isBuiltInStruct(uint32_t struct_id, ValidationState_t& vstate) {
  80. const auto& decorations = vstate.id_decorations(struct_id);
  81. return std::any_of(
  82. decorations.begin(), decorations.end(), [](const Decoration& d) {
  83. return SpvDecorationBuiltIn == d.dec_type() &&
  84. Decoration::kInvalidMember != d.struct_member_index();
  85. });
  86. }
  87. // Returns true if the given ID has the Import LinkageAttributes decoration.
  88. bool hasImportLinkageAttribute(uint32_t id, ValidationState_t& vstate) {
  89. const auto& decorations = vstate.id_decorations(id);
  90. return std::any_of(decorations.begin(), decorations.end(),
  91. [](const Decoration& d) {
  92. return SpvDecorationLinkageAttributes == d.dec_type() &&
  93. d.params().size() >= 2u &&
  94. d.params().back() == SpvLinkageTypeImport;
  95. });
  96. }
  97. // Returns a vector of all members of a structure.
  98. std::vector<uint32_t> getStructMembers(uint32_t struct_id,
  99. ValidationState_t& vstate) {
  100. const auto inst = vstate.FindDef(struct_id);
  101. return std::vector<uint32_t>(inst->words().begin() + 2, inst->words().end());
  102. }
  103. // Returns a vector of all members of a structure that have specific type.
  104. std::vector<uint32_t> getStructMembers(uint32_t struct_id, SpvOp type,
  105. ValidationState_t& vstate) {
  106. std::vector<uint32_t> members;
  107. for (auto id : getStructMembers(struct_id, vstate)) {
  108. if (type == vstate.FindDef(id)->opcode()) {
  109. members.push_back(id);
  110. }
  111. }
  112. return members;
  113. }
  114. // Returns whether the given structure is missing Offset decoration for any
  115. // member. Handles also nested structures.
  116. bool isMissingOffsetInStruct(uint32_t struct_id, ValidationState_t& vstate) {
  117. std::vector<bool> hasOffset(getStructMembers(struct_id, vstate).size(),
  118. false);
  119. // Check offsets of member decorations
  120. for (auto& decoration : vstate.id_decorations(struct_id)) {
  121. if (SpvDecorationOffset == decoration.dec_type() &&
  122. Decoration::kInvalidMember != decoration.struct_member_index()) {
  123. hasOffset[decoration.struct_member_index()] = true;
  124. }
  125. }
  126. // Check also nested structures
  127. bool nestedStructsMissingOffset = false;
  128. for (auto id : getStructMembers(struct_id, SpvOpTypeStruct, vstate)) {
  129. if (isMissingOffsetInStruct(id, vstate)) {
  130. nestedStructsMissingOffset = true;
  131. break;
  132. }
  133. }
  134. return nestedStructsMissingOffset ||
  135. !std::all_of(hasOffset.begin(), hasOffset.end(),
  136. [](const bool b) { return b; });
  137. }
  138. // Rounds x up to the next alignment. Assumes alignment is a power of two.
  139. uint32_t align(uint32_t x, uint32_t alignment) {
  140. return (x + alignment - 1) & ~(alignment - 1);
  141. }
  142. // Returns base alignment of struct member. If |roundUp| is true, also
  143. // ensure that structs and arrays are aligned at least to a multiple of 16
  144. // bytes.
  145. uint32_t getBaseAlignment(uint32_t member_id, bool roundUp,
  146. const LayoutConstraints& inherited,
  147. MemberConstraints& constraints,
  148. ValidationState_t& vstate) {
  149. const auto inst = vstate.FindDef(member_id);
  150. const auto& words = inst->words();
  151. // Minimal alignment is byte-aligned.
  152. uint32_t baseAlignment = 1;
  153. switch (inst->opcode()) {
  154. case SpvOpTypeInt:
  155. case SpvOpTypeFloat:
  156. baseAlignment = words[2] / 8;
  157. break;
  158. case SpvOpTypeVector: {
  159. const auto componentId = words[2];
  160. const auto numComponents = words[3];
  161. const auto componentAlignment = getBaseAlignment(
  162. componentId, roundUp, inherited, constraints, vstate);
  163. baseAlignment =
  164. componentAlignment * (numComponents == 3 ? 4 : numComponents);
  165. break;
  166. }
  167. case SpvOpTypeMatrix: {
  168. const auto column_type = words[2];
  169. if (inherited.majorness == kColumnMajor) {
  170. baseAlignment = getBaseAlignment(column_type, roundUp, inherited,
  171. constraints, vstate);
  172. } else {
  173. // A row-major matrix of C columns has a base alignment equal to the
  174. // base alignment of a vector of C matrix components.
  175. const auto num_columns = words[3];
  176. const auto component_inst = vstate.FindDef(column_type);
  177. const auto component_id = component_inst->words()[2];
  178. const auto componentAlignment = getBaseAlignment(
  179. component_id, roundUp, inherited, constraints, vstate);
  180. baseAlignment =
  181. componentAlignment * (num_columns == 3 ? 4 : num_columns);
  182. }
  183. } break;
  184. case SpvOpTypeArray:
  185. case SpvOpTypeRuntimeArray:
  186. baseAlignment =
  187. getBaseAlignment(words[2], roundUp, inherited, constraints, vstate);
  188. if (roundUp) baseAlignment = align(baseAlignment, 16u);
  189. break;
  190. case SpvOpTypeStruct: {
  191. const auto members = getStructMembers(member_id, vstate);
  192. for (uint32_t memberIdx = 0, numMembers = uint32_t(members.size());
  193. memberIdx < numMembers; ++memberIdx) {
  194. const auto id = members[memberIdx];
  195. const auto& constraint =
  196. constraints[std::make_pair(member_id, memberIdx)];
  197. baseAlignment = std::max(
  198. baseAlignment,
  199. getBaseAlignment(id, roundUp, constraint, constraints, vstate));
  200. }
  201. if (roundUp) baseAlignment = align(baseAlignment, 16u);
  202. break;
  203. }
  204. case SpvOpTypePointer:
  205. baseAlignment = vstate.pointer_size_and_alignment();
  206. break;
  207. default:
  208. assert(0);
  209. break;
  210. }
  211. return baseAlignment;
  212. }
  213. // Returns scalar alignment of a type.
  214. uint32_t getScalarAlignment(uint32_t type_id, ValidationState_t& vstate) {
  215. const auto inst = vstate.FindDef(type_id);
  216. const auto& words = inst->words();
  217. switch (inst->opcode()) {
  218. case SpvOpTypeInt:
  219. case SpvOpTypeFloat:
  220. return words[2] / 8;
  221. case SpvOpTypeVector:
  222. case SpvOpTypeMatrix:
  223. case SpvOpTypeArray:
  224. case SpvOpTypeRuntimeArray: {
  225. const auto compositeMemberTypeId = words[2];
  226. return getScalarAlignment(compositeMemberTypeId, vstate);
  227. }
  228. case SpvOpTypeStruct: {
  229. const auto members = getStructMembers(type_id, vstate);
  230. uint32_t max_member_alignment = 1;
  231. for (uint32_t memberIdx = 0, numMembers = uint32_t(members.size());
  232. memberIdx < numMembers; ++memberIdx) {
  233. const auto id = members[memberIdx];
  234. uint32_t member_alignment = getScalarAlignment(id, vstate);
  235. if (member_alignment > max_member_alignment) {
  236. max_member_alignment = member_alignment;
  237. }
  238. }
  239. return max_member_alignment;
  240. } break;
  241. case SpvOpTypePointer:
  242. return vstate.pointer_size_and_alignment();
  243. default:
  244. assert(0);
  245. break;
  246. }
  247. return 1;
  248. }
  249. // Returns size of a struct member. Doesn't include padding at the end of struct
  250. // or array. Assumes that in the struct case, all members have offsets.
  251. uint32_t getSize(uint32_t member_id, const LayoutConstraints& inherited,
  252. MemberConstraints& constraints, ValidationState_t& vstate) {
  253. const auto inst = vstate.FindDef(member_id);
  254. const auto& words = inst->words();
  255. switch (inst->opcode()) {
  256. case SpvOpTypeInt:
  257. case SpvOpTypeFloat:
  258. return words[2] / 8;
  259. case SpvOpTypeVector: {
  260. const auto componentId = words[2];
  261. const auto numComponents = words[3];
  262. const auto componentSize =
  263. getSize(componentId, inherited, constraints, vstate);
  264. const auto size = componentSize * numComponents;
  265. return size;
  266. }
  267. case SpvOpTypeArray: {
  268. const auto sizeInst = vstate.FindDef(words[3]);
  269. if (spvOpcodeIsSpecConstant(sizeInst->opcode())) return 0;
  270. assert(SpvOpConstant == sizeInst->opcode());
  271. const uint32_t num_elem = sizeInst->words()[3];
  272. const uint32_t elem_type = words[2];
  273. const uint32_t elem_size =
  274. getSize(elem_type, inherited, constraints, vstate);
  275. // Account for gaps due to alignments in the first N-1 elements,
  276. // then add the size of the last element.
  277. const auto size =
  278. (num_elem - 1) * GetArrayStride(member_id, vstate) + elem_size;
  279. return size;
  280. }
  281. case SpvOpTypeRuntimeArray:
  282. return 0;
  283. case SpvOpTypeMatrix: {
  284. const auto num_columns = words[3];
  285. if (inherited.majorness == kColumnMajor) {
  286. return num_columns * inherited.matrix_stride;
  287. } else {
  288. // Row major case.
  289. const auto column_type = words[2];
  290. const auto component_inst = vstate.FindDef(column_type);
  291. const auto num_rows = component_inst->words()[3];
  292. const auto scalar_elem_type = component_inst->words()[2];
  293. const uint32_t scalar_elem_size =
  294. getSize(scalar_elem_type, inherited, constraints, vstate);
  295. return (num_rows - 1) * inherited.matrix_stride +
  296. num_columns * scalar_elem_size;
  297. }
  298. }
  299. case SpvOpTypeStruct: {
  300. const auto& members = getStructMembers(member_id, vstate);
  301. if (members.empty()) return 0;
  302. const auto lastIdx = uint32_t(members.size() - 1);
  303. const auto& lastMember = members.back();
  304. uint32_t offset = 0xffffffff;
  305. // Find the offset of the last element and add the size.
  306. for (auto& decoration : vstate.id_decorations(member_id)) {
  307. if (SpvDecorationOffset == decoration.dec_type() &&
  308. decoration.struct_member_index() == (int)lastIdx) {
  309. offset = decoration.params()[0];
  310. }
  311. }
  312. // This check depends on the fact that all members have offsets. This
  313. // has been checked earlier in the flow.
  314. assert(offset != 0xffffffff);
  315. const auto& constraint = constraints[std::make_pair(lastMember, lastIdx)];
  316. return offset + getSize(lastMember, constraint, constraints, vstate);
  317. }
  318. case SpvOpTypePointer:
  319. return vstate.pointer_size_and_alignment();
  320. default:
  321. assert(0);
  322. return 0;
  323. }
  324. }
  325. // A member is defined to improperly straddle if either of the following are
  326. // true:
  327. // - It is a vector with total size less than or equal to 16 bytes, and has
  328. // Offset decorations placing its first byte at F and its last byte at L, where
  329. // floor(F / 16) != floor(L / 16).
  330. // - It is a vector with total size greater than 16 bytes and has its Offset
  331. // decorations placing its first byte at a non-integer multiple of 16.
  332. bool hasImproperStraddle(uint32_t id, uint32_t offset,
  333. const LayoutConstraints& inherited,
  334. MemberConstraints& constraints,
  335. ValidationState_t& vstate) {
  336. const auto size = getSize(id, inherited, constraints, vstate);
  337. const auto F = offset;
  338. const auto L = offset + size - 1;
  339. if (size <= 16) {
  340. if ((F >> 4) != (L >> 4)) return true;
  341. } else {
  342. if (F % 16 != 0) return true;
  343. }
  344. return false;
  345. }
  346. // Returns true if |offset| satsifies an alignment to |alignment|. In the case
  347. // of |alignment| of zero, the |offset| must also be zero.
  348. bool IsAlignedTo(uint32_t offset, uint32_t alignment) {
  349. if (alignment == 0) return offset == 0;
  350. return 0 == (offset % alignment);
  351. }
  352. // Returns SPV_SUCCESS if the given struct satisfies standard layout rules for
  353. // Block or BufferBlocks in Vulkan. Otherwise emits a diagnostic and returns
  354. // something other than SPV_SUCCESS. Matrices inherit the specified column
  355. // or row major-ness.
  356. spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
  357. const char* decoration_str, bool blockRules,
  358. bool scalar_block_layout,
  359. uint32_t incoming_offset,
  360. MemberConstraints& constraints,
  361. ValidationState_t& vstate) {
  362. if (vstate.options()->skip_block_layout) return SPV_SUCCESS;
  363. // blockRules are the same as bufferBlock rules if the uniform buffer
  364. // standard layout extension is being used.
  365. if (vstate.options()->uniform_buffer_standard_layout) blockRules = false;
  366. // Relaxed layout and scalar layout can both be in effect at the same time.
  367. // For example, relaxed layout is implied by Vulkan 1.1. But scalar layout
  368. // is more permissive than relaxed layout.
  369. const bool relaxed_block_layout = vstate.IsRelaxedBlockLayout();
  370. auto fail = [&vstate, struct_id, storage_class_str, decoration_str,
  371. blockRules, relaxed_block_layout,
  372. scalar_block_layout](uint32_t member_idx) -> DiagnosticStream {
  373. DiagnosticStream ds =
  374. std::move(vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(struct_id))
  375. << "Structure id " << struct_id << " decorated as "
  376. << decoration_str << " for variable in " << storage_class_str
  377. << " storage class must follow "
  378. << (scalar_block_layout
  379. ? "scalar "
  380. : (relaxed_block_layout ? "relaxed " : "standard "))
  381. << (blockRules ? "uniform buffer" : "storage buffer")
  382. << " layout rules: member " << member_idx << " ");
  383. return ds;
  384. };
  385. const auto& members = getStructMembers(struct_id, vstate);
  386. // To check for member overlaps, we want to traverse the members in
  387. // offset order.
  388. struct MemberOffsetPair {
  389. uint32_t member;
  390. uint32_t offset;
  391. };
  392. std::vector<MemberOffsetPair> member_offsets;
  393. member_offsets.reserve(members.size());
  394. for (uint32_t memberIdx = 0, numMembers = uint32_t(members.size());
  395. memberIdx < numMembers; memberIdx++) {
  396. uint32_t offset = 0xffffffff;
  397. for (auto& decoration : vstate.id_decorations(struct_id)) {
  398. if (decoration.struct_member_index() == (int)memberIdx) {
  399. switch (decoration.dec_type()) {
  400. case SpvDecorationOffset:
  401. offset = decoration.params()[0];
  402. break;
  403. default:
  404. break;
  405. }
  406. }
  407. }
  408. member_offsets.push_back(
  409. MemberOffsetPair{memberIdx, incoming_offset + offset});
  410. }
  411. std::stable_sort(
  412. member_offsets.begin(), member_offsets.end(),
  413. [](const MemberOffsetPair& lhs, const MemberOffsetPair& rhs) {
  414. return lhs.offset < rhs.offset;
  415. });
  416. // Now scan from lowest offest to highest offset.
  417. uint32_t nextValidOffset = 0;
  418. for (size_t ordered_member_idx = 0;
  419. ordered_member_idx < member_offsets.size(); ordered_member_idx++) {
  420. const auto& member_offset = member_offsets[ordered_member_idx];
  421. const auto memberIdx = member_offset.member;
  422. const auto offset = member_offset.offset;
  423. auto id = members[member_offset.member];
  424. const LayoutConstraints& constraint =
  425. constraints[std::make_pair(struct_id, uint32_t(memberIdx))];
  426. // Scalar layout takes precedence because it's more permissive, and implying
  427. // an alignment that divides evenly into the alignment that would otherwise
  428. // be used.
  429. const auto alignment =
  430. scalar_block_layout
  431. ? getScalarAlignment(id, vstate)
  432. : getBaseAlignment(id, blockRules, constraint, constraints, vstate);
  433. const auto inst = vstate.FindDef(id);
  434. const auto opcode = inst->opcode();
  435. const auto size = getSize(id, constraint, constraints, vstate);
  436. // Check offset.
  437. if (offset == 0xffffffff)
  438. return fail(memberIdx) << "is missing an Offset decoration";
  439. if (!scalar_block_layout && relaxed_block_layout &&
  440. opcode == SpvOpTypeVector) {
  441. // In relaxed block layout, the vector offset must be aligned to the
  442. // vector's scalar element type.
  443. const auto componentId = inst->words()[2];
  444. const auto scalar_alignment = getScalarAlignment(componentId, vstate);
  445. if (!IsAlignedTo(offset, scalar_alignment)) {
  446. return fail(memberIdx)
  447. << "at offset " << offset
  448. << " is not aligned to scalar element size " << scalar_alignment;
  449. }
  450. } else {
  451. // Without relaxed block layout, the offset must be divisible by the
  452. // alignment requirement.
  453. if (!IsAlignedTo(offset, alignment)) {
  454. return fail(memberIdx)
  455. << "at offset " << offset << " is not aligned to " << alignment;
  456. }
  457. }
  458. if (offset < nextValidOffset)
  459. return fail(memberIdx) << "at offset " << offset
  460. << " overlaps previous member ending at offset "
  461. << nextValidOffset - 1;
  462. if (!scalar_block_layout && relaxed_block_layout) {
  463. // Check improper straddle of vectors.
  464. if (SpvOpTypeVector == opcode &&
  465. hasImproperStraddle(id, offset, constraint, constraints, vstate))
  466. return fail(memberIdx)
  467. << "is an improperly straddling vector at offset " << offset;
  468. }
  469. // Check struct members recursively.
  470. spv_result_t recursive_status = SPV_SUCCESS;
  471. if (SpvOpTypeStruct == opcode &&
  472. SPV_SUCCESS != (recursive_status = checkLayout(
  473. id, storage_class_str, decoration_str, blockRules,
  474. scalar_block_layout,
  475. offset, constraints, vstate)))
  476. return recursive_status;
  477. // Check matrix stride.
  478. if (SpvOpTypeMatrix == opcode) {
  479. const auto stride = constraint.matrix_stride;
  480. if (!IsAlignedTo(stride, alignment)) {
  481. return fail(memberIdx) << "is a matrix with stride " << stride
  482. << " not satisfying alignment to " << alignment;
  483. }
  484. }
  485. // Check arrays and runtime arrays recursively.
  486. auto array_inst = inst;
  487. auto array_alignment = alignment;
  488. while (array_inst->opcode() == SpvOpTypeArray ||
  489. array_inst->opcode() == SpvOpTypeRuntimeArray) {
  490. const auto typeId = array_inst->word(2);
  491. const auto element_inst = vstate.FindDef(typeId);
  492. // Check array stride.
  493. uint32_t array_stride = 0;
  494. for (auto& decoration : vstate.id_decorations(array_inst->id())) {
  495. if (SpvDecorationArrayStride == decoration.dec_type()) {
  496. array_stride = decoration.params()[0];
  497. if (array_stride == 0) {
  498. return fail(memberIdx) << "contains an array with stride 0";
  499. }
  500. if (!IsAlignedTo(array_stride, array_alignment))
  501. return fail(memberIdx)
  502. << "contains an array with stride " << decoration.params()[0]
  503. << " not satisfying alignment to " << alignment;
  504. }
  505. }
  506. bool is_int32 = false;
  507. bool is_const = false;
  508. uint32_t num_elements = 0;
  509. if (array_inst->opcode() == SpvOpTypeArray) {
  510. std::tie(is_int32, is_const, num_elements) =
  511. vstate.EvalInt32IfConst(array_inst->word(3));
  512. }
  513. num_elements = std::max(1u, num_elements);
  514. // Check each element recursively if it is a struct. There is a
  515. // limitation to this check if the array size is a spec constant or is a
  516. // runtime array then we will only check a single element. This means
  517. // some improper straddles might be missed.
  518. if (SpvOpTypeStruct == element_inst->opcode()) {
  519. std::vector<bool> seen(16, false);
  520. for (uint32_t i = 0; i < num_elements; ++i) {
  521. uint32_t next_offset = i * array_stride + offset;
  522. // Stop checking if offsets repeat in terms of 16-byte multiples.
  523. if (seen[next_offset % 16]) {
  524. break;
  525. }
  526. if (SPV_SUCCESS !=
  527. (recursive_status = checkLayout(
  528. typeId, storage_class_str, decoration_str, blockRules,
  529. scalar_block_layout, next_offset, constraints, vstate)))
  530. return recursive_status;
  531. seen[next_offset % 16] = true;
  532. }
  533. }
  534. // Proceed to the element in case it is an array.
  535. array_inst = element_inst;
  536. array_alignment = scalar_block_layout
  537. ? getScalarAlignment(array_inst->id(), vstate)
  538. : getBaseAlignment(array_inst->id(), blockRules,
  539. constraint, constraints, vstate);
  540. const auto element_size =
  541. getSize(element_inst->id(), constraint, constraints, vstate);
  542. if (element_size > array_stride) {
  543. return fail(memberIdx)
  544. << "contains an array with stride " << array_stride
  545. << ", but with an element size of " << element_size;
  546. }
  547. }
  548. nextValidOffset = offset + size;
  549. if (!scalar_block_layout && blockRules &&
  550. (SpvOpTypeArray == opcode || SpvOpTypeStruct == opcode)) {
  551. // Uniform block rules don't permit anything in the padding of a struct
  552. // or array.
  553. nextValidOffset = align(nextValidOffset, alignment);
  554. }
  555. }
  556. return SPV_SUCCESS;
  557. }
  558. // Returns true if variable or structure id has given decoration. Handles also
  559. // nested structures.
  560. bool hasDecoration(uint32_t id, SpvDecoration decoration,
  561. ValidationState_t& vstate) {
  562. for (auto& dec : vstate.id_decorations(id)) {
  563. if (decoration == dec.dec_type()) return true;
  564. }
  565. if (SpvOpTypeStruct != vstate.FindDef(id)->opcode()) {
  566. return false;
  567. }
  568. for (auto member_id : getStructMembers(id, SpvOpTypeStruct, vstate)) {
  569. if (hasDecoration(member_id, decoration, vstate)) {
  570. return true;
  571. }
  572. }
  573. return false;
  574. }
  575. // Returns true if all ids of given type have a specified decoration.
  576. bool checkForRequiredDecoration(uint32_t struct_id, SpvDecoration decoration,
  577. SpvOp type, ValidationState_t& vstate) {
  578. const auto& members = getStructMembers(struct_id, vstate);
  579. for (size_t memberIdx = 0; memberIdx < members.size(); memberIdx++) {
  580. const auto id = members[memberIdx];
  581. if (type != vstate.FindDef(id)->opcode()) continue;
  582. bool found = false;
  583. for (auto& dec : vstate.id_decorations(id)) {
  584. if (decoration == dec.dec_type()) found = true;
  585. }
  586. for (auto& dec : vstate.id_decorations(struct_id)) {
  587. if (decoration == dec.dec_type() &&
  588. (int)memberIdx == dec.struct_member_index()) {
  589. found = true;
  590. }
  591. }
  592. if (!found) {
  593. return false;
  594. }
  595. }
  596. for (auto id : getStructMembers(struct_id, SpvOpTypeStruct, vstate)) {
  597. if (!checkForRequiredDecoration(id, decoration, type, vstate)) {
  598. return false;
  599. }
  600. }
  601. return true;
  602. }
  603. spv_result_t CheckLinkageAttrOfFunctions(ValidationState_t& vstate) {
  604. for (const auto& function : vstate.functions()) {
  605. if (function.block_count() == 0u) {
  606. // A function declaration (an OpFunction with no basic blocks), must have
  607. // a Linkage Attributes Decoration with the Import Linkage Type.
  608. if (!hasImportLinkageAttribute(function.id(), vstate)) {
  609. return vstate.diag(SPV_ERROR_INVALID_BINARY,
  610. vstate.FindDef(function.id()))
  611. << "Function declaration (id " << function.id()
  612. << ") must have a LinkageAttributes decoration with the Import "
  613. "Linkage type.";
  614. }
  615. } else {
  616. if (hasImportLinkageAttribute(function.id(), vstate)) {
  617. return vstate.diag(SPV_ERROR_INVALID_BINARY,
  618. vstate.FindDef(function.id()))
  619. << "Function definition (id " << function.id()
  620. << ") may not be decorated with Import Linkage type.";
  621. }
  622. }
  623. }
  624. return SPV_SUCCESS;
  625. }
  626. // Checks whether an imported variable is initialized by this module.
  627. spv_result_t CheckImportedVariableInitialization(ValidationState_t& vstate) {
  628. // According the SPIR-V Spec 2.16.1, it is illegal to initialize an imported
  629. // variable. This means that a module-scope OpVariable with initialization
  630. // value cannot be marked with the Import Linkage Type (import type id = 1).
  631. for (auto global_var_id : vstate.global_vars()) {
  632. // Initializer <id> is an optional argument for OpVariable. If initializer
  633. // <id> is present, the instruction will have 5 words.
  634. auto variable_instr = vstate.FindDef(global_var_id);
  635. if (variable_instr->words().size() == 5u &&
  636. hasImportLinkageAttribute(global_var_id, vstate)) {
  637. return vstate.diag(SPV_ERROR_INVALID_ID, variable_instr)
  638. << "A module-scope OpVariable with initialization value "
  639. "cannot be marked with the Import Linkage Type.";
  640. }
  641. }
  642. return SPV_SUCCESS;
  643. }
  644. // Checks whether a builtin variable is valid.
  645. spv_result_t CheckBuiltInVariable(uint32_t var_id, ValidationState_t& vstate) {
  646. const auto& decorations = vstate.id_decorations(var_id);
  647. for (const auto& d : decorations) {
  648. if (spvIsVulkanEnv(vstate.context()->target_env)) {
  649. if (d.dec_type() == SpvDecorationLocation ||
  650. d.dec_type() == SpvDecorationComponent) {
  651. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
  652. << "A BuiltIn variable (id " << var_id
  653. << ") cannot have any Location or Component decorations";
  654. }
  655. }
  656. }
  657. return SPV_SUCCESS;
  658. }
  659. // Checks whether proper decorations have been appied to the entry points.
  660. spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) {
  661. for (uint32_t entry_point : vstate.entry_points()) {
  662. const auto& descs = vstate.entry_point_descriptions(entry_point);
  663. int num_builtin_inputs = 0;
  664. int num_builtin_outputs = 0;
  665. int num_workgroup_variables = 0;
  666. int num_workgroup_variables_with_block = 0;
  667. int num_workgroup_variables_with_aliased = 0;
  668. for (const auto& desc : descs) {
  669. std::unordered_set<Instruction*> seen_vars;
  670. for (auto interface : desc.interfaces) {
  671. Instruction* var_instr = vstate.FindDef(interface);
  672. if (!var_instr || SpvOpVariable != var_instr->opcode()) {
  673. return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
  674. << "Interfaces passed to OpEntryPoint must be of type "
  675. "OpTypeVariable. Found Op"
  676. << spvOpcodeString(var_instr->opcode()) << ".";
  677. }
  678. const SpvStorageClass storage_class =
  679. var_instr->GetOperandAs<SpvStorageClass>(2);
  680. if (vstate.version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
  681. // Starting in 1.4, OpEntryPoint must list all global variables
  682. // it statically uses and those interfaces must be unique.
  683. if (storage_class == SpvStorageClassFunction) {
  684. return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
  685. << "OpEntryPoint interfaces should only list global "
  686. "variables";
  687. }
  688. if (!seen_vars.insert(var_instr).second) {
  689. return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
  690. << "Non-unique OpEntryPoint interface "
  691. << vstate.getIdName(interface) << " is disallowed";
  692. }
  693. } else {
  694. if (storage_class != SpvStorageClassInput &&
  695. storage_class != SpvStorageClassOutput) {
  696. return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
  697. << "OpEntryPoint interfaces must be OpVariables with "
  698. "Storage Class of Input(1) or Output(3). Found Storage "
  699. "Class "
  700. << storage_class << " for Entry Point id " << entry_point
  701. << ".";
  702. }
  703. }
  704. const uint32_t ptr_id = var_instr->word(1);
  705. Instruction* ptr_instr = vstate.FindDef(ptr_id);
  706. // It is guaranteed (by validator ID checks) that ptr_instr is
  707. // OpTypePointer. Word 3 of this instruction is the type being pointed
  708. // to.
  709. const uint32_t type_id = ptr_instr->word(3);
  710. Instruction* type_instr = vstate.FindDef(type_id);
  711. if (type_instr && SpvOpTypeStruct == type_instr->opcode() &&
  712. isBuiltInStruct(type_id, vstate)) {
  713. if (storage_class == SpvStorageClassInput) ++num_builtin_inputs;
  714. if (storage_class == SpvStorageClassOutput) ++num_builtin_outputs;
  715. if (num_builtin_inputs > 1 || num_builtin_outputs > 1) break;
  716. if (auto error = CheckBuiltInVariable(interface, vstate))
  717. return error;
  718. } else if (isBuiltInVar(interface, vstate)) {
  719. if (auto error = CheckBuiltInVariable(interface, vstate))
  720. return error;
  721. }
  722. if (storage_class == SpvStorageClassWorkgroup) {
  723. ++num_workgroup_variables;
  724. if (type_instr && SpvOpTypeStruct == type_instr->opcode()) {
  725. if (hasDecoration(type_id, SpvDecorationBlock, vstate))
  726. ++num_workgroup_variables_with_block;
  727. if (hasDecoration(var_instr->id(), SpvDecorationAliased, vstate))
  728. ++num_workgroup_variables_with_aliased;
  729. }
  730. }
  731. }
  732. if (num_builtin_inputs > 1 || num_builtin_outputs > 1) {
  733. return vstate.diag(SPV_ERROR_INVALID_BINARY,
  734. vstate.FindDef(entry_point))
  735. << "There must be at most one object per Storage Class that can "
  736. "contain a structure type containing members decorated with "
  737. "BuiltIn, consumed per entry-point. Entry Point id "
  738. << entry_point << " does not meet this requirement.";
  739. }
  740. // The LinkageAttributes Decoration cannot be applied to functions
  741. // targeted by an OpEntryPoint instruction
  742. for (auto& decoration : vstate.id_decorations(entry_point)) {
  743. if (SpvDecorationLinkageAttributes == decoration.dec_type()) {
  744. const char* linkage_name =
  745. reinterpret_cast<const char*>(&decoration.params()[0]);
  746. return vstate.diag(SPV_ERROR_INVALID_BINARY,
  747. vstate.FindDef(entry_point))
  748. << "The LinkageAttributes Decoration (Linkage name: "
  749. << linkage_name << ") cannot be applied to function id "
  750. << entry_point
  751. << " because it is targeted by an OpEntryPoint instruction.";
  752. }
  753. }
  754. if (vstate.HasCapability(SpvCapabilityWorkgroupMemoryExplicitLayoutKHR) &&
  755. num_workgroup_variables > 0 &&
  756. num_workgroup_variables_with_block > 0) {
  757. if (num_workgroup_variables != num_workgroup_variables_with_block) {
  758. return vstate.diag(SPV_ERROR_INVALID_BINARY, vstate.FindDef(entry_point))
  759. << "When declaring WorkgroupMemoryExplicitLayoutKHR, "
  760. "either all or none of the Workgroup Storage Class variables "
  761. "in the entry point interface must point to struct types "
  762. "decorated with Block. Entry point id "
  763. << entry_point << " does not meet this requirement.";
  764. }
  765. if (num_workgroup_variables_with_block > 1 &&
  766. num_workgroup_variables_with_block !=
  767. num_workgroup_variables_with_aliased) {
  768. return vstate.diag(SPV_ERROR_INVALID_BINARY, vstate.FindDef(entry_point))
  769. << "When declaring WorkgroupMemoryExplicitLayoutKHR, "
  770. "if more than one Workgroup Storage Class variable in "
  771. "the entry point interface point to a type decorated "
  772. "with Block, all of them must be decorated with Aliased. "
  773. "Entry point id "
  774. << entry_point << " does not meet this requirement.";
  775. }
  776. }
  777. }
  778. }
  779. return SPV_SUCCESS;
  780. }
  781. // Load |constraints| with all the member constraints for structs contained
  782. // within the given array type.
  783. void ComputeMemberConstraintsForArray(MemberConstraints* constraints,
  784. uint32_t array_id,
  785. const LayoutConstraints& inherited,
  786. ValidationState_t& vstate);
  787. // Load |constraints| with all the member constraints for the given struct,
  788. // and all its contained structs.
  789. void ComputeMemberConstraintsForStruct(MemberConstraints* constraints,
  790. uint32_t struct_id,
  791. const LayoutConstraints& inherited,
  792. ValidationState_t& vstate) {
  793. assert(constraints);
  794. const auto& members = getStructMembers(struct_id, vstate);
  795. for (uint32_t memberIdx = 0, numMembers = uint32_t(members.size());
  796. memberIdx < numMembers; memberIdx++) {
  797. LayoutConstraints& constraint =
  798. (*constraints)[std::make_pair(struct_id, memberIdx)];
  799. constraint = inherited;
  800. for (auto& decoration : vstate.id_decorations(struct_id)) {
  801. if (decoration.struct_member_index() == (int)memberIdx) {
  802. switch (decoration.dec_type()) {
  803. case SpvDecorationRowMajor:
  804. constraint.majorness = kRowMajor;
  805. break;
  806. case SpvDecorationColMajor:
  807. constraint.majorness = kColumnMajor;
  808. break;
  809. case SpvDecorationMatrixStride:
  810. constraint.matrix_stride = decoration.params()[0];
  811. break;
  812. default:
  813. break;
  814. }
  815. }
  816. }
  817. // Now recurse
  818. auto member_type_id = members[memberIdx];
  819. const auto member_type_inst = vstate.FindDef(member_type_id);
  820. const auto opcode = member_type_inst->opcode();
  821. switch (opcode) {
  822. case SpvOpTypeArray:
  823. case SpvOpTypeRuntimeArray:
  824. ComputeMemberConstraintsForArray(constraints, member_type_id, inherited,
  825. vstate);
  826. break;
  827. case SpvOpTypeStruct:
  828. ComputeMemberConstraintsForStruct(constraints, member_type_id,
  829. inherited, vstate);
  830. break;
  831. default:
  832. break;
  833. }
  834. }
  835. }
  836. void ComputeMemberConstraintsForArray(MemberConstraints* constraints,
  837. uint32_t array_id,
  838. const LayoutConstraints& inherited,
  839. ValidationState_t& vstate) {
  840. assert(constraints);
  841. auto elem_type_id = vstate.FindDef(array_id)->words()[2];
  842. const auto elem_type_inst = vstate.FindDef(elem_type_id);
  843. const auto opcode = elem_type_inst->opcode();
  844. switch (opcode) {
  845. case SpvOpTypeArray:
  846. case SpvOpTypeRuntimeArray:
  847. ComputeMemberConstraintsForArray(constraints, elem_type_id, inherited,
  848. vstate);
  849. break;
  850. case SpvOpTypeStruct:
  851. ComputeMemberConstraintsForStruct(constraints, elem_type_id, inherited,
  852. vstate);
  853. break;
  854. default:
  855. break;
  856. }
  857. }
  858. spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
  859. // Set of entry points that are known to use a push constant.
  860. std::unordered_set<uint32_t> uses_push_constant;
  861. for (const auto& inst : vstate.ordered_instructions()) {
  862. const auto& words = inst.words();
  863. if (SpvOpVariable == inst.opcode()) {
  864. const auto var_id = inst.id();
  865. // For storage class / decoration combinations, see Vulkan 14.5.4 "Offset
  866. // and Stride Assignment".
  867. const auto storageClass = words[3];
  868. const bool uniform = storageClass == SpvStorageClassUniform;
  869. const bool uniform_constant =
  870. storageClass == SpvStorageClassUniformConstant;
  871. const bool push_constant = storageClass == SpvStorageClassPushConstant;
  872. const bool storage_buffer = storageClass == SpvStorageClassStorageBuffer;
  873. if (spvIsVulkanEnv(vstate.context()->target_env)) {
  874. // Vulkan 14.5.1: There must be no more than one PushConstant block
  875. // per entry point.
  876. if (push_constant) {
  877. auto entry_points = vstate.EntryPointReferences(var_id);
  878. for (auto ep_id : entry_points) {
  879. const bool already_used = !uses_push_constant.insert(ep_id).second;
  880. if (already_used) {
  881. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
  882. << "Entry point id '" << ep_id
  883. << "' uses more than one PushConstant interface.\n"
  884. << "From Vulkan spec, section 14.5.1:\n"
  885. << "There must be no more than one push constant block "
  886. << "statically used per shader entry point.";
  887. }
  888. }
  889. }
  890. // Vulkan 14.5.2: Check DescriptorSet and Binding decoration for
  891. // UniformConstant which cannot be a struct.
  892. if (uniform_constant) {
  893. auto entry_points = vstate.EntryPointReferences(var_id);
  894. if (!entry_points.empty() &&
  895. !hasDecoration(var_id, SpvDecorationDescriptorSet, vstate)) {
  896. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
  897. << "UniformConstant id '" << var_id
  898. << "' is missing DescriptorSet decoration.\n"
  899. << "From Vulkan spec, section 14.5.2:\n"
  900. << "These variables must have DescriptorSet and Binding "
  901. "decorations specified";
  902. }
  903. if (!entry_points.empty() &&
  904. !hasDecoration(var_id, SpvDecorationBinding, vstate)) {
  905. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
  906. << "UniformConstant id '" << var_id
  907. << "' is missing Binding decoration.\n"
  908. << "From Vulkan spec, section 14.5.2:\n"
  909. << "These variables must have DescriptorSet and Binding "
  910. "decorations specified";
  911. }
  912. }
  913. }
  914. if (spvIsOpenGLEnv(vstate.context()->target_env)) {
  915. bool has_block = hasDecoration(var_id, SpvDecorationBlock, vstate);
  916. bool has_buffer_block =
  917. hasDecoration(var_id, SpvDecorationBufferBlock, vstate);
  918. if ((uniform && (has_block || has_buffer_block)) ||
  919. (storage_buffer && has_block)) {
  920. auto entry_points = vstate.EntryPointReferences(var_id);
  921. if (!entry_points.empty() &&
  922. !hasDecoration(var_id, SpvDecorationBinding, vstate)) {
  923. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
  924. << (uniform ? "Uniform" : "Storage Buffer") << " id '"
  925. << var_id << "' is missing Binding decoration.\n"
  926. << "From ARB_gl_spirv extension:\n"
  927. << "Uniform and shader storage block variables must "
  928. << "also be decorated with a *Binding*.";
  929. }
  930. }
  931. }
  932. const bool phys_storage_buffer =
  933. storageClass == SpvStorageClassPhysicalStorageBufferEXT;
  934. const bool workgroup = storageClass == SpvStorageClassWorkgroup;
  935. if (uniform || push_constant || storage_buffer || phys_storage_buffer ||
  936. workgroup) {
  937. const auto ptrInst = vstate.FindDef(words[1]);
  938. assert(SpvOpTypePointer == ptrInst->opcode());
  939. auto id = ptrInst->words()[3];
  940. auto id_inst = vstate.FindDef(id);
  941. // Jump through one level of arraying.
  942. if (!workgroup && (id_inst->opcode() == SpvOpTypeArray ||
  943. id_inst->opcode() == SpvOpTypeRuntimeArray)) {
  944. id = id_inst->GetOperandAs<uint32_t>(1u);
  945. id_inst = vstate.FindDef(id);
  946. }
  947. // Struct requirement is checked on variables so just move on here.
  948. if (SpvOpTypeStruct != id_inst->opcode()) continue;
  949. MemberConstraints constraints;
  950. ComputeMemberConstraintsForStruct(&constraints, id, LayoutConstraints(),
  951. vstate);
  952. // Prepare for messages
  953. const char* sc_str =
  954. uniform ? "Uniform"
  955. : (push_constant ? "PushConstant"
  956. : (workgroup ? "Workgroup"
  957. : "StorageBuffer"));
  958. if (spvIsVulkanEnv(vstate.context()->target_env)) {
  959. const bool block = hasDecoration(id, SpvDecorationBlock, vstate);
  960. const bool buffer_block =
  961. hasDecoration(id, SpvDecorationBufferBlock, vstate);
  962. if (storage_buffer && buffer_block) {
  963. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
  964. << "Storage buffer id '" << var_id
  965. << " In Vulkan, BufferBlock is disallowed on variables in "
  966. "the StorageBuffer storage class";
  967. }
  968. // Vulkan 14.5.1/2: Check Block decoration for PushConstant, Uniform
  969. // and StorageBuffer variables. Uniform can also use BufferBlock.
  970. if (push_constant && !block) {
  971. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  972. << "PushConstant id '" << id
  973. << "' is missing Block decoration.\n"
  974. << "From Vulkan spec, section 14.5.1:\n"
  975. << "Such variables must be identified with a Block "
  976. "decoration";
  977. }
  978. if (storage_buffer && !block) {
  979. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  980. << "StorageBuffer id '" << id
  981. << "' is missing Block decoration.\n"
  982. << "From Vulkan spec, section 14.5.2:\n"
  983. << "Such variables must be identified with a Block "
  984. "decoration";
  985. }
  986. if (uniform && !block && !buffer_block) {
  987. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  988. << "Uniform id '" << id
  989. << "' is missing Block or BufferBlock decoration.\n"
  990. << "From Vulkan spec, section 14.5.2:\n"
  991. << "Such variables must be identified with a Block or "
  992. "BufferBlock decoration";
  993. }
  994. // Vulkan 14.5.2: Check DescriptorSet and Binding decoration for
  995. // Uniform and StorageBuffer variables.
  996. if (uniform || storage_buffer) {
  997. auto entry_points = vstate.EntryPointReferences(var_id);
  998. if (!entry_points.empty() &&
  999. !hasDecoration(var_id, SpvDecorationDescriptorSet, vstate)) {
  1000. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
  1001. << sc_str << " id '" << var_id
  1002. << "' is missing DescriptorSet decoration.\n"
  1003. << "From Vulkan spec, section 14.5.2:\n"
  1004. << "These variables must have DescriptorSet and Binding "
  1005. "decorations specified";
  1006. }
  1007. if (!entry_points.empty() &&
  1008. !hasDecoration(var_id, SpvDecorationBinding, vstate)) {
  1009. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
  1010. << sc_str << " id '" << var_id
  1011. << "' is missing Binding decoration.\n"
  1012. << "From Vulkan spec, section 14.5.2:\n"
  1013. << "These variables must have DescriptorSet and Binding "
  1014. "decorations specified";
  1015. }
  1016. }
  1017. }
  1018. for (const auto& dec : vstate.id_decorations(id)) {
  1019. const bool blockDeco = SpvDecorationBlock == dec.dec_type();
  1020. const bool bufferDeco = SpvDecorationBufferBlock == dec.dec_type();
  1021. const bool blockRules = uniform && blockDeco;
  1022. const bool bufferRules =
  1023. (uniform && bufferDeco) ||
  1024. ((push_constant || storage_buffer ||
  1025. phys_storage_buffer || workgroup) && blockDeco);
  1026. if (uniform && blockDeco) {
  1027. vstate.RegisterPointerToUniformBlock(ptrInst->id());
  1028. vstate.RegisterStructForUniformBlock(id);
  1029. }
  1030. if ((uniform && bufferDeco) ||
  1031. ((storage_buffer || phys_storage_buffer) && blockDeco)) {
  1032. vstate.RegisterPointerToStorageBuffer(ptrInst->id());
  1033. vstate.RegisterStructForStorageBuffer(id);
  1034. }
  1035. if (blockRules || bufferRules) {
  1036. const char* deco_str = blockDeco ? "Block" : "BufferBlock";
  1037. spv_result_t recursive_status = SPV_SUCCESS;
  1038. const bool scalar_block_layout = workgroup ?
  1039. vstate.options()->workgroup_scalar_block_layout :
  1040. vstate.options()->scalar_block_layout;
  1041. if (isMissingOffsetInStruct(id, vstate)) {
  1042. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1043. << "Structure id " << id << " decorated as " << deco_str
  1044. << " must be explicitly laid out with Offset "
  1045. "decorations.";
  1046. } else if (hasDecoration(id, SpvDecorationGLSLShared, vstate)) {
  1047. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1048. << "Structure id " << id << " decorated as " << deco_str
  1049. << " must not use GLSLShared decoration.";
  1050. } else if (hasDecoration(id, SpvDecorationGLSLPacked, vstate)) {
  1051. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1052. << "Structure id " << id << " decorated as " << deco_str
  1053. << " must not use GLSLPacked decoration.";
  1054. } else if (!checkForRequiredDecoration(id, SpvDecorationArrayStride,
  1055. SpvOpTypeArray, vstate)) {
  1056. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1057. << "Structure id " << id << " decorated as " << deco_str
  1058. << " must be explicitly laid out with ArrayStride "
  1059. "decorations.";
  1060. } else if (!checkForRequiredDecoration(id,
  1061. SpvDecorationMatrixStride,
  1062. SpvOpTypeMatrix, vstate)) {
  1063. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1064. << "Structure id " << id << " decorated as " << deco_str
  1065. << " must be explicitly laid out with MatrixStride "
  1066. "decorations.";
  1067. } else if (blockRules &&
  1068. (SPV_SUCCESS != (recursive_status = checkLayout(
  1069. id, sc_str, deco_str, true,
  1070. scalar_block_layout, 0,
  1071. constraints, vstate)))) {
  1072. return recursive_status;
  1073. } else if (bufferRules &&
  1074. (SPV_SUCCESS != (recursive_status = checkLayout(
  1075. id, sc_str, deco_str, false,
  1076. scalar_block_layout, 0,
  1077. constraints, vstate)))) {
  1078. return recursive_status;
  1079. }
  1080. }
  1081. }
  1082. }
  1083. }
  1084. }
  1085. return SPV_SUCCESS;
  1086. }
  1087. // Returns true if |decoration| cannot be applied to the same id more than once.
  1088. bool AtMostOncePerId(SpvDecoration decoration) {
  1089. return decoration == SpvDecorationArrayStride;
  1090. }
  1091. // Returns true if |decoration| cannot be applied to the same member more than
  1092. // once.
  1093. bool AtMostOncePerMember(SpvDecoration decoration) {
  1094. switch (decoration) {
  1095. case SpvDecorationOffset:
  1096. case SpvDecorationMatrixStride:
  1097. case SpvDecorationRowMajor:
  1098. case SpvDecorationColMajor:
  1099. return true;
  1100. default:
  1101. return false;
  1102. }
  1103. }
  1104. // Returns the string name for |decoration|.
  1105. const char* GetDecorationName(SpvDecoration decoration) {
  1106. switch (decoration) {
  1107. case SpvDecorationAliased:
  1108. return "Aliased";
  1109. case SpvDecorationRestrict:
  1110. return "Restrict";
  1111. case SpvDecorationArrayStride:
  1112. return "ArrayStride";
  1113. case SpvDecorationOffset:
  1114. return "Offset";
  1115. case SpvDecorationMatrixStride:
  1116. return "MatrixStride";
  1117. case SpvDecorationRowMajor:
  1118. return "RowMajor";
  1119. case SpvDecorationColMajor:
  1120. return "ColMajor";
  1121. case SpvDecorationBlock:
  1122. return "Block";
  1123. case SpvDecorationBufferBlock:
  1124. return "BufferBlock";
  1125. default:
  1126. return "";
  1127. }
  1128. }
  1129. spv_result_t CheckDecorationsCompatibility(ValidationState_t& vstate) {
  1130. using PerIDKey = std::tuple<SpvDecoration, uint32_t>;
  1131. using PerMemberKey = std::tuple<SpvDecoration, uint32_t, uint32_t>;
  1132. // An Array of pairs where the decorations in the pair cannot both be applied
  1133. // to the same id.
  1134. static const SpvDecoration mutually_exclusive_per_id[][2] = {
  1135. {SpvDecorationBlock, SpvDecorationBufferBlock},
  1136. {SpvDecorationRestrict, SpvDecorationAliased}};
  1137. static const auto num_mutually_exclusive_per_id_pairs =
  1138. sizeof(mutually_exclusive_per_id) / (2 * sizeof(SpvDecoration));
  1139. // An Array of pairs where the decorations in the pair cannot both be applied
  1140. // to the same member.
  1141. static const SpvDecoration mutually_exclusive_per_member[][2] = {
  1142. {SpvDecorationRowMajor, SpvDecorationColMajor}};
  1143. static const auto num_mutually_exclusive_per_mem_pairs =
  1144. sizeof(mutually_exclusive_per_member) / (2 * sizeof(SpvDecoration));
  1145. std::set<PerIDKey> seen_per_id;
  1146. std::set<PerMemberKey> seen_per_member;
  1147. for (const auto& inst : vstate.ordered_instructions()) {
  1148. const auto& words = inst.words();
  1149. if (SpvOpDecorate == inst.opcode()) {
  1150. const auto id = words[1];
  1151. const auto dec_type = static_cast<SpvDecoration>(words[2]);
  1152. const auto k = PerIDKey(dec_type, id);
  1153. const auto already_used = !seen_per_id.insert(k).second;
  1154. if (already_used && AtMostOncePerId(dec_type)) {
  1155. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1156. << "ID '" << id << "' decorated with "
  1157. << GetDecorationName(dec_type)
  1158. << " multiple times is not allowed.";
  1159. }
  1160. // Verify certain mutually exclusive decorations are not both applied on
  1161. // an ID.
  1162. for (uint32_t pair_idx = 0;
  1163. pair_idx < num_mutually_exclusive_per_id_pairs; ++pair_idx) {
  1164. SpvDecoration excl_dec_type = SpvDecorationMax;
  1165. if (mutually_exclusive_per_id[pair_idx][0] == dec_type) {
  1166. excl_dec_type = mutually_exclusive_per_id[pair_idx][1];
  1167. } else if (mutually_exclusive_per_id[pair_idx][1] == dec_type) {
  1168. excl_dec_type = mutually_exclusive_per_id[pair_idx][0];
  1169. } else {
  1170. continue;
  1171. }
  1172. const auto excl_k = PerIDKey(excl_dec_type, id);
  1173. if (seen_per_id.find(excl_k) != seen_per_id.end()) {
  1174. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1175. << "ID '" << id << "' decorated with both "
  1176. << GetDecorationName(dec_type) << " and "
  1177. << GetDecorationName(excl_dec_type) << " is not allowed.";
  1178. }
  1179. }
  1180. } else if (SpvOpMemberDecorate == inst.opcode()) {
  1181. const auto id = words[1];
  1182. const auto member_id = words[2];
  1183. const auto dec_type = static_cast<SpvDecoration>(words[3]);
  1184. const auto k = PerMemberKey(dec_type, id, member_id);
  1185. const auto already_used = !seen_per_member.insert(k).second;
  1186. if (already_used && AtMostOncePerMember(dec_type)) {
  1187. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1188. << "ID '" << id << "', member '" << member_id
  1189. << "' decorated with " << GetDecorationName(dec_type)
  1190. << " multiple times is not allowed.";
  1191. }
  1192. // Verify certain mutually exclusive decorations are not both applied on
  1193. // a (ID, member) tuple.
  1194. for (uint32_t pair_idx = 0;
  1195. pair_idx < num_mutually_exclusive_per_mem_pairs; ++pair_idx) {
  1196. SpvDecoration excl_dec_type = SpvDecorationMax;
  1197. if (mutually_exclusive_per_member[pair_idx][0] == dec_type) {
  1198. excl_dec_type = mutually_exclusive_per_member[pair_idx][1];
  1199. } else if (mutually_exclusive_per_member[pair_idx][1] == dec_type) {
  1200. excl_dec_type = mutually_exclusive_per_member[pair_idx][0];
  1201. } else {
  1202. continue;
  1203. }
  1204. const auto excl_k = PerMemberKey(excl_dec_type, id, member_id);
  1205. if (seen_per_member.find(excl_k) != seen_per_member.end()) {
  1206. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1207. << "ID '" << id << "', member '" << member_id
  1208. << "' decorated with both " << GetDecorationName(dec_type)
  1209. << " and " << GetDecorationName(excl_dec_type)
  1210. << " is not allowed.";
  1211. }
  1212. }
  1213. }
  1214. }
  1215. return SPV_SUCCESS;
  1216. }
  1217. spv_result_t CheckVulkanMemoryModelDeprecatedDecorations(
  1218. ValidationState_t& vstate) {
  1219. if (vstate.memory_model() != SpvMemoryModelVulkanKHR) return SPV_SUCCESS;
  1220. std::string msg;
  1221. std::ostringstream str(msg);
  1222. for (const auto& def : vstate.all_definitions()) {
  1223. const auto inst = def.second;
  1224. const auto id = inst->id();
  1225. for (const auto& dec : vstate.id_decorations(id)) {
  1226. const auto member = dec.struct_member_index();
  1227. if (dec.dec_type() == SpvDecorationCoherent ||
  1228. dec.dec_type() == SpvDecorationVolatile) {
  1229. str << (dec.dec_type() == SpvDecorationCoherent ? "Coherent"
  1230. : "Volatile");
  1231. str << " decoration targeting " << vstate.getIdName(id);
  1232. if (member != Decoration::kInvalidMember) {
  1233. str << " (member index " << member << ")";
  1234. }
  1235. str << " is banned when using the Vulkan memory model.";
  1236. return vstate.diag(SPV_ERROR_INVALID_ID, inst) << str.str();
  1237. }
  1238. }
  1239. }
  1240. return SPV_SUCCESS;
  1241. }
  1242. // Returns SPV_SUCCESS if validation rules are satisfied for FPRoundingMode
  1243. // decorations. Otherwise emits a diagnostic and returns something other than
  1244. // SPV_SUCCESS.
  1245. spv_result_t CheckFPRoundingModeForShaders(ValidationState_t& vstate,
  1246. const Instruction& inst,
  1247. const Decoration& decoration) {
  1248. // Validates width-only conversion instruction for floating-point object
  1249. // i.e., OpFConvert
  1250. if (inst.opcode() != SpvOpFConvert) {
  1251. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1252. << "FPRoundingMode decoration can be applied only to a "
  1253. "width-only conversion instruction for floating-point "
  1254. "object.";
  1255. }
  1256. if (spvIsVulkanEnv(vstate.context()->target_env)) {
  1257. const auto mode = decoration.params()[0];
  1258. if ((mode != SpvFPRoundingModeRTE) && (mode != SpvFPRoundingModeRTZ)) {
  1259. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1260. << vstate.VkErrorID(4675)
  1261. << "In Vulkan, the FPRoundingMode mode must only by RTE or RTZ.";
  1262. }
  1263. }
  1264. // Validates Object operand of an OpStore
  1265. for (const auto& use : inst.uses()) {
  1266. const auto store = use.first;
  1267. if (store->opcode() == SpvOpFConvert) continue;
  1268. if (spvOpcodeIsDebug(store->opcode())) continue;
  1269. if (store->IsNonSemantic()) continue;
  1270. if (spvOpcodeIsDecoration(store->opcode())) continue;
  1271. if (store->opcode() != SpvOpStore) {
  1272. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1273. << "FPRoundingMode decoration can be applied only to the "
  1274. "Object operand of an OpStore.";
  1275. }
  1276. if (use.second != 2) {
  1277. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1278. << "FPRoundingMode decoration can be applied only to the "
  1279. "Object operand of an OpStore.";
  1280. }
  1281. const auto ptr_inst = vstate.FindDef(store->GetOperandAs<uint32_t>(0));
  1282. const auto ptr_type = vstate.FindDef(ptr_inst->GetOperandAs<uint32_t>(0));
  1283. const auto half_float_id = ptr_type->GetOperandAs<uint32_t>(2);
  1284. if (!vstate.IsFloatScalarOrVectorType(half_float_id) ||
  1285. vstate.GetBitWidth(half_float_id) != 16) {
  1286. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1287. << "FPRoundingMode decoration can be applied only to the "
  1288. "Object operand of an OpStore storing through a pointer "
  1289. "to "
  1290. "a 16-bit floating-point scalar or vector object.";
  1291. }
  1292. // Validates storage class of the pointer to the OpStore
  1293. const auto storage = ptr_type->GetOperandAs<uint32_t>(1);
  1294. if (storage != SpvStorageClassStorageBuffer &&
  1295. storage != SpvStorageClassUniform &&
  1296. storage != SpvStorageClassPushConstant &&
  1297. storage != SpvStorageClassInput && storage != SpvStorageClassOutput &&
  1298. storage != SpvStorageClassPhysicalStorageBufferEXT) {
  1299. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1300. << "FPRoundingMode decoration can be applied only to the "
  1301. "Object operand of an OpStore in the StorageBuffer, "
  1302. "PhysicalStorageBufferEXT, Uniform, PushConstant, Input, or "
  1303. "Output Storage Classes.";
  1304. }
  1305. }
  1306. return SPV_SUCCESS;
  1307. }
  1308. // Returns SPV_SUCCESS if validation rules are satisfied for the NonWritable
  1309. // decoration. Otherwise emits a diagnostic and returns something other than
  1310. // SPV_SUCCESS. The |inst| parameter is the object being decorated. This must
  1311. // be called after TypePass and AnnotateCheckDecorationsOfBuffers are called.
  1312. spv_result_t CheckNonWritableDecoration(ValidationState_t& vstate,
  1313. const Instruction& inst,
  1314. const Decoration& decoration) {
  1315. assert(inst.id() && "Parser ensures the target of the decoration has an ID");
  1316. if (decoration.struct_member_index() == Decoration::kInvalidMember) {
  1317. // The target must be a memory object declaration.
  1318. // First, it must be a variable or function parameter.
  1319. const auto opcode = inst.opcode();
  1320. const auto type_id = inst.type_id();
  1321. if (opcode != SpvOpVariable && opcode != SpvOpFunctionParameter) {
  1322. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1323. << "Target of NonWritable decoration must be a memory object "
  1324. "declaration (a variable or a function parameter)";
  1325. }
  1326. const auto var_storage_class = opcode == SpvOpVariable
  1327. ? inst.GetOperandAs<SpvStorageClass>(2)
  1328. : SpvStorageClassMax;
  1329. if ((var_storage_class == SpvStorageClassFunction ||
  1330. var_storage_class == SpvStorageClassPrivate) &&
  1331. vstate.features().nonwritable_var_in_function_or_private) {
  1332. // New permitted feature in SPIR-V 1.4.
  1333. } else if (
  1334. // It may point to a UBO, SSBO, or storage image.
  1335. vstate.IsPointerToUniformBlock(type_id) ||
  1336. vstate.IsPointerToStorageBuffer(type_id) ||
  1337. vstate.IsPointerToStorageImage(type_id)) {
  1338. } else {
  1339. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1340. << "Target of NonWritable decoration is invalid: must point to a "
  1341. "storage image, uniform block, "
  1342. << (vstate.features().nonwritable_var_in_function_or_private
  1343. ? "storage buffer, or variable in Private or Function "
  1344. "storage class"
  1345. : "or storage buffer");
  1346. }
  1347. }
  1348. return SPV_SUCCESS;
  1349. }
  1350. // Returns SPV_SUCCESS if validation rules are satisfied for Uniform or
  1351. // UniformId decorations. Otherwise emits a diagnostic and returns something
  1352. // other than SPV_SUCCESS. Assumes each decoration on a group has been
  1353. // propagated down to the group members. The |inst| parameter is the object
  1354. // being decorated.
  1355. spv_result_t CheckUniformDecoration(ValidationState_t& vstate,
  1356. const Instruction& inst,
  1357. const Decoration& decoration) {
  1358. const char* const dec_name =
  1359. decoration.dec_type() == SpvDecorationUniform ? "Uniform" : "UniformId";
  1360. // Uniform or UniformId must decorate an "object"
  1361. // - has a result ID
  1362. // - is an instantiation of a non-void type. So it has a type ID, and that
  1363. // type is not void.
  1364. // We already know the result ID is non-zero.
  1365. if (inst.type_id() == 0) {
  1366. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1367. << dec_name << " decoration applied to a non-object";
  1368. }
  1369. if (Instruction* type_inst = vstate.FindDef(inst.type_id())) {
  1370. if (type_inst->opcode() == SpvOpTypeVoid) {
  1371. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1372. << dec_name << " decoration applied to a value with void type";
  1373. }
  1374. } else {
  1375. // We might never get here because this would have been rejected earlier in
  1376. // the flow.
  1377. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1378. << dec_name << " decoration applied to an object with invalid type";
  1379. }
  1380. // Use of Uniform with OpDecorate is checked elsewhere.
  1381. // Use of UniformId with OpDecorateId is checked elsewhere.
  1382. if (decoration.dec_type() == SpvDecorationUniformId) {
  1383. assert(decoration.params().size() == 1 &&
  1384. "Grammar ensures UniformId has one parameter");
  1385. // The scope id is an execution scope.
  1386. if (auto error =
  1387. ValidateExecutionScope(vstate, &inst, decoration.params()[0]))
  1388. return error;
  1389. }
  1390. return SPV_SUCCESS;
  1391. }
  1392. // Returns SPV_SUCCESS if validation rules are satisfied for NoSignedWrap or
  1393. // NoUnsignedWrap decorations. Otherwise emits a diagnostic and returns
  1394. // something other than SPV_SUCCESS. Assumes each decoration on a group has been
  1395. // propagated down to the group members.
  1396. spv_result_t CheckIntegerWrapDecoration(ValidationState_t& vstate,
  1397. const Instruction& inst,
  1398. const Decoration& decoration) {
  1399. switch (inst.opcode()) {
  1400. case SpvOpIAdd:
  1401. case SpvOpISub:
  1402. case SpvOpIMul:
  1403. case SpvOpShiftLeftLogical:
  1404. case SpvOpSNegate:
  1405. return SPV_SUCCESS;
  1406. case SpvOpExtInst:
  1407. // TODO(dneto): Only certain extended instructions allow these
  1408. // decorations. For now allow anything.
  1409. return SPV_SUCCESS;
  1410. default:
  1411. break;
  1412. }
  1413. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1414. << (decoration.dec_type() == SpvDecorationNoSignedWrap
  1415. ? "NoSignedWrap"
  1416. : "NoUnsignedWrap")
  1417. << " decoration may not be applied to "
  1418. << spvOpcodeString(inst.opcode());
  1419. }
  1420. // Returns SPV_SUCCESS if validation rules are satisfied for the Component
  1421. // decoration. Otherwise emits a diagnostic and returns something other than
  1422. // SPV_SUCCESS.
  1423. spv_result_t CheckComponentDecoration(ValidationState_t& vstate,
  1424. const Instruction& inst,
  1425. const Decoration& decoration) {
  1426. assert(inst.id() && "Parser ensures the target of the decoration has an ID");
  1427. uint32_t type_id;
  1428. if (decoration.struct_member_index() == Decoration::kInvalidMember) {
  1429. // The target must be a memory object declaration.
  1430. const auto opcode = inst.opcode();
  1431. if (opcode != SpvOpVariable && opcode != SpvOpFunctionParameter) {
  1432. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1433. << "Target of Component decoration must be a memory object "
  1434. "declaration (a variable or a function parameter)";
  1435. }
  1436. // Only valid for the Input and Output Storage Classes.
  1437. const auto storage_class = opcode == SpvOpVariable
  1438. ? inst.GetOperandAs<SpvStorageClass>(2)
  1439. : SpvStorageClassMax;
  1440. if (storage_class != SpvStorageClassInput &&
  1441. storage_class != SpvStorageClassOutput &&
  1442. storage_class != SpvStorageClassMax) {
  1443. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1444. << "Target of Component decoration is invalid: must point to a "
  1445. "Storage Class of Input(1) or Output(3). Found Storage "
  1446. "Class "
  1447. << storage_class;
  1448. }
  1449. type_id = inst.type_id();
  1450. if (vstate.IsPointerType(type_id)) {
  1451. const auto pointer = vstate.FindDef(type_id);
  1452. type_id = pointer->GetOperandAs<uint32_t>(2);
  1453. }
  1454. } else {
  1455. if (inst.opcode() != SpvOpTypeStruct) {
  1456. return vstate.diag(SPV_ERROR_INVALID_DATA, &inst)
  1457. << "Attempted to get underlying data type via member index for "
  1458. "non-struct type.";
  1459. }
  1460. type_id = inst.word(decoration.struct_member_index() + 2);
  1461. }
  1462. if (spvIsVulkanEnv(vstate.context()->target_env)) {
  1463. // Strip the array, if present.
  1464. if (vstate.GetIdOpcode(type_id) == SpvOpTypeArray) {
  1465. type_id = vstate.FindDef(type_id)->word(2u);
  1466. }
  1467. if (!vstate.IsIntScalarOrVectorType(type_id) &&
  1468. !vstate.IsFloatScalarOrVectorType(type_id)) {
  1469. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1470. << "Component decoration specified for type "
  1471. << vstate.getIdName(type_id) << " that is not a scalar or vector";
  1472. }
  1473. // For 16-, and 32-bit types, it is invalid if this sequence of components
  1474. // gets larger than 3.
  1475. const auto bit_width = vstate.GetBitWidth(type_id);
  1476. if (bit_width == 16 || bit_width == 32) {
  1477. assert(decoration.params().size() == 1 &&
  1478. "Grammar ensures Component has one parameter");
  1479. const auto component = decoration.params()[0];
  1480. const auto last_component = component + vstate.GetDimension(type_id) - 1;
  1481. if (last_component > 3) {
  1482. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1483. << "Sequence of components starting with " << component
  1484. << " and ending with " << last_component
  1485. << " gets larger than 3";
  1486. }
  1487. }
  1488. }
  1489. return SPV_SUCCESS;
  1490. }
  1491. // Returns SPV_SUCCESS if validation rules are satisfied for the Block
  1492. // decoration. Otherwise emits a diagnostic and returns something other than
  1493. // SPV_SUCCESS.
  1494. spv_result_t CheckBlockDecoration(ValidationState_t& vstate,
  1495. const Instruction& inst,
  1496. const Decoration& decoration) {
  1497. assert(inst.id() && "Parser ensures the target of the decoration has an ID");
  1498. if (inst.opcode() != SpvOpTypeStruct) {
  1499. const char* const dec_name =
  1500. decoration.dec_type() == SpvDecorationBlock ? "Block" : "BufferBlock";
  1501. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1502. << dec_name << " decoration on a non-struct type.";
  1503. }
  1504. return SPV_SUCCESS;
  1505. }
  1506. spv_result_t CheckLocationDecoration(ValidationState_t& vstate,
  1507. const Instruction& inst,
  1508. const Decoration& decoration) {
  1509. if (inst.opcode() == SpvOpVariable) return SPV_SUCCESS;
  1510. if (decoration.struct_member_index() != Decoration::kInvalidMember &&
  1511. inst.opcode() == SpvOpTypeStruct) {
  1512. return SPV_SUCCESS;
  1513. }
  1514. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1515. << "Location decoration can only be applied to a variable or member "
  1516. "of a structure type";
  1517. }
  1518. #define PASS_OR_BAIL_AT_LINE(X, LINE) \
  1519. { \
  1520. spv_result_t e##LINE = (X); \
  1521. if (e##LINE != SPV_SUCCESS) return e##LINE; \
  1522. } static_assert(true, "require extra semicolon")
  1523. #define PASS_OR_BAIL(X) PASS_OR_BAIL_AT_LINE(X, __LINE__)
  1524. // Check rules for decorations where we start from the decoration rather
  1525. // than the decorated object. Assumes each decoration on a group have been
  1526. // propagated down to the group members.
  1527. spv_result_t CheckDecorationsFromDecoration(ValidationState_t& vstate) {
  1528. // Some rules are only checked for shaders.
  1529. const bool is_shader = vstate.HasCapability(SpvCapabilityShader);
  1530. for (const auto& kv : vstate.id_decorations()) {
  1531. const uint32_t id = kv.first;
  1532. const auto& decorations = kv.second;
  1533. if (decorations.empty()) continue;
  1534. const Instruction* inst = vstate.FindDef(id);
  1535. assert(inst);
  1536. // We assume the decorations applied to a decoration group have already
  1537. // been propagated down to the group members.
  1538. if (inst->opcode() == SpvOpDecorationGroup) continue;
  1539. for (const auto& decoration : decorations) {
  1540. switch (decoration.dec_type()) {
  1541. case SpvDecorationComponent:
  1542. PASS_OR_BAIL(CheckComponentDecoration(vstate, *inst, decoration));
  1543. break;
  1544. case SpvDecorationFPRoundingMode:
  1545. if (is_shader)
  1546. PASS_OR_BAIL(
  1547. CheckFPRoundingModeForShaders(vstate, *inst, decoration));
  1548. break;
  1549. case SpvDecorationNonWritable:
  1550. PASS_OR_BAIL(CheckNonWritableDecoration(vstate, *inst, decoration));
  1551. break;
  1552. case SpvDecorationUniform:
  1553. case SpvDecorationUniformId:
  1554. PASS_OR_BAIL(CheckUniformDecoration(vstate, *inst, decoration));
  1555. break;
  1556. case SpvDecorationNoSignedWrap:
  1557. case SpvDecorationNoUnsignedWrap:
  1558. PASS_OR_BAIL(CheckIntegerWrapDecoration(vstate, *inst, decoration));
  1559. break;
  1560. case SpvDecorationBlock:
  1561. case SpvDecorationBufferBlock:
  1562. PASS_OR_BAIL(CheckBlockDecoration(vstate, *inst, decoration));
  1563. break;
  1564. case SpvDecorationLocation:
  1565. PASS_OR_BAIL(CheckLocationDecoration(vstate, *inst, decoration));
  1566. break;
  1567. default:
  1568. break;
  1569. }
  1570. }
  1571. }
  1572. return SPV_SUCCESS;
  1573. }
  1574. } // namespace
  1575. spv_result_t ValidateDecorations(ValidationState_t& vstate) {
  1576. if (auto error = CheckImportedVariableInitialization(vstate)) return error;
  1577. if (auto error = CheckDecorationsOfEntryPoints(vstate)) return error;
  1578. if (auto error = CheckDecorationsOfBuffers(vstate)) return error;
  1579. if (auto error = CheckDecorationsCompatibility(vstate)) return error;
  1580. if (auto error = CheckLinkageAttrOfFunctions(vstate)) return error;
  1581. if (auto error = CheckVulkanMemoryModelDeprecatedDecorations(vstate))
  1582. return error;
  1583. if (auto error = CheckDecorationsFromDecoration(vstate)) return error;
  1584. return SPV_SUCCESS;
  1585. }
  1586. } // namespace val
  1587. } // namespace spvtools