validate_decorations.cpp 98 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309
  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/util/string_utils.h"
  28. #include "source/val/validate_scopes.h"
  29. #include "source/val/validation_state.h"
  30. namespace spvtools {
  31. namespace val {
  32. namespace {
  33. // Distinguish between row and column major matrix layouts.
  34. enum MatrixLayout { kRowMajor, kColumnMajor };
  35. // A functor for hashing a pair of integers.
  36. struct PairHash {
  37. std::size_t operator()(const std::pair<uint32_t, uint32_t> pair) const {
  38. const uint32_t a = pair.first;
  39. const uint32_t b = pair.second;
  40. const uint32_t rotated_b = (b >> 2) | ((b & 3) << 30);
  41. return a ^ rotated_b;
  42. }
  43. };
  44. // Struct member layout attributes that are inherited through arrays.
  45. struct LayoutConstraints {
  46. explicit LayoutConstraints(
  47. MatrixLayout the_majorness = MatrixLayout::kColumnMajor,
  48. uint32_t stride = 0)
  49. : majorness(the_majorness), matrix_stride(stride) {}
  50. MatrixLayout majorness;
  51. uint32_t matrix_stride;
  52. };
  53. // A type for mapping (struct id, member id) to layout constraints.
  54. using MemberConstraints = std::unordered_map<std::pair<uint32_t, uint32_t>,
  55. LayoutConstraints, PairHash>;
  56. // Returns the array stride of the given array type.
  57. uint32_t GetArrayStride(uint32_t array_id, ValidationState_t& vstate) {
  58. for (auto& decoration : vstate.id_decorations(array_id)) {
  59. if (spv::Decoration::ArrayStride == decoration.dec_type()) {
  60. return decoration.params()[0];
  61. }
  62. }
  63. return 0;
  64. }
  65. // Returns true if the given structure type has a Block decoration.
  66. bool isBlock(uint32_t struct_id, ValidationState_t& vstate) {
  67. const auto& decorations = vstate.id_decorations(struct_id);
  68. return std::any_of(decorations.begin(), decorations.end(),
  69. [](const Decoration& d) {
  70. return spv::Decoration::Block == d.dec_type();
  71. });
  72. }
  73. // Returns true if the given ID has the Import LinkageAttributes decoration.
  74. bool hasImportLinkageAttribute(uint32_t id, ValidationState_t& vstate) {
  75. const auto& decorations = vstate.id_decorations(id);
  76. return std::any_of(
  77. decorations.begin(), decorations.end(), [](const Decoration& d) {
  78. return spv::Decoration::LinkageAttributes == d.dec_type() &&
  79. d.params().size() >= 2u &&
  80. spv::LinkageType(d.params().back()) == spv::LinkageType::Import;
  81. });
  82. }
  83. // Returns a vector of all members of a structure.
  84. std::vector<uint32_t> getStructMembers(uint32_t struct_id,
  85. ValidationState_t& vstate) {
  86. const auto inst = vstate.FindDef(struct_id);
  87. return std::vector<uint32_t>(inst->words().begin() + 2, inst->words().end());
  88. }
  89. // Returns a vector of all members of a structure that have specific type.
  90. std::vector<uint32_t> getStructMembers(uint32_t struct_id, spv::Op type,
  91. ValidationState_t& vstate) {
  92. std::vector<uint32_t> members;
  93. for (auto id : getStructMembers(struct_id, vstate)) {
  94. if (type == vstate.FindDef(id)->opcode()) {
  95. members.push_back(id);
  96. }
  97. }
  98. return members;
  99. }
  100. // Returns whether the given structure is missing Offset decoration for any
  101. // member. Handles also nested structures.
  102. bool isMissingOffsetInStruct(uint32_t struct_id, ValidationState_t& vstate) {
  103. const auto* inst = vstate.FindDef(struct_id);
  104. std::vector<bool> hasOffset;
  105. std::vector<uint32_t> struct_members;
  106. if (inst->opcode() == spv::Op::OpTypeStruct) {
  107. // Check offsets of member decorations.
  108. struct_members = getStructMembers(struct_id, vstate);
  109. hasOffset.resize(struct_members.size(), false);
  110. for (auto& decoration : vstate.id_decorations(struct_id)) {
  111. if (spv::Decoration::Offset == decoration.dec_type() &&
  112. Decoration::kInvalidMember != decoration.struct_member_index()) {
  113. // Offset 0xffffffff is not valid so ignore it for simplicity's sake.
  114. if (decoration.params()[0] == 0xffffffff) return true;
  115. hasOffset[decoration.struct_member_index()] = true;
  116. }
  117. }
  118. } else if (inst->opcode() == spv::Op::OpTypeArray ||
  119. inst->opcode() == spv::Op::OpTypeRuntimeArray) {
  120. hasOffset.resize(1, true);
  121. struct_members.push_back(inst->GetOperandAs<uint32_t>(1u));
  122. }
  123. // Look through nested structs (which may be in an array).
  124. bool nestedStructsMissingOffset = false;
  125. for (auto id : struct_members) {
  126. if (isMissingOffsetInStruct(id, vstate)) {
  127. nestedStructsMissingOffset = true;
  128. break;
  129. }
  130. }
  131. return nestedStructsMissingOffset ||
  132. !std::all_of(hasOffset.begin(), hasOffset.end(),
  133. [](const bool b) { return b; });
  134. }
  135. // Rounds x up to the next alignment. Assumes alignment is a power of two.
  136. uint32_t align(uint32_t x, uint32_t alignment) {
  137. return (x + alignment - 1) & ~(alignment - 1);
  138. }
  139. // Returns base alignment of struct member. If |roundUp| is true, also
  140. // ensure that structs, arrays, and matrices are aligned at least to a
  141. // multiple of 16 bytes. (That is, when roundUp is true, this function
  142. // returns the *extended* alignment as it's called by the Vulkan spec.)
  143. uint32_t getBaseAlignment(uint32_t member_id, bool roundUp,
  144. const LayoutConstraints& inherited,
  145. MemberConstraints& constraints,
  146. ValidationState_t& vstate) {
  147. const auto inst = vstate.FindDef(member_id);
  148. const auto& words = inst->words();
  149. // Minimal alignment is byte-aligned.
  150. uint32_t baseAlignment = 1;
  151. switch (inst->opcode()) {
  152. case spv::Op::OpTypeSampledImage:
  153. case spv::Op::OpTypeSampler:
  154. case spv::Op::OpTypeImage:
  155. if (vstate.HasCapability(spv::Capability::BindlessTextureNV))
  156. return vstate.samplerimage_variable_address_mode() / 8;
  157. assert(0);
  158. return 0;
  159. case spv::Op::OpTypeInt:
  160. case spv::Op::OpTypeFloat:
  161. baseAlignment = words[2] / 8;
  162. break;
  163. case spv::Op::OpTypeVector: {
  164. const auto componentId = words[2];
  165. const auto numComponents = words[3];
  166. const auto componentAlignment = getBaseAlignment(
  167. componentId, roundUp, inherited, constraints, vstate);
  168. baseAlignment =
  169. componentAlignment * (numComponents == 3 ? 4 : numComponents);
  170. break;
  171. }
  172. case spv::Op::OpTypeMatrix: {
  173. const auto column_type = words[2];
  174. if (inherited.majorness == kColumnMajor) {
  175. baseAlignment = getBaseAlignment(column_type, roundUp, inherited,
  176. constraints, vstate);
  177. } else {
  178. // A row-major matrix of C columns has a base alignment equal to the
  179. // base alignment of a vector of C matrix components.
  180. const auto num_columns = words[3];
  181. const auto component_inst = vstate.FindDef(column_type);
  182. const auto component_id = component_inst->words()[2];
  183. const auto componentAlignment = getBaseAlignment(
  184. component_id, roundUp, inherited, constraints, vstate);
  185. baseAlignment =
  186. componentAlignment * (num_columns == 3 ? 4 : num_columns);
  187. }
  188. if (roundUp) baseAlignment = align(baseAlignment, 16u);
  189. } break;
  190. case spv::Op::OpTypeArray:
  191. case spv::Op::OpTypeRuntimeArray:
  192. baseAlignment =
  193. getBaseAlignment(words[2], roundUp, inherited, constraints, vstate);
  194. if (roundUp) baseAlignment = align(baseAlignment, 16u);
  195. break;
  196. case spv::Op::OpTypeStruct: {
  197. const auto members = getStructMembers(member_id, vstate);
  198. for (uint32_t memberIdx = 0, numMembers = uint32_t(members.size());
  199. memberIdx < numMembers; ++memberIdx) {
  200. const auto id = members[memberIdx];
  201. const auto& constraint =
  202. constraints[std::make_pair(member_id, memberIdx)];
  203. baseAlignment = std::max(
  204. baseAlignment,
  205. getBaseAlignment(id, roundUp, constraint, constraints, vstate));
  206. }
  207. if (roundUp) baseAlignment = align(baseAlignment, 16u);
  208. break;
  209. }
  210. case spv::Op::OpTypePointer:
  211. case spv::Op::OpTypeUntypedPointerKHR:
  212. baseAlignment = vstate.pointer_size_and_alignment();
  213. break;
  214. default:
  215. assert(0);
  216. break;
  217. }
  218. return baseAlignment;
  219. }
  220. // Returns scalar alignment of a type.
  221. uint32_t getScalarAlignment(uint32_t type_id, ValidationState_t& vstate) {
  222. const auto inst = vstate.FindDef(type_id);
  223. const auto& words = inst->words();
  224. switch (inst->opcode()) {
  225. case spv::Op::OpTypeSampledImage:
  226. case spv::Op::OpTypeSampler:
  227. case spv::Op::OpTypeImage:
  228. if (vstate.HasCapability(spv::Capability::BindlessTextureNV))
  229. return vstate.samplerimage_variable_address_mode() / 8;
  230. assert(0);
  231. return 0;
  232. case spv::Op::OpTypeInt:
  233. case spv::Op::OpTypeFloat:
  234. return words[2] / 8;
  235. case spv::Op::OpTypeVector:
  236. case spv::Op::OpTypeMatrix:
  237. case spv::Op::OpTypeArray:
  238. case spv::Op::OpTypeRuntimeArray: {
  239. const auto compositeMemberTypeId = words[2];
  240. return getScalarAlignment(compositeMemberTypeId, vstate);
  241. }
  242. case spv::Op::OpTypeStruct: {
  243. const auto members = getStructMembers(type_id, vstate);
  244. uint32_t max_member_alignment = 1;
  245. for (uint32_t memberIdx = 0, numMembers = uint32_t(members.size());
  246. memberIdx < numMembers; ++memberIdx) {
  247. const auto id = members[memberIdx];
  248. uint32_t member_alignment = getScalarAlignment(id, vstate);
  249. if (member_alignment > max_member_alignment) {
  250. max_member_alignment = member_alignment;
  251. }
  252. }
  253. return max_member_alignment;
  254. } break;
  255. case spv::Op::OpTypePointer:
  256. case spv::Op::OpTypeUntypedPointerKHR:
  257. return vstate.pointer_size_and_alignment();
  258. default:
  259. assert(0);
  260. break;
  261. }
  262. return 1;
  263. }
  264. // Returns size of a struct member. Doesn't include padding at the end of struct
  265. // or array. Assumes that in the struct case, all members have offsets.
  266. uint32_t getSize(uint32_t member_id, const LayoutConstraints& inherited,
  267. MemberConstraints& constraints, ValidationState_t& vstate) {
  268. const auto inst = vstate.FindDef(member_id);
  269. const auto& words = inst->words();
  270. switch (inst->opcode()) {
  271. case spv::Op::OpTypeSampledImage:
  272. case spv::Op::OpTypeSampler:
  273. case spv::Op::OpTypeImage:
  274. if (vstate.HasCapability(spv::Capability::BindlessTextureNV))
  275. return vstate.samplerimage_variable_address_mode() / 8;
  276. assert(0);
  277. return 0;
  278. case spv::Op::OpTypeInt:
  279. case spv::Op::OpTypeFloat:
  280. return words[2] / 8;
  281. case spv::Op::OpTypeVector: {
  282. const auto componentId = words[2];
  283. const auto numComponents = words[3];
  284. const auto componentSize =
  285. getSize(componentId, inherited, constraints, vstate);
  286. const auto size = componentSize * numComponents;
  287. return size;
  288. }
  289. case spv::Op::OpTypeArray: {
  290. const auto sizeInst = vstate.FindDef(words[3]);
  291. if (spvOpcodeIsSpecConstant(sizeInst->opcode())) return 0;
  292. assert(spv::Op::OpConstant == sizeInst->opcode());
  293. const uint32_t num_elem = sizeInst->words()[3];
  294. const uint32_t elem_type = words[2];
  295. const uint32_t elem_size =
  296. getSize(elem_type, inherited, constraints, vstate);
  297. // Account for gaps due to alignments in the first N-1 elements,
  298. // then add the size of the last element.
  299. const auto size =
  300. (num_elem - 1) * GetArrayStride(member_id, vstate) + elem_size;
  301. return size;
  302. }
  303. case spv::Op::OpTypeRuntimeArray:
  304. return 0;
  305. case spv::Op::OpTypeMatrix: {
  306. const auto num_columns = words[3];
  307. if (inherited.majorness == kColumnMajor) {
  308. return num_columns * inherited.matrix_stride;
  309. } else {
  310. // Row major case.
  311. const auto column_type = words[2];
  312. const auto component_inst = vstate.FindDef(column_type);
  313. const auto num_rows = component_inst->words()[3];
  314. const auto scalar_elem_type = component_inst->words()[2];
  315. const uint32_t scalar_elem_size =
  316. getSize(scalar_elem_type, inherited, constraints, vstate);
  317. return (num_rows - 1) * inherited.matrix_stride +
  318. num_columns * scalar_elem_size;
  319. }
  320. }
  321. case spv::Op::OpTypeStruct: {
  322. const auto& members = getStructMembers(member_id, vstate);
  323. if (members.empty()) return 0;
  324. const auto lastIdx = uint32_t(members.size() - 1);
  325. const auto& lastMember = members.back();
  326. uint32_t offset = 0xffffffff;
  327. // Find the offset of the last element and add the size.
  328. auto member_decorations =
  329. vstate.id_member_decorations(member_id, lastIdx);
  330. for (auto decoration = member_decorations.begin;
  331. decoration != member_decorations.end; ++decoration) {
  332. assert(decoration->struct_member_index() == (int)lastIdx);
  333. if (spv::Decoration::Offset == decoration->dec_type()) {
  334. offset = decoration->params()[0];
  335. }
  336. }
  337. // This check depends on the fact that all members have offsets. This
  338. // has been checked earlier in the flow.
  339. assert(offset != 0xffffffff);
  340. const auto& constraint = constraints[std::make_pair(lastMember, lastIdx)];
  341. return offset + getSize(lastMember, constraint, constraints, vstate);
  342. }
  343. case spv::Op::OpTypePointer:
  344. case spv::Op::OpTypeUntypedPointerKHR:
  345. return vstate.pointer_size_and_alignment();
  346. default:
  347. assert(0);
  348. return 0;
  349. }
  350. }
  351. // A member is defined to improperly straddle if either of the following are
  352. // true:
  353. // - It is a vector with total size less than or equal to 16 bytes, and has
  354. // Offset decorations placing its first byte at F and its last byte at L, where
  355. // floor(F / 16) != floor(L / 16).
  356. // - It is a vector with total size greater than 16 bytes and has its Offset
  357. // decorations placing its first byte at a non-integer multiple of 16.
  358. bool hasImproperStraddle(uint32_t id, uint32_t offset,
  359. const LayoutConstraints& inherited,
  360. MemberConstraints& constraints,
  361. ValidationState_t& vstate) {
  362. const auto size = getSize(id, inherited, constraints, vstate);
  363. const auto F = offset;
  364. const auto L = offset + size - 1;
  365. if (size <= 16) {
  366. if ((F >> 4) != (L >> 4)) return true;
  367. } else {
  368. if (F % 16 != 0) return true;
  369. }
  370. return false;
  371. }
  372. // Returns true if |offset| satsifies an alignment to |alignment|. In the case
  373. // of |alignment| of zero, the |offset| must also be zero.
  374. bool IsAlignedTo(uint32_t offset, uint32_t alignment) {
  375. if (alignment == 0) return offset == 0;
  376. return 0 == (offset % alignment);
  377. }
  378. // Returns SPV_SUCCESS if the given struct satisfies standard layout rules for
  379. // Block or BufferBlocks in Vulkan. Otherwise emits a diagnostic and returns
  380. // something other than SPV_SUCCESS. Matrices inherit the specified column
  381. // or row major-ness.
  382. spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str,
  383. const char* decoration_str, bool blockRules,
  384. bool scalar_block_layout,
  385. uint32_t incoming_offset,
  386. MemberConstraints& constraints,
  387. ValidationState_t& vstate) {
  388. if (vstate.options()->skip_block_layout) return SPV_SUCCESS;
  389. // blockRules are the same as bufferBlock rules if the uniform buffer
  390. // standard layout extension is being used.
  391. if (vstate.options()->uniform_buffer_standard_layout) blockRules = false;
  392. // Relaxed layout and scalar layout can both be in effect at the same time.
  393. // For example, relaxed layout is implied by Vulkan 1.1. But scalar layout
  394. // is more permissive than relaxed layout.
  395. const bool relaxed_block_layout = vstate.IsRelaxedBlockLayout();
  396. auto fail = [&vstate, struct_id, storage_class_str, decoration_str,
  397. blockRules, relaxed_block_layout,
  398. scalar_block_layout](uint32_t member_idx) -> DiagnosticStream {
  399. DiagnosticStream ds =
  400. std::move(vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(struct_id))
  401. << "Structure id " << struct_id << " decorated as "
  402. << decoration_str << " for variable in " << storage_class_str
  403. << " storage class must follow "
  404. << (scalar_block_layout
  405. ? "scalar "
  406. : (relaxed_block_layout ? "relaxed " : "standard "))
  407. << (blockRules ? "uniform buffer" : "storage buffer")
  408. << " layout rules: member " << member_idx << " ");
  409. return ds;
  410. };
  411. // If we are checking the layout of untyped pointers or physical storage
  412. // buffer pointers, we may not actually have a struct here. Instead, pretend
  413. // we have a struct with a single member at offset 0.
  414. const auto& struct_type = vstate.FindDef(struct_id);
  415. std::vector<uint32_t> members;
  416. if (struct_type->opcode() == spv::Op::OpTypeStruct) {
  417. members = getStructMembers(struct_id, vstate);
  418. } else {
  419. members.push_back(struct_id);
  420. }
  421. // To check for member overlaps, we want to traverse the members in
  422. // offset order.
  423. struct MemberOffsetPair {
  424. uint32_t member;
  425. uint32_t offset;
  426. };
  427. std::vector<MemberOffsetPair> member_offsets;
  428. // With untyped pointers or physical storage buffers, we might be checking
  429. // layouts that do not originate from a structure.
  430. if (struct_type->opcode() == spv::Op::OpTypeStruct) {
  431. member_offsets.reserve(members.size());
  432. for (uint32_t memberIdx = 0, numMembers = uint32_t(members.size());
  433. memberIdx < numMembers; memberIdx++) {
  434. uint32_t offset = 0xffffffff;
  435. auto member_decorations =
  436. vstate.id_member_decorations(struct_id, memberIdx);
  437. for (auto decoration = member_decorations.begin;
  438. decoration != member_decorations.end; ++decoration) {
  439. assert(decoration->struct_member_index() == (int)memberIdx);
  440. switch (decoration->dec_type()) {
  441. case spv::Decoration::Offset:
  442. offset = decoration->params()[0];
  443. break;
  444. default:
  445. break;
  446. }
  447. }
  448. member_offsets.push_back(
  449. MemberOffsetPair{memberIdx, incoming_offset + offset});
  450. }
  451. std::stable_sort(
  452. member_offsets.begin(), member_offsets.end(),
  453. [](const MemberOffsetPair& lhs, const MemberOffsetPair& rhs) {
  454. return lhs.offset < rhs.offset;
  455. });
  456. } else {
  457. member_offsets.push_back({0, 0});
  458. }
  459. // Now scan from lowest offset to highest offset.
  460. uint32_t nextValidOffset = 0;
  461. for (size_t ordered_member_idx = 0;
  462. ordered_member_idx < member_offsets.size(); ordered_member_idx++) {
  463. const auto& member_offset = member_offsets[ordered_member_idx];
  464. const auto memberIdx = member_offset.member;
  465. const auto offset = member_offset.offset;
  466. auto id = members[member_offset.member];
  467. const LayoutConstraints& constraint =
  468. constraints[std::make_pair(struct_id, uint32_t(memberIdx))];
  469. // Scalar layout takes precedence because it's more permissive, and implying
  470. // an alignment that divides evenly into the alignment that would otherwise
  471. // be used.
  472. const auto alignment =
  473. scalar_block_layout
  474. ? getScalarAlignment(id, vstate)
  475. : getBaseAlignment(id, blockRules, constraint, constraints, vstate);
  476. const auto inst = vstate.FindDef(id);
  477. const auto opcode = inst->opcode();
  478. const auto size = getSize(id, constraint, constraints, vstate);
  479. // Check offset.
  480. if (offset == 0xffffffff)
  481. return fail(memberIdx) << "is missing an Offset decoration";
  482. if (opcode == spv::Op::OpTypeRuntimeArray &&
  483. ordered_member_idx != member_offsets.size() - 1) {
  484. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(struct_id))
  485. << vstate.VkErrorID(4680) << "Structure id " << struct_id
  486. << " has a runtime array at offset " << offset
  487. << ", but other members at larger offsets";
  488. }
  489. if (!scalar_block_layout && relaxed_block_layout &&
  490. opcode == spv::Op::OpTypeVector) {
  491. // In relaxed block layout, the vector offset must be aligned to the
  492. // vector's scalar element type.
  493. const auto componentId = inst->words()[2];
  494. const auto scalar_alignment = getScalarAlignment(componentId, vstate);
  495. if (!IsAlignedTo(offset, scalar_alignment)) {
  496. return fail(memberIdx)
  497. << "at offset " << offset
  498. << " is not aligned to scalar element size " << scalar_alignment;
  499. }
  500. } else {
  501. // Without relaxed block layout, the offset must be divisible by the
  502. // alignment requirement.
  503. if (!IsAlignedTo(offset, alignment)) {
  504. return fail(memberIdx)
  505. << "at offset " << offset << " is not aligned to " << alignment;
  506. }
  507. }
  508. if (offset < nextValidOffset)
  509. return fail(memberIdx) << "at offset " << offset
  510. << " overlaps previous member ending at offset "
  511. << nextValidOffset - 1;
  512. if (!scalar_block_layout && relaxed_block_layout) {
  513. // Check improper straddle of vectors.
  514. if (spv::Op::OpTypeVector == opcode &&
  515. hasImproperStraddle(id, offset, constraint, constraints, vstate))
  516. return fail(memberIdx)
  517. << "is an improperly straddling vector at offset " << offset;
  518. }
  519. // Check struct members recursively.
  520. spv_result_t recursive_status = SPV_SUCCESS;
  521. if (spv::Op::OpTypeStruct == opcode &&
  522. SPV_SUCCESS != (recursive_status = checkLayout(
  523. id, storage_class_str, decoration_str, blockRules,
  524. scalar_block_layout, offset, constraints, vstate)))
  525. return recursive_status;
  526. // Check matrix stride.
  527. if (spv::Op::OpTypeMatrix == opcode) {
  528. const auto stride = constraint.matrix_stride;
  529. if (!IsAlignedTo(stride, alignment)) {
  530. return fail(memberIdx) << "is a matrix with stride " << stride
  531. << " not satisfying alignment to " << alignment;
  532. }
  533. }
  534. // Check arrays and runtime arrays recursively.
  535. auto array_inst = inst;
  536. auto array_alignment = alignment;
  537. while (array_inst->opcode() == spv::Op::OpTypeArray ||
  538. array_inst->opcode() == spv::Op::OpTypeRuntimeArray) {
  539. const auto typeId = array_inst->word(2);
  540. const auto element_inst = vstate.FindDef(typeId);
  541. // Check array stride.
  542. uint32_t array_stride = 0;
  543. for (auto& decoration : vstate.id_decorations(array_inst->id())) {
  544. if (spv::Decoration::ArrayStride == decoration.dec_type()) {
  545. array_stride = decoration.params()[0];
  546. if (array_stride == 0) {
  547. return fail(memberIdx) << "contains an array with stride 0";
  548. }
  549. if (!IsAlignedTo(array_stride, array_alignment))
  550. return fail(memberIdx)
  551. << "contains an array with stride " << decoration.params()[0]
  552. << " not satisfying alignment to " << alignment;
  553. }
  554. }
  555. bool is_int32 = false;
  556. bool is_const = false;
  557. uint32_t num_elements = 0;
  558. if (array_inst->opcode() == spv::Op::OpTypeArray) {
  559. std::tie(is_int32, is_const, num_elements) =
  560. vstate.EvalInt32IfConst(array_inst->word(3));
  561. }
  562. num_elements = std::max(1u, num_elements);
  563. // Check each element recursively if it is a struct. There is a
  564. // limitation to this check if the array size is a spec constant or is a
  565. // runtime array then we will only check a single element. This means
  566. // some improper straddles might be missed.
  567. if (spv::Op::OpTypeStruct == element_inst->opcode()) {
  568. std::vector<bool> seen(16, false);
  569. for (uint32_t i = 0; i < num_elements; ++i) {
  570. uint32_t next_offset = i * array_stride + offset;
  571. // Stop checking if offsets repeat in terms of 16-byte multiples.
  572. if (seen[next_offset % 16]) {
  573. break;
  574. }
  575. if (SPV_SUCCESS !=
  576. (recursive_status = checkLayout(
  577. typeId, storage_class_str, decoration_str, blockRules,
  578. scalar_block_layout, next_offset, constraints, vstate)))
  579. return recursive_status;
  580. seen[next_offset % 16] = true;
  581. }
  582. } else if (spv::Op::OpTypeMatrix == element_inst->opcode()) {
  583. // Matrix stride would be on the array element in the struct.
  584. const auto stride = constraint.matrix_stride;
  585. if (!IsAlignedTo(stride, alignment)) {
  586. return fail(memberIdx)
  587. << "is a matrix with stride " << stride
  588. << " not satisfying alignment to " << alignment;
  589. }
  590. }
  591. // Proceed to the element in case it is an array.
  592. array_inst = element_inst;
  593. array_alignment = scalar_block_layout
  594. ? getScalarAlignment(array_inst->id(), vstate)
  595. : getBaseAlignment(array_inst->id(), blockRules,
  596. constraint, constraints, vstate);
  597. const auto element_size =
  598. getSize(element_inst->id(), constraint, constraints, vstate);
  599. if (element_size > array_stride) {
  600. return fail(memberIdx)
  601. << "contains an array with stride " << array_stride
  602. << ", but with an element size of " << element_size;
  603. }
  604. }
  605. nextValidOffset = offset + size;
  606. if (!scalar_block_layout &&
  607. (spv::Op::OpTypeArray == opcode || spv::Op::OpTypeStruct == opcode)) {
  608. // Non-scalar block layout rules don't permit anything in the padding of
  609. // a struct or array.
  610. nextValidOffset = align(nextValidOffset, alignment);
  611. }
  612. }
  613. return SPV_SUCCESS;
  614. }
  615. // Returns true if variable or structure id has given decoration. Handles also
  616. // nested structures.
  617. bool hasDecoration(uint32_t id, spv::Decoration decoration,
  618. ValidationState_t& vstate) {
  619. for (auto& dec : vstate.id_decorations(id)) {
  620. if (decoration == dec.dec_type()) return true;
  621. }
  622. if (spv::Op::OpTypeStruct != vstate.FindDef(id)->opcode()) {
  623. return false;
  624. }
  625. for (auto member_id : getStructMembers(id, spv::Op::OpTypeStruct, vstate)) {
  626. if (hasDecoration(member_id, decoration, vstate)) {
  627. return true;
  628. }
  629. }
  630. return false;
  631. }
  632. // Returns true if all ids of given type have a specified decoration.
  633. bool checkForRequiredDecoration(uint32_t struct_id,
  634. std::function<bool(spv::Decoration)> checker,
  635. spv::Op type, ValidationState_t& vstate) {
  636. const auto& members = getStructMembers(struct_id, vstate);
  637. for (size_t memberIdx = 0; memberIdx < members.size(); memberIdx++) {
  638. auto id = members[memberIdx];
  639. if (type == spv::Op::OpTypeMatrix) {
  640. // Matrix decorations also apply to arrays of matrices.
  641. auto memberInst = vstate.FindDef(id);
  642. while (memberInst->opcode() == spv::Op::OpTypeArray ||
  643. memberInst->opcode() == spv::Op::OpTypeRuntimeArray) {
  644. memberInst = vstate.FindDef(memberInst->GetOperandAs<uint32_t>(1u));
  645. }
  646. id = memberInst->id();
  647. }
  648. if (type != vstate.FindDef(id)->opcode()) continue;
  649. bool found = false;
  650. for (auto& dec : vstate.id_decorations(id)) {
  651. if (checker(dec.dec_type())) found = true;
  652. }
  653. for (auto& dec : vstate.id_decorations(struct_id)) {
  654. if (checker(dec.dec_type()) &&
  655. (int)memberIdx == dec.struct_member_index()) {
  656. found = true;
  657. }
  658. }
  659. if (!found) {
  660. return false;
  661. }
  662. }
  663. for (auto id : getStructMembers(struct_id, spv::Op::OpTypeStruct, vstate)) {
  664. if (!checkForRequiredDecoration(id, checker, type, vstate)) {
  665. return false;
  666. }
  667. }
  668. return true;
  669. }
  670. spv_result_t CheckLinkageAttrOfFunctions(ValidationState_t& vstate) {
  671. for (const auto& function : vstate.functions()) {
  672. if (function.block_count() == 0u) {
  673. // A function declaration (an OpFunction with no basic blocks), must have
  674. // a Linkage Attributes Decoration with the Import Linkage Type.
  675. if (!hasImportLinkageAttribute(function.id(), vstate)) {
  676. return vstate.diag(SPV_ERROR_INVALID_BINARY,
  677. vstate.FindDef(function.id()))
  678. << "Function declaration (id " << function.id()
  679. << ") must have a LinkageAttributes decoration with the Import "
  680. "Linkage type.";
  681. }
  682. } else {
  683. if (hasImportLinkageAttribute(function.id(), vstate)) {
  684. return vstate.diag(SPV_ERROR_INVALID_BINARY,
  685. vstate.FindDef(function.id()))
  686. << "Function definition (id " << function.id()
  687. << ") may not be decorated with Import Linkage type.";
  688. }
  689. }
  690. }
  691. return SPV_SUCCESS;
  692. }
  693. // Checks whether an imported variable is initialized by this module.
  694. spv_result_t CheckImportedVariableInitialization(ValidationState_t& vstate) {
  695. // According the SPIR-V Spec 2.16.1, it is illegal to initialize an imported
  696. // variable. This means that a module-scope OpVariable with initialization
  697. // value cannot be marked with the Import Linkage Type (import type id = 1).
  698. for (auto global_var_id : vstate.global_vars()) {
  699. // Initializer <id> is an optional argument for OpVariable. If initializer
  700. // <id> is present, the instruction will have 5 words.
  701. auto variable_instr = vstate.FindDef(global_var_id);
  702. if (variable_instr->words().size() == 5u &&
  703. hasImportLinkageAttribute(global_var_id, vstate)) {
  704. return vstate.diag(SPV_ERROR_INVALID_ID, variable_instr)
  705. << "A module-scope OpVariable with initialization value "
  706. "cannot be marked with the Import Linkage Type.";
  707. }
  708. }
  709. return SPV_SUCCESS;
  710. }
  711. // Checks whether a builtin variable is valid.
  712. spv_result_t CheckBuiltInVariable(uint32_t var_id, ValidationState_t& vstate) {
  713. const auto& decorations = vstate.id_decorations(var_id);
  714. for (const auto& d : decorations) {
  715. if (spvIsVulkanEnv(vstate.context()->target_env)) {
  716. if (d.dec_type() == spv::Decoration::Location ||
  717. d.dec_type() == spv::Decoration::Component) {
  718. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
  719. << vstate.VkErrorID(4915) << "A BuiltIn variable (id " << var_id
  720. << ") cannot have any Location or Component decorations";
  721. }
  722. }
  723. }
  724. return SPV_SUCCESS;
  725. }
  726. // Checks whether proper decorations have been applied to the entry points.
  727. spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) {
  728. for (uint32_t entry_point : vstate.entry_points()) {
  729. const auto& descs = vstate.entry_point_descriptions(entry_point);
  730. int num_builtin_block_inputs = 0;
  731. int num_builtin_block_outputs = 0;
  732. int num_workgroup_variables = 0;
  733. int num_workgroup_variables_with_block = 0;
  734. int num_workgroup_variables_with_aliased = 0;
  735. bool has_task_payload = false;
  736. for (const auto& desc : descs) {
  737. std::unordered_set<Instruction*> seen_vars;
  738. std::unordered_set<spv::BuiltIn> input_var_builtin;
  739. std::unordered_set<spv::BuiltIn> output_var_builtin;
  740. for (auto interface : desc.interfaces) {
  741. Instruction* var_instr = vstate.FindDef(interface);
  742. if (!var_instr ||
  743. (spv::Op::OpVariable != var_instr->opcode() &&
  744. spv::Op::OpUntypedVariableKHR != var_instr->opcode())) {
  745. return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
  746. << "Interfaces passed to OpEntryPoint must be variables. "
  747. "Found Op"
  748. << spvOpcodeString(var_instr->opcode()) << ".";
  749. }
  750. const bool untyped_pointers =
  751. var_instr->opcode() == spv::Op::OpUntypedVariableKHR;
  752. const auto sc_index = 2u;
  753. const spv::StorageClass storage_class =
  754. var_instr->GetOperandAs<spv::StorageClass>(sc_index);
  755. if (vstate.version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
  756. // SPV_EXT_mesh_shader, at most one task payload is permitted
  757. // per entry point
  758. if (storage_class == spv::StorageClass::TaskPayloadWorkgroupEXT) {
  759. if (has_task_payload) {
  760. return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
  761. << "There can be at most one OpVariable with storage "
  762. "class TaskPayloadWorkgroupEXT associated with "
  763. "an OpEntryPoint";
  764. }
  765. has_task_payload = true;
  766. }
  767. }
  768. if (vstate.version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
  769. // Starting in 1.4, OpEntryPoint must list all global variables
  770. // it statically uses and those interfaces must be unique.
  771. if (storage_class == spv::StorageClass::Function) {
  772. return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
  773. << "OpEntryPoint interfaces should only list global "
  774. "variables";
  775. }
  776. if (!seen_vars.insert(var_instr).second) {
  777. return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
  778. << "Non-unique OpEntryPoint interface "
  779. << vstate.getIdName(interface) << " is disallowed";
  780. }
  781. } else {
  782. if (storage_class != spv::StorageClass::Input &&
  783. storage_class != spv::StorageClass::Output) {
  784. return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
  785. << "OpEntryPoint interfaces must be OpVariables with "
  786. "Storage Class of Input(1) or Output(3). Found Storage "
  787. "Class "
  788. << uint32_t(storage_class) << " for Entry Point id "
  789. << entry_point << ".";
  790. }
  791. }
  792. // It is guaranteed (by validator ID checks) that ptr_instr is
  793. // OpTypePointer. Word 3 of this instruction is the type being pointed
  794. // to. For untyped variables, the pointee type comes from the data type
  795. // operand.
  796. const uint32_t type_id =
  797. untyped_pointers ? var_instr->word(4)
  798. : vstate.FindDef(var_instr->word(1))->word(3);
  799. Instruction* type_instr = vstate.FindDef(type_id);
  800. const bool is_struct =
  801. type_instr && spv::Op::OpTypeStruct == type_instr->opcode();
  802. // Search all Built-in (on the variable or the struct)
  803. bool has_built_in = false;
  804. for (auto& dec :
  805. vstate.id_decorations(is_struct ? type_id : interface)) {
  806. if (dec.dec_type() != spv::Decoration::BuiltIn) continue;
  807. has_built_in = true;
  808. if (!spvIsVulkanEnv(vstate.context()->target_env)) continue;
  809. const spv::BuiltIn builtin = dec.builtin();
  810. if (storage_class == spv::StorageClass::Input) {
  811. if (!input_var_builtin.insert(builtin).second) {
  812. return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
  813. << vstate.VkErrorID(9658)
  814. << "OpEntryPoint contains duplicate input variables "
  815. "with "
  816. << vstate.grammar().lookupOperandName(
  817. SPV_OPERAND_TYPE_BUILT_IN, (uint32_t)builtin)
  818. << " builtin";
  819. }
  820. }
  821. if (storage_class == spv::StorageClass::Output) {
  822. if (!output_var_builtin.insert(builtin).second) {
  823. return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
  824. << vstate.VkErrorID(9659)
  825. << "OpEntryPoint contains duplicate output variables "
  826. "with "
  827. << vstate.grammar().lookupOperandName(
  828. SPV_OPERAND_TYPE_BUILT_IN, (uint32_t)builtin)
  829. << " builtin";
  830. }
  831. }
  832. }
  833. if (has_built_in) {
  834. if (auto error = CheckBuiltInVariable(interface, vstate))
  835. return error;
  836. if (is_struct) {
  837. if (!isBlock(type_id, vstate)) {
  838. return vstate.diag(SPV_ERROR_INVALID_DATA,
  839. vstate.FindDef(type_id))
  840. << vstate.VkErrorID(4919)
  841. << "Interface struct has no Block decoration but has "
  842. "BuiltIn members. "
  843. "Location decorations must be used on each member of "
  844. "OpVariable with a structure type that is a block not "
  845. "decorated with Location.";
  846. }
  847. if (storage_class == spv::StorageClass::Input)
  848. ++num_builtin_block_inputs;
  849. if (storage_class == spv::StorageClass::Output)
  850. ++num_builtin_block_outputs;
  851. if (num_builtin_block_inputs > 1 || num_builtin_block_outputs > 1)
  852. break;
  853. }
  854. }
  855. if (storage_class == spv::StorageClass::Workgroup) {
  856. ++num_workgroup_variables;
  857. if (type_instr) {
  858. if (spv::Op::OpTypeStruct == type_instr->opcode()) {
  859. if (hasDecoration(type_id, spv::Decoration::Block, vstate)) {
  860. ++num_workgroup_variables_with_block;
  861. } else if (untyped_pointers &&
  862. vstate.HasCapability(spv::Capability::Shader)) {
  863. return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
  864. << "Untyped workgroup variables in shaders must be "
  865. "block decorated";
  866. }
  867. if (hasDecoration(var_instr->id(), spv::Decoration::Aliased,
  868. vstate))
  869. ++num_workgroup_variables_with_aliased;
  870. } else if (untyped_pointers &&
  871. vstate.HasCapability(spv::Capability::Shader)) {
  872. return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
  873. << "Untyped workgroup variables in shaders must be block "
  874. "decorated structs";
  875. }
  876. }
  877. }
  878. if (spvIsVulkanEnv(vstate.context()->target_env)) {
  879. const auto* models = vstate.GetExecutionModels(entry_point);
  880. const bool has_frag =
  881. models->find(spv::ExecutionModel::Fragment) != models->end();
  882. const bool has_vert =
  883. models->find(spv::ExecutionModel::Vertex) != models->end();
  884. for (const auto& decoration :
  885. vstate.id_decorations(var_instr->id())) {
  886. if (decoration == spv::Decoration::Flat ||
  887. decoration == spv::Decoration::NoPerspective ||
  888. decoration == spv::Decoration::Sample ||
  889. decoration == spv::Decoration::Centroid) {
  890. // VUID 04670 already validates these decorations are input/output
  891. if (storage_class == spv::StorageClass::Input &&
  892. (models->size() > 1 || has_vert)) {
  893. return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
  894. << vstate.VkErrorID(6202)
  895. << vstate.SpvDecorationString(decoration.dec_type())
  896. << " decorated variable must not be used in vertex "
  897. "execution model as an Input storage class for Entry "
  898. "Point id "
  899. << entry_point << ".";
  900. } else if (storage_class == spv::StorageClass::Output &&
  901. (models->size() > 1 || has_frag)) {
  902. return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
  903. << vstate.VkErrorID(6201)
  904. << vstate.SpvDecorationString(decoration.dec_type())
  905. << " decorated variable must not be used in fragment "
  906. "execution model as an Output storage class for "
  907. "Entry Point id "
  908. << entry_point << ".";
  909. }
  910. }
  911. }
  912. const bool has_flat =
  913. hasDecoration(var_instr->id(), spv::Decoration::Flat, vstate);
  914. if (has_frag && storage_class == spv::StorageClass::Input &&
  915. !has_flat &&
  916. ((vstate.IsFloatScalarType(type_id) &&
  917. vstate.GetBitWidth(type_id) == 64) ||
  918. vstate.IsIntScalarOrVectorType(type_id))) {
  919. return vstate.diag(SPV_ERROR_INVALID_ID, var_instr)
  920. << vstate.VkErrorID(4744)
  921. << "Fragment OpEntryPoint operand "
  922. << interface << " with Input interfaces with integer or "
  923. "float type must have a Flat decoration "
  924. "for Entry Point id "
  925. << entry_point << ".";
  926. }
  927. }
  928. }
  929. if (num_builtin_block_inputs > 1 || num_builtin_block_outputs > 1) {
  930. return vstate.diag(SPV_ERROR_INVALID_BINARY,
  931. vstate.FindDef(entry_point))
  932. << "There must be at most one object per Storage Class that can "
  933. "contain a structure type containing members decorated with "
  934. "BuiltIn, consumed per entry-point. Entry Point id "
  935. << entry_point << " does not meet this requirement.";
  936. }
  937. // The LinkageAttributes Decoration cannot be applied to functions
  938. // targeted by an OpEntryPoint instruction
  939. for (auto& decoration : vstate.id_decorations(entry_point)) {
  940. if (spv::Decoration::LinkageAttributes == decoration.dec_type()) {
  941. const std::string linkage_name =
  942. spvtools::utils::MakeString(decoration.params());
  943. return vstate.diag(SPV_ERROR_INVALID_BINARY,
  944. vstate.FindDef(entry_point))
  945. << "The LinkageAttributes Decoration (Linkage name: "
  946. << linkage_name << ") cannot be applied to function id "
  947. << entry_point
  948. << " because it is targeted by an OpEntryPoint instruction.";
  949. }
  950. }
  951. const bool workgroup_blocks_allowed = vstate.HasCapability(
  952. spv::Capability::WorkgroupMemoryExplicitLayoutKHR);
  953. if (workgroup_blocks_allowed &&
  954. !vstate.HasCapability(spv::Capability::UntypedPointersKHR) &&
  955. num_workgroup_variables > 0 &&
  956. num_workgroup_variables_with_block > 0) {
  957. if (num_workgroup_variables != num_workgroup_variables_with_block) {
  958. return vstate.diag(SPV_ERROR_INVALID_BINARY,
  959. vstate.FindDef(entry_point))
  960. << "When declaring WorkgroupMemoryExplicitLayoutKHR, "
  961. "either all or none of the Workgroup Storage Class "
  962. "variables "
  963. "in the entry point interface must point to struct types "
  964. "decorated with Block (unless the "
  965. "UntypedPointersKHR capability is declared). "
  966. "Entry point id "
  967. << entry_point << " does not meet this requirement.";
  968. }
  969. if (num_workgroup_variables_with_block > 1 &&
  970. num_workgroup_variables_with_block !=
  971. num_workgroup_variables_with_aliased) {
  972. return vstate.diag(SPV_ERROR_INVALID_BINARY,
  973. vstate.FindDef(entry_point))
  974. << "When declaring WorkgroupMemoryExplicitLayoutKHR, "
  975. "if more than one Workgroup Storage Class variable in "
  976. "the entry point interface point to a type decorated "
  977. "with Block, all of them must be decorated with Aliased "
  978. "(unless the UntypedPointerWorkgroupKHR capability is "
  979. "declared). Entry point id "
  980. << entry_point << " does not meet this requirement.";
  981. }
  982. } else if (!workgroup_blocks_allowed &&
  983. num_workgroup_variables_with_block > 0) {
  984. return vstate.diag(SPV_ERROR_INVALID_BINARY,
  985. vstate.FindDef(entry_point))
  986. << "Workgroup Storage Class variables can't be decorated with "
  987. "Block unless declaring the WorkgroupMemoryExplicitLayoutKHR "
  988. "capability.";
  989. }
  990. }
  991. }
  992. return SPV_SUCCESS;
  993. }
  994. // Load |constraints| with all the member constraints for structs contained
  995. // within the given array type.
  996. void ComputeMemberConstraintsForArray(MemberConstraints* constraints,
  997. uint32_t array_id,
  998. const LayoutConstraints& inherited,
  999. ValidationState_t& vstate);
  1000. // Load |constraints| with all the member constraints for the given struct,
  1001. // and all its contained structs.
  1002. void ComputeMemberConstraintsForStruct(MemberConstraints* constraints,
  1003. uint32_t struct_id,
  1004. const LayoutConstraints& inherited,
  1005. ValidationState_t& vstate) {
  1006. assert(constraints);
  1007. const auto& members = getStructMembers(struct_id, vstate);
  1008. for (uint32_t memberIdx = 0, numMembers = uint32_t(members.size());
  1009. memberIdx < numMembers; memberIdx++) {
  1010. LayoutConstraints& constraint =
  1011. (*constraints)[std::make_pair(struct_id, memberIdx)];
  1012. constraint = inherited;
  1013. auto member_decorations =
  1014. vstate.id_member_decorations(struct_id, memberIdx);
  1015. for (auto decoration = member_decorations.begin;
  1016. decoration != member_decorations.end; ++decoration) {
  1017. assert(decoration->struct_member_index() == (int)memberIdx);
  1018. switch (decoration->dec_type()) {
  1019. case spv::Decoration::RowMajor:
  1020. constraint.majorness = kRowMajor;
  1021. break;
  1022. case spv::Decoration::ColMajor:
  1023. constraint.majorness = kColumnMajor;
  1024. break;
  1025. case spv::Decoration::MatrixStride:
  1026. constraint.matrix_stride = decoration->params()[0];
  1027. break;
  1028. default:
  1029. break;
  1030. }
  1031. }
  1032. // Now recurse
  1033. auto member_type_id = members[memberIdx];
  1034. const auto member_type_inst = vstate.FindDef(member_type_id);
  1035. const auto opcode = member_type_inst->opcode();
  1036. switch (opcode) {
  1037. case spv::Op::OpTypeArray:
  1038. case spv::Op::OpTypeRuntimeArray:
  1039. ComputeMemberConstraintsForArray(constraints, member_type_id, inherited,
  1040. vstate);
  1041. break;
  1042. case spv::Op::OpTypeStruct:
  1043. ComputeMemberConstraintsForStruct(constraints, member_type_id,
  1044. inherited, vstate);
  1045. break;
  1046. default:
  1047. break;
  1048. }
  1049. }
  1050. }
  1051. void ComputeMemberConstraintsForArray(MemberConstraints* constraints,
  1052. uint32_t array_id,
  1053. const LayoutConstraints& inherited,
  1054. ValidationState_t& vstate) {
  1055. assert(constraints);
  1056. auto elem_type_id = vstate.FindDef(array_id)->words()[2];
  1057. const auto elem_type_inst = vstate.FindDef(elem_type_id);
  1058. const auto opcode = elem_type_inst->opcode();
  1059. switch (opcode) {
  1060. case spv::Op::OpTypeArray:
  1061. case spv::Op::OpTypeRuntimeArray:
  1062. ComputeMemberConstraintsForArray(constraints, elem_type_id, inherited,
  1063. vstate);
  1064. break;
  1065. case spv::Op::OpTypeStruct:
  1066. ComputeMemberConstraintsForStruct(constraints, elem_type_id, inherited,
  1067. vstate);
  1068. break;
  1069. default:
  1070. break;
  1071. }
  1072. }
  1073. spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) {
  1074. // Set of entry points that are known to use a push constant.
  1075. std::unordered_set<uint32_t> uses_push_constant;
  1076. for (const auto& inst : vstate.ordered_instructions()) {
  1077. const auto& words = inst.words();
  1078. auto type_id = inst.type_id();
  1079. const Instruction* type_inst = vstate.FindDef(type_id);
  1080. bool scalar_block_layout = false;
  1081. MemberConstraints constraints;
  1082. if (spv::Op::OpVariable == inst.opcode() ||
  1083. spv::Op::OpUntypedVariableKHR == inst.opcode()) {
  1084. const bool untyped_pointer =
  1085. inst.opcode() == spv::Op::OpUntypedVariableKHR;
  1086. const auto var_id = inst.id();
  1087. // For storage class / decoration combinations, see Vulkan 14.5.4 "Offset
  1088. // and Stride Assignment".
  1089. const auto storageClassVal = words[3];
  1090. const auto storageClass = spv::StorageClass(storageClassVal);
  1091. const bool uniform = storageClass == spv::StorageClass::Uniform;
  1092. const bool uniform_constant =
  1093. storageClass == spv::StorageClass::UniformConstant;
  1094. const bool push_constant =
  1095. storageClass == spv::StorageClass::PushConstant;
  1096. const bool storage_buffer =
  1097. storageClass == spv::StorageClass::StorageBuffer;
  1098. if (spvIsVulkanEnv(vstate.context()->target_env)) {
  1099. // Vulkan: There must be no more than one PushConstant block per entry
  1100. // point.
  1101. if (push_constant) {
  1102. auto entry_points = vstate.EntryPointReferences(var_id);
  1103. for (auto ep_id : entry_points) {
  1104. const bool already_used = !uses_push_constant.insert(ep_id).second;
  1105. if (already_used) {
  1106. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
  1107. << vstate.VkErrorID(6674) << "Entry point id '" << ep_id
  1108. << "' uses more than one PushConstant interface.\n"
  1109. << "From Vulkan spec:\n"
  1110. << "There must be no more than one push constant block "
  1111. << "statically used per shader entry point.";
  1112. }
  1113. }
  1114. }
  1115. // Vulkan: Check DescriptorSet and Binding decoration for
  1116. // UniformConstant which cannot be a struct.
  1117. if (uniform_constant) {
  1118. auto entry_points = vstate.EntryPointReferences(var_id);
  1119. if (!entry_points.empty() &&
  1120. !hasDecoration(var_id, spv::Decoration::DescriptorSet, vstate)) {
  1121. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
  1122. << vstate.VkErrorID(6677) << "UniformConstant id '" << var_id
  1123. << "' is missing DescriptorSet decoration.\n"
  1124. << "From Vulkan spec:\n"
  1125. << "These variables must have DescriptorSet and Binding "
  1126. "decorations specified";
  1127. }
  1128. if (!entry_points.empty() &&
  1129. !hasDecoration(var_id, spv::Decoration::Binding, vstate)) {
  1130. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
  1131. << vstate.VkErrorID(6677) << "UniformConstant id '" << var_id
  1132. << "' is missing Binding decoration.\n"
  1133. << "From Vulkan spec:\n"
  1134. << "These variables must have DescriptorSet and Binding "
  1135. "decorations specified";
  1136. }
  1137. }
  1138. }
  1139. if (spvIsOpenGLEnv(vstate.context()->target_env)) {
  1140. bool has_block = hasDecoration(var_id, spv::Decoration::Block, vstate);
  1141. bool has_buffer_block =
  1142. hasDecoration(var_id, spv::Decoration::BufferBlock, vstate);
  1143. if ((uniform && (has_block || has_buffer_block)) ||
  1144. (storage_buffer && has_block)) {
  1145. auto entry_points = vstate.EntryPointReferences(var_id);
  1146. if (!entry_points.empty() &&
  1147. !hasDecoration(var_id, spv::Decoration::Binding, vstate)) {
  1148. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
  1149. << (uniform ? "Uniform" : "Storage Buffer") << " id '"
  1150. << var_id << "' is missing Binding decoration.\n"
  1151. << "From ARB_gl_spirv extension:\n"
  1152. << "Uniform and shader storage block variables must "
  1153. << "also be decorated with a *Binding*.";
  1154. }
  1155. }
  1156. }
  1157. const bool phys_storage_buffer =
  1158. storageClass == spv::StorageClass::PhysicalStorageBuffer;
  1159. const bool workgroup =
  1160. storageClass == spv::StorageClass::Workgroup &&
  1161. vstate.HasCapability(
  1162. spv::Capability::WorkgroupMemoryExplicitLayoutKHR);
  1163. if (uniform || push_constant || storage_buffer || phys_storage_buffer ||
  1164. workgroup) {
  1165. const auto ptrInst = vstate.FindDef(words[1]);
  1166. assert(spv::Op::OpTypePointer == ptrInst->opcode() ||
  1167. spv::Op::OpTypeUntypedPointerKHR == ptrInst->opcode());
  1168. auto id = untyped_pointer ? (words.size() > 4 ? words[4] : 0)
  1169. : ptrInst->words()[3];
  1170. if (id != 0) {
  1171. auto id_inst = vstate.FindDef(id);
  1172. // Jump through one level of arraying.
  1173. if (!workgroup &&
  1174. (id_inst->opcode() == spv::Op::OpTypeArray ||
  1175. id_inst->opcode() == spv::Op::OpTypeRuntimeArray)) {
  1176. id = id_inst->GetOperandAs<uint32_t>(1u);
  1177. id_inst = vstate.FindDef(id);
  1178. }
  1179. // Struct requirement is checked on variables so just move on here.
  1180. if (spv::Op::OpTypeStruct != id_inst->opcode()) continue;
  1181. ComputeMemberConstraintsForStruct(&constraints, id,
  1182. LayoutConstraints(), vstate);
  1183. }
  1184. // Prepare for messages
  1185. const char* sc_str =
  1186. uniform ? "Uniform"
  1187. : (push_constant ? "PushConstant"
  1188. : (workgroup ? "Workgroup"
  1189. : "StorageBuffer"));
  1190. if (spvIsVulkanEnv(vstate.context()->target_env)) {
  1191. const bool block = hasDecoration(id, spv::Decoration::Block, vstate);
  1192. const bool buffer_block =
  1193. hasDecoration(id, spv::Decoration::BufferBlock, vstate);
  1194. if (storage_buffer && buffer_block) {
  1195. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
  1196. << vstate.VkErrorID(6675) << "Storage buffer id '" << var_id
  1197. << " In Vulkan, BufferBlock is disallowed on variables in "
  1198. "the StorageBuffer storage class";
  1199. }
  1200. // Vulkan: Check Block decoration for PushConstant, Uniform
  1201. // and StorageBuffer variables. Uniform can also use BufferBlock.
  1202. if (push_constant && !block) {
  1203. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1204. << vstate.VkErrorID(6675) << "PushConstant id '" << id
  1205. << "' is missing Block decoration.\n"
  1206. << "From Vulkan spec:\n"
  1207. << "Such variables must be identified with a Block "
  1208. "decoration";
  1209. }
  1210. if (storage_buffer && !block) {
  1211. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1212. << vstate.VkErrorID(6675) << "StorageBuffer id '" << id
  1213. << "' is missing Block decoration.\n"
  1214. << "From Vulkan spec:\n"
  1215. << "Such variables must be identified with a Block "
  1216. "decoration";
  1217. }
  1218. if (uniform && !block && !buffer_block) {
  1219. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1220. << vstate.VkErrorID(6676) << "Uniform id '" << id
  1221. << "' is missing Block or BufferBlock decoration.\n"
  1222. << "From Vulkan spec:\n"
  1223. << "Such variables must be identified with a Block or "
  1224. "BufferBlock decoration";
  1225. }
  1226. // Vulkan: Check DescriptorSet and Binding decoration for
  1227. // Uniform and StorageBuffer variables.
  1228. if (uniform || storage_buffer) {
  1229. auto entry_points = vstate.EntryPointReferences(var_id);
  1230. if (!entry_points.empty() &&
  1231. !hasDecoration(var_id, spv::Decoration::DescriptorSet,
  1232. vstate)) {
  1233. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
  1234. << vstate.VkErrorID(6677) << sc_str << " id '" << var_id
  1235. << "' is missing DescriptorSet decoration.\n"
  1236. << "From Vulkan spec:\n"
  1237. << "These variables must have DescriptorSet and Binding "
  1238. "decorations specified";
  1239. }
  1240. if (!entry_points.empty() &&
  1241. !hasDecoration(var_id, spv::Decoration::Binding, vstate)) {
  1242. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id))
  1243. << vstate.VkErrorID(6677) << sc_str << " id '" << var_id
  1244. << "' is missing Binding decoration.\n"
  1245. << "From Vulkan spec:\n"
  1246. << "These variables must have DescriptorSet and Binding "
  1247. "decorations specified";
  1248. }
  1249. }
  1250. }
  1251. if (id != 0) {
  1252. for (const auto& dec : vstate.id_decorations(id)) {
  1253. const bool blockDeco = spv::Decoration::Block == dec.dec_type();
  1254. const bool bufferDeco =
  1255. spv::Decoration::BufferBlock == dec.dec_type();
  1256. const bool blockRules = uniform && blockDeco;
  1257. const bool bufferRules = (uniform && bufferDeco) ||
  1258. ((push_constant || storage_buffer ||
  1259. phys_storage_buffer || workgroup) &&
  1260. blockDeco);
  1261. if (uniform && blockDeco) {
  1262. vstate.RegisterPointerToUniformBlock(ptrInst->id());
  1263. vstate.RegisterStructForUniformBlock(id);
  1264. }
  1265. if ((uniform && bufferDeco) ||
  1266. ((storage_buffer || phys_storage_buffer) && blockDeco)) {
  1267. vstate.RegisterPointerToStorageBuffer(ptrInst->id());
  1268. vstate.RegisterStructForStorageBuffer(id);
  1269. }
  1270. if (blockRules || bufferRules) {
  1271. const char* deco_str = blockDeco ? "Block" : "BufferBlock";
  1272. spv_result_t recursive_status = SPV_SUCCESS;
  1273. scalar_block_layout =
  1274. workgroup ? vstate.options()->workgroup_scalar_block_layout
  1275. : vstate.options()->scalar_block_layout;
  1276. if (isMissingOffsetInStruct(id, vstate)) {
  1277. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1278. << "Structure id " << id << " decorated as " << deco_str
  1279. << " must be explicitly laid out with Offset "
  1280. "decorations.";
  1281. }
  1282. if (!checkForRequiredDecoration(
  1283. id,
  1284. [](spv::Decoration d) {
  1285. return d == spv::Decoration::ArrayStride;
  1286. },
  1287. spv::Op::OpTypeArray, vstate)) {
  1288. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1289. << "Structure id " << id << " decorated as " << deco_str
  1290. << " must be explicitly laid out with ArrayStride "
  1291. "decorations.";
  1292. }
  1293. if (!checkForRequiredDecoration(
  1294. id,
  1295. [](spv::Decoration d) {
  1296. return d == spv::Decoration::MatrixStride;
  1297. },
  1298. spv::Op::OpTypeMatrix, vstate)) {
  1299. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1300. << "Structure id " << id << " decorated as " << deco_str
  1301. << " must be explicitly laid out with MatrixStride "
  1302. "decorations.";
  1303. }
  1304. if (!checkForRequiredDecoration(
  1305. id,
  1306. [](spv::Decoration d) {
  1307. return d == spv::Decoration::RowMajor ||
  1308. d == spv::Decoration::ColMajor;
  1309. },
  1310. spv::Op::OpTypeMatrix, vstate)) {
  1311. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1312. << "Structure id " << id << " decorated as " << deco_str
  1313. << " must be explicitly laid out with RowMajor or "
  1314. "ColMajor decorations.";
  1315. }
  1316. if (spvIsVulkanEnv(vstate.context()->target_env)) {
  1317. if (blockRules &&
  1318. (SPV_SUCCESS !=
  1319. (recursive_status = checkLayout(id, sc_str, deco_str, true,
  1320. scalar_block_layout, 0,
  1321. constraints, vstate)))) {
  1322. return recursive_status;
  1323. } else if (bufferRules &&
  1324. (SPV_SUCCESS != (recursive_status = checkLayout(
  1325. id, sc_str, deco_str, false,
  1326. scalar_block_layout, 0,
  1327. constraints, vstate)))) {
  1328. return recursive_status;
  1329. }
  1330. }
  1331. }
  1332. }
  1333. }
  1334. }
  1335. } else if (type_inst && type_inst->opcode() == spv::Op::OpTypePointer &&
  1336. type_inst->GetOperandAs<spv::StorageClass>(1u) ==
  1337. spv::StorageClass::PhysicalStorageBuffer) {
  1338. const bool buffer = true;
  1339. const auto pointee_type_id = type_inst->GetOperandAs<uint32_t>(2u);
  1340. const auto* data_type_inst = vstate.FindDef(pointee_type_id);
  1341. scalar_block_layout = vstate.options()->scalar_block_layout;
  1342. if (data_type_inst->opcode() == spv::Op::OpTypeStruct) {
  1343. ComputeMemberConstraintsForStruct(&constraints, pointee_type_id,
  1344. LayoutConstraints(), vstate);
  1345. }
  1346. if (auto res = checkLayout(pointee_type_id, "PhysicalStorageBuffer",
  1347. "Block", !buffer, scalar_block_layout, 0,
  1348. constraints, vstate)) {
  1349. return res;
  1350. }
  1351. } else if (vstate.HasCapability(spv::Capability::UntypedPointersKHR) &&
  1352. spvIsVulkanEnv(vstate.context()->target_env)) {
  1353. // Untyped variables are checked above. Here we check that instructions
  1354. // using an untyped pointer have a valid layout.
  1355. uint32_t ptr_ty_id = 0;
  1356. uint32_t data_type_id = 0;
  1357. switch (inst.opcode()) {
  1358. case spv::Op::OpUntypedAccessChainKHR:
  1359. case spv::Op::OpUntypedInBoundsAccessChainKHR:
  1360. case spv::Op::OpUntypedPtrAccessChainKHR:
  1361. case spv::Op::OpUntypedInBoundsPtrAccessChainKHR:
  1362. ptr_ty_id = inst.type_id();
  1363. data_type_id = inst.GetOperandAs<uint32_t>(2);
  1364. break;
  1365. case spv::Op::OpLoad:
  1366. if (vstate.GetIdOpcode(vstate.GetOperandTypeId(&inst, 2)) ==
  1367. spv::Op::OpTypeUntypedPointerKHR) {
  1368. const auto ptr_id = inst.GetOperandAs<uint32_t>(2);
  1369. ptr_ty_id = vstate.FindDef(ptr_id)->type_id();
  1370. data_type_id = inst.type_id();
  1371. }
  1372. break;
  1373. case spv::Op::OpStore:
  1374. if (vstate.GetIdOpcode(vstate.GetOperandTypeId(&inst, 0)) ==
  1375. spv::Op::OpTypeUntypedPointerKHR) {
  1376. const auto ptr_id = inst.GetOperandAs<uint32_t>(0);
  1377. ptr_ty_id = vstate.FindDef(ptr_id)->type_id();
  1378. data_type_id = vstate.GetOperandTypeId(&inst, 1);
  1379. }
  1380. break;
  1381. case spv::Op::OpUntypedArrayLengthKHR:
  1382. ptr_ty_id = vstate.FindDef(inst.GetOperandAs<uint32_t>(3))->type_id();
  1383. data_type_id = inst.GetOperandAs<uint32_t>(2);
  1384. break;
  1385. default:
  1386. break;
  1387. }
  1388. if (ptr_ty_id == 0 || data_type_id == 0) {
  1389. // Not an untyped pointer.
  1390. continue;
  1391. }
  1392. const auto sc =
  1393. vstate.FindDef(ptr_ty_id)->GetOperandAs<spv::StorageClass>(1);
  1394. const char* sc_str =
  1395. sc == spv::StorageClass::Uniform
  1396. ? "Uniform"
  1397. : (sc == spv::StorageClass::PushConstant
  1398. ? "PushConstant"
  1399. : (sc == spv::StorageClass::Workgroup ? "Workgroup"
  1400. : "StorageBuffer"));
  1401. auto data_type = vstate.FindDef(data_type_id);
  1402. scalar_block_layout =
  1403. sc == spv::StorageClass::Workgroup
  1404. ? vstate.options()->workgroup_scalar_block_layout
  1405. : vstate.options()->scalar_block_layout;
  1406. // If the data type is an array that contains a Block- or
  1407. // BufferBlock-decorated struct, then use the struct for layout checks
  1408. // instead of the array. In this case, the array represents a descriptor
  1409. // array which should not have an explicit layout.
  1410. if (data_type->opcode() == spv::Op::OpTypeArray ||
  1411. data_type->opcode() == spv::Op::OpTypeRuntimeArray) {
  1412. const auto ele_type =
  1413. vstate.FindDef(data_type->GetOperandAs<uint32_t>(1u));
  1414. if (ele_type->opcode() == spv::Op::OpTypeStruct &&
  1415. (vstate.HasDecoration(ele_type->id(), spv::Decoration::Block) ||
  1416. vstate.HasDecoration(ele_type->id(),
  1417. spv::Decoration::BufferBlock))) {
  1418. data_type = ele_type;
  1419. data_type_id = ele_type->id();
  1420. }
  1421. }
  1422. // Assume uniform storage class uses block rules unless we see a
  1423. // BufferBlock decorated struct in the data type.
  1424. bool bufferRules = sc == spv::StorageClass::Uniform ? false : true;
  1425. if (data_type->opcode() == spv::Op::OpTypeStruct) {
  1426. if (sc == spv::StorageClass::Uniform) {
  1427. bufferRules =
  1428. vstate.HasDecoration(data_type_id, spv::Decoration::BufferBlock);
  1429. }
  1430. ComputeMemberConstraintsForStruct(&constraints, data_type_id,
  1431. LayoutConstraints(), vstate);
  1432. }
  1433. const char* deco_str =
  1434. bufferRules
  1435. ? (sc == spv::StorageClass::Uniform ? "BufferBlock" : "Block")
  1436. : "Block";
  1437. if (auto result =
  1438. checkLayout(data_type_id, sc_str, deco_str, !bufferRules,
  1439. scalar_block_layout, 0, constraints, vstate)) {
  1440. return result;
  1441. }
  1442. }
  1443. }
  1444. return SPV_SUCCESS;
  1445. }
  1446. // Returns true if |decoration| cannot be applied to the same id more than once.
  1447. bool AtMostOncePerId(spv::Decoration decoration) {
  1448. return decoration != spv::Decoration::UserSemantic &&
  1449. decoration != spv::Decoration::FuncParamAttr;
  1450. }
  1451. // Returns true if |decoration| cannot be applied to the same member more than
  1452. // once.
  1453. bool AtMostOncePerMember(spv::Decoration decoration) {
  1454. return decoration != spv::Decoration::UserSemantic;
  1455. }
  1456. spv_result_t CheckDecorationsCompatibility(ValidationState_t& vstate) {
  1457. using PerIDKey = std::tuple<spv::Decoration, uint32_t>;
  1458. using PerMemberKey = std::tuple<spv::Decoration, uint32_t, uint32_t>;
  1459. // An Array of pairs where the decorations in the pair cannot both be applied
  1460. // to the same id.
  1461. static const spv::Decoration mutually_exclusive_per_id[][2] = {
  1462. {spv::Decoration::Block, spv::Decoration::BufferBlock},
  1463. {spv::Decoration::Restrict, spv::Decoration::Aliased},
  1464. {spv::Decoration::RestrictPointer, spv::Decoration::AliasedPointer}};
  1465. static const auto num_mutually_exclusive_per_id_pairs =
  1466. sizeof(mutually_exclusive_per_id) / (2 * sizeof(spv::Decoration));
  1467. // An Array of pairs where the decorations in the pair cannot both be applied
  1468. // to the same member.
  1469. static const spv::Decoration mutually_exclusive_per_member[][2] = {
  1470. {spv::Decoration::RowMajor, spv::Decoration::ColMajor}};
  1471. static const auto num_mutually_exclusive_per_mem_pairs =
  1472. sizeof(mutually_exclusive_per_member) / (2 * sizeof(spv::Decoration));
  1473. std::set<PerIDKey> seen_per_id;
  1474. std::set<PerMemberKey> seen_per_member;
  1475. for (const auto& inst : vstate.ordered_instructions()) {
  1476. const auto& words = inst.words();
  1477. if (spv::Op::OpDecorate == inst.opcode()) {
  1478. const auto id = words[1];
  1479. const auto dec_type = static_cast<spv::Decoration>(words[2]);
  1480. const auto k = PerIDKey(dec_type, id);
  1481. const auto already_used = !seen_per_id.insert(k).second;
  1482. if (already_used && AtMostOncePerId(dec_type)) {
  1483. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1484. << "ID '" << id << "' decorated with "
  1485. << vstate.SpvDecorationString(dec_type)
  1486. << " multiple times is not allowed.";
  1487. }
  1488. // Verify certain mutually exclusive decorations are not both applied on
  1489. // an ID.
  1490. for (uint32_t pair_idx = 0;
  1491. pair_idx < num_mutually_exclusive_per_id_pairs; ++pair_idx) {
  1492. spv::Decoration excl_dec_type = spv::Decoration::Max;
  1493. if (mutually_exclusive_per_id[pair_idx][0] == dec_type) {
  1494. excl_dec_type = mutually_exclusive_per_id[pair_idx][1];
  1495. } else if (mutually_exclusive_per_id[pair_idx][1] == dec_type) {
  1496. excl_dec_type = mutually_exclusive_per_id[pair_idx][0];
  1497. } else {
  1498. continue;
  1499. }
  1500. const auto excl_k = PerIDKey(excl_dec_type, id);
  1501. if (seen_per_id.find(excl_k) != seen_per_id.end()) {
  1502. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1503. << "ID '" << id << "' decorated with both "
  1504. << vstate.SpvDecorationString(dec_type) << " and "
  1505. << vstate.SpvDecorationString(excl_dec_type)
  1506. << " is not allowed.";
  1507. }
  1508. }
  1509. } else if (spv::Op::OpMemberDecorate == inst.opcode()) {
  1510. const auto id = words[1];
  1511. const auto member_id = words[2];
  1512. const auto dec_type = static_cast<spv::Decoration>(words[3]);
  1513. const auto k = PerMemberKey(dec_type, id, member_id);
  1514. const auto already_used = !seen_per_member.insert(k).second;
  1515. if (already_used && AtMostOncePerMember(dec_type)) {
  1516. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1517. << "ID '" << id << "', member '" << member_id
  1518. << "' decorated with " << vstate.SpvDecorationString(dec_type)
  1519. << " multiple times is not allowed.";
  1520. }
  1521. // Verify certain mutually exclusive decorations are not both applied on
  1522. // a (ID, member) tuple.
  1523. for (uint32_t pair_idx = 0;
  1524. pair_idx < num_mutually_exclusive_per_mem_pairs; ++pair_idx) {
  1525. spv::Decoration excl_dec_type = spv::Decoration::Max;
  1526. if (mutually_exclusive_per_member[pair_idx][0] == dec_type) {
  1527. excl_dec_type = mutually_exclusive_per_member[pair_idx][1];
  1528. } else if (mutually_exclusive_per_member[pair_idx][1] == dec_type) {
  1529. excl_dec_type = mutually_exclusive_per_member[pair_idx][0];
  1530. } else {
  1531. continue;
  1532. }
  1533. const auto excl_k = PerMemberKey(excl_dec_type, id, member_id);
  1534. if (seen_per_member.find(excl_k) != seen_per_member.end()) {
  1535. return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
  1536. << "ID '" << id << "', member '" << member_id
  1537. << "' decorated with both "
  1538. << vstate.SpvDecorationString(dec_type) << " and "
  1539. << vstate.SpvDecorationString(excl_dec_type)
  1540. << " is not allowed.";
  1541. }
  1542. }
  1543. }
  1544. }
  1545. return SPV_SUCCESS;
  1546. }
  1547. spv_result_t CheckVulkanMemoryModelDeprecatedDecorations(
  1548. ValidationState_t& vstate) {
  1549. if (vstate.memory_model() != spv::MemoryModel::VulkanKHR) return SPV_SUCCESS;
  1550. std::string msg;
  1551. std::ostringstream str(msg);
  1552. for (const auto& def : vstate.all_definitions()) {
  1553. const auto inst = def.second;
  1554. const auto id = inst->id();
  1555. for (const auto& dec : vstate.id_decorations(id)) {
  1556. const auto member = dec.struct_member_index();
  1557. if (dec.dec_type() == spv::Decoration::Coherent ||
  1558. dec.dec_type() == spv::Decoration::Volatile) {
  1559. str << (dec.dec_type() == spv::Decoration::Coherent ? "Coherent"
  1560. : "Volatile");
  1561. str << " decoration targeting " << vstate.getIdName(id);
  1562. if (member != Decoration::kInvalidMember) {
  1563. str << " (member index " << member << ")";
  1564. }
  1565. str << " is banned when using the Vulkan memory model.";
  1566. return vstate.diag(SPV_ERROR_INVALID_ID, inst) << str.str();
  1567. }
  1568. }
  1569. }
  1570. return SPV_SUCCESS;
  1571. }
  1572. // Returns SPV_SUCCESS if validation rules are satisfied for FPRoundingMode
  1573. // decorations. Otherwise emits a diagnostic and returns something other than
  1574. // SPV_SUCCESS.
  1575. spv_result_t CheckFPRoundingModeForShaders(ValidationState_t& vstate,
  1576. const Instruction& inst,
  1577. const Decoration& decoration) {
  1578. // Validates width-only conversion instruction for floating-point object
  1579. // i.e., OpFConvert
  1580. if (inst.opcode() != spv::Op::OpFConvert) {
  1581. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1582. << "FPRoundingMode decoration can be applied only to a "
  1583. "width-only conversion instruction for floating-point "
  1584. "object.";
  1585. }
  1586. if (spvIsVulkanEnv(vstate.context()->target_env)) {
  1587. const auto mode = spv::FPRoundingMode(decoration.params()[0]);
  1588. if ((mode != spv::FPRoundingMode::RTE) &&
  1589. (mode != spv::FPRoundingMode::RTZ)) {
  1590. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1591. << vstate.VkErrorID(4675)
  1592. << "In Vulkan, the FPRoundingMode mode must only by RTE or RTZ.";
  1593. }
  1594. }
  1595. // Validates Object operand of an OpStore
  1596. for (const auto& use : inst.uses()) {
  1597. const auto store = use.first;
  1598. if (store->opcode() == spv::Op::OpFConvert) continue;
  1599. if (spvOpcodeIsDebug(store->opcode())) continue;
  1600. if (store->IsNonSemantic()) continue;
  1601. if (spvOpcodeIsDecoration(store->opcode())) continue;
  1602. if (store->opcode() != spv::Op::OpStore) {
  1603. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1604. << "FPRoundingMode decoration can be applied only to the "
  1605. "Object operand of an OpStore.";
  1606. }
  1607. if (use.second != 2) {
  1608. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1609. << "FPRoundingMode decoration can be applied only to the "
  1610. "Object operand of an OpStore.";
  1611. }
  1612. const auto ptr_inst = vstate.FindDef(store->GetOperandAs<uint32_t>(0));
  1613. const auto ptr_type = vstate.FindDef(ptr_inst->GetOperandAs<uint32_t>(0));
  1614. const auto half_float_id = ptr_type->GetOperandAs<uint32_t>(2);
  1615. if (!vstate.IsFloatScalarOrVectorType(half_float_id) ||
  1616. vstate.GetBitWidth(half_float_id) != 16) {
  1617. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1618. << "FPRoundingMode decoration can be applied only to the "
  1619. "Object operand of an OpStore storing through a pointer "
  1620. "to "
  1621. "a 16-bit floating-point scalar or vector object.";
  1622. }
  1623. // Validates storage class of the pointer to the OpStore
  1624. const auto storage = ptr_type->GetOperandAs<spv::StorageClass>(1);
  1625. if (storage != spv::StorageClass::StorageBuffer &&
  1626. storage != spv::StorageClass::Uniform &&
  1627. storage != spv::StorageClass::PushConstant &&
  1628. storage != spv::StorageClass::Input &&
  1629. storage != spv::StorageClass::Output &&
  1630. storage != spv::StorageClass::PhysicalStorageBuffer) {
  1631. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1632. << "FPRoundingMode decoration can be applied only to the "
  1633. "Object operand of an OpStore in the StorageBuffer, "
  1634. "PhysicalStorageBuffer, Uniform, PushConstant, Input, or "
  1635. "Output Storage Classes.";
  1636. }
  1637. }
  1638. return SPV_SUCCESS;
  1639. }
  1640. // Returns SPV_SUCCESS if validation rules are satisfied for the NonWritable
  1641. // decoration. Otherwise emits a diagnostic and returns something other than
  1642. // SPV_SUCCESS. The |inst| parameter is the object being decorated. This must
  1643. // be called after TypePass and AnnotateCheckDecorationsOfBuffers are called.
  1644. spv_result_t CheckNonWritableDecoration(ValidationState_t& vstate,
  1645. const Instruction& inst,
  1646. const Decoration& decoration) {
  1647. assert(inst.id() && "Parser ensures the target of the decoration has an ID");
  1648. if (decoration.struct_member_index() == Decoration::kInvalidMember) {
  1649. // The target must be a memory object declaration.
  1650. // First, it must be a variable or function parameter.
  1651. const auto opcode = inst.opcode();
  1652. const auto type_id = inst.type_id();
  1653. if (opcode != spv::Op::OpVariable &&
  1654. opcode != spv::Op::OpUntypedVariableKHR &&
  1655. opcode != spv::Op::OpFunctionParameter &&
  1656. opcode != spv::Op::OpRawAccessChainNV) {
  1657. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1658. << "Target of NonWritable decoration must be a memory object "
  1659. "declaration (a variable or a function parameter)";
  1660. }
  1661. const auto var_storage_class =
  1662. opcode == spv::Op::OpVariable
  1663. ? inst.GetOperandAs<spv::StorageClass>(2)
  1664. : opcode == spv::Op::OpUntypedVariableKHR
  1665. ? inst.GetOperandAs<spv::StorageClass>(3)
  1666. : spv::StorageClass::Max;
  1667. if ((var_storage_class == spv::StorageClass::Function ||
  1668. var_storage_class == spv::StorageClass::Private) &&
  1669. vstate.features().nonwritable_var_in_function_or_private) {
  1670. // New permitted feature in SPIR-V 1.4.
  1671. } else if (
  1672. // It may point to a UBO, SSBO, storage image, or raw access chain.
  1673. vstate.IsPointerToUniformBlock(type_id) ||
  1674. vstate.IsPointerToStorageBuffer(type_id) ||
  1675. vstate.IsPointerToStorageImage(type_id) ||
  1676. opcode == spv::Op::OpRawAccessChainNV) {
  1677. } else {
  1678. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1679. << "Target of NonWritable decoration is invalid: must point to a "
  1680. "storage image, uniform block, "
  1681. << (vstate.features().nonwritable_var_in_function_or_private
  1682. ? "storage buffer, or variable in Private or Function "
  1683. "storage class"
  1684. : "or storage buffer");
  1685. }
  1686. }
  1687. return SPV_SUCCESS;
  1688. }
  1689. // Returns SPV_SUCCESS if validation rules are satisfied for Uniform or
  1690. // UniformId decorations. Otherwise emits a diagnostic and returns something
  1691. // other than SPV_SUCCESS. Assumes each decoration on a group has been
  1692. // propagated down to the group members. The |inst| parameter is the object
  1693. // being decorated.
  1694. spv_result_t CheckUniformDecoration(ValidationState_t& vstate,
  1695. const Instruction& inst,
  1696. const Decoration& decoration) {
  1697. const char* const dec_name = decoration.dec_type() == spv::Decoration::Uniform
  1698. ? "Uniform"
  1699. : "UniformId";
  1700. // Uniform or UniformId must decorate an "object"
  1701. // - has a result ID
  1702. // - is an instantiation of a non-void type. So it has a type ID, and that
  1703. // type is not void.
  1704. // We already know the result ID is non-zero.
  1705. if (inst.type_id() == 0) {
  1706. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1707. << dec_name << " decoration applied to a non-object";
  1708. }
  1709. if (Instruction* type_inst = vstate.FindDef(inst.type_id())) {
  1710. if (type_inst->opcode() == spv::Op::OpTypeVoid) {
  1711. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1712. << dec_name << " decoration applied to a value with void type";
  1713. }
  1714. } else {
  1715. // We might never get here because this would have been rejected earlier in
  1716. // the flow.
  1717. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1718. << dec_name << " decoration applied to an object with invalid type";
  1719. }
  1720. // Use of Uniform with OpDecorate is checked elsewhere.
  1721. // Use of UniformId with OpDecorateId is checked elsewhere.
  1722. if (decoration.dec_type() == spv::Decoration::UniformId) {
  1723. assert(decoration.params().size() == 1 &&
  1724. "Grammar ensures UniformId has one parameter");
  1725. // The scope id is an execution scope.
  1726. if (auto error =
  1727. ValidateExecutionScope(vstate, &inst, decoration.params()[0]))
  1728. return error;
  1729. }
  1730. return SPV_SUCCESS;
  1731. }
  1732. // Returns SPV_SUCCESS if validation rules are satisfied for NoSignedWrap or
  1733. // NoUnsignedWrap decorations. Otherwise emits a diagnostic and returns
  1734. // something other than SPV_SUCCESS. Assumes each decoration on a group has been
  1735. // propagated down to the group members.
  1736. spv_result_t CheckIntegerWrapDecoration(ValidationState_t& vstate,
  1737. const Instruction& inst,
  1738. const Decoration& decoration) {
  1739. switch (inst.opcode()) {
  1740. case spv::Op::OpIAdd:
  1741. case spv::Op::OpISub:
  1742. case spv::Op::OpIMul:
  1743. case spv::Op::OpShiftLeftLogical:
  1744. case spv::Op::OpSNegate:
  1745. return SPV_SUCCESS;
  1746. case spv::Op::OpExtInst:
  1747. case spv::Op::OpExtInstWithForwardRefsKHR:
  1748. // TODO(dneto): Only certain extended instructions allow these
  1749. // decorations. For now allow anything.
  1750. return SPV_SUCCESS;
  1751. default:
  1752. break;
  1753. }
  1754. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1755. << (decoration.dec_type() == spv::Decoration::NoSignedWrap
  1756. ? "NoSignedWrap"
  1757. : "NoUnsignedWrap")
  1758. << " decoration may not be applied to "
  1759. << spvOpcodeString(inst.opcode());
  1760. }
  1761. // Returns SPV_SUCCESS if validation rules are satisfied for the Component
  1762. // decoration. Otherwise emits a diagnostic and returns something other than
  1763. // SPV_SUCCESS.
  1764. spv_result_t CheckComponentDecoration(ValidationState_t& vstate,
  1765. const Instruction& inst,
  1766. const Decoration& decoration) {
  1767. assert(inst.id() && "Parser ensures the target of the decoration has an ID");
  1768. assert(decoration.params().size() == 1 &&
  1769. "Grammar ensures Component has one parameter");
  1770. uint32_t type_id;
  1771. if (decoration.struct_member_index() == Decoration::kInvalidMember) {
  1772. // The target must be a memory object declaration.
  1773. const auto opcode = inst.opcode();
  1774. if (opcode != spv::Op::OpVariable &&
  1775. opcode != spv::Op::OpFunctionParameter) {
  1776. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1777. << "Target of Component decoration must be a memory object "
  1778. "declaration (a variable or a function parameter)";
  1779. }
  1780. // Only valid for the Input and Output Storage Classes.
  1781. const auto storage_class = opcode == spv::Op::OpVariable
  1782. ? inst.GetOperandAs<spv::StorageClass>(2)
  1783. : spv::StorageClass::Max;
  1784. if (storage_class != spv::StorageClass::Input &&
  1785. storage_class != spv::StorageClass::Output &&
  1786. storage_class != spv::StorageClass::Max) {
  1787. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1788. << "Target of Component decoration is invalid: must point to a "
  1789. "Storage Class of Input(1) or Output(3). Found Storage "
  1790. "Class "
  1791. << uint32_t(storage_class);
  1792. }
  1793. type_id = inst.type_id();
  1794. if (vstate.IsPointerType(type_id)) {
  1795. const auto pointer = vstate.FindDef(type_id);
  1796. type_id = pointer->GetOperandAs<uint32_t>(2);
  1797. }
  1798. } else {
  1799. if (inst.opcode() != spv::Op::OpTypeStruct) {
  1800. return vstate.diag(SPV_ERROR_INVALID_DATA, &inst)
  1801. << "Attempted to get underlying data type via member index for "
  1802. "non-struct type.";
  1803. }
  1804. type_id = inst.word(decoration.struct_member_index() + 2);
  1805. }
  1806. if (spvIsVulkanEnv(vstate.context()->target_env)) {
  1807. // Strip the array, if present.
  1808. while (vstate.GetIdOpcode(type_id) == spv::Op::OpTypeArray) {
  1809. type_id = vstate.FindDef(type_id)->word(2u);
  1810. }
  1811. if (!vstate.IsIntScalarOrVectorType(type_id) &&
  1812. !vstate.IsFloatScalarOrVectorType(type_id)) {
  1813. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1814. << vstate.VkErrorID(10583)
  1815. << "Component decoration specified for type "
  1816. << vstate.getIdName(type_id) << " that is not a scalar or vector";
  1817. }
  1818. const auto component = decoration.params()[0];
  1819. if (component > 3) {
  1820. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1821. << vstate.VkErrorID(4920)
  1822. << "Component decoration value must not be greater than 3";
  1823. }
  1824. const auto dimension = vstate.GetDimension(type_id);
  1825. const auto bit_width = vstate.GetBitWidth(type_id);
  1826. if (bit_width == 16 || bit_width == 32) {
  1827. const auto sum_component = component + dimension;
  1828. if (sum_component > 4) {
  1829. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1830. << vstate.VkErrorID(4921)
  1831. << "Sequence of components starting with " << component
  1832. << " and ending with " << (sum_component - 1)
  1833. << " gets larger than 3";
  1834. }
  1835. } else if (bit_width == 64) {
  1836. if (dimension > 2) {
  1837. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1838. << vstate.VkErrorID(7703)
  1839. << "Component decoration only allowed on 64-bit scalar and "
  1840. "2-component vector";
  1841. }
  1842. if (component == 1 || component == 3) {
  1843. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1844. << vstate.VkErrorID(4923)
  1845. << "Component decoration value must not be 1 or 3 for 64-bit "
  1846. "data types";
  1847. }
  1848. // 64-bit is double per component dimension
  1849. const auto sum_component = component + (2 * dimension);
  1850. if (sum_component > 4) {
  1851. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1852. << vstate.VkErrorID(4922)
  1853. << "Sequence of components starting with " << component
  1854. << " and ending with " << (sum_component - 1)
  1855. << " gets larger than 3";
  1856. }
  1857. }
  1858. }
  1859. return SPV_SUCCESS;
  1860. }
  1861. // Returns SPV_SUCCESS if validation rules are satisfied for the Block
  1862. // decoration. Otherwise emits a diagnostic and returns something other than
  1863. // SPV_SUCCESS.
  1864. spv_result_t CheckBlockDecoration(ValidationState_t& vstate,
  1865. const Instruction& inst,
  1866. const Decoration& decoration) {
  1867. assert(inst.id() && "Parser ensures the target of the decoration has an ID");
  1868. if (inst.opcode() != spv::Op::OpTypeStruct) {
  1869. const char* const dec_name = decoration.dec_type() == spv::Decoration::Block
  1870. ? "Block"
  1871. : "BufferBlock";
  1872. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1873. << dec_name << " decoration on a non-struct type.";
  1874. }
  1875. return SPV_SUCCESS;
  1876. }
  1877. spv_result_t CheckLocationDecoration(ValidationState_t& vstate,
  1878. const Instruction& inst,
  1879. const Decoration& decoration) {
  1880. if (inst.opcode() == spv::Op::OpVariable) return SPV_SUCCESS;
  1881. if (decoration.struct_member_index() != Decoration::kInvalidMember &&
  1882. inst.opcode() == spv::Op::OpTypeStruct) {
  1883. return SPV_SUCCESS;
  1884. }
  1885. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1886. << "Location decoration can only be applied to a variable or member "
  1887. "of a structure type";
  1888. }
  1889. spv_result_t CheckRelaxPrecisionDecoration(ValidationState_t& vstate,
  1890. const Instruction& inst,
  1891. const Decoration& decoration) {
  1892. // This is not the most precise check, but the rules for RelaxPrecision are
  1893. // very general, and it will be difficult to implement precisely. For now,
  1894. // I will only check for the cases that cause problems for the optimizer.
  1895. if (!spvOpcodeGeneratesType(inst.opcode())) {
  1896. return SPV_SUCCESS;
  1897. }
  1898. if (decoration.struct_member_index() != Decoration::kInvalidMember &&
  1899. inst.opcode() == spv::Op::OpTypeStruct) {
  1900. return SPV_SUCCESS;
  1901. }
  1902. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  1903. << "RelaxPrecision decoration cannot be applied to a type";
  1904. }
  1905. #define PASS_OR_BAIL_AT_LINE(X, LINE) \
  1906. { \
  1907. spv_result_t e##LINE = (X); \
  1908. if (e##LINE != SPV_SUCCESS) return e##LINE; \
  1909. } static_assert(true, "require extra semicolon")
  1910. #define PASS_OR_BAIL(X) PASS_OR_BAIL_AT_LINE(X, __LINE__)
  1911. // Check rules for decorations where we start from the decoration rather
  1912. // than the decorated object. Assumes each decoration on a group have been
  1913. // propagated down to the group members.
  1914. spv_result_t CheckDecorationsFromDecoration(ValidationState_t& vstate) {
  1915. // Some rules are only checked for shaders.
  1916. const bool is_shader = vstate.HasCapability(spv::Capability::Shader);
  1917. for (const auto& kv : vstate.id_decorations()) {
  1918. const uint32_t id = kv.first;
  1919. const auto& decorations = kv.second;
  1920. if (decorations.empty()) continue;
  1921. const Instruction* inst = vstate.FindDef(id);
  1922. assert(inst);
  1923. // We assume the decorations applied to a decoration group have already
  1924. // been propagated down to the group members.
  1925. if (inst->opcode() == spv::Op::OpDecorationGroup) continue;
  1926. for (const auto& decoration : decorations) {
  1927. switch (decoration.dec_type()) {
  1928. case spv::Decoration::Component:
  1929. PASS_OR_BAIL(CheckComponentDecoration(vstate, *inst, decoration));
  1930. break;
  1931. case spv::Decoration::FPRoundingMode:
  1932. if (is_shader)
  1933. PASS_OR_BAIL(
  1934. CheckFPRoundingModeForShaders(vstate, *inst, decoration));
  1935. break;
  1936. case spv::Decoration::NonWritable:
  1937. PASS_OR_BAIL(CheckNonWritableDecoration(vstate, *inst, decoration));
  1938. break;
  1939. case spv::Decoration::Uniform:
  1940. case spv::Decoration::UniformId:
  1941. PASS_OR_BAIL(CheckUniformDecoration(vstate, *inst, decoration));
  1942. break;
  1943. case spv::Decoration::NoSignedWrap:
  1944. case spv::Decoration::NoUnsignedWrap:
  1945. PASS_OR_BAIL(CheckIntegerWrapDecoration(vstate, *inst, decoration));
  1946. break;
  1947. case spv::Decoration::Block:
  1948. case spv::Decoration::BufferBlock:
  1949. PASS_OR_BAIL(CheckBlockDecoration(vstate, *inst, decoration));
  1950. break;
  1951. case spv::Decoration::Location:
  1952. PASS_OR_BAIL(CheckLocationDecoration(vstate, *inst, decoration));
  1953. break;
  1954. case spv::Decoration::RelaxedPrecision:
  1955. PASS_OR_BAIL(
  1956. CheckRelaxPrecisionDecoration(vstate, *inst, decoration));
  1957. break;
  1958. default:
  1959. break;
  1960. }
  1961. }
  1962. }
  1963. return SPV_SUCCESS;
  1964. }
  1965. bool AllowsLayout(ValidationState_t& vstate, const spv::StorageClass sc) {
  1966. switch (sc) {
  1967. case spv::StorageClass::StorageBuffer:
  1968. case spv::StorageClass::Uniform:
  1969. case spv::StorageClass::PhysicalStorageBuffer:
  1970. case spv::StorageClass::PushConstant:
  1971. // Always explicitly laid out.
  1972. return true;
  1973. case spv::StorageClass::UniformConstant:
  1974. return false;
  1975. case spv::StorageClass::Workgroup:
  1976. return vstate.HasCapability(
  1977. spv::Capability::WorkgroupMemoryExplicitLayoutKHR);
  1978. case spv::StorageClass::Function:
  1979. case spv::StorageClass::Private:
  1980. return vstate.version() <= SPV_SPIRV_VERSION_WORD(1, 4);
  1981. case spv::StorageClass::Input:
  1982. case spv::StorageClass::Output:
  1983. // Block is used generally and mesh shaders use Offset.
  1984. return true;
  1985. default:
  1986. // TODO: Some storage classes in ray tracing use explicit layout
  1987. // decorations, but it is not well documented which. For now treat other
  1988. // storage classes as allowed to be laid out. See Vulkan internal issue
  1989. // 4192.
  1990. return true;
  1991. }
  1992. }
  1993. bool UsesExplicitLayout(ValidationState_t& vstate, uint32_t type_id,
  1994. std::unordered_map<uint32_t, bool>& cache) {
  1995. if (type_id == 0) {
  1996. return false;
  1997. }
  1998. if (cache.count(type_id)) {
  1999. return cache[type_id];
  2000. }
  2001. bool res = false;
  2002. const auto type_inst = vstate.FindDef(type_id);
  2003. if (type_inst->opcode() == spv::Op::OpTypeStruct ||
  2004. type_inst->opcode() == spv::Op::OpTypeArray ||
  2005. type_inst->opcode() == spv::Op::OpTypeRuntimeArray ||
  2006. type_inst->opcode() == spv::Op::OpTypePointer ||
  2007. type_inst->opcode() == spv::Op::OpTypeUntypedPointerKHR) {
  2008. const auto& id_decs = vstate.id_decorations();
  2009. const auto iter = id_decs.find(type_id);
  2010. if (iter != id_decs.end()) {
  2011. bool allowLayoutDecorations = false;
  2012. if (type_inst->opcode() == spv::Op::OpTypePointer) {
  2013. const auto sc = type_inst->GetOperandAs<spv::StorageClass>(1);
  2014. allowLayoutDecorations = AllowsLayout(vstate, sc);
  2015. }
  2016. if (!allowLayoutDecorations) {
  2017. res = std::any_of(
  2018. iter->second.begin(), iter->second.end(), [](const Decoration& d) {
  2019. return d.dec_type() == spv::Decoration::Block ||
  2020. d.dec_type() == spv::Decoration::BufferBlock ||
  2021. d.dec_type() == spv::Decoration::Offset ||
  2022. d.dec_type() == spv::Decoration::ArrayStride ||
  2023. d.dec_type() == spv::Decoration::MatrixStride;
  2024. });
  2025. }
  2026. }
  2027. if (!res) {
  2028. switch (type_inst->opcode()) {
  2029. case spv::Op::OpTypeStruct:
  2030. for (uint32_t i = 1; !res && i < type_inst->operands().size(); i++) {
  2031. res = UsesExplicitLayout(
  2032. vstate, type_inst->GetOperandAs<uint32_t>(i), cache);
  2033. }
  2034. break;
  2035. case spv::Op::OpTypeArray:
  2036. case spv::Op::OpTypeRuntimeArray:
  2037. res = UsesExplicitLayout(vstate, type_inst->GetOperandAs<uint32_t>(1),
  2038. cache);
  2039. break;
  2040. case spv::Op::OpTypePointer: {
  2041. const auto sc = type_inst->GetOperandAs<spv::StorageClass>(1);
  2042. if (!AllowsLayout(vstate, sc)) {
  2043. res = UsesExplicitLayout(
  2044. vstate, type_inst->GetOperandAs<uint32_t>(2), cache);
  2045. }
  2046. }
  2047. default:
  2048. break;
  2049. }
  2050. }
  2051. }
  2052. cache[type_id] = res;
  2053. return res;
  2054. }
  2055. spv_result_t CheckInvalidVulkanExplicitLayout(ValidationState_t& vstate) {
  2056. if (!spvIsVulkanEnv(vstate.context()->target_env)) {
  2057. return SPV_SUCCESS;
  2058. }
  2059. std::unordered_map<uint32_t, bool> cache;
  2060. for (const auto& inst : vstate.ordered_instructions()) {
  2061. const auto type_id = inst.type_id();
  2062. const auto type_inst = vstate.FindDef(type_id);
  2063. uint32_t fail_id = 0;
  2064. // Variables are the main place to check for improper decorations, but some
  2065. // untyped pointer instructions must also be checked since those types may
  2066. // never be instantiated by a variable. Unlike verifying a valid layout,
  2067. // physical storage buffer does not need checked here since it is always
  2068. // explicitly laid out.
  2069. switch (inst.opcode()) {
  2070. case spv::Op::OpVariable:
  2071. case spv::Op::OpUntypedVariableKHR: {
  2072. const auto sc = inst.GetOperandAs<spv::StorageClass>(2);
  2073. auto check_id = type_id;
  2074. if (inst.opcode() == spv::Op::OpUntypedVariableKHR) {
  2075. if (inst.operands().size() > 3) {
  2076. check_id = inst.GetOperandAs<uint32_t>(3);
  2077. }
  2078. }
  2079. if (!AllowsLayout(vstate, sc) &&
  2080. UsesExplicitLayout(vstate, check_id, cache)) {
  2081. fail_id = check_id;
  2082. }
  2083. break;
  2084. }
  2085. case spv::Op::OpUntypedAccessChainKHR:
  2086. case spv::Op::OpUntypedInBoundsAccessChainKHR:
  2087. case spv::Op::OpUntypedPtrAccessChainKHR:
  2088. case spv::Op::OpUntypedInBoundsPtrAccessChainKHR: {
  2089. // Check both the base type and return type. The return type may have an
  2090. // invalid array stride.
  2091. const auto sc = type_inst->GetOperandAs<spv::StorageClass>(1);
  2092. const auto base_type_id = inst.GetOperandAs<uint32_t>(2);
  2093. if (!AllowsLayout(vstate, sc)) {
  2094. if (UsesExplicitLayout(vstate, base_type_id, cache)) {
  2095. fail_id = base_type_id;
  2096. } else if (UsesExplicitLayout(vstate, type_id, cache)) {
  2097. fail_id = type_id;
  2098. }
  2099. }
  2100. break;
  2101. }
  2102. case spv::Op::OpUntypedArrayLengthKHR: {
  2103. // Check the data type.
  2104. const auto ptr_ty_id =
  2105. vstate.FindDef(inst.GetOperandAs<uint32_t>(3))->type_id();
  2106. const auto ptr_ty = vstate.FindDef(ptr_ty_id);
  2107. const auto sc = ptr_ty->GetOperandAs<spv::StorageClass>(1);
  2108. const auto base_type_id = inst.GetOperandAs<uint32_t>(2);
  2109. if (!AllowsLayout(vstate, sc) &&
  2110. UsesExplicitLayout(vstate, base_type_id, cache)) {
  2111. fail_id = base_type_id;
  2112. }
  2113. break;
  2114. }
  2115. case spv::Op::OpLoad: {
  2116. const auto ptr_id = inst.GetOperandAs<uint32_t>(2);
  2117. const auto ptr_type = vstate.FindDef(vstate.FindDef(ptr_id)->type_id());
  2118. if (ptr_type->opcode() == spv::Op::OpTypeUntypedPointerKHR) {
  2119. // For untyped pointers check the return type for an invalid layout.
  2120. const auto sc = ptr_type->GetOperandAs<spv::StorageClass>(1);
  2121. if (!AllowsLayout(vstate, sc) &&
  2122. UsesExplicitLayout(vstate, type_id, cache)) {
  2123. fail_id = type_id;
  2124. }
  2125. }
  2126. break;
  2127. }
  2128. case spv::Op::OpStore: {
  2129. const auto ptr_id = inst.GetOperandAs<uint32_t>(1);
  2130. const auto ptr_type = vstate.FindDef(vstate.FindDef(ptr_id)->type_id());
  2131. if (ptr_type->opcode() == spv::Op::OpTypeUntypedPointerKHR) {
  2132. // For untyped pointers, check the type of the data operand for an
  2133. // invalid layout.
  2134. const auto sc = ptr_type->GetOperandAs<spv::StorageClass>(1);
  2135. const auto data_type_id = vstate.GetOperandTypeId(&inst, 2);
  2136. if (!AllowsLayout(vstate, sc) &&
  2137. UsesExplicitLayout(vstate, data_type_id, cache)) {
  2138. fail_id = inst.GetOperandAs<uint32_t>(2);
  2139. }
  2140. }
  2141. break;
  2142. }
  2143. default:
  2144. break;
  2145. }
  2146. if (fail_id != 0) {
  2147. return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
  2148. << "Invalid explicit layout decorations on type for operand "
  2149. << vstate.getIdName(fail_id);
  2150. }
  2151. }
  2152. return SPV_SUCCESS;
  2153. }
  2154. } // namespace
  2155. spv_result_t ValidateDecorations(ValidationState_t& vstate) {
  2156. if (auto error = CheckImportedVariableInitialization(vstate)) return error;
  2157. if (auto error = CheckDecorationsOfEntryPoints(vstate)) return error;
  2158. if (auto error = CheckDecorationsOfBuffers(vstate)) return error;
  2159. if (auto error = CheckDecorationsCompatibility(vstate)) return error;
  2160. if (auto error = CheckLinkageAttrOfFunctions(vstate)) return error;
  2161. if (auto error = CheckVulkanMemoryModelDeprecatedDecorations(vstate))
  2162. return error;
  2163. if (auto error = CheckDecorationsFromDecoration(vstate)) return error;
  2164. if (auto error = CheckInvalidVulkanExplicitLayout(vstate)) return error;
  2165. return SPV_SUCCESS;
  2166. }
  2167. } // namespace val
  2168. } // namespace spvtools