validate_decorations.cpp 78 KB

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