validate_builtins.cpp 96 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386
  1. // Copyright (c) 2018 Google LLC.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Validates correctness of built-in variables.
  15. #include "validate.h"
  16. #include <functional>
  17. #include <list>
  18. #include <map>
  19. #include <set>
  20. #include <sstream>
  21. #include <stack>
  22. #include <unordered_map>
  23. #include <vector>
  24. #include "diagnostic.h"
  25. #include "opcode.h"
  26. #include "spirv_target_env.h"
  27. #include "util/bitutils.h"
  28. #include "val/instruction.h"
  29. #include "val/validation_state.h"
  30. namespace libspirv {
  31. namespace {
  32. // Returns a short textual description of the id defined by the given
  33. // instruction.
  34. std::string GetIdDesc(const Instruction& inst) {
  35. std::ostringstream ss;
  36. ss << "ID <" << inst.id() << "> (Op" << spvOpcodeString(inst.opcode()) << ")";
  37. return ss.str();
  38. }
  39. // Gets underlying data type which is
  40. // - member type if instruction is OpTypeStruct
  41. // (member index is taken from decoration).
  42. // - data type if id creates a pointer.
  43. // - type of the constant if instruction is OpConst or OpSpecConst.
  44. //
  45. // Fails in any other case. The function is based on built-ins allowed by
  46. // the Vulkan spec.
  47. // TODO: If non-Vulkan validation rules are added then it might need
  48. // to be refactored.
  49. spv_result_t GetUnderlyingType(const ValidationState_t& _,
  50. const Decoration& decoration,
  51. const Instruction& inst,
  52. uint32_t* underlying_type) {
  53. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  54. assert(inst.opcode() == SpvOpTypeStruct);
  55. *underlying_type = inst.word(decoration.struct_member_index() + 2);
  56. return SPV_SUCCESS;
  57. }
  58. assert(inst.opcode() != SpvOpTypeStruct);
  59. if (spvOpcodeIsConstant(inst.opcode())) {
  60. *underlying_type = inst.type_id();
  61. return SPV_SUCCESS;
  62. }
  63. uint32_t storage_class = 0;
  64. if (!_.GetPointerTypeInfo(inst.type_id(), underlying_type, &storage_class)) {
  65. return _.diag(SPV_ERROR_INVALID_DATA)
  66. << GetIdDesc(inst)
  67. << " is decorated with BuiltIn. BuiltIn decoration should only be "
  68. "applied to struct types, variables and constants.";
  69. }
  70. return SPV_SUCCESS;
  71. }
  72. // Returns Storage Class used by the instruction if applicable.
  73. // Returns SpvStorageClassMax if not.
  74. SpvStorageClass GetStorageClass(const Instruction& inst) {
  75. switch (inst.opcode()) {
  76. case SpvOpTypePointer:
  77. case SpvOpTypeForwardPointer: {
  78. return SpvStorageClass(inst.word(2));
  79. }
  80. case SpvOpVariable: {
  81. return SpvStorageClass(inst.word(3));
  82. }
  83. case SpvOpGenericCastToPtrExplicit: {
  84. return SpvStorageClass(inst.word(4));
  85. }
  86. default: { break; }
  87. }
  88. return SpvStorageClassMax;
  89. }
  90. // Helper class managing validation of built-ins.
  91. // TODO: Generic functionality of this class can be moved into
  92. // ValidationState_t to be made available to other users.
  93. class BuiltInsValidator {
  94. public:
  95. BuiltInsValidator(const ValidationState_t& vstate) : _(vstate) {}
  96. // Run validation.
  97. spv_result_t Run();
  98. private:
  99. // Goes through all decorations in the module, if decoration is BuiltIn
  100. // calls ValidateSingleBuiltInAtDefinition().
  101. spv_result_t ValidateBuiltInsAtDefinition();
  102. // Validates the instruction defining an id with built-in decoration.
  103. // Can be called multiple times for the same id, if multiple built-ins are
  104. // specified. Seeds id_to_at_reference_checks_ with decorated ids if needed.
  105. spv_result_t ValidateSingleBuiltInAtDefinition(const Decoration& decoration,
  106. const Instruction& inst);
  107. // The following section contains functions which are called when id defined
  108. // by |inst| is decorated with BuiltIn |decoration|.
  109. // Most functions are specific to a single built-in and have naming scheme:
  110. // ValidateXYZAtDefinition. Some functions are common to multiple kinds of
  111. // BuiltIn.
  112. spv_result_t ValidateClipOrCullDistanceAtDefinition(
  113. const Decoration& decoration, const Instruction& inst);
  114. spv_result_t ValidateFragCoordAtDefinition(const Decoration& decoration,
  115. const Instruction& inst);
  116. spv_result_t ValidateFragDepthAtDefinition(const Decoration& decoration,
  117. const Instruction& inst);
  118. spv_result_t ValidateFrontFacingAtDefinition(const Decoration& decoration,
  119. const Instruction& inst);
  120. spv_result_t ValidateHelperInvocationAtDefinition(
  121. const Decoration& decoration, const Instruction& inst);
  122. spv_result_t ValidateInvocationIdAtDefinition(const Decoration& decoration,
  123. const Instruction& inst);
  124. spv_result_t ValidateInstanceIndexAtDefinition(const Decoration& decoration,
  125. const Instruction& inst);
  126. spv_result_t ValidateLayerOrViewportIndexAtDefinition(
  127. const Decoration& decoration, const Instruction& inst);
  128. spv_result_t ValidatePatchVerticesAtDefinition(const Decoration& decoration,
  129. const Instruction& inst);
  130. spv_result_t ValidatePointCoordAtDefinition(const Decoration& decoration,
  131. const Instruction& inst);
  132. spv_result_t ValidatePointSizeAtDefinition(const Decoration& decoration,
  133. const Instruction& inst);
  134. spv_result_t ValidatePositionAtDefinition(const Decoration& decoration,
  135. const Instruction& inst);
  136. spv_result_t ValidatePrimitiveIdAtDefinition(const Decoration& decoration,
  137. const Instruction& inst);
  138. spv_result_t ValidateSampleIdAtDefinition(const Decoration& decoration,
  139. const Instruction& inst);
  140. spv_result_t ValidateSampleMaskAtDefinition(const Decoration& decoration,
  141. const Instruction& inst);
  142. spv_result_t ValidateSamplePositionAtDefinition(const Decoration& decoration,
  143. const Instruction& inst);
  144. spv_result_t ValidateTessCoordAtDefinition(const Decoration& decoration,
  145. const Instruction& inst);
  146. spv_result_t ValidateTessLevelOuterAtDefinition(const Decoration& decoration,
  147. const Instruction& inst);
  148. spv_result_t ValidateTessLevelInnerAtDefinition(const Decoration& decoration,
  149. const Instruction& inst);
  150. spv_result_t ValidateVertexIndexAtDefinition(const Decoration& decoration,
  151. const Instruction& inst);
  152. spv_result_t ValidateWorkgroupSizeAtDefinition(const Decoration& decoration,
  153. const Instruction& inst);
  154. // Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId.
  155. spv_result_t ValidateComputeShaderI32Vec3InputAtDefinition(
  156. const Decoration& decoration, const Instruction& inst);
  157. // The following section contains functions which are called when id defined
  158. // by |referenced_inst| is
  159. // 1. referenced by |referenced_from_inst|
  160. // 2. dependent on |built_in_inst| which is decorated with BuiltIn
  161. // |decoration|. Most functions are specific to a single built-in and have
  162. // naming scheme: ValidateXYZAtReference. Some functions are common to
  163. // multiple kinds of BuiltIn.
  164. spv_result_t ValidateFragCoordAtReference(
  165. const Decoration& decoration, const Instruction& built_in_inst,
  166. const Instruction& referenced_inst,
  167. const Instruction& referenced_from_inst);
  168. spv_result_t ValidateFragDepthAtReference(
  169. const Decoration& decoration, const Instruction& built_in_inst,
  170. const Instruction& referenced_inst,
  171. const Instruction& referenced_from_inst);
  172. spv_result_t ValidateFrontFacingAtReference(
  173. const Decoration& decoration, const Instruction& built_in_inst,
  174. const Instruction& referenced_inst,
  175. const Instruction& referenced_from_inst);
  176. spv_result_t ValidateHelperInvocationAtReference(
  177. const Decoration& decoration, const Instruction& built_in_inst,
  178. const Instruction& referenced_inst,
  179. const Instruction& referenced_from_inst);
  180. spv_result_t ValidateInvocationIdAtReference(
  181. const Decoration& decoration, const Instruction& built_in_inst,
  182. const Instruction& referenced_inst,
  183. const Instruction& referenced_from_inst);
  184. spv_result_t ValidateInstanceIndexAtReference(
  185. const Decoration& decoration, const Instruction& built_in_inst,
  186. const Instruction& referenced_inst,
  187. const Instruction& referenced_from_inst);
  188. spv_result_t ValidatePatchVerticesAtReference(
  189. const Decoration& decoration, const Instruction& built_in_inst,
  190. const Instruction& referenced_inst,
  191. const Instruction& referenced_from_inst);
  192. spv_result_t ValidatePointCoordAtReference(
  193. const Decoration& decoration, const Instruction& built_in_inst,
  194. const Instruction& referenced_inst,
  195. const Instruction& referenced_from_inst);
  196. spv_result_t ValidatePointSizeAtReference(
  197. const Decoration& decoration, const Instruction& built_in_inst,
  198. const Instruction& referenced_inst,
  199. const Instruction& referenced_from_inst);
  200. spv_result_t ValidatePositionAtReference(
  201. const Decoration& decoration, const Instruction& built_in_inst,
  202. const Instruction& referenced_inst,
  203. const Instruction& referenced_from_inst);
  204. spv_result_t ValidatePrimitiveIdAtReference(
  205. const Decoration& decoration, const Instruction& built_in_inst,
  206. const Instruction& referenced_inst,
  207. const Instruction& referenced_from_inst);
  208. spv_result_t ValidateSampleIdAtReference(
  209. const Decoration& decoration, const Instruction& built_in_inst,
  210. const Instruction& referenced_inst,
  211. const Instruction& referenced_from_inst);
  212. spv_result_t ValidateSampleMaskAtReference(
  213. const Decoration& decoration, const Instruction& built_in_inst,
  214. const Instruction& referenced_inst,
  215. const Instruction& referenced_from_inst);
  216. spv_result_t ValidateSamplePositionAtReference(
  217. const Decoration& decoration, const Instruction& built_in_inst,
  218. const Instruction& referenced_inst,
  219. const Instruction& referenced_from_inst);
  220. spv_result_t ValidateTessCoordAtReference(
  221. const Decoration& decoration, const Instruction& built_in_inst,
  222. const Instruction& referenced_inst,
  223. const Instruction& referenced_from_inst);
  224. spv_result_t ValidateTessLevelAtReference(
  225. const Decoration& decoration, const Instruction& built_in_inst,
  226. const Instruction& referenced_inst,
  227. const Instruction& referenced_from_inst);
  228. spv_result_t ValidateVertexIndexAtReference(
  229. const Decoration& decoration, const Instruction& built_in_inst,
  230. const Instruction& referenced_inst,
  231. const Instruction& referenced_from_inst);
  232. spv_result_t ValidateLayerOrViewportIndexAtReference(
  233. const Decoration& decoration, const Instruction& built_in_inst,
  234. const Instruction& referenced_inst,
  235. const Instruction& referenced_from_inst);
  236. spv_result_t ValidateWorkgroupSizeAtReference(
  237. const Decoration& decoration, const Instruction& built_in_inst,
  238. const Instruction& referenced_inst,
  239. const Instruction& referenced_from_inst);
  240. spv_result_t ValidateClipOrCullDistanceAtReference(
  241. const Decoration& decoration, const Instruction& built_in_inst,
  242. const Instruction& referenced_inst,
  243. const Instruction& referenced_from_inst);
  244. // Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId.
  245. spv_result_t ValidateComputeShaderI32Vec3InputAtReference(
  246. const Decoration& decoration, const Instruction& built_in_inst,
  247. const Instruction& referenced_inst,
  248. const Instruction& referenced_from_inst);
  249. // Validates that |built_in_inst| is not (even indirectly) referenced from
  250. // within a function which can be called with |execution_model|.
  251. //
  252. // |comment| - text explaining why the restriction was imposed.
  253. // |decoration| - BuiltIn decoration which causes the restriction.
  254. // |referenced_inst| - instruction which is dependent on |built_in_inst| and
  255. // defines the id which was referenced.
  256. // |referenced_from_inst| - instruction which references id defined by
  257. // |referenced_inst| from within a function.
  258. spv_result_t ValidateNotCalledWithExecutionModel(
  259. const char* comment, SpvExecutionModel execution_model,
  260. const Decoration& decoration, const Instruction& built_in_inst,
  261. const Instruction& referenced_inst,
  262. const Instruction& referenced_from_inst);
  263. // The following section contains functions which check that the decorated
  264. // variable has the type specified in the function name. |diag| would be
  265. // called with a corresponding error message, if validation is not successful.
  266. spv_result_t ValidateBool(
  267. const Decoration& decoration, const Instruction& inst,
  268. const std::function<spv_result_t(const std::string& message)>& diag);
  269. spv_result_t ValidateI32(
  270. const Decoration& decoration, const Instruction& inst,
  271. const std::function<spv_result_t(const std::string& message)>& diag);
  272. spv_result_t ValidateI32Vec(
  273. const Decoration& decoration, const Instruction& inst,
  274. uint32_t num_components,
  275. const std::function<spv_result_t(const std::string& message)>& diag);
  276. spv_result_t ValidateI32Arr(
  277. const Decoration& decoration, const Instruction& inst,
  278. const std::function<spv_result_t(const std::string& message)>& diag);
  279. spv_result_t ValidateF32(
  280. const Decoration& decoration, const Instruction& inst,
  281. const std::function<spv_result_t(const std::string& message)>& diag);
  282. spv_result_t ValidateF32Vec(
  283. const Decoration& decoration, const Instruction& inst,
  284. uint32_t num_components,
  285. const std::function<spv_result_t(const std::string& message)>& diag);
  286. // If |num_components| is zero, the number of components is not checked.
  287. spv_result_t ValidateF32Arr(
  288. const Decoration& decoration, const Instruction& inst,
  289. uint32_t num_components,
  290. const std::function<spv_result_t(const std::string& message)>& diag);
  291. // Generates strings like "Member #0 of struct ID <2>".
  292. std::string GetDefinitionDesc(const Decoration& decoration,
  293. const Instruction& inst) const;
  294. // Generates strings like "ID <51> (OpTypePointer) is referencing ID <2>
  295. // (OpTypeStruct) which is decorated with BuiltIn Position".
  296. std::string GetReferenceDesc(
  297. const Decoration& decoration, const Instruction& built_in_inst,
  298. const Instruction& referenced_inst,
  299. const Instruction& referenced_from_inst,
  300. SpvExecutionModel execution_model = SpvExecutionModelMax) const;
  301. // Generates strings like "ID <51> (OpTypePointer) uses storage class
  302. // UniformConstant".
  303. std::string GetStorageClassDesc(const Instruction& inst) const;
  304. // Updates inner working of the class. Is called sequentially for every
  305. // instruction.
  306. void Update(const Instruction& inst);
  307. // Traverses call tree and computes function_to_entry_points_.
  308. void ComputeFunctionToEntryPointMapping();
  309. const ValidationState_t& _;
  310. // Mapping id -> list of rules which validate instruction referencing the
  311. // id. Rules can create new rules and add them to this container.
  312. // Using std::map, and not std::unordered_map to avoid iterator invalidation
  313. // during rehashing.
  314. std::map<uint32_t, std::list<std::function<spv_result_t(const Instruction&)>>>
  315. id_to_at_reference_checks_;
  316. // Id of the function we are currently inside. 0 if not inside a function.
  317. uint32_t function_id_ = 0;
  318. // Entry points which can (indirectly) call the current function.
  319. // The pointer either points to a vector inside to function_to_entry_points_
  320. // or to no_entry_points_. The pointer is guaranteed to never be null.
  321. const std::vector<uint32_t> no_entry_points;
  322. const std::vector<uint32_t>* entry_points_ = &no_entry_points;
  323. // Mapping function -> array of entry points inside this
  324. // module which can (indirectly) call the function.
  325. std::unordered_map<uint32_t, std::vector<uint32_t>> function_to_entry_points_;
  326. // Execution models with which the current function can be called.
  327. std::set<SpvExecutionModel> execution_models_;
  328. };
  329. void BuiltInsValidator::Update(const Instruction& inst) {
  330. const SpvOp opcode = inst.opcode();
  331. if (opcode == SpvOpFunction) {
  332. // Entering a function.
  333. assert(function_id_ == 0);
  334. function_id_ = inst.id();
  335. execution_models_.clear();
  336. const auto it = function_to_entry_points_.find(function_id_);
  337. if (it == function_to_entry_points_.end()) {
  338. entry_points_ = &no_entry_points;
  339. } else {
  340. entry_points_ = &it->second;
  341. // Collect execution models from all entry points from which the current
  342. // function can be called.
  343. for (const uint32_t entry_point : *entry_points_) {
  344. if (const auto* models = _.GetExecutionModels(entry_point)) {
  345. execution_models_.insert(models->begin(), models->end());
  346. }
  347. }
  348. }
  349. }
  350. if (opcode == SpvOpFunctionEnd) {
  351. // Exiting a function.
  352. assert(function_id_ != 0);
  353. function_id_ = 0;
  354. entry_points_ = &no_entry_points;
  355. execution_models_.clear();
  356. }
  357. }
  358. void BuiltInsValidator::ComputeFunctionToEntryPointMapping() {
  359. // TODO: Move this into validation_state.cpp.
  360. for (const uint32_t entry_point : _.entry_points()) {
  361. std::stack<uint32_t> call_stack;
  362. std::set<uint32_t> visited;
  363. call_stack.push(entry_point);
  364. while (!call_stack.empty()) {
  365. const uint32_t called_func_id = call_stack.top();
  366. call_stack.pop();
  367. if (!visited.insert(called_func_id).second) continue;
  368. function_to_entry_points_[called_func_id].push_back(entry_point);
  369. const Function* called_func = _.function(called_func_id);
  370. assert(called_func);
  371. for (const uint32_t new_call : called_func->function_call_targets()) {
  372. call_stack.push(new_call);
  373. }
  374. }
  375. }
  376. }
  377. std::string BuiltInsValidator::GetDefinitionDesc(
  378. const Decoration& decoration, const Instruction& inst) const {
  379. std::ostringstream ss;
  380. if (decoration.struct_member_index() != Decoration::kInvalidMember) {
  381. assert(inst.opcode() == SpvOpTypeStruct);
  382. ss << "Member #" << decoration.struct_member_index();
  383. ss << " of struct ID <" << inst.id() << ">";
  384. } else {
  385. ss << GetIdDesc(inst);
  386. }
  387. return ss.str();
  388. }
  389. std::string BuiltInsValidator::GetReferenceDesc(
  390. const Decoration& decoration, const Instruction& built_in_inst,
  391. const Instruction& referenced_inst, const Instruction& referenced_from_inst,
  392. SpvExecutionModel execution_model) const {
  393. std::ostringstream ss;
  394. ss << GetIdDesc(referenced_from_inst) << " is referencing "
  395. << GetIdDesc(referenced_inst);
  396. if (built_in_inst.id() != referenced_inst.id()) {
  397. ss << " which is dependent on " << GetIdDesc(built_in_inst);
  398. }
  399. ss << " which is decorated with BuiltIn ";
  400. ss << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  401. decoration.params()[0]);
  402. if (function_id_) {
  403. ss << " in function <" << function_id_ << ">";
  404. if (execution_model != SpvExecutionModelMax) {
  405. ss << " called with execution model ";
  406. ss << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_EXECUTION_MODEL,
  407. execution_model);
  408. }
  409. }
  410. ss << ".";
  411. return ss.str();
  412. }
  413. std::string BuiltInsValidator::GetStorageClassDesc(
  414. const Instruction& inst) const {
  415. std::ostringstream ss;
  416. ss << GetIdDesc(inst) << " uses storage class ";
  417. ss << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_STORAGE_CLASS,
  418. GetStorageClass(inst));
  419. ss << ".";
  420. return ss.str();
  421. }
  422. spv_result_t BuiltInsValidator::ValidateBool(
  423. const Decoration& decoration, const Instruction& inst,
  424. const std::function<spv_result_t(const std::string& message)>& diag) {
  425. uint32_t underlying_type = 0;
  426. if (spv_result_t error =
  427. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  428. return error;
  429. }
  430. if (!_.IsBoolScalarType(underlying_type)) {
  431. return diag(GetDefinitionDesc(decoration, inst) + " is not a bool scalar.");
  432. }
  433. return SPV_SUCCESS;
  434. }
  435. spv_result_t BuiltInsValidator::ValidateI32(
  436. const Decoration& decoration, const Instruction& inst,
  437. const std::function<spv_result_t(const std::string& message)>& diag) {
  438. uint32_t underlying_type = 0;
  439. if (spv_result_t error =
  440. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  441. return error;
  442. }
  443. if (!_.IsIntScalarType(underlying_type)) {
  444. return diag(GetDefinitionDesc(decoration, inst) + " is not an int scalar.");
  445. }
  446. const uint32_t bit_width = _.GetBitWidth(underlying_type);
  447. if (bit_width != 32) {
  448. std::ostringstream ss;
  449. ss << GetDefinitionDesc(decoration, inst) << " has bit width " << bit_width
  450. << ".";
  451. return diag(ss.str());
  452. }
  453. return SPV_SUCCESS;
  454. }
  455. spv_result_t BuiltInsValidator::ValidateF32(
  456. const Decoration& decoration, const Instruction& inst,
  457. const std::function<spv_result_t(const std::string& message)>& diag) {
  458. uint32_t underlying_type = 0;
  459. if (spv_result_t error =
  460. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  461. return error;
  462. }
  463. if (!_.IsFloatScalarType(underlying_type)) {
  464. return diag(GetDefinitionDesc(decoration, inst) +
  465. " is not a float scalar.");
  466. }
  467. const uint32_t bit_width = _.GetBitWidth(underlying_type);
  468. if (bit_width != 32) {
  469. std::ostringstream ss;
  470. ss << GetDefinitionDesc(decoration, inst) << " has bit width " << bit_width
  471. << ".";
  472. return diag(ss.str());
  473. }
  474. return SPV_SUCCESS;
  475. }
  476. spv_result_t BuiltInsValidator::ValidateI32Vec(
  477. const Decoration& decoration, const Instruction& inst,
  478. uint32_t num_components,
  479. const std::function<spv_result_t(const std::string& message)>& diag) {
  480. uint32_t underlying_type = 0;
  481. if (spv_result_t error =
  482. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  483. return error;
  484. }
  485. if (!_.IsIntVectorType(underlying_type)) {
  486. return diag(GetDefinitionDesc(decoration, inst) + " is not an int vector.");
  487. }
  488. const uint32_t actual_num_components = _.GetDimension(underlying_type);
  489. if (_.GetDimension(underlying_type) != num_components) {
  490. std::ostringstream ss;
  491. ss << GetDefinitionDesc(decoration, inst) << " has "
  492. << actual_num_components << " components.";
  493. return diag(ss.str());
  494. }
  495. const uint32_t bit_width = _.GetBitWidth(underlying_type);
  496. if (bit_width != 32) {
  497. std::ostringstream ss;
  498. ss << GetDefinitionDesc(decoration, inst)
  499. << " has components with bit width " << bit_width << ".";
  500. return diag(ss.str());
  501. }
  502. return SPV_SUCCESS;
  503. }
  504. spv_result_t BuiltInsValidator::ValidateF32Vec(
  505. const Decoration& decoration, const Instruction& inst,
  506. uint32_t num_components,
  507. const std::function<spv_result_t(const std::string& message)>& diag) {
  508. uint32_t underlying_type = 0;
  509. if (spv_result_t error =
  510. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  511. return error;
  512. }
  513. if (!_.IsFloatVectorType(underlying_type)) {
  514. return diag(GetDefinitionDesc(decoration, inst) +
  515. " is not a float vector.");
  516. }
  517. const uint32_t actual_num_components = _.GetDimension(underlying_type);
  518. if (_.GetDimension(underlying_type) != num_components) {
  519. std::ostringstream ss;
  520. ss << GetDefinitionDesc(decoration, inst) << " has "
  521. << actual_num_components << " components.";
  522. return diag(ss.str());
  523. }
  524. const uint32_t bit_width = _.GetBitWidth(underlying_type);
  525. if (bit_width != 32) {
  526. std::ostringstream ss;
  527. ss << GetDefinitionDesc(decoration, inst)
  528. << " has components with bit width " << bit_width << ".";
  529. return diag(ss.str());
  530. }
  531. return SPV_SUCCESS;
  532. }
  533. spv_result_t BuiltInsValidator::ValidateI32Arr(
  534. const Decoration& decoration, const Instruction& inst,
  535. const std::function<spv_result_t(const std::string& message)>& diag) {
  536. uint32_t underlying_type = 0;
  537. if (spv_result_t error =
  538. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  539. return error;
  540. }
  541. const Instruction* const type_inst = _.FindDef(underlying_type);
  542. if (type_inst->opcode() != SpvOpTypeArray) {
  543. return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
  544. }
  545. const uint32_t component_type = type_inst->word(2);
  546. if (!_.IsIntScalarType(component_type)) {
  547. return diag(GetDefinitionDesc(decoration, inst) +
  548. " components are not int scalar.");
  549. }
  550. const uint32_t bit_width = _.GetBitWidth(component_type);
  551. if (bit_width != 32) {
  552. std::ostringstream ss;
  553. ss << GetDefinitionDesc(decoration, inst)
  554. << " has components with bit width " << bit_width << ".";
  555. return diag(ss.str());
  556. }
  557. return SPV_SUCCESS;
  558. }
  559. spv_result_t BuiltInsValidator::ValidateF32Arr(
  560. const Decoration& decoration, const Instruction& inst,
  561. uint32_t num_components,
  562. const std::function<spv_result_t(const std::string& message)>& diag) {
  563. uint32_t underlying_type = 0;
  564. if (spv_result_t error =
  565. GetUnderlyingType(_, decoration, inst, &underlying_type)) {
  566. return error;
  567. }
  568. const Instruction* const type_inst = _.FindDef(underlying_type);
  569. if (type_inst->opcode() != SpvOpTypeArray) {
  570. return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
  571. }
  572. const uint32_t component_type = type_inst->word(2);
  573. if (!_.IsFloatScalarType(component_type)) {
  574. return diag(GetDefinitionDesc(decoration, inst) +
  575. " components are not float scalar.");
  576. }
  577. const uint32_t bit_width = _.GetBitWidth(component_type);
  578. if (bit_width != 32) {
  579. std::ostringstream ss;
  580. ss << GetDefinitionDesc(decoration, inst)
  581. << " has components with bit width " << bit_width << ".";
  582. return diag(ss.str());
  583. }
  584. if (num_components != 0) {
  585. uint64_t actual_num_components = 0;
  586. if (!_.GetConstantValUint64(type_inst->word(3), &actual_num_components)) {
  587. assert(0 && "Array type definition is corrupt");
  588. }
  589. if (actual_num_components != num_components) {
  590. std::ostringstream ss;
  591. ss << GetDefinitionDesc(decoration, inst) << " has "
  592. << actual_num_components << " components.";
  593. return diag(ss.str());
  594. }
  595. }
  596. return SPV_SUCCESS;
  597. }
  598. spv_result_t BuiltInsValidator::ValidateNotCalledWithExecutionModel(
  599. const char* comment, SpvExecutionModel execution_model,
  600. const Decoration& decoration, const Instruction& built_in_inst,
  601. const Instruction& referenced_inst,
  602. const Instruction& referenced_from_inst) {
  603. if (function_id_) {
  604. if (execution_models_.count(execution_model)) {
  605. const char* execution_model_str = _.grammar().lookupOperandName(
  606. SPV_OPERAND_TYPE_EXECUTION_MODEL, execution_model);
  607. const char* built_in_str = _.grammar().lookupOperandName(
  608. SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]);
  609. return _.diag(SPV_ERROR_INVALID_DATA)
  610. << comment << " " << GetIdDesc(referenced_inst) << " depends on "
  611. << GetIdDesc(built_in_inst) << " which is decorated with BuiltIn "
  612. << built_in_str << "."
  613. << " Id <" << referenced_inst.id() << "> is later referenced by "
  614. << GetIdDesc(referenced_from_inst) << " in function <"
  615. << function_id_ << "> which is called with execution model "
  616. << execution_model_str << ".";
  617. }
  618. } else {
  619. // Propagate this rule to all dependant ids in the global scope.
  620. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  621. std::bind(&BuiltInsValidator::ValidateNotCalledWithExecutionModel, this,
  622. comment, execution_model, decoration, built_in_inst,
  623. referenced_from_inst, std::placeholders::_1));
  624. }
  625. return SPV_SUCCESS;
  626. }
  627. spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtDefinition(
  628. const Decoration& decoration, const Instruction& inst) {
  629. if (spvIsVulkanEnv(_.context()->target_env)) {
  630. if (spv_result_t error = ValidateF32Arr(
  631. decoration, inst, /* Any number of components */ 0,
  632. [this, &decoration](const std::string& message) -> spv_result_t {
  633. return _.diag(SPV_ERROR_INVALID_DATA)
  634. << "According to the Vulkan spec BuiltIn "
  635. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  636. decoration.params()[0])
  637. << " variable needs to be a 32-bit float array. "
  638. << message;
  639. })) {
  640. return error;
  641. }
  642. }
  643. // Seed at reference checks with this built-in.
  644. return ValidateClipOrCullDistanceAtReference(decoration, inst, inst, inst);
  645. }
  646. spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference(
  647. const Decoration& decoration, const Instruction& built_in_inst,
  648. const Instruction& referenced_inst,
  649. const Instruction& referenced_from_inst) {
  650. if (spvIsVulkanEnv(_.context()->target_env)) {
  651. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  652. if (storage_class != SpvStorageClassMax &&
  653. storage_class != SpvStorageClassInput &&
  654. storage_class != SpvStorageClassOutput) {
  655. return _.diag(SPV_ERROR_INVALID_DATA)
  656. << "Vulkan spec allows BuiltIn "
  657. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  658. decoration.params()[0])
  659. << " to be only used for variables with Input or Output storage "
  660. "class. "
  661. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  662. referenced_from_inst)
  663. << " " << GetStorageClassDesc(referenced_from_inst);
  664. }
  665. if (storage_class == SpvStorageClassInput) {
  666. assert(function_id_ == 0);
  667. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  668. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this,
  669. "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
  670. "used for variables with Input storage class if execution model is "
  671. "Vertex.",
  672. SpvExecutionModelVertex, decoration, built_in_inst,
  673. referenced_from_inst, std::placeholders::_1));
  674. }
  675. if (storage_class == SpvStorageClassOutput) {
  676. assert(function_id_ == 0);
  677. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  678. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this,
  679. "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
  680. "used for variables with Output storage class if execution model is "
  681. "Fragment.",
  682. SpvExecutionModelFragment, decoration, built_in_inst,
  683. referenced_from_inst, std::placeholders::_1));
  684. }
  685. for (const SpvExecutionModel execution_model : execution_models_) {
  686. switch (execution_model) {
  687. case SpvExecutionModelFragment:
  688. case SpvExecutionModelVertex:
  689. case SpvExecutionModelTessellationControl:
  690. case SpvExecutionModelTessellationEvaluation:
  691. case SpvExecutionModelGeometry: {
  692. // Ok.
  693. break;
  694. }
  695. default: {
  696. return _.diag(SPV_ERROR_INVALID_DATA)
  697. << "Vulkan spec allows BuiltIn "
  698. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  699. decoration.params()[0])
  700. << " to be used only with Fragment, Vertex, "
  701. "TessellationControl, TessellationEvaluation or Geometry "
  702. "execution models. "
  703. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  704. referenced_from_inst, execution_model);
  705. }
  706. }
  707. }
  708. }
  709. if (function_id_ == 0) {
  710. // Propagate this rule to all dependant ids in the global scope.
  711. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  712. std::bind(&BuiltInsValidator::ValidateClipOrCullDistanceAtReference,
  713. this, decoration, built_in_inst, referenced_from_inst,
  714. std::placeholders::_1));
  715. }
  716. return SPV_SUCCESS;
  717. }
  718. spv_result_t BuiltInsValidator::ValidateFragCoordAtDefinition(
  719. const Decoration& decoration, const Instruction& inst) {
  720. if (spvIsVulkanEnv(_.context()->target_env)) {
  721. if (spv_result_t error = ValidateF32Vec(
  722. decoration, inst, 4,
  723. [this](const std::string& message) -> spv_result_t {
  724. return _.diag(SPV_ERROR_INVALID_DATA)
  725. << "According to the Vulkan spec BuiltIn FragCoord "
  726. "variable needs to be a 4-component 32-bit float "
  727. "vector. "
  728. << message;
  729. })) {
  730. return error;
  731. }
  732. }
  733. // Seed at reference checks with this built-in.
  734. return ValidateFragCoordAtReference(decoration, inst, inst, inst);
  735. }
  736. spv_result_t BuiltInsValidator::ValidateFragCoordAtReference(
  737. const Decoration& decoration, const Instruction& built_in_inst,
  738. const Instruction& referenced_inst,
  739. const Instruction& referenced_from_inst) {
  740. if (spvIsVulkanEnv(_.context()->target_env)) {
  741. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  742. if (storage_class != SpvStorageClassMax &&
  743. storage_class != SpvStorageClassInput) {
  744. return _.diag(SPV_ERROR_INVALID_DATA)
  745. << "Vulkan spec allows BuiltIn FragCoord to be only used for "
  746. "variables with Input storage class. "
  747. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  748. referenced_from_inst)
  749. << " " << GetStorageClassDesc(referenced_from_inst);
  750. }
  751. for (const SpvExecutionModel execution_model : execution_models_) {
  752. if (execution_model != SpvExecutionModelFragment) {
  753. return _.diag(SPV_ERROR_INVALID_DATA)
  754. << "Vulkan spec allows BuiltIn FragCoord to be used only with "
  755. "Fragment execution model. "
  756. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  757. referenced_from_inst, execution_model);
  758. }
  759. }
  760. }
  761. if (function_id_ == 0) {
  762. // Propagate this rule to all dependant ids in the global scope.
  763. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  764. &BuiltInsValidator::ValidateFragCoordAtReference, this, decoration,
  765. built_in_inst, referenced_from_inst, std::placeholders::_1));
  766. }
  767. return SPV_SUCCESS;
  768. }
  769. spv_result_t BuiltInsValidator::ValidateFragDepthAtDefinition(
  770. const Decoration& decoration, const Instruction& inst) {
  771. if (spvIsVulkanEnv(_.context()->target_env)) {
  772. if (spv_result_t error = ValidateF32(
  773. decoration, inst,
  774. [this](const std::string& message) -> spv_result_t {
  775. return _.diag(SPV_ERROR_INVALID_DATA)
  776. << "According to the Vulkan spec BuiltIn FragDepth "
  777. "variable needs to be a 32-bit float scalar. "
  778. << message;
  779. })) {
  780. return error;
  781. }
  782. }
  783. // Seed at reference checks with this built-in.
  784. return ValidateFragDepthAtReference(decoration, inst, inst, inst);
  785. }
  786. spv_result_t BuiltInsValidator::ValidateFragDepthAtReference(
  787. const Decoration& decoration, const Instruction& built_in_inst,
  788. const Instruction& referenced_inst,
  789. const Instruction& referenced_from_inst) {
  790. if (spvIsVulkanEnv(_.context()->target_env)) {
  791. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  792. if (storage_class != SpvStorageClassMax &&
  793. storage_class != SpvStorageClassOutput) {
  794. return _.diag(SPV_ERROR_INVALID_DATA)
  795. << "Vulkan spec allows BuiltIn FragDepth to be only used for "
  796. "variables with Output storage class. "
  797. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  798. referenced_from_inst)
  799. << " " << GetStorageClassDesc(referenced_from_inst);
  800. }
  801. for (const SpvExecutionModel execution_model : execution_models_) {
  802. if (execution_model != SpvExecutionModelFragment) {
  803. return _.diag(SPV_ERROR_INVALID_DATA)
  804. << "Vulkan spec allows BuiltIn FragDepth to be used only with "
  805. "Fragment execution model. "
  806. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  807. referenced_from_inst, execution_model);
  808. }
  809. }
  810. for (const uint32_t entry_point : *entry_points_) {
  811. // Every entry point from which this function is called needs to have
  812. // Execution Mode DepthReplacing.
  813. const auto* modes = _.GetExecutionModes(entry_point);
  814. if (!modes || !modes->count(SpvExecutionModeDepthReplacing)) {
  815. return _.diag(SPV_ERROR_INVALID_DATA)
  816. << "Vulkan spec requires DepthReplacing execution mode to be "
  817. "declared when using BuiltIn FragDepth. "
  818. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  819. referenced_from_inst);
  820. }
  821. }
  822. }
  823. if (function_id_ == 0) {
  824. // Propagate this rule to all dependant ids in the global scope.
  825. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  826. &BuiltInsValidator::ValidateFragDepthAtReference, this, decoration,
  827. built_in_inst, referenced_from_inst, std::placeholders::_1));
  828. }
  829. return SPV_SUCCESS;
  830. }
  831. spv_result_t BuiltInsValidator::ValidateFrontFacingAtDefinition(
  832. const Decoration& decoration, const Instruction& inst) {
  833. if (spvIsVulkanEnv(_.context()->target_env)) {
  834. if (spv_result_t error = ValidateBool(
  835. decoration, inst,
  836. [this](const std::string& message) -> spv_result_t {
  837. return _.diag(SPV_ERROR_INVALID_DATA)
  838. << "According to the Vulkan spec BuiltIn FrontFacing "
  839. "variable needs to be a bool scalar. "
  840. << message;
  841. })) {
  842. return error;
  843. }
  844. }
  845. // Seed at reference checks with this built-in.
  846. return ValidateFrontFacingAtReference(decoration, inst, inst, inst);
  847. }
  848. spv_result_t BuiltInsValidator::ValidateFrontFacingAtReference(
  849. const Decoration& decoration, const Instruction& built_in_inst,
  850. const Instruction& referenced_inst,
  851. const Instruction& referenced_from_inst) {
  852. if (spvIsVulkanEnv(_.context()->target_env)) {
  853. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  854. if (storage_class != SpvStorageClassMax &&
  855. storage_class != SpvStorageClassInput) {
  856. return _.diag(SPV_ERROR_INVALID_DATA)
  857. << "Vulkan spec allows BuiltIn FrontFacing to be only used for "
  858. "variables with Input storage class. "
  859. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  860. referenced_from_inst)
  861. << " " << GetStorageClassDesc(referenced_from_inst);
  862. }
  863. for (const SpvExecutionModel execution_model : execution_models_) {
  864. if (execution_model != SpvExecutionModelFragment) {
  865. return _.diag(SPV_ERROR_INVALID_DATA)
  866. << "Vulkan spec allows BuiltIn FrontFacing to be used only with "
  867. "Fragment execution model. "
  868. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  869. referenced_from_inst, execution_model);
  870. }
  871. }
  872. }
  873. if (function_id_ == 0) {
  874. // Propagate this rule to all dependant ids in the global scope.
  875. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  876. &BuiltInsValidator::ValidateFrontFacingAtReference, this, decoration,
  877. built_in_inst, referenced_from_inst, std::placeholders::_1));
  878. }
  879. return SPV_SUCCESS;
  880. }
  881. spv_result_t BuiltInsValidator::ValidateHelperInvocationAtDefinition(
  882. const Decoration& decoration, const Instruction& inst) {
  883. if (spvIsVulkanEnv(_.context()->target_env)) {
  884. if (spv_result_t error = ValidateBool(
  885. decoration, inst,
  886. [this](const std::string& message) -> spv_result_t {
  887. return _.diag(SPV_ERROR_INVALID_DATA)
  888. << "According to the Vulkan spec BuiltIn HelperInvocation "
  889. "variable needs to be a bool scalar. "
  890. << message;
  891. })) {
  892. return error;
  893. }
  894. }
  895. // Seed at reference checks with this built-in.
  896. return ValidateHelperInvocationAtReference(decoration, inst, inst, inst);
  897. }
  898. spv_result_t BuiltInsValidator::ValidateHelperInvocationAtReference(
  899. const Decoration& decoration, const Instruction& built_in_inst,
  900. const Instruction& referenced_inst,
  901. const Instruction& referenced_from_inst) {
  902. if (spvIsVulkanEnv(_.context()->target_env)) {
  903. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  904. if (storage_class != SpvStorageClassMax &&
  905. storage_class != SpvStorageClassInput) {
  906. return _.diag(SPV_ERROR_INVALID_DATA)
  907. << "Vulkan spec allows BuiltIn HelperInvocation to be only used "
  908. "for variables with Input storage class. "
  909. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  910. referenced_from_inst)
  911. << " " << GetStorageClassDesc(referenced_from_inst);
  912. }
  913. for (const SpvExecutionModel execution_model : execution_models_) {
  914. if (execution_model != SpvExecutionModelFragment) {
  915. return _.diag(SPV_ERROR_INVALID_DATA)
  916. << "Vulkan spec allows BuiltIn HelperInvocation to be used only "
  917. "with Fragment execution model. "
  918. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  919. referenced_from_inst, execution_model);
  920. }
  921. }
  922. }
  923. if (function_id_ == 0) {
  924. // Propagate this rule to all dependant ids in the global scope.
  925. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  926. std::bind(&BuiltInsValidator::ValidateHelperInvocationAtReference, this,
  927. decoration, built_in_inst, referenced_from_inst,
  928. std::placeholders::_1));
  929. }
  930. return SPV_SUCCESS;
  931. }
  932. spv_result_t BuiltInsValidator::ValidateInvocationIdAtDefinition(
  933. const Decoration& decoration, const Instruction& inst) {
  934. if (spvIsVulkanEnv(_.context()->target_env)) {
  935. if (spv_result_t error = ValidateI32(
  936. decoration, inst,
  937. [this](const std::string& message) -> spv_result_t {
  938. return _.diag(SPV_ERROR_INVALID_DATA)
  939. << "According to the Vulkan spec BuiltIn InvocationId "
  940. "variable needs to be a 32-bit int scalar. "
  941. << message;
  942. })) {
  943. return error;
  944. }
  945. }
  946. // Seed at reference checks with this built-in.
  947. return ValidateInvocationIdAtReference(decoration, inst, inst, inst);
  948. }
  949. spv_result_t BuiltInsValidator::ValidateInvocationIdAtReference(
  950. const Decoration& decoration, const Instruction& built_in_inst,
  951. const Instruction& referenced_inst,
  952. const Instruction& referenced_from_inst) {
  953. if (spvIsVulkanEnv(_.context()->target_env)) {
  954. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  955. if (storage_class != SpvStorageClassMax &&
  956. storage_class != SpvStorageClassInput) {
  957. return _.diag(SPV_ERROR_INVALID_DATA)
  958. << "Vulkan spec allows BuiltIn InvocationId to be only used for "
  959. "variables with Input storage class. "
  960. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  961. referenced_from_inst)
  962. << " " << GetStorageClassDesc(referenced_from_inst);
  963. }
  964. for (const SpvExecutionModel execution_model : execution_models_) {
  965. if (execution_model != SpvExecutionModelTessellationControl &&
  966. execution_model != SpvExecutionModelGeometry) {
  967. return _.diag(SPV_ERROR_INVALID_DATA)
  968. << "Vulkan spec allows BuiltIn InvocationId to be used only "
  969. "with TessellationControl or Geometry execution models. "
  970. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  971. referenced_from_inst, execution_model);
  972. }
  973. }
  974. }
  975. if (function_id_ == 0) {
  976. // Propagate this rule to all dependant ids in the global scope.
  977. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  978. &BuiltInsValidator::ValidateInvocationIdAtReference, this, decoration,
  979. built_in_inst, referenced_from_inst, std::placeholders::_1));
  980. }
  981. return SPV_SUCCESS;
  982. }
  983. spv_result_t BuiltInsValidator::ValidateInstanceIndexAtDefinition(
  984. const Decoration& decoration, const Instruction& inst) {
  985. if (spvIsVulkanEnv(_.context()->target_env)) {
  986. if (spv_result_t error = ValidateI32(
  987. decoration, inst,
  988. [this](const std::string& message) -> spv_result_t {
  989. return _.diag(SPV_ERROR_INVALID_DATA)
  990. << "According to the Vulkan spec BuiltIn InstanceIndex "
  991. "variable needs to be a 32-bit int scalar. "
  992. << message;
  993. })) {
  994. return error;
  995. }
  996. }
  997. // Seed at reference checks with this built-in.
  998. return ValidateInstanceIndexAtReference(decoration, inst, inst, inst);
  999. }
  1000. spv_result_t BuiltInsValidator::ValidateInstanceIndexAtReference(
  1001. const Decoration& decoration, const Instruction& built_in_inst,
  1002. const Instruction& referenced_inst,
  1003. const Instruction& referenced_from_inst) {
  1004. if (spvIsVulkanEnv(_.context()->target_env)) {
  1005. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1006. if (storage_class != SpvStorageClassMax &&
  1007. storage_class != SpvStorageClassInput) {
  1008. return _.diag(SPV_ERROR_INVALID_DATA)
  1009. << "Vulkan spec allows BuiltIn InstanceIndex to be only used for "
  1010. "variables with Input storage class. "
  1011. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1012. referenced_from_inst)
  1013. << " " << GetStorageClassDesc(referenced_from_inst);
  1014. }
  1015. for (const SpvExecutionModel execution_model : execution_models_) {
  1016. if (execution_model != SpvExecutionModelVertex) {
  1017. return _.diag(SPV_ERROR_INVALID_DATA)
  1018. << "Vulkan spec allows BuiltIn InstanceIndex to be used only "
  1019. "with Vertex execution model. "
  1020. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1021. referenced_from_inst, execution_model);
  1022. }
  1023. }
  1024. }
  1025. if (function_id_ == 0) {
  1026. // Propagate this rule to all dependant ids in the global scope.
  1027. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1028. &BuiltInsValidator::ValidateInstanceIndexAtReference, this, decoration,
  1029. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1030. }
  1031. return SPV_SUCCESS;
  1032. }
  1033. spv_result_t BuiltInsValidator::ValidatePatchVerticesAtDefinition(
  1034. const Decoration& decoration, const Instruction& inst) {
  1035. if (spvIsVulkanEnv(_.context()->target_env)) {
  1036. if (spv_result_t error = ValidateI32(
  1037. decoration, inst,
  1038. [this](const std::string& message) -> spv_result_t {
  1039. return _.diag(SPV_ERROR_INVALID_DATA)
  1040. << "According to the Vulkan spec BuiltIn PatchVertices "
  1041. "variable needs to be a 32-bit int scalar. "
  1042. << message;
  1043. })) {
  1044. return error;
  1045. }
  1046. }
  1047. // Seed at reference checks with this built-in.
  1048. return ValidatePatchVerticesAtReference(decoration, inst, inst, inst);
  1049. }
  1050. spv_result_t BuiltInsValidator::ValidatePatchVerticesAtReference(
  1051. const Decoration& decoration, const Instruction& built_in_inst,
  1052. const Instruction& referenced_inst,
  1053. const Instruction& referenced_from_inst) {
  1054. if (spvIsVulkanEnv(_.context()->target_env)) {
  1055. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1056. if (storage_class != SpvStorageClassMax &&
  1057. storage_class != SpvStorageClassInput) {
  1058. return _.diag(SPV_ERROR_INVALID_DATA)
  1059. << "Vulkan spec allows BuiltIn PatchVertices to be only used for "
  1060. "variables with Input storage class. "
  1061. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1062. referenced_from_inst)
  1063. << " " << GetStorageClassDesc(referenced_from_inst);
  1064. }
  1065. for (const SpvExecutionModel execution_model : execution_models_) {
  1066. if (execution_model != SpvExecutionModelTessellationControl &&
  1067. execution_model != SpvExecutionModelTessellationEvaluation) {
  1068. return _.diag(SPV_ERROR_INVALID_DATA)
  1069. << "Vulkan spec allows BuiltIn PatchVertices to be used only "
  1070. "with TessellationControl or TessellationEvaluation "
  1071. "execution models. "
  1072. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1073. referenced_from_inst, execution_model);
  1074. }
  1075. }
  1076. }
  1077. if (function_id_ == 0) {
  1078. // Propagate this rule to all dependant ids in the global scope.
  1079. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1080. &BuiltInsValidator::ValidatePatchVerticesAtReference, this, decoration,
  1081. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1082. }
  1083. return SPV_SUCCESS;
  1084. }
  1085. spv_result_t BuiltInsValidator::ValidatePointCoordAtDefinition(
  1086. const Decoration& decoration, const Instruction& inst) {
  1087. if (spvIsVulkanEnv(_.context()->target_env)) {
  1088. if (spv_result_t error = ValidateF32Vec(
  1089. decoration, inst, 2,
  1090. [this](const std::string& message) -> spv_result_t {
  1091. return _.diag(SPV_ERROR_INVALID_DATA)
  1092. << "According to the Vulkan spec BuiltIn PointCoord "
  1093. "variable needs to be a 2-component 32-bit float "
  1094. "vector. "
  1095. << message;
  1096. })) {
  1097. return error;
  1098. }
  1099. }
  1100. // Seed at reference checks with this built-in.
  1101. return ValidatePointCoordAtReference(decoration, inst, inst, inst);
  1102. }
  1103. spv_result_t BuiltInsValidator::ValidatePointCoordAtReference(
  1104. const Decoration& decoration, const Instruction& built_in_inst,
  1105. const Instruction& referenced_inst,
  1106. const Instruction& referenced_from_inst) {
  1107. if (spvIsVulkanEnv(_.context()->target_env)) {
  1108. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1109. if (storage_class != SpvStorageClassMax &&
  1110. storage_class != SpvStorageClassInput) {
  1111. return _.diag(SPV_ERROR_INVALID_DATA)
  1112. << "Vulkan spec allows BuiltIn PointCoord to be only used for "
  1113. "variables with Input storage class. "
  1114. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1115. referenced_from_inst)
  1116. << " " << GetStorageClassDesc(referenced_from_inst);
  1117. }
  1118. for (const SpvExecutionModel execution_model : execution_models_) {
  1119. if (execution_model != SpvExecutionModelFragment) {
  1120. return _.diag(SPV_ERROR_INVALID_DATA)
  1121. << "Vulkan spec allows BuiltIn PointCoord to be used only with "
  1122. "Fragment execution model. "
  1123. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1124. referenced_from_inst, execution_model);
  1125. }
  1126. }
  1127. }
  1128. if (function_id_ == 0) {
  1129. // Propagate this rule to all dependant ids in the global scope.
  1130. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1131. &BuiltInsValidator::ValidatePointCoordAtReference, this, decoration,
  1132. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1133. }
  1134. return SPV_SUCCESS;
  1135. }
  1136. spv_result_t BuiltInsValidator::ValidatePointSizeAtDefinition(
  1137. const Decoration& decoration, const Instruction& inst) {
  1138. if (spvIsVulkanEnv(_.context()->target_env)) {
  1139. if (spv_result_t error = ValidateF32(
  1140. decoration, inst,
  1141. [this](const std::string& message) -> spv_result_t {
  1142. return _.diag(SPV_ERROR_INVALID_DATA)
  1143. << "According to the Vulkan spec BuiltIn PointSize "
  1144. "variable needs to be a 32-bit float scalar. "
  1145. << message;
  1146. })) {
  1147. return error;
  1148. }
  1149. }
  1150. // Seed at reference checks with this built-in.
  1151. return ValidatePointSizeAtReference(decoration, inst, inst, inst);
  1152. }
  1153. spv_result_t BuiltInsValidator::ValidatePointSizeAtReference(
  1154. const Decoration& decoration, const Instruction& built_in_inst,
  1155. const Instruction& referenced_inst,
  1156. const Instruction& referenced_from_inst) {
  1157. if (spvIsVulkanEnv(_.context()->target_env)) {
  1158. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1159. if (storage_class != SpvStorageClassMax &&
  1160. storage_class != SpvStorageClassInput &&
  1161. storage_class != SpvStorageClassOutput) {
  1162. return _.diag(SPV_ERROR_INVALID_DATA)
  1163. << "Vulkan spec allows BuiltIn PointSize to be only used for "
  1164. "variables with Input or Output storage class. "
  1165. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1166. referenced_from_inst)
  1167. << " " << GetStorageClassDesc(referenced_from_inst);
  1168. }
  1169. if (storage_class == SpvStorageClassInput) {
  1170. assert(function_id_ == 0);
  1171. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1172. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this,
  1173. "Vulkan spec doesn't allow BuiltIn PointSize to be used for "
  1174. "variables with Input storage class if execution model is Vertex.",
  1175. SpvExecutionModelVertex, decoration, built_in_inst,
  1176. referenced_from_inst, std::placeholders::_1));
  1177. }
  1178. for (const SpvExecutionModel execution_model : execution_models_) {
  1179. switch (execution_model) {
  1180. case SpvExecutionModelVertex:
  1181. case SpvExecutionModelTessellationControl:
  1182. case SpvExecutionModelTessellationEvaluation:
  1183. case SpvExecutionModelGeometry: {
  1184. // Ok.
  1185. break;
  1186. }
  1187. default: {
  1188. return _.diag(SPV_ERROR_INVALID_DATA)
  1189. << "Vulkan spec allows BuiltIn PointSize to be used only with "
  1190. "Vertex, TessellationControl, TessellationEvaluation or "
  1191. "Geometry execution models. "
  1192. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1193. referenced_from_inst, execution_model);
  1194. }
  1195. }
  1196. }
  1197. }
  1198. if (function_id_ == 0) {
  1199. // Propagate this rule to all dependant ids in the global scope.
  1200. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1201. &BuiltInsValidator::ValidatePointSizeAtReference, this, decoration,
  1202. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1203. }
  1204. return SPV_SUCCESS;
  1205. }
  1206. spv_result_t BuiltInsValidator::ValidatePositionAtDefinition(
  1207. const Decoration& decoration, const Instruction& inst) {
  1208. if (spvIsVulkanEnv(_.context()->target_env)) {
  1209. if (spv_result_t error = ValidateF32Vec(
  1210. decoration, inst, 4,
  1211. [this](const std::string& message) -> spv_result_t {
  1212. return _.diag(SPV_ERROR_INVALID_DATA)
  1213. << "According to the Vulkan spec BuiltIn Position "
  1214. "variable needs to be a 4-component 32-bit float "
  1215. "vector. "
  1216. << message;
  1217. })) {
  1218. return error;
  1219. }
  1220. }
  1221. // Seed at reference checks with this built-in.
  1222. return ValidatePositionAtReference(decoration, inst, inst, inst);
  1223. }
  1224. spv_result_t BuiltInsValidator::ValidatePositionAtReference(
  1225. const Decoration& decoration, const Instruction& built_in_inst,
  1226. const Instruction& referenced_inst,
  1227. const Instruction& referenced_from_inst) {
  1228. if (spvIsVulkanEnv(_.context()->target_env)) {
  1229. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1230. if (storage_class != SpvStorageClassMax &&
  1231. storage_class != SpvStorageClassInput &&
  1232. storage_class != SpvStorageClassOutput) {
  1233. return _.diag(SPV_ERROR_INVALID_DATA)
  1234. << "Vulkan spec allows BuiltIn Position to be only used for "
  1235. "variables with Input or Output storage class. "
  1236. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1237. referenced_from_inst)
  1238. << " " << GetStorageClassDesc(referenced_from_inst);
  1239. }
  1240. if (storage_class == SpvStorageClassInput) {
  1241. assert(function_id_ == 0);
  1242. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1243. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this,
  1244. "Vulkan spec doesn't allow BuiltIn Position to be used for variables "
  1245. "with Input storage class if execution model is Vertex.",
  1246. SpvExecutionModelVertex, decoration, built_in_inst,
  1247. referenced_from_inst, std::placeholders::_1));
  1248. }
  1249. for (const SpvExecutionModel execution_model : execution_models_) {
  1250. switch (execution_model) {
  1251. case SpvExecutionModelVertex:
  1252. case SpvExecutionModelTessellationControl:
  1253. case SpvExecutionModelTessellationEvaluation:
  1254. case SpvExecutionModelGeometry: {
  1255. // Ok.
  1256. break;
  1257. }
  1258. default: {
  1259. return _.diag(SPV_ERROR_INVALID_DATA)
  1260. << "Vulkan spec allows BuiltIn Position to be used only with "
  1261. "Vertex, TessellationControl, TessellationEvaluation or "
  1262. "Geometry execution models. "
  1263. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1264. referenced_from_inst, execution_model);
  1265. }
  1266. }
  1267. }
  1268. }
  1269. if (function_id_ == 0) {
  1270. // Propagate this rule to all dependant ids in the global scope.
  1271. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1272. &BuiltInsValidator::ValidatePositionAtReference, this, decoration,
  1273. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1274. }
  1275. return SPV_SUCCESS;
  1276. }
  1277. spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtDefinition(
  1278. const Decoration& decoration, const Instruction& inst) {
  1279. if (spvIsVulkanEnv(_.context()->target_env)) {
  1280. if (spv_result_t error = ValidateI32(
  1281. decoration, inst,
  1282. [this](const std::string& message) -> spv_result_t {
  1283. return _.diag(SPV_ERROR_INVALID_DATA)
  1284. << "According to the Vulkan spec BuiltIn PrimitiveId "
  1285. "variable needs to be a 32-bit int scalar. "
  1286. << message;
  1287. })) {
  1288. return error;
  1289. }
  1290. }
  1291. // Seed at reference checks with this built-in.
  1292. return ValidatePrimitiveIdAtReference(decoration, inst, inst, inst);
  1293. }
  1294. spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtReference(
  1295. const Decoration& decoration, const Instruction& built_in_inst,
  1296. const Instruction& referenced_inst,
  1297. const Instruction& referenced_from_inst) {
  1298. if (spvIsVulkanEnv(_.context()->target_env)) {
  1299. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1300. if (storage_class != SpvStorageClassMax &&
  1301. storage_class != SpvStorageClassInput &&
  1302. storage_class != SpvStorageClassOutput) {
  1303. return _.diag(SPV_ERROR_INVALID_DATA)
  1304. << "Vulkan spec allows BuiltIn PrimitiveId to be only used for "
  1305. "variables with Input or Output storage class. "
  1306. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1307. referenced_from_inst)
  1308. << " " << GetStorageClassDesc(referenced_from_inst);
  1309. }
  1310. if (storage_class == SpvStorageClassOutput) {
  1311. assert(function_id_ == 0);
  1312. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1313. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this,
  1314. "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
  1315. "variables with Output storage class if execution model is "
  1316. "TessellationControl.",
  1317. SpvExecutionModelTessellationControl, decoration, built_in_inst,
  1318. referenced_from_inst, std::placeholders::_1));
  1319. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1320. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this,
  1321. "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
  1322. "variables with Output storage class if execution model is "
  1323. "TessellationEvaluation.",
  1324. SpvExecutionModelTessellationEvaluation, decoration, built_in_inst,
  1325. referenced_from_inst, std::placeholders::_1));
  1326. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1327. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this,
  1328. "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
  1329. "variables with Output storage class if execution model is Fragment.",
  1330. SpvExecutionModelFragment, decoration, built_in_inst,
  1331. referenced_from_inst, std::placeholders::_1));
  1332. }
  1333. for (const SpvExecutionModel execution_model : execution_models_) {
  1334. switch (execution_model) {
  1335. case SpvExecutionModelFragment:
  1336. case SpvExecutionModelTessellationControl:
  1337. case SpvExecutionModelTessellationEvaluation:
  1338. case SpvExecutionModelGeometry: {
  1339. // Ok.
  1340. break;
  1341. }
  1342. default: {
  1343. return _.diag(SPV_ERROR_INVALID_DATA)
  1344. << "Vulkan spec allows BuiltIn PrimitiveId to be used only "
  1345. "with Fragment, TessellationControl, "
  1346. "TessellationEvaluation or Geometry execution models. "
  1347. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1348. referenced_from_inst, execution_model);
  1349. }
  1350. }
  1351. }
  1352. }
  1353. if (function_id_ == 0) {
  1354. // Propagate this rule to all dependant ids in the global scope.
  1355. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1356. &BuiltInsValidator::ValidatePrimitiveIdAtReference, this, decoration,
  1357. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1358. }
  1359. return SPV_SUCCESS;
  1360. }
  1361. spv_result_t BuiltInsValidator::ValidateSampleIdAtDefinition(
  1362. const Decoration& decoration, const Instruction& inst) {
  1363. if (spvIsVulkanEnv(_.context()->target_env)) {
  1364. if (spv_result_t error = ValidateI32(
  1365. decoration, inst,
  1366. [this](const std::string& message) -> spv_result_t {
  1367. return _.diag(SPV_ERROR_INVALID_DATA)
  1368. << "According to the Vulkan spec BuiltIn SampleId "
  1369. "variable needs to be a 32-bit int scalar. "
  1370. << message;
  1371. })) {
  1372. return error;
  1373. }
  1374. }
  1375. // Seed at reference checks with this built-in.
  1376. return ValidateSampleIdAtReference(decoration, inst, inst, inst);
  1377. }
  1378. spv_result_t BuiltInsValidator::ValidateSampleIdAtReference(
  1379. const Decoration& decoration, const Instruction& built_in_inst,
  1380. const Instruction& referenced_inst,
  1381. const Instruction& referenced_from_inst) {
  1382. if (spvIsVulkanEnv(_.context()->target_env)) {
  1383. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1384. if (storage_class != SpvStorageClassMax &&
  1385. storage_class != SpvStorageClassInput) {
  1386. return _.diag(SPV_ERROR_INVALID_DATA)
  1387. << "Vulkan spec allows BuiltIn SampleId to be only used for "
  1388. "variables with Input storage class. "
  1389. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1390. referenced_from_inst)
  1391. << " " << GetStorageClassDesc(referenced_from_inst);
  1392. }
  1393. for (const SpvExecutionModel execution_model : execution_models_) {
  1394. if (execution_model != SpvExecutionModelFragment) {
  1395. return _.diag(SPV_ERROR_INVALID_DATA)
  1396. << "Vulkan spec allows BuiltIn SampleId to be used only with "
  1397. "Fragment execution model. "
  1398. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1399. referenced_from_inst, execution_model);
  1400. }
  1401. }
  1402. }
  1403. if (function_id_ == 0) {
  1404. // Propagate this rule to all dependant ids in the global scope.
  1405. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1406. &BuiltInsValidator::ValidateSampleIdAtReference, this, decoration,
  1407. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1408. }
  1409. return SPV_SUCCESS;
  1410. }
  1411. spv_result_t BuiltInsValidator::ValidateSampleMaskAtDefinition(
  1412. const Decoration& decoration, const Instruction& inst) {
  1413. if (spvIsVulkanEnv(_.context()->target_env)) {
  1414. if (spv_result_t error = ValidateI32Arr(
  1415. decoration, inst,
  1416. [this](const std::string& message) -> spv_result_t {
  1417. return _.diag(SPV_ERROR_INVALID_DATA)
  1418. << "According to the Vulkan spec BuiltIn SampleMask "
  1419. "variable needs to be a 32-bit int array. "
  1420. << message;
  1421. })) {
  1422. return error;
  1423. }
  1424. }
  1425. // Seed at reference checks with this built-in.
  1426. return ValidateSampleMaskAtReference(decoration, inst, inst, inst);
  1427. }
  1428. spv_result_t BuiltInsValidator::ValidateSampleMaskAtReference(
  1429. const Decoration& decoration, const Instruction& built_in_inst,
  1430. const Instruction& referenced_inst,
  1431. const Instruction& referenced_from_inst) {
  1432. if (spvIsVulkanEnv(_.context()->target_env)) {
  1433. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1434. if (storage_class != SpvStorageClassMax &&
  1435. storage_class != SpvStorageClassInput &&
  1436. storage_class != SpvStorageClassOutput) {
  1437. return _.diag(SPV_ERROR_INVALID_DATA)
  1438. << "Vulkan spec allows BuiltIn SampleMask to be only used for "
  1439. "variables with Input or Output storage class. "
  1440. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1441. referenced_from_inst)
  1442. << " " << GetStorageClassDesc(referenced_from_inst);
  1443. }
  1444. for (const SpvExecutionModel execution_model : execution_models_) {
  1445. if (execution_model != SpvExecutionModelFragment) {
  1446. return _.diag(SPV_ERROR_INVALID_DATA)
  1447. << "Vulkan spec allows BuiltIn SampleMask to be used only with "
  1448. "Fragment execution model. "
  1449. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1450. referenced_from_inst, execution_model);
  1451. }
  1452. }
  1453. }
  1454. if (function_id_ == 0) {
  1455. // Propagate this rule to all dependant ids in the global scope.
  1456. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1457. &BuiltInsValidator::ValidateSampleMaskAtReference, this, decoration,
  1458. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1459. }
  1460. return SPV_SUCCESS;
  1461. }
  1462. spv_result_t BuiltInsValidator::ValidateSamplePositionAtDefinition(
  1463. const Decoration& decoration, const Instruction& inst) {
  1464. if (spvIsVulkanEnv(_.context()->target_env)) {
  1465. if (spv_result_t error = ValidateF32Vec(
  1466. decoration, inst, 2,
  1467. [this](const std::string& message) -> spv_result_t {
  1468. return _.diag(SPV_ERROR_INVALID_DATA)
  1469. << "According to the Vulkan spec BuiltIn SamplePosition "
  1470. "variable needs to be a 2-component 32-bit float "
  1471. "vector. "
  1472. << message;
  1473. })) {
  1474. return error;
  1475. }
  1476. }
  1477. // Seed at reference checks with this built-in.
  1478. return ValidateSamplePositionAtReference(decoration, inst, inst, inst);
  1479. }
  1480. spv_result_t BuiltInsValidator::ValidateSamplePositionAtReference(
  1481. const Decoration& decoration, const Instruction& built_in_inst,
  1482. const Instruction& referenced_inst,
  1483. const Instruction& referenced_from_inst) {
  1484. if (spvIsVulkanEnv(_.context()->target_env)) {
  1485. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1486. if (storage_class != SpvStorageClassMax &&
  1487. storage_class != SpvStorageClassInput) {
  1488. return _.diag(SPV_ERROR_INVALID_DATA)
  1489. << "Vulkan spec allows BuiltIn SamplePosition to be only used for "
  1490. "variables with Input storage class. "
  1491. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1492. referenced_from_inst)
  1493. << " " << GetStorageClassDesc(referenced_from_inst);
  1494. }
  1495. for (const SpvExecutionModel execution_model : execution_models_) {
  1496. if (execution_model != SpvExecutionModelFragment) {
  1497. return _.diag(SPV_ERROR_INVALID_DATA)
  1498. << "Vulkan spec allows BuiltIn SamplePosition to be used only "
  1499. "with "
  1500. "Fragment execution model. "
  1501. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1502. referenced_from_inst, execution_model);
  1503. }
  1504. }
  1505. }
  1506. if (function_id_ == 0) {
  1507. // Propagate this rule to all dependant ids in the global scope.
  1508. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1509. &BuiltInsValidator::ValidateSamplePositionAtReference, this, decoration,
  1510. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1511. }
  1512. return SPV_SUCCESS;
  1513. }
  1514. spv_result_t BuiltInsValidator::ValidateTessCoordAtDefinition(
  1515. const Decoration& decoration, const Instruction& inst) {
  1516. if (spvIsVulkanEnv(_.context()->target_env)) {
  1517. if (spv_result_t error = ValidateF32Vec(
  1518. decoration, inst, 3,
  1519. [this](const std::string& message) -> spv_result_t {
  1520. return _.diag(SPV_ERROR_INVALID_DATA)
  1521. << "According to the Vulkan spec BuiltIn TessCoord "
  1522. "variable needs to be a 3-component 32-bit float "
  1523. "vector. "
  1524. << message;
  1525. })) {
  1526. return error;
  1527. }
  1528. }
  1529. // Seed at reference checks with this built-in.
  1530. return ValidateTessCoordAtReference(decoration, inst, inst, inst);
  1531. }
  1532. spv_result_t BuiltInsValidator::ValidateTessCoordAtReference(
  1533. const Decoration& decoration, const Instruction& built_in_inst,
  1534. const Instruction& referenced_inst,
  1535. const Instruction& referenced_from_inst) {
  1536. if (spvIsVulkanEnv(_.context()->target_env)) {
  1537. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1538. if (storage_class != SpvStorageClassMax &&
  1539. storage_class != SpvStorageClassInput) {
  1540. return _.diag(SPV_ERROR_INVALID_DATA)
  1541. << "Vulkan spec allows BuiltIn TessCoord to be only used for "
  1542. "variables with Input storage class. "
  1543. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1544. referenced_from_inst)
  1545. << " " << GetStorageClassDesc(referenced_from_inst);
  1546. }
  1547. for (const SpvExecutionModel execution_model : execution_models_) {
  1548. if (execution_model != SpvExecutionModelTessellationEvaluation) {
  1549. return _.diag(SPV_ERROR_INVALID_DATA)
  1550. << "Vulkan spec allows BuiltIn TessCoord to be used only with "
  1551. "TessellationEvaluation execution model. "
  1552. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1553. referenced_from_inst, execution_model);
  1554. }
  1555. }
  1556. }
  1557. if (function_id_ == 0) {
  1558. // Propagate this rule to all dependant ids in the global scope.
  1559. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1560. &BuiltInsValidator::ValidateTessCoordAtReference, this, decoration,
  1561. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1562. }
  1563. return SPV_SUCCESS;
  1564. }
  1565. spv_result_t BuiltInsValidator::ValidateTessLevelOuterAtDefinition(
  1566. const Decoration& decoration, const Instruction& inst) {
  1567. if (spvIsVulkanEnv(_.context()->target_env)) {
  1568. if (spv_result_t error = ValidateF32Arr(
  1569. decoration, inst, 4,
  1570. [this](const std::string& message) -> spv_result_t {
  1571. return _.diag(SPV_ERROR_INVALID_DATA)
  1572. << "According to the Vulkan spec BuiltIn TessLevelOuter "
  1573. "variable needs to be a 4-component 32-bit float "
  1574. "array. "
  1575. << message;
  1576. })) {
  1577. return error;
  1578. }
  1579. }
  1580. // Seed at reference checks with this built-in.
  1581. return ValidateTessLevelAtReference(decoration, inst, inst, inst);
  1582. }
  1583. spv_result_t BuiltInsValidator::ValidateTessLevelInnerAtDefinition(
  1584. const Decoration& decoration, const Instruction& inst) {
  1585. if (spvIsVulkanEnv(_.context()->target_env)) {
  1586. if (spv_result_t error = ValidateF32Arr(
  1587. decoration, inst, 2,
  1588. [this](const std::string& message) -> spv_result_t {
  1589. return _.diag(SPV_ERROR_INVALID_DATA)
  1590. << "According to the Vulkan spec BuiltIn TessLevelOuter "
  1591. "variable needs to be a 2-component 32-bit float "
  1592. "array. "
  1593. << message;
  1594. })) {
  1595. return error;
  1596. }
  1597. }
  1598. // Seed at reference checks with this built-in.
  1599. return ValidateTessLevelAtReference(decoration, inst, inst, inst);
  1600. }
  1601. spv_result_t BuiltInsValidator::ValidateTessLevelAtReference(
  1602. const Decoration& decoration, const Instruction& built_in_inst,
  1603. const Instruction& referenced_inst,
  1604. const Instruction& referenced_from_inst) {
  1605. if (spvIsVulkanEnv(_.context()->target_env)) {
  1606. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1607. if (storage_class != SpvStorageClassMax &&
  1608. storage_class != SpvStorageClassInput &&
  1609. storage_class != SpvStorageClassOutput) {
  1610. return _.diag(SPV_ERROR_INVALID_DATA)
  1611. << "Vulkan spec allows BuiltIn "
  1612. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  1613. decoration.params()[0])
  1614. << " to be only used for variables with Input or Output storage "
  1615. "class. "
  1616. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1617. referenced_from_inst)
  1618. << " " << GetStorageClassDesc(referenced_from_inst);
  1619. }
  1620. if (storage_class == SpvStorageClassInput) {
  1621. assert(function_id_ == 0);
  1622. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1623. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this,
  1624. "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be used "
  1625. "for variables with Input storage class if execution model is "
  1626. "TessellationControl.",
  1627. SpvExecutionModelTessellationControl, decoration, built_in_inst,
  1628. referenced_from_inst, std::placeholders::_1));
  1629. }
  1630. if (storage_class == SpvStorageClassOutput) {
  1631. assert(function_id_ == 0);
  1632. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1633. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this,
  1634. "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be used "
  1635. "for variables with Output storage class if execution model is "
  1636. "TessellationEvaluation.",
  1637. SpvExecutionModelTessellationEvaluation, decoration, built_in_inst,
  1638. referenced_from_inst, std::placeholders::_1));
  1639. }
  1640. for (const SpvExecutionModel execution_model : execution_models_) {
  1641. switch (execution_model) {
  1642. case SpvExecutionModelTessellationControl:
  1643. case SpvExecutionModelTessellationEvaluation: {
  1644. // Ok.
  1645. break;
  1646. }
  1647. default: {
  1648. return _.diag(SPV_ERROR_INVALID_DATA)
  1649. << "Vulkan spec allows BuiltIn "
  1650. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  1651. decoration.params()[0])
  1652. << " to be used only with TessellationControl or "
  1653. "TessellationEvaluation execution models. "
  1654. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1655. referenced_from_inst, execution_model);
  1656. }
  1657. }
  1658. }
  1659. }
  1660. if (function_id_ == 0) {
  1661. // Propagate this rule to all dependant ids in the global scope.
  1662. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1663. &BuiltInsValidator::ValidateTessLevelAtReference, this, decoration,
  1664. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1665. }
  1666. return SPV_SUCCESS;
  1667. }
  1668. spv_result_t BuiltInsValidator::ValidateVertexIndexAtDefinition(
  1669. const Decoration& decoration, const Instruction& inst) {
  1670. if (spvIsVulkanEnv(_.context()->target_env)) {
  1671. if (spv_result_t error = ValidateI32(
  1672. decoration, inst,
  1673. [this](const std::string& message) -> spv_result_t {
  1674. return _.diag(SPV_ERROR_INVALID_DATA)
  1675. << "According to the Vulkan spec BuiltIn VertexIndex "
  1676. "variable needs to be a 32-bit int scalar. "
  1677. << message;
  1678. })) {
  1679. return error;
  1680. }
  1681. }
  1682. // Seed at reference checks with this built-in.
  1683. return ValidateVertexIndexAtReference(decoration, inst, inst, inst);
  1684. }
  1685. spv_result_t BuiltInsValidator::ValidateVertexIndexAtReference(
  1686. const Decoration& decoration, const Instruction& built_in_inst,
  1687. const Instruction& referenced_inst,
  1688. const Instruction& referenced_from_inst) {
  1689. if (spvIsVulkanEnv(_.context()->target_env)) {
  1690. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1691. if (storage_class != SpvStorageClassMax &&
  1692. storage_class != SpvStorageClassInput) {
  1693. return _.diag(SPV_ERROR_INVALID_DATA)
  1694. << "Vulkan spec allows BuiltIn VertexIndex to be only used for "
  1695. "variables with Input storage class. "
  1696. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1697. referenced_from_inst)
  1698. << " " << GetStorageClassDesc(referenced_from_inst);
  1699. }
  1700. for (const SpvExecutionModel execution_model : execution_models_) {
  1701. if (execution_model != SpvExecutionModelVertex) {
  1702. return _.diag(SPV_ERROR_INVALID_DATA)
  1703. << "Vulkan spec allows BuiltIn VertexIndex to be used only with "
  1704. "Vertex execution model. "
  1705. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1706. referenced_from_inst, execution_model);
  1707. }
  1708. }
  1709. }
  1710. if (function_id_ == 0) {
  1711. // Propagate this rule to all dependant ids in the global scope.
  1712. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1713. &BuiltInsValidator::ValidateVertexIndexAtReference, this, decoration,
  1714. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1715. }
  1716. return SPV_SUCCESS;
  1717. }
  1718. spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtDefinition(
  1719. const Decoration& decoration, const Instruction& inst) {
  1720. if (spvIsVulkanEnv(_.context()->target_env)) {
  1721. if (spv_result_t error = ValidateI32(
  1722. decoration, inst,
  1723. [this, &decoration](const std::string& message) -> spv_result_t {
  1724. return _.diag(SPV_ERROR_INVALID_DATA)
  1725. << "According to the Vulkan spec BuiltIn "
  1726. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  1727. decoration.params()[0])
  1728. << "variable needs to be a 32-bit int scalar. " << message;
  1729. })) {
  1730. return error;
  1731. }
  1732. }
  1733. // Seed at reference checks with this built-in.
  1734. return ValidateLayerOrViewportIndexAtReference(decoration, inst, inst, inst);
  1735. }
  1736. spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference(
  1737. const Decoration& decoration, const Instruction& built_in_inst,
  1738. const Instruction& referenced_inst,
  1739. const Instruction& referenced_from_inst) {
  1740. if (spvIsVulkanEnv(_.context()->target_env)) {
  1741. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1742. if (storage_class != SpvStorageClassMax &&
  1743. storage_class != SpvStorageClassInput &&
  1744. storage_class != SpvStorageClassOutput) {
  1745. return _.diag(SPV_ERROR_INVALID_DATA)
  1746. << "Vulkan spec allows BuiltIn "
  1747. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  1748. decoration.params()[0])
  1749. << " to be only used for variables with Input or Output storage "
  1750. "class. "
  1751. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1752. referenced_from_inst)
  1753. << " " << GetStorageClassDesc(referenced_from_inst);
  1754. }
  1755. if (storage_class == SpvStorageClassInput) {
  1756. assert(function_id_ == 0);
  1757. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1758. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this,
  1759. "Vulkan spec doesn't allow BuiltIn Layer and ViewportIndex to be "
  1760. "used for variables with Input storage class if execution model is "
  1761. "Geometry.",
  1762. SpvExecutionModelGeometry, decoration, built_in_inst,
  1763. referenced_from_inst, std::placeholders::_1));
  1764. }
  1765. if (storage_class == SpvStorageClassOutput) {
  1766. assert(function_id_ == 0);
  1767. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1768. &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this,
  1769. "Vulkan spec doesn't allow BuiltIn Layer and ViewportIndex to be "
  1770. "used for variables with Output storage class if execution model is "
  1771. "Fragment.",
  1772. SpvExecutionModelFragment, decoration, built_in_inst,
  1773. referenced_from_inst, std::placeholders::_1));
  1774. }
  1775. for (const SpvExecutionModel execution_model : execution_models_) {
  1776. switch (execution_model) {
  1777. case SpvExecutionModelGeometry:
  1778. case SpvExecutionModelFragment: {
  1779. // Ok.
  1780. break;
  1781. }
  1782. default: {
  1783. return _.diag(SPV_ERROR_INVALID_DATA)
  1784. << "Vulkan spec allows BuiltIn "
  1785. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  1786. decoration.params()[0])
  1787. << " to be used only with Fragment or Geometry execution "
  1788. "models. "
  1789. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1790. referenced_from_inst, execution_model);
  1791. }
  1792. }
  1793. }
  1794. }
  1795. if (function_id_ == 0) {
  1796. // Propagate this rule to all dependant ids in the global scope.
  1797. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
  1798. std::bind(&BuiltInsValidator::ValidateLayerOrViewportIndexAtReference,
  1799. this, decoration, built_in_inst, referenced_from_inst,
  1800. std::placeholders::_1));
  1801. }
  1802. return SPV_SUCCESS;
  1803. }
  1804. spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtDefinition(
  1805. const Decoration& decoration, const Instruction& inst) {
  1806. if (spvIsVulkanEnv(_.context()->target_env)) {
  1807. if (spv_result_t error = ValidateI32Vec(
  1808. decoration, inst, 3,
  1809. [this, &decoration](const std::string& message) -> spv_result_t {
  1810. return _.diag(SPV_ERROR_INVALID_DATA)
  1811. << "According to the Vulkan spec BuiltIn "
  1812. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  1813. decoration.params()[0])
  1814. << " variable needs to be a 3-component 32-bit int "
  1815. "vector. "
  1816. << message;
  1817. })) {
  1818. return error;
  1819. }
  1820. }
  1821. // Seed at reference checks with this built-in.
  1822. return ValidateComputeShaderI32Vec3InputAtReference(decoration, inst, inst,
  1823. inst);
  1824. }
  1825. spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference(
  1826. const Decoration& decoration, const Instruction& built_in_inst,
  1827. const Instruction& referenced_inst,
  1828. const Instruction& referenced_from_inst) {
  1829. if (spvIsVulkanEnv(_.context()->target_env)) {
  1830. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1831. if (storage_class != SpvStorageClassMax &&
  1832. storage_class != SpvStorageClassInput) {
  1833. return _.diag(SPV_ERROR_INVALID_DATA)
  1834. << "Vulkan spec allows BuiltIn "
  1835. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  1836. decoration.params()[0])
  1837. << " to be only used for variables with Input storage class. "
  1838. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1839. referenced_from_inst)
  1840. << " " << GetStorageClassDesc(referenced_from_inst);
  1841. }
  1842. for (const SpvExecutionModel execution_model : execution_models_) {
  1843. if (execution_model != SpvExecutionModelGLCompute) {
  1844. return _.diag(SPV_ERROR_INVALID_DATA)
  1845. << "Vulkan spec allows BuiltIn "
  1846. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  1847. decoration.params()[0])
  1848. << " to be used only with GLCompute execution model. "
  1849. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1850. referenced_from_inst, execution_model);
  1851. }
  1852. }
  1853. }
  1854. if (function_id_ == 0) {
  1855. // Propagate this rule to all dependant ids in the global scope.
  1856. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1857. &BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference, this,
  1858. decoration, built_in_inst, referenced_from_inst,
  1859. std::placeholders::_1));
  1860. }
  1861. return SPV_SUCCESS;
  1862. }
  1863. spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtDefinition(
  1864. const Decoration& decoration, const Instruction& inst) {
  1865. if (spvIsVulkanEnv(_.context()->target_env)) {
  1866. if (!spvOpcodeIsConstant(inst.opcode())) {
  1867. return _.diag(SPV_ERROR_INVALID_DATA)
  1868. << "Vulkan spec requires BuiltIn WorkgroupSize to be a constant. "
  1869. << GetIdDesc(inst) << " is not a constant.";
  1870. }
  1871. if (spv_result_t error = ValidateI32Vec(
  1872. decoration, inst, 3,
  1873. [this](const std::string& message) -> spv_result_t {
  1874. return _.diag(SPV_ERROR_INVALID_DATA)
  1875. << "According to the Vulkan spec BuiltIn WorkgroupSize "
  1876. "variable "
  1877. "needs to be a 3-component 32-bit int vector. "
  1878. << message;
  1879. })) {
  1880. return error;
  1881. }
  1882. }
  1883. // Seed at reference checks with this built-in.
  1884. return ValidateWorkgroupSizeAtReference(decoration, inst, inst, inst);
  1885. }
  1886. spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference(
  1887. const Decoration& decoration, const Instruction& built_in_inst,
  1888. const Instruction& referenced_inst,
  1889. const Instruction& referenced_from_inst) {
  1890. if (spvIsVulkanEnv(_.context()->target_env)) {
  1891. const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
  1892. if (storage_class != SpvStorageClassMax &&
  1893. storage_class != SpvStorageClassInput) {
  1894. return _.diag(SPV_ERROR_INVALID_DATA)
  1895. << "Vulkan spec allows BuiltIn "
  1896. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  1897. decoration.params()[0])
  1898. << " to be only used for variables with Input storage class. "
  1899. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1900. referenced_from_inst)
  1901. << " " << GetStorageClassDesc(referenced_from_inst);
  1902. }
  1903. for (const SpvExecutionModel execution_model : execution_models_) {
  1904. if (execution_model != SpvExecutionModelGLCompute) {
  1905. return _.diag(SPV_ERROR_INVALID_DATA)
  1906. << "Vulkan spec allows BuiltIn "
  1907. << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
  1908. decoration.params()[0])
  1909. << " to be used only with GLCompute execution model. "
  1910. << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
  1911. referenced_from_inst, execution_model);
  1912. }
  1913. }
  1914. }
  1915. if (function_id_ == 0) {
  1916. // Propagate this rule to all dependant ids in the global scope.
  1917. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
  1918. &BuiltInsValidator::ValidateWorkgroupSizeAtReference, this, decoration,
  1919. built_in_inst, referenced_from_inst, std::placeholders::_1));
  1920. }
  1921. return SPV_SUCCESS;
  1922. }
  1923. spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
  1924. const Decoration& decoration, const Instruction& inst) {
  1925. const SpvBuiltIn label = SpvBuiltIn(decoration.params()[0]);
  1926. // If you are adding a new BuiltIn enum, please register it here.
  1927. // If the newly added enum has validation rules associated with it
  1928. // consider leaving a TODO and/or creating an issue.
  1929. switch (label) {
  1930. case SpvBuiltInClipDistance:
  1931. case SpvBuiltInCullDistance: {
  1932. return ValidateClipOrCullDistanceAtDefinition(decoration, inst);
  1933. }
  1934. case SpvBuiltInFragCoord: {
  1935. return ValidateFragCoordAtDefinition(decoration, inst);
  1936. }
  1937. case SpvBuiltInFragDepth: {
  1938. return ValidateFragDepthAtDefinition(decoration, inst);
  1939. }
  1940. case SpvBuiltInFrontFacing: {
  1941. return ValidateFrontFacingAtDefinition(decoration, inst);
  1942. }
  1943. case SpvBuiltInGlobalInvocationId:
  1944. case SpvBuiltInLocalInvocationId:
  1945. case SpvBuiltInNumWorkgroups:
  1946. case SpvBuiltInWorkgroupId: {
  1947. return ValidateComputeShaderI32Vec3InputAtDefinition(decoration, inst);
  1948. }
  1949. case SpvBuiltInHelperInvocation: {
  1950. return ValidateHelperInvocationAtDefinition(decoration, inst);
  1951. }
  1952. case SpvBuiltInInvocationId: {
  1953. return ValidateInvocationIdAtDefinition(decoration, inst);
  1954. }
  1955. case SpvBuiltInInstanceIndex: {
  1956. return ValidateInstanceIndexAtDefinition(decoration, inst);
  1957. }
  1958. case SpvBuiltInLayer:
  1959. case SpvBuiltInViewportIndex: {
  1960. return ValidateLayerOrViewportIndexAtDefinition(decoration, inst);
  1961. }
  1962. case SpvBuiltInPatchVertices: {
  1963. return ValidatePatchVerticesAtDefinition(decoration, inst);
  1964. }
  1965. case SpvBuiltInPointCoord: {
  1966. return ValidatePointCoordAtDefinition(decoration, inst);
  1967. }
  1968. case SpvBuiltInPointSize: {
  1969. return ValidatePointSizeAtDefinition(decoration, inst);
  1970. }
  1971. case SpvBuiltInPosition: {
  1972. return ValidatePositionAtDefinition(decoration, inst);
  1973. }
  1974. case SpvBuiltInPrimitiveId: {
  1975. return ValidatePrimitiveIdAtDefinition(decoration, inst);
  1976. }
  1977. case SpvBuiltInSampleId: {
  1978. return ValidateSampleIdAtDefinition(decoration, inst);
  1979. }
  1980. case SpvBuiltInSampleMask: {
  1981. return ValidateSampleMaskAtDefinition(decoration, inst);
  1982. }
  1983. case SpvBuiltInSamplePosition: {
  1984. return ValidateSamplePositionAtDefinition(decoration, inst);
  1985. }
  1986. case SpvBuiltInTessCoord: {
  1987. return ValidateTessCoordAtDefinition(decoration, inst);
  1988. }
  1989. case SpvBuiltInTessLevelOuter: {
  1990. return ValidateTessLevelOuterAtDefinition(decoration, inst);
  1991. }
  1992. case SpvBuiltInTessLevelInner: {
  1993. return ValidateTessLevelInnerAtDefinition(decoration, inst);
  1994. }
  1995. case SpvBuiltInVertexIndex: {
  1996. return ValidateVertexIndexAtDefinition(decoration, inst);
  1997. }
  1998. case SpvBuiltInWorkgroupSize: {
  1999. return ValidateWorkgroupSizeAtDefinition(decoration, inst);
  2000. }
  2001. case SpvBuiltInVertexId:
  2002. case SpvBuiltInInstanceId:
  2003. case SpvBuiltInLocalInvocationIndex:
  2004. case SpvBuiltInWorkDim:
  2005. case SpvBuiltInGlobalSize:
  2006. case SpvBuiltInEnqueuedWorkgroupSize:
  2007. case SpvBuiltInGlobalOffset:
  2008. case SpvBuiltInGlobalLinearId:
  2009. case SpvBuiltInSubgroupSize:
  2010. case SpvBuiltInSubgroupMaxSize:
  2011. case SpvBuiltInNumSubgroups:
  2012. case SpvBuiltInNumEnqueuedSubgroups:
  2013. case SpvBuiltInSubgroupId:
  2014. case SpvBuiltInSubgroupLocalInvocationId:
  2015. case SpvBuiltInSubgroupEqMaskKHR:
  2016. case SpvBuiltInSubgroupGeMaskKHR:
  2017. case SpvBuiltInSubgroupGtMaskKHR:
  2018. case SpvBuiltInSubgroupLeMaskKHR:
  2019. case SpvBuiltInSubgroupLtMaskKHR:
  2020. case SpvBuiltInBaseVertex:
  2021. case SpvBuiltInBaseInstance:
  2022. case SpvBuiltInDrawIndex:
  2023. case SpvBuiltInDeviceIndex:
  2024. case SpvBuiltInViewIndex:
  2025. case SpvBuiltInBaryCoordNoPerspAMD:
  2026. case SpvBuiltInBaryCoordNoPerspCentroidAMD:
  2027. case SpvBuiltInBaryCoordNoPerspSampleAMD:
  2028. case SpvBuiltInBaryCoordSmoothAMD:
  2029. case SpvBuiltInBaryCoordSmoothCentroidAMD:
  2030. case SpvBuiltInBaryCoordSmoothSampleAMD:
  2031. case SpvBuiltInBaryCoordPullModelAMD:
  2032. case SpvBuiltInFragStencilRefEXT:
  2033. case SpvBuiltInViewportMaskNV:
  2034. case SpvBuiltInSecondaryPositionNV:
  2035. case SpvBuiltInSecondaryViewportMaskNV:
  2036. case SpvBuiltInPositionPerViewNV:
  2037. case SpvBuiltInViewportMaskPerViewNV:
  2038. case SpvBuiltInFullyCoveredEXT:
  2039. case SpvBuiltInMax: {
  2040. // No validation rules (for the moment).
  2041. break;
  2042. }
  2043. }
  2044. return SPV_SUCCESS;
  2045. }
  2046. spv_result_t BuiltInsValidator::ValidateBuiltInsAtDefinition() {
  2047. for (const auto& kv : _.id_decorations()) {
  2048. const uint32_t id = kv.first;
  2049. const auto& decorations = kv.second;
  2050. if (decorations.empty()) {
  2051. continue;
  2052. }
  2053. const Instruction* inst = _.FindDef(id);
  2054. assert(inst);
  2055. for (const auto& decoration : kv.second) {
  2056. if (decoration.dec_type() != SpvDecorationBuiltIn) {
  2057. continue;
  2058. }
  2059. if (spv_result_t error =
  2060. ValidateSingleBuiltInAtDefinition(decoration, *inst)) {
  2061. return error;
  2062. }
  2063. }
  2064. }
  2065. return SPV_SUCCESS;
  2066. }
  2067. spv_result_t BuiltInsValidator::Run() {
  2068. // First pass: validate all built-ins at definition and seed
  2069. // id_to_at_reference_checks_ with built-ins.
  2070. if (auto error = ValidateBuiltInsAtDefinition()) {
  2071. return error;
  2072. }
  2073. if (id_to_at_reference_checks_.empty()) {
  2074. // No validation tasks were seeded. Nothing else to do.
  2075. return SPV_SUCCESS;
  2076. }
  2077. ComputeFunctionToEntryPointMapping();
  2078. // Second pass: validate every id reference in the module using
  2079. // rules in id_to_at_reference_checks_.
  2080. for (const Instruction& inst : _.ordered_instructions()) {
  2081. Update(inst);
  2082. std::set<uint32_t> already_checked;
  2083. for (const auto& operand : inst.operands()) {
  2084. if (!spvIsIdType(operand.type)) {
  2085. // Not id.
  2086. continue;
  2087. }
  2088. const uint32_t id = inst.word(operand.offset);
  2089. if (id == inst.id()) {
  2090. // No need to check result id.
  2091. continue;
  2092. }
  2093. if (!already_checked.insert(id).second) {
  2094. // The instruction has already referenced this id.
  2095. continue;
  2096. }
  2097. // Instruction references the id. Run all checks associated with the id on
  2098. // the instruction. id_to_at_reference_checks_ can be modified in the
  2099. // process, iterators are safe because it's a tree-based map.
  2100. const auto it = id_to_at_reference_checks_.find(id);
  2101. if (it != id_to_at_reference_checks_.end()) {
  2102. for (const auto& check : it->second) {
  2103. if (spv_result_t error = check(inst)) {
  2104. return error;
  2105. }
  2106. }
  2107. }
  2108. }
  2109. }
  2110. return SPV_SUCCESS;
  2111. }
  2112. } // anonymous namespace
  2113. // Validates correctness of built-in variables.
  2114. spv_result_t ValidateBuiltIns(const ValidationState_t& _) {
  2115. if (!spvIsVulkanEnv(_.context()->target_env)) {
  2116. // Early return. All currently implemented rules are based on Vulkan spec.
  2117. //
  2118. // TODO: If you are adding validation rules for environments other than
  2119. // Vulkan (or general rules which are not environment independent), then you
  2120. // need to modify or remove this condition. Consider also adding early
  2121. // returns into BuiltIn-specific rules, so that the system doesn't spawn new
  2122. // rules which don't do anything.
  2123. return SPV_SUCCESS;
  2124. }
  2125. BuiltInsValidator validator(_);
  2126. return validator.Run();
  2127. }
  2128. } // namespace libspirv