validate_id.cpp 102 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767
  1. // Copyright (c) 2015-2016 The Khronos Group Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "validate.h"
  15. #include <cassert>
  16. #include <algorithm>
  17. #include <iostream>
  18. #include <iterator>
  19. #include <stack>
  20. #include <unordered_set>
  21. #include <utility>
  22. #include <vector>
  23. #include "diagnostic.h"
  24. #include "instruction.h"
  25. #include "message.h"
  26. #include "opcode.h"
  27. #include "operand.h"
  28. #include "spirv-tools/libspirv.h"
  29. #include "spirv_validator_options.h"
  30. #include "val/function.h"
  31. #include "val/validation_state.h"
  32. using libspirv::Decoration;
  33. using libspirv::Function;
  34. using libspirv::ValidationState_t;
  35. using std::function;
  36. using std::ignore;
  37. using std::make_pair;
  38. using std::pair;
  39. using std::unordered_set;
  40. using std::vector;
  41. namespace {
  42. class idUsage {
  43. public:
  44. idUsage(spv_const_context context, const spv_instruction_t* pInsts,
  45. const uint64_t instCountArg, const SpvMemoryModel memoryModelArg,
  46. const SpvAddressingModel addressingModelArg,
  47. const ValidationState_t& module, const vector<uint32_t>& entry_points,
  48. spv_position positionArg, const spvtools::MessageConsumer& consumer)
  49. : targetEnv(context->target_env),
  50. opcodeTable(context->opcode_table),
  51. operandTable(context->operand_table),
  52. extInstTable(context->ext_inst_table),
  53. firstInst(pInsts),
  54. instCount(instCountArg),
  55. memoryModel(memoryModelArg),
  56. addressingModel(addressingModelArg),
  57. position(positionArg),
  58. consumer_(consumer),
  59. module_(module),
  60. entry_points_(entry_points) {}
  61. bool isValid(const spv_instruction_t* inst);
  62. template <SpvOp>
  63. bool isValid(const spv_instruction_t* inst, const spv_opcode_desc);
  64. private:
  65. const spv_target_env targetEnv;
  66. const spv_opcode_table opcodeTable;
  67. const spv_operand_table operandTable;
  68. const spv_ext_inst_table extInstTable;
  69. const spv_instruction_t* const firstInst;
  70. const uint64_t instCount;
  71. const SpvMemoryModel memoryModel;
  72. const SpvAddressingModel addressingModel;
  73. spv_position position;
  74. const spvtools::MessageConsumer& consumer_;
  75. const ValidationState_t& module_;
  76. vector<uint32_t> entry_points_;
  77. // Returns true if the two instructions represent structs that, as far as the
  78. // validator can tell, have the exact same data layout.
  79. bool AreLayoutCompatibleStructs(const libspirv::Instruction* type1,
  80. const libspirv::Instruction* type2);
  81. // Returns true if the operands to the OpTypeStruct instruction defining the
  82. // types are the same or are layout compatible types. |type1| and |type2| must
  83. // be OpTypeStruct instructions.
  84. bool HaveLayoutCompatibleMembers(const libspirv::Instruction* type1,
  85. const libspirv::Instruction* type2);
  86. // Returns true if all decorations that affect the data layout of the struct
  87. // (like Offset), are the same for the two types. |type1| and |type2| must be
  88. // OpTypeStruct instructions.
  89. bool HaveSameLayoutDecorations(const libspirv::Instruction* type1,
  90. const libspirv::Instruction* type2);
  91. bool HasConflictingMemberOffsets(
  92. const vector<Decoration>& type1_decorations,
  93. const vector<Decoration>& type2_decorations) const;
  94. };
  95. #define DIAG(INDEX) \
  96. position->index += INDEX; \
  97. libspirv::DiagnosticStream helper(*position, consumer_, \
  98. SPV_ERROR_INVALID_DIAGNOSTIC); \
  99. helper
  100. #if 0
  101. template <>
  102. bool idUsage::isValid<SpvOpUndef>(const spv_instruction_t *inst,
  103. const spv_opcode_desc) {
  104. assert(0 && "Unimplemented!");
  105. return false;
  106. }
  107. #endif // 0
  108. template <>
  109. bool idUsage::isValid<SpvOpMemberName>(const spv_instruction_t* inst,
  110. const spv_opcode_desc) {
  111. auto typeIndex = 1;
  112. auto type = module_.FindDef(inst->words[typeIndex]);
  113. if (!type || SpvOpTypeStruct != type->opcode()) {
  114. DIAG(typeIndex) << "OpMemberName Type <id> '" << inst->words[typeIndex]
  115. << "' is not a struct type.";
  116. return false;
  117. }
  118. auto memberIndex = 2;
  119. auto member = inst->words[memberIndex];
  120. auto memberCount = (uint32_t)(type->words().size() - 2);
  121. if (memberCount <= member) {
  122. DIAG(memberIndex) << "OpMemberName Member <id> '"
  123. << inst->words[memberIndex]
  124. << "' index is larger than Type <id> '" << type->id()
  125. << "'s member count.";
  126. return false;
  127. }
  128. return true;
  129. }
  130. template <>
  131. bool idUsage::isValid<SpvOpLine>(const spv_instruction_t* inst,
  132. const spv_opcode_desc) {
  133. auto fileIndex = 1;
  134. auto file = module_.FindDef(inst->words[fileIndex]);
  135. if (!file || SpvOpString != file->opcode()) {
  136. DIAG(fileIndex) << "OpLine Target <id> '" << inst->words[fileIndex]
  137. << "' is not an OpString.";
  138. return false;
  139. }
  140. return true;
  141. }
  142. template <>
  143. bool idUsage::isValid<SpvOpDecorate>(const spv_instruction_t* inst,
  144. const spv_opcode_desc) {
  145. auto decorationIndex = 2;
  146. auto decoration = inst->words[decorationIndex];
  147. if (decoration == SpvDecorationSpecId) {
  148. auto targetIndex = 1;
  149. auto target = module_.FindDef(inst->words[targetIndex]);
  150. if (!target || !spvOpcodeIsScalarSpecConstant(target->opcode())) {
  151. DIAG(targetIndex) << "OpDecorate SpectId decoration target <id> '"
  152. << inst->words[decorationIndex]
  153. << "' is not a scalar specialization constant.";
  154. return false;
  155. }
  156. }
  157. // TODO: Add validations for all decorations.
  158. return true;
  159. }
  160. template <>
  161. bool idUsage::isValid<SpvOpMemberDecorate>(const spv_instruction_t* inst,
  162. const spv_opcode_desc) {
  163. auto structTypeIndex = 1;
  164. auto structType = module_.FindDef(inst->words[structTypeIndex]);
  165. if (!structType || SpvOpTypeStruct != structType->opcode()) {
  166. DIAG(structTypeIndex) << "OpMemberDecorate Structure type <id> '"
  167. << inst->words[structTypeIndex]
  168. << "' is not a struct type.";
  169. return false;
  170. }
  171. auto memberIndex = 2;
  172. auto member = inst->words[memberIndex];
  173. auto memberCount = static_cast<uint32_t>(structType->words().size() - 2);
  174. if (memberCount < member) {
  175. DIAG(memberIndex) << "Index " << member
  176. << " provided in OpMemberDecorate for struct <id> "
  177. << inst->words[structTypeIndex]
  178. << " is out of bounds. The structure has " << memberCount
  179. << " members. Largest valid index is " << memberCount - 1
  180. << ".";
  181. return false;
  182. }
  183. return true;
  184. }
  185. template <>
  186. bool idUsage::isValid<SpvOpDecorationGroup>(const spv_instruction_t* inst,
  187. const spv_opcode_desc) {
  188. auto decorationGroupIndex = 1;
  189. auto decorationGroup = module_.FindDef(inst->words[decorationGroupIndex]);
  190. for (auto pair : decorationGroup->uses()) {
  191. auto use = pair.first;
  192. if (use->opcode() != SpvOpDecorate && use->opcode() != SpvOpGroupDecorate &&
  193. use->opcode() != SpvOpGroupMemberDecorate &&
  194. use->opcode() != SpvOpName) {
  195. DIAG(decorationGroupIndex) << "Result id of OpDecorationGroup can only "
  196. << "be targeted by OpName, OpGroupDecorate, "
  197. << "OpDecorate, and OpGroupMemberDecorate";
  198. return false;
  199. }
  200. }
  201. return true;
  202. }
  203. template <>
  204. bool idUsage::isValid<SpvOpGroupDecorate>(const spv_instruction_t* inst,
  205. const spv_opcode_desc) {
  206. auto decorationGroupIndex = 1;
  207. auto decorationGroup = module_.FindDef(inst->words[decorationGroupIndex]);
  208. if (!decorationGroup || SpvOpDecorationGroup != decorationGroup->opcode()) {
  209. DIAG(decorationGroupIndex)
  210. << "OpGroupDecorate Decoration group <id> '"
  211. << inst->words[decorationGroupIndex] << "' is not a decoration group.";
  212. return false;
  213. }
  214. return true;
  215. }
  216. template <>
  217. bool idUsage::isValid<SpvOpGroupMemberDecorate>(const spv_instruction_t* inst,
  218. const spv_opcode_desc) {
  219. auto decorationGroupIndex = 1;
  220. auto decorationGroup = module_.FindDef(inst->words[decorationGroupIndex]);
  221. if (!decorationGroup || SpvOpDecorationGroup != decorationGroup->opcode()) {
  222. DIAG(decorationGroupIndex)
  223. << "OpGroupMemberDecorate Decoration group <id> '"
  224. << inst->words[decorationGroupIndex] << "' is not a decoration group.";
  225. return false;
  226. }
  227. // Grammar checks ensures that the number of arguments to this instruction
  228. // is an odd number: 1 decoration group + (id,literal) pairs.
  229. for (size_t i = 2; i + 1 < inst->words.size(); i = i + 2) {
  230. const uint32_t struct_id = inst->words[i];
  231. const uint32_t index = inst->words[i + 1];
  232. auto struct_instr = module_.FindDef(struct_id);
  233. if (!struct_instr || SpvOpTypeStruct != struct_instr->opcode()) {
  234. DIAG(i) << "OpGroupMemberDecorate Structure type <id> '" << struct_id
  235. << "' is not a struct type.";
  236. return false;
  237. }
  238. const uint32_t num_struct_members =
  239. static_cast<uint32_t>(struct_instr->words().size() - 2);
  240. if (index >= num_struct_members) {
  241. DIAG(i) << "Index " << index
  242. << " provided in OpGroupMemberDecorate for struct <id> "
  243. << struct_id << " is out of bounds. The structure has "
  244. << num_struct_members << " members. Largest valid index is "
  245. << num_struct_members - 1 << ".";
  246. return false;
  247. }
  248. }
  249. return true;
  250. }
  251. #if 0
  252. template <>
  253. bool idUsage::isValid<SpvOpExtInst>(const spv_instruction_t *inst,
  254. const spv_opcode_desc opcodeEntry) {}
  255. #endif // 0
  256. template <>
  257. bool idUsage::isValid<SpvOpEntryPoint>(const spv_instruction_t* inst,
  258. const spv_opcode_desc) {
  259. auto entryPointIndex = 2;
  260. auto entryPoint = module_.FindDef(inst->words[entryPointIndex]);
  261. if (!entryPoint || SpvOpFunction != entryPoint->opcode()) {
  262. DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
  263. << inst->words[entryPointIndex]
  264. << "' is not a function.";
  265. return false;
  266. }
  267. // don't check kernel function signatures
  268. const SpvExecutionModel executionModel = SpvExecutionModel(inst->words[1]);
  269. if (executionModel != SpvExecutionModelKernel) {
  270. // TODO: Check the entry point signature is void main(void), may be subject
  271. // to change
  272. auto entryPointType = module_.FindDef(entryPoint->words()[4]);
  273. if (!entryPointType || 3 != entryPointType->words().size()) {
  274. DIAG(entryPointIndex)
  275. << "OpEntryPoint Entry Point <id> '" << inst->words[entryPointIndex]
  276. << "'s function parameter count is not zero.";
  277. return false;
  278. }
  279. }
  280. std::stack<uint32_t> call_stack;
  281. std::set<uint32_t> visited;
  282. call_stack.push(entryPoint->id());
  283. while (!call_stack.empty()) {
  284. const uint32_t called_func_id = call_stack.top();
  285. call_stack.pop();
  286. if (!visited.insert(called_func_id).second) continue;
  287. const Function* called_func = module_.function(called_func_id);
  288. assert(called_func);
  289. std::string reason;
  290. if (!called_func->IsCompatibleWithExecutionModel(executionModel, &reason)) {
  291. DIAG(entryPointIndex)
  292. << "OpEntryPoint Entry Point <id> '" << inst->words[entryPointIndex]
  293. << "'s callgraph contains function <id> " << called_func_id
  294. << ", which cannot be used with the current execution model:\n"
  295. << reason;
  296. return false;
  297. }
  298. for (uint32_t new_call : called_func->function_call_targets()) {
  299. call_stack.push(new_call);
  300. }
  301. }
  302. auto returnType = module_.FindDef(entryPoint->type_id());
  303. if (!returnType || SpvOpTypeVoid != returnType->opcode()) {
  304. DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
  305. << inst->words[entryPointIndex]
  306. << "'s function return type is not void.";
  307. return false;
  308. }
  309. return true;
  310. }
  311. template <>
  312. bool idUsage::isValid<SpvOpExecutionMode>(const spv_instruction_t* inst,
  313. const spv_opcode_desc) {
  314. auto entryPointIndex = 1;
  315. auto entryPointID = inst->words[entryPointIndex];
  316. auto found =
  317. std::find(entry_points_.cbegin(), entry_points_.cend(), entryPointID);
  318. if (found == entry_points_.cend()) {
  319. DIAG(entryPointIndex) << "OpExecutionMode Entry Point <id> '"
  320. << inst->words[entryPointIndex]
  321. << "' is not the Entry Point "
  322. "operand of an OpEntryPoint.";
  323. return false;
  324. }
  325. return true;
  326. }
  327. template <>
  328. bool idUsage::isValid<SpvOpTypeVector>(const spv_instruction_t* inst,
  329. const spv_opcode_desc) {
  330. auto componentIndex = 2;
  331. auto componentType = module_.FindDef(inst->words[componentIndex]);
  332. if (!componentType || !spvOpcodeIsScalarType(componentType->opcode())) {
  333. DIAG(componentIndex) << "OpTypeVector Component Type <id> '"
  334. << inst->words[componentIndex]
  335. << "' is not a scalar type.";
  336. return false;
  337. }
  338. return true;
  339. }
  340. template <>
  341. bool idUsage::isValid<SpvOpTypeMatrix>(const spv_instruction_t* inst,
  342. const spv_opcode_desc) {
  343. auto columnTypeIndex = 2;
  344. auto columnType = module_.FindDef(inst->words[columnTypeIndex]);
  345. if (!columnType || SpvOpTypeVector != columnType->opcode()) {
  346. DIAG(columnTypeIndex) << "OpTypeMatrix Column Type <id> '"
  347. << inst->words[columnTypeIndex]
  348. << "' is not a vector.";
  349. return false;
  350. }
  351. return true;
  352. }
  353. template <>
  354. bool idUsage::isValid<SpvOpTypeSampler>(const spv_instruction_t*,
  355. const spv_opcode_desc) {
  356. // OpTypeSampler takes no arguments in Rev31 and beyond.
  357. return true;
  358. }
  359. // True if the integer constant is > 0. constWords are words of the
  360. // constant-defining instruction (either OpConstant or
  361. // OpSpecConstant). typeWords are the words of the constant's-type-defining
  362. // OpTypeInt.
  363. bool aboveZero(const vector<uint32_t>& constWords,
  364. const vector<uint32_t>& typeWords) {
  365. const uint32_t width = typeWords[2];
  366. const bool is_signed = typeWords[3] > 0;
  367. const uint32_t loWord = constWords[3];
  368. if (width > 32) {
  369. // The spec currently doesn't allow integers wider than 64 bits.
  370. const uint32_t hiWord = constWords[4]; // Must exist, per spec.
  371. if (is_signed && (hiWord >> 31)) return false;
  372. return (loWord | hiWord) > 0;
  373. } else {
  374. if (is_signed && (loWord >> 31)) return false;
  375. return loWord > 0;
  376. }
  377. }
  378. template <>
  379. bool idUsage::isValid<SpvOpTypeArray>(const spv_instruction_t* inst,
  380. const spv_opcode_desc) {
  381. auto elementTypeIndex = 2;
  382. auto elementType = module_.FindDef(inst->words[elementTypeIndex]);
  383. if (!elementType || !spvOpcodeGeneratesType(elementType->opcode())) {
  384. DIAG(elementTypeIndex) << "OpTypeArray Element Type <id> '"
  385. << inst->words[elementTypeIndex]
  386. << "' is not a type.";
  387. return false;
  388. }
  389. auto lengthIndex = 3;
  390. auto length = module_.FindDef(inst->words[lengthIndex]);
  391. if (!length || !spvOpcodeIsConstant(length->opcode())) {
  392. DIAG(lengthIndex) << "OpTypeArray Length <id> '" << inst->words[lengthIndex]
  393. << "' is not a scalar constant type.";
  394. return false;
  395. }
  396. // NOTE: Check the initialiser value of the constant
  397. auto constInst = length->words();
  398. auto constResultTypeIndex = 1;
  399. auto constResultType = module_.FindDef(constInst[constResultTypeIndex]);
  400. if (!constResultType || SpvOpTypeInt != constResultType->opcode()) {
  401. DIAG(lengthIndex) << "OpTypeArray Length <id> '" << inst->words[lengthIndex]
  402. << "' is not a constant integer type.";
  403. return false;
  404. }
  405. switch (length->opcode()) {
  406. case SpvOpSpecConstant:
  407. case SpvOpConstant:
  408. if (aboveZero(length->words(), constResultType->words())) break;
  409. // Else fall through!
  410. case SpvOpConstantNull: {
  411. DIAG(lengthIndex) << "OpTypeArray Length <id> '"
  412. << inst->words[lengthIndex]
  413. << "' default value must be at least 1.";
  414. return false;
  415. }
  416. case SpvOpSpecConstantOp:
  417. // Assume it's OK, rather than try to evaluate the operation.
  418. break;
  419. default:
  420. assert(0 && "bug in spvOpcodeIsConstant() or result type isn't int");
  421. }
  422. return true;
  423. }
  424. template <>
  425. bool idUsage::isValid<SpvOpTypeRuntimeArray>(const spv_instruction_t* inst,
  426. const spv_opcode_desc) {
  427. auto elementTypeIndex = 2;
  428. auto elementType = module_.FindDef(inst->words[elementTypeIndex]);
  429. if (!elementType || !spvOpcodeGeneratesType(elementType->opcode())) {
  430. DIAG(elementTypeIndex) << "OpTypeRuntimeArray Element Type <id> '"
  431. << inst->words[elementTypeIndex]
  432. << "' is not a type.";
  433. return false;
  434. }
  435. return true;
  436. }
  437. template <>
  438. bool idUsage::isValid<SpvOpTypeStruct>(const spv_instruction_t* inst,
  439. const spv_opcode_desc) {
  440. ValidationState_t& vstate = const_cast<ValidationState_t&>(module_);
  441. const uint32_t struct_id = inst->words[1];
  442. for (size_t memberTypeIndex = 2; memberTypeIndex < inst->words.size();
  443. ++memberTypeIndex) {
  444. auto memberTypeId = inst->words[memberTypeIndex];
  445. auto memberType = module_.FindDef(memberTypeId);
  446. if (!memberType || !spvOpcodeGeneratesType(memberType->opcode())) {
  447. DIAG(memberTypeIndex)
  448. << "OpTypeStruct Member Type <id> '" << inst->words[memberTypeIndex]
  449. << "' is not a type.";
  450. return false;
  451. }
  452. if (SpvOpTypeStruct == memberType->opcode() &&
  453. module_.IsStructTypeWithBuiltInMember(memberTypeId)) {
  454. DIAG(memberTypeIndex)
  455. << "Structure <id> " << memberTypeId
  456. << " contains members with BuiltIn decoration. Therefore this "
  457. "structure may not be contained as a member of another structure "
  458. "type. Structure <id> "
  459. << struct_id << " contains structure <id> " << memberTypeId << ".";
  460. return false;
  461. }
  462. if (module_.IsForwardPointer(memberTypeId)) {
  463. if (memberType->opcode() != SpvOpTypePointer) {
  464. DIAG(memberTypeIndex) << "Found a forward reference to a non-pointer "
  465. "type in OpTypeStruct instruction.";
  466. return false;
  467. }
  468. // If we're dealing with a forward pointer:
  469. // Find out the type that the pointer is pointing to (must be struct)
  470. // word 3 is the <id> of the type being pointed to.
  471. auto typePointingTo = module_.FindDef(memberType->words()[3]);
  472. if (typePointingTo && typePointingTo->opcode() != SpvOpTypeStruct) {
  473. // Forward declared operands of a struct may only point to a struct.
  474. DIAG(memberTypeIndex)
  475. << "A forward reference operand in an OpTypeStruct must be an "
  476. "OpTypePointer that points to an OpTypeStruct. "
  477. "Found OpTypePointer that points to Op"
  478. << spvOpcodeString(static_cast<SpvOp>(typePointingTo->opcode()))
  479. << ".";
  480. return false;
  481. }
  482. }
  483. }
  484. std::unordered_set<uint32_t> built_in_members;
  485. for (auto decoration : vstate.id_decorations(struct_id)) {
  486. if (decoration.dec_type() == SpvDecorationBuiltIn &&
  487. decoration.struct_member_index() != Decoration::kInvalidMember) {
  488. built_in_members.insert(decoration.struct_member_index());
  489. }
  490. }
  491. int num_struct_members = static_cast<int>(inst->words.size() - 2);
  492. int num_builtin_members = static_cast<int>(built_in_members.size());
  493. if (num_builtin_members > 0 && num_builtin_members != num_struct_members) {
  494. DIAG(0)
  495. << "When BuiltIn decoration is applied to a structure-type member, "
  496. "all members of that structure type must also be decorated with "
  497. "BuiltIn (No allowed mixing of built-in variables and "
  498. "non-built-in variables within a single structure). Structure id "
  499. << struct_id << " does not meet this requirement.";
  500. return false;
  501. }
  502. if (num_builtin_members > 0) {
  503. vstate.RegisterStructTypeWithBuiltInMember(struct_id);
  504. }
  505. return true;
  506. }
  507. template <>
  508. bool idUsage::isValid<SpvOpTypePointer>(const spv_instruction_t* inst,
  509. const spv_opcode_desc) {
  510. auto typeIndex = 3;
  511. auto type = module_.FindDef(inst->words[typeIndex]);
  512. if (!type || !spvOpcodeGeneratesType(type->opcode())) {
  513. DIAG(typeIndex) << "OpTypePointer Type <id> '" << inst->words[typeIndex]
  514. << "' is not a type.";
  515. return false;
  516. }
  517. return true;
  518. }
  519. template <>
  520. bool idUsage::isValid<SpvOpTypeFunction>(const spv_instruction_t* inst,
  521. const spv_opcode_desc) {
  522. auto returnTypeIndex = 2;
  523. auto returnType = module_.FindDef(inst->words[returnTypeIndex]);
  524. if (!returnType || !spvOpcodeGeneratesType(returnType->opcode())) {
  525. DIAG(returnTypeIndex) << "OpTypeFunction Return Type <id> '"
  526. << inst->words[returnTypeIndex] << "' is not a type.";
  527. return false;
  528. }
  529. size_t num_args = 0;
  530. for (size_t paramTypeIndex = 3; paramTypeIndex < inst->words.size();
  531. ++paramTypeIndex, ++num_args) {
  532. auto paramType = module_.FindDef(inst->words[paramTypeIndex]);
  533. if (!paramType || !spvOpcodeGeneratesType(paramType->opcode())) {
  534. DIAG(paramTypeIndex) << "OpTypeFunction Parameter Type <id> '"
  535. << inst->words[paramTypeIndex] << "' is not a type.";
  536. return false;
  537. }
  538. }
  539. const uint32_t num_function_args_limit =
  540. module_.options()->universal_limits_.max_function_args;
  541. if (num_args > num_function_args_limit) {
  542. DIAG(returnTypeIndex) << "OpTypeFunction may not take more than "
  543. << num_function_args_limit
  544. << " arguments. OpTypeFunction <id> '"
  545. << inst->words[1] << "' has " << num_args
  546. << " arguments.";
  547. return false;
  548. }
  549. return true;
  550. }
  551. template <>
  552. bool idUsage::isValid<SpvOpTypePipe>(const spv_instruction_t*,
  553. const spv_opcode_desc) {
  554. // OpTypePipe has no ID arguments.
  555. return true;
  556. }
  557. template <>
  558. bool idUsage::isValid<SpvOpConstantTrue>(const spv_instruction_t* inst,
  559. const spv_opcode_desc) {
  560. auto resultTypeIndex = 1;
  561. auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
  562. if (!resultType || SpvOpTypeBool != resultType->opcode()) {
  563. DIAG(resultTypeIndex) << "OpConstantTrue Result Type <id> '"
  564. << inst->words[resultTypeIndex]
  565. << "' is not a boolean type.";
  566. return false;
  567. }
  568. return true;
  569. }
  570. template <>
  571. bool idUsage::isValid<SpvOpConstantFalse>(const spv_instruction_t* inst,
  572. const spv_opcode_desc) {
  573. auto resultTypeIndex = 1;
  574. auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
  575. if (!resultType || SpvOpTypeBool != resultType->opcode()) {
  576. DIAG(resultTypeIndex) << "OpConstantFalse Result Type <id> '"
  577. << inst->words[resultTypeIndex]
  578. << "' is not a boolean type.";
  579. return false;
  580. }
  581. return true;
  582. }
  583. template <>
  584. bool idUsage::isValid<SpvOpConstantComposite>(const spv_instruction_t* inst,
  585. const spv_opcode_desc) {
  586. auto resultTypeIndex = 1;
  587. auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
  588. if (!resultType || !spvOpcodeIsComposite(resultType->opcode())) {
  589. DIAG(resultTypeIndex) << "OpConstantComposite Result Type <id> '"
  590. << inst->words[resultTypeIndex]
  591. << "' is not a composite type.";
  592. return false;
  593. }
  594. auto constituentCount = inst->words.size() - 3;
  595. switch (resultType->opcode()) {
  596. case SpvOpTypeVector: {
  597. auto componentCount = resultType->words()[3];
  598. if (componentCount != constituentCount) {
  599. // TODO: Output ID's on diagnostic
  600. DIAG(inst->words.size() - 1)
  601. << "OpConstantComposite Constituent <id> count does not match "
  602. "Result Type <id> '"
  603. << resultType->id() << "'s vector component count.";
  604. return false;
  605. }
  606. auto componentType = module_.FindDef(resultType->words()[2]);
  607. assert(componentType);
  608. for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
  609. constituentIndex++) {
  610. auto constituent = module_.FindDef(inst->words[constituentIndex]);
  611. if (!constituent ||
  612. !spvOpcodeIsConstantOrUndef(constituent->opcode())) {
  613. DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
  614. << inst->words[constituentIndex]
  615. << "' is not a constant or undef.";
  616. return false;
  617. }
  618. auto constituentResultType = module_.FindDef(constituent->type_id());
  619. if (!constituentResultType ||
  620. componentType->opcode() != constituentResultType->opcode()) {
  621. DIAG(constituentIndex)
  622. << "OpConstantComposite Constituent <id> '"
  623. << inst->words[constituentIndex]
  624. << "'s type does not match Result Type <id> '" << resultType->id()
  625. << "'s vector element type.";
  626. return false;
  627. }
  628. }
  629. } break;
  630. case SpvOpTypeMatrix: {
  631. auto columnCount = resultType->words()[3];
  632. if (columnCount != constituentCount) {
  633. // TODO: Output ID's on diagnostic
  634. DIAG(inst->words.size() - 1)
  635. << "OpConstantComposite Constituent <id> count does not match "
  636. "Result Type <id> '"
  637. << resultType->id() << "'s matrix column count.";
  638. return false;
  639. }
  640. auto columnType = module_.FindDef(resultType->words()[2]);
  641. assert(columnType);
  642. auto componentCount = columnType->words()[3];
  643. auto componentType = module_.FindDef(columnType->words()[2]);
  644. assert(componentType);
  645. for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
  646. constituentIndex++) {
  647. auto constituent = module_.FindDef(inst->words[constituentIndex]);
  648. if (!constituent || !(SpvOpConstantComposite == constituent->opcode() ||
  649. SpvOpUndef == constituent->opcode())) {
  650. // The message says "... or undef" because the spec does not say
  651. // undef is a constant.
  652. DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
  653. << inst->words[constituentIndex]
  654. << "' is not a constant composite or undef.";
  655. return false;
  656. }
  657. auto vector = module_.FindDef(constituent->type_id());
  658. assert(vector);
  659. if (columnType->opcode() != vector->opcode()) {
  660. DIAG(constituentIndex)
  661. << "OpConstantComposite Constituent <id> '"
  662. << inst->words[constituentIndex]
  663. << "' type does not match Result Type <id> '" << resultType->id()
  664. << "'s matrix column type.";
  665. return false;
  666. }
  667. auto vectorComponentType = module_.FindDef(vector->words()[2]);
  668. assert(vectorComponentType);
  669. if (componentType->id() != vectorComponentType->id()) {
  670. DIAG(constituentIndex)
  671. << "OpConstantComposite Constituent <id> '"
  672. << inst->words[constituentIndex]
  673. << "' component type does not match Result Type <id> '"
  674. << resultType->id() << "'s matrix column component type.";
  675. return false;
  676. }
  677. if (componentCount != vector->words()[3]) {
  678. DIAG(constituentIndex)
  679. << "OpConstantComposite Constituent <id> '"
  680. << inst->words[constituentIndex]
  681. << "' vector component count does not match Result Type <id> '"
  682. << resultType->id() << "'s vector component count.";
  683. return false;
  684. }
  685. }
  686. } break;
  687. case SpvOpTypeArray: {
  688. auto elementType = module_.FindDef(resultType->words()[2]);
  689. assert(elementType);
  690. auto length = module_.FindDef(resultType->words()[3]);
  691. assert(length);
  692. if (length->words()[3] != constituentCount) {
  693. DIAG(inst->words.size() - 1)
  694. << "OpConstantComposite Constituent count does not match "
  695. "Result Type <id> '"
  696. << resultType->id() << "'s array length.";
  697. return false;
  698. }
  699. for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
  700. constituentIndex++) {
  701. auto constituent = module_.FindDef(inst->words[constituentIndex]);
  702. if (!constituent ||
  703. !spvOpcodeIsConstantOrUndef(constituent->opcode())) {
  704. DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
  705. << inst->words[constituentIndex]
  706. << "' is not a constant or undef.";
  707. return false;
  708. }
  709. auto constituentType = module_.FindDef(constituent->type_id());
  710. assert(constituentType);
  711. if (elementType->id() != constituentType->id()) {
  712. DIAG(constituentIndex)
  713. << "OpConstantComposite Constituent <id> '"
  714. << inst->words[constituentIndex]
  715. << "'s type does not match Result Type <id> '" << resultType->id()
  716. << "'s array element type.";
  717. return false;
  718. }
  719. }
  720. } break;
  721. case SpvOpTypeStruct: {
  722. auto memberCount = resultType->words().size() - 2;
  723. if (memberCount != constituentCount) {
  724. DIAG(resultTypeIndex) << "OpConstantComposite Constituent <id> '"
  725. << inst->words[resultTypeIndex]
  726. << "' count does not match Result Type <id> '"
  727. << resultType->id() << "'s struct member count.";
  728. return false;
  729. }
  730. for (uint32_t constituentIndex = 3, memberIndex = 2;
  731. constituentIndex < inst->words.size();
  732. constituentIndex++, memberIndex++) {
  733. auto constituent = module_.FindDef(inst->words[constituentIndex]);
  734. if (!constituent ||
  735. !spvOpcodeIsConstantOrUndef(constituent->opcode())) {
  736. DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
  737. << inst->words[constituentIndex]
  738. << "' is not a constant or undef.";
  739. return false;
  740. }
  741. auto constituentType = module_.FindDef(constituent->type_id());
  742. assert(constituentType);
  743. auto memberType = module_.FindDef(resultType->words()[memberIndex]);
  744. assert(memberType);
  745. if (memberType->id() != constituentType->id()) {
  746. DIAG(constituentIndex)
  747. << "OpConstantComposite Constituent <id> '"
  748. << inst->words[constituentIndex]
  749. << "' type does not match the Result Type <id> '"
  750. << resultType->id() << "'s member type.";
  751. return false;
  752. }
  753. }
  754. } break;
  755. default: { assert(0 && "Unreachable!"); } break;
  756. }
  757. return true;
  758. }
  759. template <>
  760. bool idUsage::isValid<SpvOpConstantSampler>(const spv_instruction_t* inst,
  761. const spv_opcode_desc) {
  762. auto resultTypeIndex = 1;
  763. auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
  764. if (!resultType || SpvOpTypeSampler != resultType->opcode()) {
  765. DIAG(resultTypeIndex) << "OpConstantSampler Result Type <id> '"
  766. << inst->words[resultTypeIndex]
  767. << "' is not a sampler type.";
  768. return false;
  769. }
  770. return true;
  771. }
  772. // True if instruction defines a type that can have a null value, as defined by
  773. // the SPIR-V spec. Tracks composite-type components through module to check
  774. // nullability transitively.
  775. bool IsTypeNullable(const vector<uint32_t>& instruction,
  776. const ValidationState_t& module) {
  777. uint16_t opcode;
  778. uint16_t word_count;
  779. spvOpcodeSplit(instruction[0], &word_count, &opcode);
  780. switch (static_cast<SpvOp>(opcode)) {
  781. case SpvOpTypeBool:
  782. case SpvOpTypeInt:
  783. case SpvOpTypeFloat:
  784. case SpvOpTypePointer:
  785. case SpvOpTypeEvent:
  786. case SpvOpTypeDeviceEvent:
  787. case SpvOpTypeReserveId:
  788. case SpvOpTypeQueue:
  789. return true;
  790. case SpvOpTypeArray:
  791. case SpvOpTypeMatrix:
  792. case SpvOpTypeVector: {
  793. auto base_type = module.FindDef(instruction[2]);
  794. return base_type && IsTypeNullable(base_type->words(), module);
  795. }
  796. case SpvOpTypeStruct: {
  797. for (size_t elementIndex = 2; elementIndex < instruction.size();
  798. ++elementIndex) {
  799. auto element = module.FindDef(instruction[elementIndex]);
  800. if (!element || !IsTypeNullable(element->words(), module)) return false;
  801. }
  802. return true;
  803. }
  804. default:
  805. return false;
  806. }
  807. }
  808. template <>
  809. bool idUsage::isValid<SpvOpConstantNull>(const spv_instruction_t* inst,
  810. const spv_opcode_desc) {
  811. auto resultTypeIndex = 1;
  812. auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
  813. if (!resultType || !IsTypeNullable(resultType->words(), module_)) {
  814. DIAG(resultTypeIndex) << "OpConstantNull Result Type <id> '"
  815. << inst->words[resultTypeIndex]
  816. << "' cannot have a null value.";
  817. return false;
  818. }
  819. return true;
  820. }
  821. template <>
  822. bool idUsage::isValid<SpvOpSpecConstantTrue>(const spv_instruction_t* inst,
  823. const spv_opcode_desc) {
  824. auto resultTypeIndex = 1;
  825. auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
  826. if (!resultType || SpvOpTypeBool != resultType->opcode()) {
  827. DIAG(resultTypeIndex) << "OpSpecConstantTrue Result Type <id> '"
  828. << inst->words[resultTypeIndex]
  829. << "' is not a boolean type.";
  830. return false;
  831. }
  832. return true;
  833. }
  834. template <>
  835. bool idUsage::isValid<SpvOpSpecConstantFalse>(const spv_instruction_t* inst,
  836. const spv_opcode_desc) {
  837. auto resultTypeIndex = 1;
  838. auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
  839. if (!resultType || SpvOpTypeBool != resultType->opcode()) {
  840. DIAG(resultTypeIndex) << "OpSpecConstantFalse Result Type <id> '"
  841. << inst->words[resultTypeIndex]
  842. << "' is not a boolean type.";
  843. return false;
  844. }
  845. return true;
  846. }
  847. template <>
  848. bool idUsage::isValid<SpvOpSampledImage>(const spv_instruction_t* inst,
  849. const spv_opcode_desc) {
  850. auto resultTypeIndex = 2;
  851. auto resultID = inst->words[resultTypeIndex];
  852. auto sampledImageInstr = module_.FindDef(resultID);
  853. // We need to validate 2 things:
  854. // * All OpSampledImage instructions must be in the same block in which their
  855. // Result <id> are consumed.
  856. // * Result <id> from OpSampledImage instructions must not appear as operands
  857. // to OpPhi instructions or OpSelect instructions, or any instructions other
  858. // than the image lookup and query instructions specified to take an operand
  859. // whose type is OpTypeSampledImage.
  860. std::vector<uint32_t> consumers = module_.getSampledImageConsumers(resultID);
  861. if (!consumers.empty()) {
  862. for (auto consumer_id : consumers) {
  863. auto consumer_instr = module_.FindDef(consumer_id);
  864. auto consumer_opcode = consumer_instr->opcode();
  865. if (consumer_instr->block() != sampledImageInstr->block()) {
  866. DIAG(resultTypeIndex)
  867. << "All OpSampledImage instructions must be in the same block in "
  868. "which their Result <id> are consumed. OpSampledImage Result "
  869. "Type <id> '"
  870. << resultID
  871. << "' has a consumer in a different basic "
  872. "block. The consumer instruction <id> is '"
  873. << consumer_id << "'.";
  874. return false;
  875. }
  876. // TODO: The following check is incomplete. We should also check that the
  877. // Sampled Image is not used by instructions that should not take
  878. // SampledImage as an argument. We could find the list of valid
  879. // instructions by scanning for "Sampled Image" in the operand description
  880. // field in the grammar file.
  881. if (consumer_opcode == SpvOpPhi || consumer_opcode == SpvOpSelect) {
  882. DIAG(resultTypeIndex)
  883. << "Result <id> from OpSampledImage instruction must not appear as "
  884. "operands of Op"
  885. << spvOpcodeString(static_cast<SpvOp>(consumer_opcode)) << "."
  886. << " Found result <id> '" << resultID << "' as an operand of <id> '"
  887. << consumer_id << "'.";
  888. return false;
  889. }
  890. }
  891. }
  892. return true;
  893. }
  894. template <>
  895. bool idUsage::isValid<SpvOpSpecConstantComposite>(const spv_instruction_t* inst,
  896. const spv_opcode_desc) {
  897. // The result type must be a composite type.
  898. auto resultTypeIndex = 1;
  899. auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
  900. if (!resultType || !spvOpcodeIsComposite(resultType->opcode())) {
  901. DIAG(resultTypeIndex) << "OpSpecConstantComposite Result Type <id> '"
  902. << inst->words[resultTypeIndex]
  903. << "' is not a composite type.";
  904. return false;
  905. }
  906. // Validation checks differ based on the type of composite type.
  907. auto constituentCount = inst->words.size() - 3;
  908. switch (resultType->opcode()) {
  909. // For Vectors, the following must be met:
  910. // * Number of constituents in the result type and the vector must match.
  911. // * All the components of the vector must have the same type (or specialize
  912. // to the same type). OpConstant and OpSpecConstant are allowed.
  913. // To check that condition, we check each supplied value argument's type
  914. // against the element type of the result type.
  915. case SpvOpTypeVector: {
  916. auto componentCount = resultType->words()[3];
  917. if (componentCount != constituentCount) {
  918. DIAG(inst->words.size() - 1)
  919. << "OpSpecConstantComposite Constituent <id> count does not match "
  920. "Result Type <id> '"
  921. << resultType->id() << "'s vector component count.";
  922. return false;
  923. }
  924. auto componentType = module_.FindDef(resultType->words()[2]);
  925. assert(componentType);
  926. for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
  927. constituentIndex++) {
  928. auto constituent = module_.FindDef(inst->words[constituentIndex]);
  929. if (!constituent ||
  930. !spvOpcodeIsConstantOrUndef(constituent->opcode())) {
  931. DIAG(constituentIndex) << "OpSpecConstantComposite Constituent <id> '"
  932. << inst->words[constituentIndex]
  933. << "' is not a constant or undef.";
  934. return false;
  935. }
  936. auto constituentResultType = module_.FindDef(constituent->type_id());
  937. if (!constituentResultType ||
  938. componentType->opcode() != constituentResultType->opcode()) {
  939. DIAG(constituentIndex)
  940. << "OpSpecConstantComposite Constituent <id> '"
  941. << inst->words[constituentIndex]
  942. << "'s type does not match Result Type <id> '" << resultType->id()
  943. << "'s vector element type.";
  944. return false;
  945. }
  946. }
  947. break;
  948. }
  949. case SpvOpTypeMatrix: {
  950. auto columnCount = resultType->words()[3];
  951. if (columnCount != constituentCount) {
  952. DIAG(inst->words.size() - 1)
  953. << "OpSpecConstantComposite Constituent <id> count does not match "
  954. "Result Type <id> '"
  955. << resultType->id() << "'s matrix column count.";
  956. return false;
  957. }
  958. auto columnType = module_.FindDef(resultType->words()[2]);
  959. assert(columnType);
  960. auto componentCount = columnType->words()[3];
  961. auto componentType = module_.FindDef(columnType->words()[2]);
  962. assert(componentType);
  963. for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
  964. constituentIndex++) {
  965. auto constituent = module_.FindDef(inst->words[constituentIndex]);
  966. auto constituentOpCode = constituent->opcode();
  967. if (!constituent || !(SpvOpSpecConstantComposite == constituentOpCode ||
  968. SpvOpConstantComposite == constituentOpCode ||
  969. SpvOpUndef == constituentOpCode)) {
  970. // The message says "... or undef" because the spec does not say
  971. // undef is a constant.
  972. DIAG(constituentIndex) << "OpSpecConstantComposite Constituent <id> '"
  973. << inst->words[constituentIndex]
  974. << "' is not a constant composite or undef.";
  975. return false;
  976. }
  977. auto vector = module_.FindDef(constituent->type_id());
  978. assert(vector);
  979. if (columnType->opcode() != vector->opcode()) {
  980. DIAG(constituentIndex)
  981. << "OpSpecConstantComposite Constituent <id> '"
  982. << inst->words[constituentIndex]
  983. << "' type does not match Result Type <id> '" << resultType->id()
  984. << "'s matrix column type.";
  985. return false;
  986. }
  987. auto vectorComponentType = module_.FindDef(vector->words()[2]);
  988. assert(vectorComponentType);
  989. if (componentType->id() != vectorComponentType->id()) {
  990. DIAG(constituentIndex)
  991. << "OpSpecConstantComposite Constituent <id> '"
  992. << inst->words[constituentIndex]
  993. << "' component type does not match Result Type <id> '"
  994. << resultType->id() << "'s matrix column component type.";
  995. return false;
  996. }
  997. if (componentCount != vector->words()[3]) {
  998. DIAG(constituentIndex)
  999. << "OpSpecConstantComposite Constituent <id> '"
  1000. << inst->words[constituentIndex]
  1001. << "' vector component count does not match Result Type <id> '"
  1002. << resultType->id() << "'s vector component count.";
  1003. return false;
  1004. }
  1005. }
  1006. break;
  1007. }
  1008. case SpvOpTypeArray: {
  1009. auto elementType = module_.FindDef(resultType->words()[2]);
  1010. assert(elementType);
  1011. auto length = module_.FindDef(resultType->words()[3]);
  1012. assert(length);
  1013. if (length->words()[3] != constituentCount) {
  1014. DIAG(inst->words.size() - 1)
  1015. << "OpSpecConstantComposite Constituent count does not match "
  1016. "Result Type <id> '"
  1017. << resultType->id() << "'s array length.";
  1018. return false;
  1019. }
  1020. for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
  1021. constituentIndex++) {
  1022. auto constituent = module_.FindDef(inst->words[constituentIndex]);
  1023. if (!constituent ||
  1024. !spvOpcodeIsConstantOrUndef(constituent->opcode())) {
  1025. DIAG(constituentIndex) << "OpSpecConstantComposite Constituent <id> '"
  1026. << inst->words[constituentIndex]
  1027. << "' is not a constant or undef.";
  1028. return false;
  1029. }
  1030. auto constituentType = module_.FindDef(constituent->type_id());
  1031. assert(constituentType);
  1032. if (elementType->id() != constituentType->id()) {
  1033. DIAG(constituentIndex)
  1034. << "OpSpecConstantComposite Constituent <id> '"
  1035. << inst->words[constituentIndex]
  1036. << "'s type does not match Result Type <id> '" << resultType->id()
  1037. << "'s array element type.";
  1038. return false;
  1039. }
  1040. }
  1041. break;
  1042. }
  1043. case SpvOpTypeStruct: {
  1044. auto memberCount = resultType->words().size() - 2;
  1045. if (memberCount != constituentCount) {
  1046. DIAG(resultTypeIndex) << "OpSpecConstantComposite Constituent <id> '"
  1047. << inst->words[resultTypeIndex]
  1048. << "' count does not match Result Type <id> '"
  1049. << resultType->id() << "'s struct member count.";
  1050. return false;
  1051. }
  1052. for (uint32_t constituentIndex = 3, memberIndex = 2;
  1053. constituentIndex < inst->words.size();
  1054. constituentIndex++, memberIndex++) {
  1055. auto constituent = module_.FindDef(inst->words[constituentIndex]);
  1056. if (!constituent ||
  1057. !spvOpcodeIsConstantOrUndef(constituent->opcode())) {
  1058. DIAG(constituentIndex) << "OpSpecConstantComposite Constituent <id> '"
  1059. << inst->words[constituentIndex]
  1060. << "' is not a constant or undef.";
  1061. return false;
  1062. }
  1063. auto constituentType = module_.FindDef(constituent->type_id());
  1064. assert(constituentType);
  1065. auto memberType = module_.FindDef(resultType->words()[memberIndex]);
  1066. assert(memberType);
  1067. if (memberType->id() != constituentType->id()) {
  1068. DIAG(constituentIndex)
  1069. << "OpSpecConstantComposite Constituent <id> '"
  1070. << inst->words[constituentIndex]
  1071. << "' type does not match the Result Type <id> '"
  1072. << resultType->id() << "'s member type.";
  1073. return false;
  1074. }
  1075. }
  1076. break;
  1077. }
  1078. default: { assert(0 && "Unreachable!"); } break;
  1079. }
  1080. return true;
  1081. }
  1082. #if 0
  1083. template <>
  1084. bool idUsage::isValid<SpvOpSpecConstantOp>(const spv_instruction_t *inst) {}
  1085. #endif
  1086. template <>
  1087. bool idUsage::isValid<SpvOpVariable>(const spv_instruction_t* inst,
  1088. const spv_opcode_desc) {
  1089. auto resultTypeIndex = 1;
  1090. auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
  1091. if (!resultType || SpvOpTypePointer != resultType->opcode()) {
  1092. DIAG(resultTypeIndex) << "OpVariable Result Type <id> '"
  1093. << inst->words[resultTypeIndex]
  1094. << "' is not a pointer type.";
  1095. return false;
  1096. }
  1097. const auto initialiserIndex = 4;
  1098. if (initialiserIndex < inst->words.size()) {
  1099. const auto initialiser = module_.FindDef(inst->words[initialiserIndex]);
  1100. const auto storageClassIndex = 3;
  1101. const auto is_module_scope_var =
  1102. initialiser && (initialiser->opcode() == SpvOpVariable) &&
  1103. (initialiser->word(storageClassIndex) != SpvStorageClassFunction);
  1104. const auto is_constant =
  1105. initialiser && spvOpcodeIsConstant(initialiser->opcode());
  1106. if (!initialiser || !(is_constant || is_module_scope_var)) {
  1107. DIAG(initialiserIndex)
  1108. << "OpVariable Initializer <id> '" << inst->words[initialiserIndex]
  1109. << "' is not a constant or module-scope variable.";
  1110. return false;
  1111. }
  1112. }
  1113. return true;
  1114. }
  1115. template <>
  1116. bool idUsage::isValid<SpvOpLoad>(const spv_instruction_t* inst,
  1117. const spv_opcode_desc) {
  1118. auto resultTypeIndex = 1;
  1119. auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
  1120. if (!resultType) {
  1121. DIAG(resultTypeIndex) << "OpLoad Result Type <id> '"
  1122. << inst->words[resultTypeIndex] << "' is not defind.";
  1123. return false;
  1124. }
  1125. const bool uses_variable_pointer =
  1126. module_.features().variable_pointers ||
  1127. module_.features().variable_pointers_storage_buffer;
  1128. auto pointerIndex = 3;
  1129. auto pointer = module_.FindDef(inst->words[pointerIndex]);
  1130. if (!pointer ||
  1131. (addressingModel == SpvAddressingModelLogical &&
  1132. ((!uses_variable_pointer &&
  1133. !spvOpcodeReturnsLogicalPointer(pointer->opcode())) ||
  1134. (uses_variable_pointer &&
  1135. !spvOpcodeReturnsLogicalVariablePointer(pointer->opcode()))))) {
  1136. DIAG(pointerIndex) << "OpLoad Pointer <id> '" << inst->words[pointerIndex]
  1137. << "' is not a logical pointer.";
  1138. return false;
  1139. }
  1140. auto pointerType = module_.FindDef(pointer->type_id());
  1141. if (!pointerType || pointerType->opcode() != SpvOpTypePointer) {
  1142. DIAG(pointerIndex) << "OpLoad type for pointer <id> '"
  1143. << inst->words[pointerIndex]
  1144. << "' is not a pointer type.";
  1145. return false;
  1146. }
  1147. auto pointeeType = module_.FindDef(pointerType->words()[3]);
  1148. if (!pointeeType || resultType->id() != pointeeType->id()) {
  1149. DIAG(resultTypeIndex) << "OpLoad Result Type <id> '"
  1150. << inst->words[resultTypeIndex]
  1151. << "' does not match Pointer <id> '" << pointer->id()
  1152. << "'s type.";
  1153. return false;
  1154. }
  1155. return true;
  1156. }
  1157. template <>
  1158. bool idUsage::isValid<SpvOpStore>(const spv_instruction_t* inst,
  1159. const spv_opcode_desc) {
  1160. const bool uses_variable_pointer =
  1161. module_.features().variable_pointers ||
  1162. module_.features().variable_pointers_storage_buffer;
  1163. const auto pointerIndex = 1;
  1164. auto pointer = module_.FindDef(inst->words[pointerIndex]);
  1165. if (!pointer ||
  1166. (addressingModel == SpvAddressingModelLogical &&
  1167. ((!uses_variable_pointer &&
  1168. !spvOpcodeReturnsLogicalPointer(pointer->opcode())) ||
  1169. (uses_variable_pointer &&
  1170. !spvOpcodeReturnsLogicalVariablePointer(pointer->opcode()))))) {
  1171. DIAG(pointerIndex) << "OpStore Pointer <id> '" << inst->words[pointerIndex]
  1172. << "' is not a logical pointer.";
  1173. return false;
  1174. }
  1175. auto pointerType = module_.FindDef(pointer->type_id());
  1176. if (!pointer || pointerType->opcode() != SpvOpTypePointer) {
  1177. DIAG(pointerIndex) << "OpStore type for pointer <id> '"
  1178. << inst->words[pointerIndex]
  1179. << "' is not a pointer type.";
  1180. return false;
  1181. }
  1182. auto type = module_.FindDef(pointerType->words()[3]);
  1183. assert(type);
  1184. if (SpvOpTypeVoid == type->opcode()) {
  1185. DIAG(pointerIndex) << "OpStore Pointer <id> '" << inst->words[pointerIndex]
  1186. << "'s type is void.";
  1187. return false;
  1188. }
  1189. // validate storage class
  1190. {
  1191. uint32_t dataType;
  1192. uint32_t storageClass;
  1193. if (!module_.GetPointerTypeInfo(pointerType->id(), &dataType,
  1194. &storageClass)) {
  1195. DIAG(pointerIndex) << "OpStore Pointer <id> '"
  1196. << inst->words[pointerIndex]
  1197. << "' is not pointer type";
  1198. return false;
  1199. }
  1200. if (storageClass == SpvStorageClassUniformConstant ||
  1201. storageClass == SpvStorageClassInput ||
  1202. storageClass == SpvStorageClassPushConstant) {
  1203. DIAG(pointerIndex) << "OpStore Pointer <id> '"
  1204. << inst->words[pointerIndex]
  1205. << "' storage class is read-only";
  1206. return false;
  1207. }
  1208. }
  1209. auto objectIndex = 2;
  1210. auto object = module_.FindDef(inst->words[objectIndex]);
  1211. if (!object || !object->type_id()) {
  1212. DIAG(objectIndex) << "OpStore Object <id> '" << inst->words[objectIndex]
  1213. << "' is not an object.";
  1214. return false;
  1215. }
  1216. auto objectType = module_.FindDef(object->type_id());
  1217. assert(objectType);
  1218. if (SpvOpTypeVoid == objectType->opcode()) {
  1219. DIAG(objectIndex) << "OpStore Object <id> '" << inst->words[objectIndex]
  1220. << "'s type is void.";
  1221. return false;
  1222. }
  1223. if (type->id() != objectType->id()) {
  1224. if (!module_.options()->relax_struct_store ||
  1225. type->opcode() != SpvOpTypeStruct ||
  1226. objectType->opcode() != SpvOpTypeStruct) {
  1227. DIAG(pointerIndex) << "OpStore Pointer <id> '"
  1228. << inst->words[pointerIndex]
  1229. << "'s type does not match Object <id> '"
  1230. << object->id() << "'s type.";
  1231. return false;
  1232. }
  1233. // TODO: Check for layout compatible matricies and arrays as well.
  1234. if (!AreLayoutCompatibleStructs(type, objectType)) {
  1235. DIAG(pointerIndex) << "OpStore Pointer <id> '"
  1236. << inst->words[pointerIndex]
  1237. << "'s layout does not match Object <id> '"
  1238. << object->id() << "'s layout.";
  1239. return false;
  1240. }
  1241. }
  1242. return true;
  1243. }
  1244. template <>
  1245. bool idUsage::isValid<SpvOpCopyMemory>(const spv_instruction_t* inst,
  1246. const spv_opcode_desc) {
  1247. auto targetIndex = 1;
  1248. auto target = module_.FindDef(inst->words[targetIndex]);
  1249. if (!target) return false;
  1250. auto sourceIndex = 2;
  1251. auto source = module_.FindDef(inst->words[sourceIndex]);
  1252. if (!source) return false;
  1253. auto targetPointerType = module_.FindDef(target->type_id());
  1254. assert(targetPointerType);
  1255. auto targetType = module_.FindDef(targetPointerType->words()[3]);
  1256. assert(targetType);
  1257. auto sourcePointerType = module_.FindDef(source->type_id());
  1258. assert(sourcePointerType);
  1259. auto sourceType = module_.FindDef(sourcePointerType->words()[3]);
  1260. assert(sourceType);
  1261. if (targetType->id() != sourceType->id()) {
  1262. DIAG(sourceIndex) << "OpCopyMemory Target <id> '"
  1263. << inst->words[sourceIndex]
  1264. << "'s type does not match Source <id> '"
  1265. << sourceType->id() << "'s type.";
  1266. return false;
  1267. }
  1268. return true;
  1269. }
  1270. template <>
  1271. bool idUsage::isValid<SpvOpCopyMemorySized>(const spv_instruction_t* inst,
  1272. const spv_opcode_desc) {
  1273. auto targetIndex = 1;
  1274. auto target = module_.FindDef(inst->words[targetIndex]);
  1275. if (!target) return false;
  1276. auto sourceIndex = 2;
  1277. auto source = module_.FindDef(inst->words[sourceIndex]);
  1278. if (!source) return false;
  1279. auto sizeIndex = 3;
  1280. auto size = module_.FindDef(inst->words[sizeIndex]);
  1281. if (!size) return false;
  1282. auto targetPointerType = module_.FindDef(target->type_id());
  1283. if (!targetPointerType || SpvOpTypePointer != targetPointerType->opcode()) {
  1284. DIAG(targetIndex) << "OpCopyMemorySized Target <id> '"
  1285. << inst->words[targetIndex] << "' is not a pointer.";
  1286. return false;
  1287. }
  1288. auto sourcePointerType = module_.FindDef(source->type_id());
  1289. if (!sourcePointerType || SpvOpTypePointer != sourcePointerType->opcode()) {
  1290. DIAG(sourceIndex) << "OpCopyMemorySized Source <id> '"
  1291. << inst->words[sourceIndex] << "' is not a pointer.";
  1292. return false;
  1293. }
  1294. switch (size->opcode()) {
  1295. // TODO: The following opcode's are assumed to be valid, refer to the
  1296. // following bug https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13871 for
  1297. // clarification
  1298. case SpvOpConstant:
  1299. case SpvOpSpecConstant: {
  1300. auto sizeType = module_.FindDef(size->type_id());
  1301. assert(sizeType);
  1302. if (SpvOpTypeInt != sizeType->opcode()) {
  1303. DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
  1304. << inst->words[sizeIndex]
  1305. << "'s type is not an integer type.";
  1306. return false;
  1307. }
  1308. } break;
  1309. case SpvOpVariable: {
  1310. auto pointerType = module_.FindDef(size->type_id());
  1311. assert(pointerType);
  1312. auto sizeType = module_.FindDef(pointerType->type_id());
  1313. if (!sizeType || SpvOpTypeInt != sizeType->opcode()) {
  1314. DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
  1315. << inst->words[sizeIndex]
  1316. << "'s variable type is not an integer type.";
  1317. return false;
  1318. }
  1319. } break;
  1320. default:
  1321. DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
  1322. << inst->words[sizeIndex]
  1323. << "' is not a constant or variable.";
  1324. return false;
  1325. }
  1326. // TODO: Check that consant is a least size 1, see the same bug as above for
  1327. // clarification?
  1328. return true;
  1329. }
  1330. template <>
  1331. bool idUsage::isValid<SpvOpAccessChain>(const spv_instruction_t* inst,
  1332. const spv_opcode_desc) {
  1333. std::string instr_name =
  1334. "Op" + std::string(spvOpcodeString(static_cast<SpvOp>(inst->opcode)));
  1335. // The result type must be OpTypePointer. Result Type is at word 1.
  1336. auto resultTypeIndex = 1;
  1337. auto resultTypeInstr = module_.FindDef(inst->words[resultTypeIndex]);
  1338. if (SpvOpTypePointer != resultTypeInstr->opcode()) {
  1339. DIAG(resultTypeIndex) << "The Result Type of " << instr_name << " <id> '"
  1340. << inst->words[2]
  1341. << "' must be OpTypePointer. Found Op"
  1342. << spvOpcodeString(
  1343. static_cast<SpvOp>(resultTypeInstr->opcode()))
  1344. << ".";
  1345. return false;
  1346. }
  1347. // Result type is a pointer. Find out what it's pointing to.
  1348. // This will be used to make sure the indexing results in the same type.
  1349. // OpTypePointer word 3 is the type being pointed to.
  1350. auto resultTypePointedTo = module_.FindDef(resultTypeInstr->word(3));
  1351. // Base must be a pointer, pointing to the base of a composite object.
  1352. auto baseIdIndex = 3;
  1353. auto baseInstr = module_.FindDef(inst->words[baseIdIndex]);
  1354. auto baseTypeInstr = module_.FindDef(baseInstr->type_id());
  1355. if (!baseTypeInstr || SpvOpTypePointer != baseTypeInstr->opcode()) {
  1356. DIAG(baseIdIndex) << "The Base <id> '" << inst->words[baseIdIndex]
  1357. << "' in " << instr_name
  1358. << " instruction must be a pointer.";
  1359. return false;
  1360. }
  1361. // The result pointer storage class and base pointer storage class must match.
  1362. // Word 2 of OpTypePointer is the Storage Class.
  1363. auto resultTypeStorageClass = resultTypeInstr->word(2);
  1364. auto baseTypeStorageClass = baseTypeInstr->word(2);
  1365. if (resultTypeStorageClass != baseTypeStorageClass) {
  1366. DIAG(resultTypeIndex) << "The result pointer storage class and base "
  1367. "pointer storage class in "
  1368. << instr_name << " do not match.";
  1369. return false;
  1370. }
  1371. // The type pointed to by OpTypePointer (word 3) must be a composite type.
  1372. auto typePointedTo = module_.FindDef(baseTypeInstr->word(3));
  1373. // Check Universal Limit (SPIR-V Spec. Section 2.17).
  1374. // The number of indexes passed to OpAccessChain may not exceed 255
  1375. // The instruction includes 4 words + N words (for N indexes)
  1376. const size_t num_indexes = inst->words.size() - 4;
  1377. const size_t num_indexes_limit =
  1378. module_.options()->universal_limits_.max_access_chain_indexes;
  1379. if (num_indexes > num_indexes_limit) {
  1380. DIAG(resultTypeIndex) << "The number of indexes in " << instr_name
  1381. << " may not exceed " << num_indexes_limit
  1382. << ". Found " << num_indexes << " indexes.";
  1383. return false;
  1384. }
  1385. // Indexes walk the type hierarchy to the desired depth, potentially down to
  1386. // scalar granularity. The first index in Indexes will select the top-level
  1387. // member/element/component/element of the base composite. All composite
  1388. // constituents use zero-based numbering, as described by their OpType...
  1389. // instruction. The second index will apply similarly to that result, and so
  1390. // on. Once any non-composite type is reached, there must be no remaining
  1391. // (unused) indexes.
  1392. for (size_t i = 4; i < inst->words.size(); ++i) {
  1393. const uint32_t cur_word = inst->words[i];
  1394. // Earlier ID checks ensure that cur_word definition exists.
  1395. auto cur_word_instr = module_.FindDef(cur_word);
  1396. // The index must be a scalar integer type (See OpAccessChain in the Spec.)
  1397. auto indexTypeInstr = module_.FindDef(cur_word_instr->type_id());
  1398. if (!indexTypeInstr || SpvOpTypeInt != indexTypeInstr->opcode()) {
  1399. DIAG(i) << "Indexes passed to " << instr_name
  1400. << " must be of type integer.";
  1401. return false;
  1402. }
  1403. switch (typePointedTo->opcode()) {
  1404. case SpvOpTypeMatrix:
  1405. case SpvOpTypeVector:
  1406. case SpvOpTypeArray:
  1407. case SpvOpTypeRuntimeArray: {
  1408. // In OpTypeMatrix, OpTypeVector, OpTypeArray, and OpTypeRuntimeArray,
  1409. // word 2 is the Element Type.
  1410. typePointedTo = module_.FindDef(typePointedTo->word(2));
  1411. break;
  1412. }
  1413. case SpvOpTypeStruct: {
  1414. // In case of structures, there is an additional constraint on the
  1415. // index: the index must be an OpConstant.
  1416. if (SpvOpConstant != cur_word_instr->opcode()) {
  1417. DIAG(i) << "The <id> passed to " << instr_name
  1418. << " to index into a "
  1419. "structure must be an OpConstant.";
  1420. return false;
  1421. }
  1422. // Get the index value from the OpConstant (word 3 of OpConstant).
  1423. // OpConstant could be a signed integer. But it's okay to treat it as
  1424. // unsigned because a negative constant int would never be seen as
  1425. // correct as a struct offset, since structs can't have more than 2
  1426. // billion members.
  1427. const uint32_t cur_index = cur_word_instr->word(3);
  1428. // The index points to the struct member we want, therefore, the index
  1429. // should be less than the number of struct members.
  1430. const uint32_t num_struct_members =
  1431. static_cast<uint32_t>(typePointedTo->words().size() - 2);
  1432. if (cur_index >= num_struct_members) {
  1433. DIAG(i) << "Index is out of bounds: " << instr_name
  1434. << " can not find index " << cur_index
  1435. << " into the structure <id> '" << typePointedTo->id()
  1436. << "'. This structure has " << num_struct_members
  1437. << " members. Largest valid index is "
  1438. << num_struct_members - 1 << ".";
  1439. return false;
  1440. }
  1441. // Struct members IDs start at word 2 of OpTypeStruct.
  1442. auto structMemberId = typePointedTo->word(cur_index + 2);
  1443. typePointedTo = module_.FindDef(structMemberId);
  1444. break;
  1445. }
  1446. default: {
  1447. // Give an error. reached non-composite type while indexes still remain.
  1448. DIAG(i) << instr_name
  1449. << " reached non-composite type while indexes "
  1450. "still remain to be traversed.";
  1451. return false;
  1452. }
  1453. }
  1454. }
  1455. // At this point, we have fully walked down from the base using the indeces.
  1456. // The type being pointed to should be the same as the result type.
  1457. if (typePointedTo->id() != resultTypePointedTo->id()) {
  1458. DIAG(resultTypeIndex)
  1459. << instr_name << " result type (Op"
  1460. << spvOpcodeString(static_cast<SpvOp>(resultTypePointedTo->opcode()))
  1461. << ") does not match the type that results from indexing into the base "
  1462. "<id> (Op"
  1463. << spvOpcodeString(static_cast<SpvOp>(typePointedTo->opcode())) << ").";
  1464. return false;
  1465. }
  1466. return true;
  1467. }
  1468. template <>
  1469. bool idUsage::isValid<SpvOpInBoundsAccessChain>(
  1470. const spv_instruction_t* inst, const spv_opcode_desc opcodeEntry) {
  1471. return isValid<SpvOpAccessChain>(inst, opcodeEntry);
  1472. }
  1473. template <>
  1474. bool idUsage::isValid<SpvOpPtrAccessChain>(const spv_instruction_t* inst,
  1475. const spv_opcode_desc opcodeEntry) {
  1476. // OpPtrAccessChain's validation rules are similar to OpAccessChain, with one
  1477. // difference: word 4 must be id of an integer (Element <id>).
  1478. // The grammar guarantees that there are at least 5 words in the instruction
  1479. // (i.e. if there are fewer than 5 words, the SPIR-V code will not compile.)
  1480. int elem_index = 4;
  1481. // We can remove the Element <id> from the instruction words, and simply call
  1482. // the validation code of OpAccessChain.
  1483. spv_instruction_t new_inst = *inst;
  1484. new_inst.words.erase(new_inst.words.begin() + elem_index);
  1485. return isValid<SpvOpAccessChain>(&new_inst, opcodeEntry);
  1486. }
  1487. template <>
  1488. bool idUsage::isValid<SpvOpInBoundsPtrAccessChain>(
  1489. const spv_instruction_t* inst, const spv_opcode_desc opcodeEntry) {
  1490. // Has the same validation rules as OpPtrAccessChain
  1491. return isValid<SpvOpPtrAccessChain>(inst, opcodeEntry);
  1492. }
  1493. #if 0
  1494. template <>
  1495. bool idUsage::isValid<SpvOpArrayLength>(const spv_instruction_t *inst,
  1496. const spv_opcode_desc opcodeEntry) {}
  1497. #endif
  1498. #if 0
  1499. template <>
  1500. bool idUsage::isValid<SpvOpImagePointer>(const spv_instruction_t *inst,
  1501. const spv_opcode_desc opcodeEntry) {}
  1502. #endif
  1503. #if 0
  1504. template <>
  1505. bool idUsage::isValid<SpvOpGenericPtrMemSemantics>(
  1506. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  1507. #endif
  1508. template <>
  1509. bool idUsage::isValid<SpvOpFunction>(const spv_instruction_t* inst,
  1510. const spv_opcode_desc) {
  1511. auto resultTypeIndex = 1;
  1512. auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
  1513. if (!resultType) return false;
  1514. auto functionTypeIndex = 4;
  1515. auto functionType = module_.FindDef(inst->words[functionTypeIndex]);
  1516. if (!functionType || SpvOpTypeFunction != functionType->opcode()) {
  1517. DIAG(functionTypeIndex)
  1518. << "OpFunction Function Type <id> '" << inst->words[functionTypeIndex]
  1519. << "' is not a function type.";
  1520. return false;
  1521. }
  1522. auto returnType = module_.FindDef(functionType->words()[2]);
  1523. assert(returnType);
  1524. if (returnType->id() != resultType->id()) {
  1525. DIAG(resultTypeIndex) << "OpFunction Result Type <id> '"
  1526. << inst->words[resultTypeIndex]
  1527. << "' does not match the Function Type <id> '"
  1528. << resultType->id() << "'s return type.";
  1529. return false;
  1530. }
  1531. return true;
  1532. }
  1533. template <>
  1534. bool idUsage::isValid<SpvOpFunctionParameter>(const spv_instruction_t* inst,
  1535. const spv_opcode_desc) {
  1536. auto resultTypeIndex = 1;
  1537. auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
  1538. if (!resultType) return false;
  1539. // NOTE: Find OpFunction & ensure OpFunctionParameter is not out of place.
  1540. size_t paramIndex = 0;
  1541. assert(firstInst < inst && "Invalid instruction pointer");
  1542. while (firstInst != --inst) {
  1543. if (SpvOpFunction == inst->opcode) {
  1544. break;
  1545. } else if (SpvOpFunctionParameter == inst->opcode) {
  1546. paramIndex++;
  1547. }
  1548. }
  1549. auto functionType = module_.FindDef(inst->words[4]);
  1550. assert(functionType);
  1551. if (paramIndex >= functionType->words().size() - 3) {
  1552. DIAG(0) << "Too many OpFunctionParameters for " << inst->words[2]
  1553. << ": expected " << functionType->words().size() - 3
  1554. << " based on the function's type";
  1555. return false;
  1556. }
  1557. auto paramType = module_.FindDef(functionType->words()[paramIndex + 3]);
  1558. assert(paramType);
  1559. if (resultType->id() != paramType->id()) {
  1560. DIAG(resultTypeIndex) << "OpFunctionParameter Result Type <id> '"
  1561. << inst->words[resultTypeIndex]
  1562. << "' does not match the OpTypeFunction parameter "
  1563. "type of the same index.";
  1564. return false;
  1565. }
  1566. return true;
  1567. }
  1568. template <>
  1569. bool idUsage::isValid<SpvOpFunctionCall>(const spv_instruction_t* inst,
  1570. const spv_opcode_desc) {
  1571. auto resultTypeIndex = 1;
  1572. auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
  1573. if (!resultType) return false;
  1574. auto functionIndex = 3;
  1575. auto function = module_.FindDef(inst->words[functionIndex]);
  1576. if (!function || SpvOpFunction != function->opcode()) {
  1577. DIAG(functionIndex) << "OpFunctionCall Function <id> '"
  1578. << inst->words[functionIndex] << "' is not a function.";
  1579. return false;
  1580. }
  1581. auto returnType = module_.FindDef(function->type_id());
  1582. assert(returnType);
  1583. if (returnType->id() != resultType->id()) {
  1584. DIAG(resultTypeIndex) << "OpFunctionCall Result Type <id> '"
  1585. << inst->words[resultTypeIndex]
  1586. << "'s type does not match Function <id> '"
  1587. << returnType->id() << "'s return type.";
  1588. return false;
  1589. }
  1590. auto functionType = module_.FindDef(function->words()[4]);
  1591. assert(functionType);
  1592. auto functionCallArgCount = inst->words.size() - 4;
  1593. auto functionParamCount = functionType->words().size() - 3;
  1594. if (functionParamCount != functionCallArgCount) {
  1595. DIAG(inst->words.size() - 1)
  1596. << "OpFunctionCall Function <id>'s parameter count does not match "
  1597. "the argument count.";
  1598. return false;
  1599. }
  1600. for (size_t argumentIndex = 4, paramIndex = 3;
  1601. argumentIndex < inst->words.size(); argumentIndex++, paramIndex++) {
  1602. auto argument = module_.FindDef(inst->words[argumentIndex]);
  1603. if (!argument) return false;
  1604. auto argumentType = module_.FindDef(argument->type_id());
  1605. assert(argumentType);
  1606. auto parameterType = module_.FindDef(functionType->words()[paramIndex]);
  1607. assert(parameterType);
  1608. if (argumentType->id() != parameterType->id()) {
  1609. DIAG(argumentIndex) << "OpFunctionCall Argument <id> '"
  1610. << inst->words[argumentIndex]
  1611. << "'s type does not match Function <id> '"
  1612. << parameterType->id() << "'s parameter type.";
  1613. return false;
  1614. }
  1615. }
  1616. return true;
  1617. }
  1618. template <>
  1619. bool idUsage::isValid<SpvOpVectorShuffle>(const spv_instruction_t* inst,
  1620. const spv_opcode_desc) {
  1621. auto instr_name = [&inst]() {
  1622. std::string name =
  1623. "Op" + std::string(spvOpcodeString(static_cast<SpvOp>(inst->opcode)));
  1624. return name;
  1625. };
  1626. // Result Type must be an OpTypeVector.
  1627. auto resultTypeIndex = 1;
  1628. auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
  1629. if (!resultType || resultType->opcode() != SpvOpTypeVector) {
  1630. DIAG(resultTypeIndex) << "The Result Type of " << instr_name()
  1631. << " must be OpTypeVector. Found Op"
  1632. << spvOpcodeString(
  1633. static_cast<SpvOp>(resultType->opcode()))
  1634. << ".";
  1635. return false;
  1636. }
  1637. // The number of components in Result Type must be the same as the number of
  1638. // Component operands.
  1639. auto componentCount = inst->words.size() - 5;
  1640. auto vectorComponentCountIndex = 3;
  1641. auto resultVectorDimension = resultType->words()[vectorComponentCountIndex];
  1642. if (componentCount != resultVectorDimension) {
  1643. DIAG(inst->words.size() - 1)
  1644. << instr_name()
  1645. << " component literals count does not match "
  1646. "Result Type <id> '"
  1647. << resultType->id() << "'s vector component count.";
  1648. return false;
  1649. }
  1650. // Vector 1 and Vector 2 must both have vector types, with the same Component
  1651. // Type as Result Type.
  1652. auto vector1Index = 3;
  1653. auto vector1Object = module_.FindDef(inst->words[vector1Index]);
  1654. auto vector1Type = module_.FindDef(vector1Object->type_id());
  1655. auto vector2Index = 4;
  1656. auto vector2Object = module_.FindDef(inst->words[vector2Index]);
  1657. auto vector2Type = module_.FindDef(vector2Object->type_id());
  1658. if (!vector1Type || vector1Type->opcode() != SpvOpTypeVector) {
  1659. DIAG(vector1Index) << "The type of Vector 1 must be OpTypeVector.";
  1660. return false;
  1661. }
  1662. if (!vector2Type || vector2Type->opcode() != SpvOpTypeVector) {
  1663. DIAG(vector2Index) << "The type of Vector 2 must be OpTypeVector.";
  1664. return false;
  1665. }
  1666. auto vectorComponentTypeIndex = 2;
  1667. auto resultComponentType = resultType->words()[vectorComponentTypeIndex];
  1668. auto vector1ComponentType = vector1Type->words()[vectorComponentTypeIndex];
  1669. if (vector1ComponentType != resultComponentType) {
  1670. DIAG(vector1Index) << "The Component Type of Vector 1 must be the same "
  1671. "as ResultType.";
  1672. return false;
  1673. }
  1674. auto vector2ComponentType = vector2Type->words()[vectorComponentTypeIndex];
  1675. if (vector2ComponentType != resultComponentType) {
  1676. DIAG(vector2Index) << "The Component Type of Vector 2 must be the same "
  1677. "as ResultType.";
  1678. return false;
  1679. }
  1680. // All Component literals must either be FFFFFFFF or in [0, N - 1].
  1681. auto vector1ComponentCount = vector1Type->words()[vectorComponentCountIndex];
  1682. auto vector2ComponentCount = vector2Type->words()[vectorComponentCountIndex];
  1683. auto N = vector1ComponentCount + vector2ComponentCount;
  1684. auto firstLiteralIndex = 5;
  1685. for (size_t i = firstLiteralIndex; i < inst->words.size(); ++i) {
  1686. auto literal = inst->words[i];
  1687. if (literal != 0xFFFFFFFF && literal >= N) {
  1688. DIAG(i) << "Component literal value " << literal << " is greater than "
  1689. << N - 1 << ".";
  1690. return false;
  1691. }
  1692. }
  1693. return true;
  1694. }
  1695. template <>
  1696. bool idUsage::isValid<SpvOpPhi>(const spv_instruction_t* inst,
  1697. const spv_opcode_desc /*opcodeEntry*/) {
  1698. auto thisInst = module_.FindDef(inst->words[2]);
  1699. SpvOp typeOp = module_.GetIdOpcode(thisInst->type_id());
  1700. if (!spvOpcodeGeneratesType(typeOp)) {
  1701. DIAG(0) << "OpPhi's type <id> " << module_.getIdName(thisInst->type_id())
  1702. << " is not a type instruction.";
  1703. return false;
  1704. }
  1705. auto block = thisInst->block();
  1706. size_t numInOps = inst->words.size() - 3;
  1707. if (numInOps % 2 != 0) {
  1708. DIAG(0) << "OpPhi does not have an equal number of incoming values and "
  1709. "basic blocks.";
  1710. return false;
  1711. }
  1712. // Create a uniqued vector of predecessor ids for comparison against
  1713. // incoming values. OpBranchConditional %cond %label %label produces two
  1714. // predecessors in the CFG.
  1715. std::vector<uint32_t> predIds;
  1716. std::transform(block->predecessors()->begin(), block->predecessors()->end(),
  1717. std::back_inserter(predIds),
  1718. [](const libspirv::BasicBlock* b) { return b->id(); });
  1719. std::sort(predIds.begin(), predIds.end());
  1720. predIds.erase(std::unique(predIds.begin(), predIds.end()), predIds.end());
  1721. size_t numEdges = numInOps / 2;
  1722. if (numEdges != predIds.size()) {
  1723. DIAG(0) << "OpPhi's number of incoming blocks (" << numEdges
  1724. << ") does not match block's predecessor count ("
  1725. << block->predecessors()->size() << ").";
  1726. return false;
  1727. }
  1728. for (size_t i = 3; i < inst->words.size(); ++i) {
  1729. auto incId = inst->words[i];
  1730. if (i % 2 == 1) {
  1731. // Incoming value type must match the phi result type.
  1732. auto incTypeId = module_.GetTypeId(incId);
  1733. if (thisInst->type_id() != incTypeId) {
  1734. DIAG(i) << "OpPhi's result type <id> "
  1735. << module_.getIdName(thisInst->type_id())
  1736. << " does not match incoming value <id> "
  1737. << module_.getIdName(incId) << " type <id> "
  1738. << module_.getIdName(incTypeId) << ".";
  1739. return false;
  1740. }
  1741. } else {
  1742. if (module_.GetIdOpcode(incId) != SpvOpLabel) {
  1743. DIAG(i) << "OpPhi's incoming basic block <id> "
  1744. << module_.getIdName(incId) << " is not an OpLabel.";
  1745. return false;
  1746. }
  1747. // Incoming basic block must be an immediate predecessor of the phi's
  1748. // block.
  1749. if (!std::binary_search(predIds.begin(), predIds.end(), incId)) {
  1750. DIAG(i) << "OpPhi's incoming basic block <id> "
  1751. << module_.getIdName(incId) << " is not a predecessor of <id> "
  1752. << module_.getIdName(block->id()) << ".";
  1753. return false;
  1754. }
  1755. }
  1756. }
  1757. return true;
  1758. }
  1759. #if 0
  1760. template <>
  1761. bool idUsage::isValid<OpLoopMerge>(const spv_instruction_t *inst,
  1762. const spv_opcode_desc opcodeEntry) {}
  1763. #endif
  1764. #if 0
  1765. template <>
  1766. bool idUsage::isValid<OpSelectionMerge>(
  1767. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  1768. #endif
  1769. #if 0
  1770. template <>
  1771. bool idUsage::isValid<OpBranch>(const spv_instruction_t *inst,
  1772. const spv_opcode_desc opcodeEntry) {}
  1773. #endif
  1774. template <>
  1775. bool idUsage::isValid<SpvOpBranchConditional>(const spv_instruction_t* inst,
  1776. const spv_opcode_desc) {
  1777. const size_t numOperands = inst->words.size() - 1;
  1778. const size_t condOperandIndex = 1;
  1779. const size_t targetTrueIndex = 2;
  1780. const size_t targetFalseIndex = 3;
  1781. // num_operands is either 3 or 5 --- if 5, the last two need to be literal
  1782. // integers
  1783. if (numOperands != 3 && numOperands != 5) {
  1784. DIAG(0) << "OpBranchConditional requires either 3 or 5 parameters";
  1785. return false;
  1786. }
  1787. bool ret = true;
  1788. // grab the condition operand and check that it is a bool
  1789. const auto condOp = module_.FindDef(inst->words[condOperandIndex]);
  1790. if (!condOp || !module_.IsBoolScalarType(condOp->type_id())) {
  1791. DIAG(0)
  1792. << "Condition operand for OpBranchConditional must be of boolean type";
  1793. ret = false;
  1794. }
  1795. // target operands must be OpLabel
  1796. // note that we don't need to check that the target labels are in the same
  1797. // function,
  1798. // PerformCfgChecks already checks for that
  1799. const auto targetOpTrue = module_.FindDef(inst->words[targetTrueIndex]);
  1800. if (!targetOpTrue || SpvOpLabel != targetOpTrue->opcode()) {
  1801. DIAG(0) << "The 'True Label' operand for OpBranchConditional must be the "
  1802. "ID of an OpLabel instruction";
  1803. ret = false;
  1804. }
  1805. const auto targetOpFalse = module_.FindDef(inst->words[targetFalseIndex]);
  1806. if (!targetOpFalse || SpvOpLabel != targetOpFalse->opcode()) {
  1807. DIAG(0) << "The 'False Label' operand for OpBranchConditional must be the "
  1808. "ID of an OpLabel instruction";
  1809. ret = false;
  1810. }
  1811. return ret;
  1812. }
  1813. #if 0
  1814. template <>
  1815. bool idUsage::isValid<OpSwitch>(const spv_instruction_t *inst,
  1816. const spv_opcode_desc opcodeEntry) {}
  1817. #endif
  1818. template <>
  1819. bool idUsage::isValid<SpvOpReturnValue>(const spv_instruction_t* inst,
  1820. const spv_opcode_desc) {
  1821. auto valueIndex = 1;
  1822. auto value = module_.FindDef(inst->words[valueIndex]);
  1823. if (!value || !value->type_id()) {
  1824. DIAG(valueIndex) << "OpReturnValue Value <id> '" << inst->words[valueIndex]
  1825. << "' does not represent a value.";
  1826. return false;
  1827. }
  1828. auto valueType = module_.FindDef(value->type_id());
  1829. if (!valueType || SpvOpTypeVoid == valueType->opcode()) {
  1830. DIAG(valueIndex) << "OpReturnValue value's type <id> '" << value->type_id()
  1831. << "' is missing or void.";
  1832. return false;
  1833. }
  1834. const bool uses_variable_pointer =
  1835. module_.features().variable_pointers ||
  1836. module_.features().variable_pointers_storage_buffer;
  1837. if (addressingModel == SpvAddressingModelLogical &&
  1838. SpvOpTypePointer == valueType->opcode() && !uses_variable_pointer &&
  1839. !module_.options()->relax_logcial_pointer) {
  1840. DIAG(valueIndex)
  1841. << "OpReturnValue value's type <id> '" << value->type_id()
  1842. << "' is a pointer, which is invalid in the Logical addressing model.";
  1843. return false;
  1844. }
  1845. // NOTE: Find OpFunction
  1846. const spv_instruction_t* function = inst - 1;
  1847. while (firstInst != function) {
  1848. if (SpvOpFunction == function->opcode) break;
  1849. function--;
  1850. }
  1851. if (SpvOpFunction != function->opcode) {
  1852. DIAG(valueIndex) << "OpReturnValue is not in a basic block.";
  1853. return false;
  1854. }
  1855. auto returnType = module_.FindDef(function->words[1]);
  1856. if (!returnType || returnType->id() != valueType->id()) {
  1857. DIAG(valueIndex) << "OpReturnValue Value <id> '" << inst->words[valueIndex]
  1858. << "'s type does not match OpFunction's return type.";
  1859. return false;
  1860. }
  1861. return true;
  1862. }
  1863. #if 0
  1864. template <>
  1865. bool idUsage::isValid<OpLifetimeStart>(const spv_instruction_t *inst,
  1866. const spv_opcode_desc opcodeEntry) {
  1867. }
  1868. #endif
  1869. #if 0
  1870. template <>
  1871. bool idUsage::isValid<OpLifetimeStop>(const spv_instruction_t *inst,
  1872. const spv_opcode_desc opcodeEntry) {}
  1873. #endif
  1874. #if 0
  1875. template <>
  1876. bool idUsage::isValid<OpAtomicInit>(const spv_instruction_t *inst,
  1877. const spv_opcode_desc opcodeEntry) {}
  1878. #endif
  1879. #if 0
  1880. template <>
  1881. bool idUsage::isValid<OpAtomicLoad>(const spv_instruction_t *inst,
  1882. const spv_opcode_desc opcodeEntry) {}
  1883. #endif
  1884. #if 0
  1885. template <>
  1886. bool idUsage::isValid<OpAtomicStore>(const spv_instruction_t *inst,
  1887. const spv_opcode_desc opcodeEntry) {}
  1888. #endif
  1889. #if 0
  1890. template <>
  1891. bool idUsage::isValid<OpAtomicExchange>(
  1892. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  1893. #endif
  1894. #if 0
  1895. template <>
  1896. bool idUsage::isValid<OpAtomicCompareExchange>(
  1897. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  1898. #endif
  1899. #if 0
  1900. template <>
  1901. bool idUsage::isValid<OpAtomicCompareExchangeWeak>(
  1902. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  1903. #endif
  1904. #if 0
  1905. template <>
  1906. bool idUsage::isValid<OpAtomicIIncrement>(
  1907. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  1908. #endif
  1909. #if 0
  1910. template <>
  1911. bool idUsage::isValid<OpAtomicIDecrement>(
  1912. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  1913. #endif
  1914. #if 0
  1915. template <>
  1916. bool idUsage::isValid<OpAtomicIAdd>(const spv_instruction_t *inst,
  1917. const spv_opcode_desc opcodeEntry) {}
  1918. #endif
  1919. #if 0
  1920. template <>
  1921. bool idUsage::isValid<OpAtomicISub>(const spv_instruction_t *inst,
  1922. const spv_opcode_desc opcodeEntry) {}
  1923. #endif
  1924. #if 0
  1925. template <>
  1926. bool idUsage::isValid<OpAtomicUMin>(const spv_instruction_t *inst,
  1927. const spv_opcode_desc opcodeEntry) {}
  1928. #endif
  1929. #if 0
  1930. template <>
  1931. bool idUsage::isValid<OpAtomicUMax>(const spv_instruction_t *inst,
  1932. const spv_opcode_desc opcodeEntry) {}
  1933. #endif
  1934. #if 0
  1935. template <>
  1936. bool idUsage::isValid<OpAtomicAnd>(const spv_instruction_t *inst,
  1937. const spv_opcode_desc opcodeEntry) {}
  1938. #endif
  1939. #if 0
  1940. template <>
  1941. bool idUsage::isValid<OpAtomicOr>(const spv_instruction_t *inst,
  1942. const spv_opcode_desc opcodeEntry) {}
  1943. #endif
  1944. #if 0
  1945. template <>
  1946. bool idUsage::isValid<OpAtomicXor>(const spv_instruction_t *inst,
  1947. const spv_opcode_desc opcodeEntry) {}
  1948. #endif
  1949. #if 0
  1950. template <>
  1951. bool idUsage::isValid<OpAtomicIMin>(const spv_instruction_t *inst,
  1952. const spv_opcode_desc opcodeEntry) {}
  1953. #endif
  1954. #if 0
  1955. template <>
  1956. bool idUsage::isValid<OpAtomicIMax>(const spv_instruction_t *inst,
  1957. const spv_opcode_desc opcodeEntry) {}
  1958. #endif
  1959. #if 0
  1960. template <>
  1961. bool idUsage::isValid<OpEmitStreamVertex>(
  1962. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  1963. #endif
  1964. #if 0
  1965. template <>
  1966. bool idUsage::isValid<OpEndStreamPrimitive>(
  1967. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  1968. #endif
  1969. #if 0
  1970. template <>
  1971. bool idUsage::isValid<OpGroupAsyncCopy>(
  1972. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  1973. #endif
  1974. #if 0
  1975. template <>
  1976. bool idUsage::isValid<OpGroupWaitEvents>(
  1977. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  1978. #endif
  1979. #if 0
  1980. template <>
  1981. bool idUsage::isValid<OpGroupAll>(const spv_instruction_t *inst,
  1982. const spv_opcode_desc opcodeEntry) {}
  1983. #endif
  1984. #if 0
  1985. template <>
  1986. bool idUsage::isValid<OpGroupAny>(const spv_instruction_t *inst,
  1987. const spv_opcode_desc opcodeEntry) {}
  1988. #endif
  1989. #if 0
  1990. template <>
  1991. bool idUsage::isValid<OpGroupBroadcast>(
  1992. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  1993. #endif
  1994. #if 0
  1995. template <>
  1996. bool idUsage::isValid<OpGroupIAdd>(const spv_instruction_t *inst,
  1997. const spv_opcode_desc opcodeEntry) {}
  1998. #endif
  1999. #if 0
  2000. template <>
  2001. bool idUsage::isValid<OpGroupFAdd>(const spv_instruction_t *inst,
  2002. const spv_opcode_desc opcodeEntry) {}
  2003. #endif
  2004. #if 0
  2005. template <>
  2006. bool idUsage::isValid<OpGroupFMin>(const spv_instruction_t *inst,
  2007. const spv_opcode_desc opcodeEntry) {}
  2008. #endif
  2009. #if 0
  2010. template <>
  2011. bool idUsage::isValid<OpGroupUMin>(const spv_instruction_t *inst,
  2012. const spv_opcode_desc opcodeEntry) {}
  2013. #endif
  2014. #if 0
  2015. template <>
  2016. bool idUsage::isValid<OpGroupSMin>(const spv_instruction_t *inst,
  2017. const spv_opcode_desc opcodeEntry) {}
  2018. #endif
  2019. #if 0
  2020. template <>
  2021. bool idUsage::isValid<OpGroupFMax>(const spv_instruction_t *inst,
  2022. const spv_opcode_desc opcodeEntry) {}
  2023. #endif
  2024. #if 0
  2025. template <>
  2026. bool idUsage::isValid<OpGroupUMax>(const spv_instruction_t *inst,
  2027. const spv_opcode_desc opcodeEntry) {}
  2028. #endif
  2029. #if 0
  2030. template <>
  2031. bool idUsage::isValid<OpGroupSMax>(const spv_instruction_t *inst,
  2032. const spv_opcode_desc opcodeEntry) {}
  2033. #endif
  2034. #if 0
  2035. template <>
  2036. bool idUsage::isValid<OpEnqueueMarker>(const spv_instruction_t *inst,
  2037. const spv_opcode_desc opcodeEntry) {
  2038. }
  2039. #endif
  2040. #if 0
  2041. template <>
  2042. bool idUsage::isValid<OpEnqueueKernel>(const spv_instruction_t *inst,
  2043. const spv_opcode_desc opcodeEntry) {
  2044. }
  2045. #endif
  2046. #if 0
  2047. template <>
  2048. bool idUsage::isValid<OpGetKernelNDrangeSubGroupCount>(
  2049. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2050. #endif
  2051. #if 0
  2052. template <>
  2053. bool idUsage::isValid<OpGetKernelNDrangeMaxSubGroupSize>(
  2054. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2055. #endif
  2056. #if 0
  2057. template <>
  2058. bool idUsage::isValid<OpGetKernelWorkGroupSize>(
  2059. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2060. #endif
  2061. #if 0
  2062. template <>
  2063. bool idUsage::isValid<OpGetKernelPreferredWorkGroupSizeMultiple>(
  2064. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2065. #endif
  2066. #if 0
  2067. template <>
  2068. bool idUsage::isValid<OpRetainEvent>(const spv_instruction_t *inst,
  2069. const spv_opcode_desc opcodeEntry) {}
  2070. #endif
  2071. #if 0
  2072. template <>
  2073. bool idUsage::isValid<OpReleaseEvent>(const spv_instruction_t *inst,
  2074. const spv_opcode_desc opcodeEntry) {}
  2075. #endif
  2076. #if 0
  2077. template <>
  2078. bool idUsage::isValid<OpCreateUserEvent>(
  2079. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2080. #endif
  2081. #if 0
  2082. template <>
  2083. bool idUsage::isValid<OpIsValidEvent>(const spv_instruction_t *inst,
  2084. const spv_opcode_desc opcodeEntry) {}
  2085. #endif
  2086. #if 0
  2087. template <>
  2088. bool idUsage::isValid<OpSetUserEventStatus>(
  2089. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2090. #endif
  2091. #if 0
  2092. template <>
  2093. bool idUsage::isValid<OpCaptureEventProfilingInfo>(
  2094. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2095. #endif
  2096. #if 0
  2097. template <>
  2098. bool idUsage::isValid<OpGetDefaultQueue>(
  2099. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2100. #endif
  2101. #if 0
  2102. template <>
  2103. bool idUsage::isValid<OpBuildNDRange>(const spv_instruction_t *inst,
  2104. const spv_opcode_desc opcodeEntry) {}
  2105. #endif
  2106. #if 0
  2107. template <>
  2108. bool idUsage::isValid<OpReadPipe>(const spv_instruction_t *inst,
  2109. const spv_opcode_desc opcodeEntry) {}
  2110. #endif
  2111. #if 0
  2112. template <>
  2113. bool idUsage::isValid<OpWritePipe>(const spv_instruction_t *inst,
  2114. const spv_opcode_desc opcodeEntry) {}
  2115. #endif
  2116. #if 0
  2117. template <>
  2118. bool idUsage::isValid<OpReservedReadPipe>(
  2119. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2120. #endif
  2121. #if 0
  2122. template <>
  2123. bool idUsage::isValid<OpReservedWritePipe>(
  2124. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2125. #endif
  2126. #if 0
  2127. template <>
  2128. bool idUsage::isValid<OpReserveReadPipePackets>(
  2129. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2130. #endif
  2131. #if 0
  2132. template <>
  2133. bool idUsage::isValid<OpReserveWritePipePackets>(
  2134. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2135. #endif
  2136. #if 0
  2137. template <>
  2138. bool idUsage::isValid<OpCommitReadPipe>(
  2139. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2140. #endif
  2141. #if 0
  2142. template <>
  2143. bool idUsage::isValid<OpCommitWritePipe>(
  2144. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2145. #endif
  2146. #if 0
  2147. template <>
  2148. bool idUsage::isValid<OpIsValidReserveId>(
  2149. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2150. #endif
  2151. #if 0
  2152. template <>
  2153. bool idUsage::isValid<OpGetNumPipePackets>(
  2154. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2155. #endif
  2156. #if 0
  2157. template <>
  2158. bool idUsage::isValid<OpGetMaxPipePackets>(
  2159. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2160. #endif
  2161. #if 0
  2162. template <>
  2163. bool idUsage::isValid<OpGroupReserveReadPipePackets>(
  2164. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2165. #endif
  2166. #if 0
  2167. template <>
  2168. bool idUsage::isValid<OpGroupReserveWritePipePackets>(
  2169. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2170. #endif
  2171. #if 0
  2172. template <>
  2173. bool idUsage::isValid<OpGroupCommitReadPipe>(
  2174. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2175. #endif
  2176. #if 0
  2177. template <>
  2178. bool idUsage::isValid<OpGroupCommitWritePipe>(
  2179. const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
  2180. #endif
  2181. #undef DIAG
  2182. bool idUsage::isValid(const spv_instruction_t* inst) {
  2183. spv_opcode_desc opcodeEntry = nullptr;
  2184. if (spvOpcodeTableValueLookup(targetEnv, opcodeTable, inst->opcode,
  2185. &opcodeEntry))
  2186. return false;
  2187. #define CASE(OpCode) \
  2188. case Spv##OpCode: \
  2189. return isValid<Spv##OpCode>(inst, opcodeEntry);
  2190. #define TODO(OpCode) \
  2191. case Spv##OpCode: \
  2192. return true;
  2193. switch (inst->opcode) {
  2194. TODO(OpUndef)
  2195. CASE(OpMemberName)
  2196. CASE(OpLine)
  2197. CASE(OpDecorate)
  2198. CASE(OpMemberDecorate)
  2199. CASE(OpDecorationGroup)
  2200. CASE(OpGroupDecorate)
  2201. CASE(OpGroupMemberDecorate)
  2202. TODO(OpExtInst)
  2203. CASE(OpEntryPoint)
  2204. CASE(OpExecutionMode)
  2205. CASE(OpTypeVector)
  2206. CASE(OpTypeMatrix)
  2207. CASE(OpTypeSampler)
  2208. CASE(OpTypeArray)
  2209. CASE(OpTypeRuntimeArray)
  2210. CASE(OpTypeStruct)
  2211. CASE(OpTypePointer)
  2212. CASE(OpTypeFunction)
  2213. CASE(OpTypePipe)
  2214. CASE(OpConstantTrue)
  2215. CASE(OpConstantFalse)
  2216. CASE(OpConstantComposite)
  2217. CASE(OpConstantSampler)
  2218. CASE(OpConstantNull)
  2219. CASE(OpSpecConstantTrue)
  2220. CASE(OpSpecConstantFalse)
  2221. CASE(OpSpecConstantComposite)
  2222. CASE(OpSampledImage)
  2223. TODO(OpSpecConstantOp)
  2224. CASE(OpVariable)
  2225. CASE(OpLoad)
  2226. CASE(OpStore)
  2227. CASE(OpCopyMemory)
  2228. CASE(OpCopyMemorySized)
  2229. CASE(OpAccessChain)
  2230. CASE(OpInBoundsAccessChain)
  2231. CASE(OpPtrAccessChain)
  2232. CASE(OpInBoundsPtrAccessChain)
  2233. TODO(OpArrayLength)
  2234. TODO(OpGenericPtrMemSemantics)
  2235. CASE(OpFunction)
  2236. CASE(OpFunctionParameter)
  2237. CASE(OpFunctionCall)
  2238. // Conversion opcodes are validated in validate_conversion.cpp.
  2239. CASE(OpVectorShuffle)
  2240. // Other composite opcodes are validated in validate_composites.cpp.
  2241. // Arithmetic opcodes are validated in validate_arithmetics.cpp.
  2242. // Bitwise opcodes are validated in validate_bitwise.cpp.
  2243. // Logical opcodes are validated in validate_logicals.cpp.
  2244. // Derivative opcodes are validated in validate_derivatives.cpp.
  2245. CASE(OpPhi)
  2246. TODO(OpLoopMerge)
  2247. TODO(OpSelectionMerge)
  2248. TODO(OpBranch)
  2249. CASE(OpBranchConditional)
  2250. TODO(OpSwitch)
  2251. CASE(OpReturnValue)
  2252. TODO(OpLifetimeStart)
  2253. TODO(OpLifetimeStop)
  2254. TODO(OpAtomicLoad)
  2255. TODO(OpAtomicStore)
  2256. TODO(OpAtomicExchange)
  2257. TODO(OpAtomicCompareExchange)
  2258. TODO(OpAtomicCompareExchangeWeak)
  2259. TODO(OpAtomicIIncrement)
  2260. TODO(OpAtomicIDecrement)
  2261. TODO(OpAtomicIAdd)
  2262. TODO(OpAtomicISub)
  2263. TODO(OpAtomicUMin)
  2264. TODO(OpAtomicUMax)
  2265. TODO(OpAtomicAnd)
  2266. TODO(OpAtomicOr)
  2267. TODO(OpAtomicSMin)
  2268. TODO(OpAtomicSMax)
  2269. TODO(OpEmitStreamVertex)
  2270. TODO(OpEndStreamPrimitive)
  2271. TODO(OpGroupAsyncCopy)
  2272. TODO(OpGroupWaitEvents)
  2273. TODO(OpGroupAll)
  2274. TODO(OpGroupAny)
  2275. TODO(OpGroupBroadcast)
  2276. TODO(OpGroupIAdd)
  2277. TODO(OpGroupFAdd)
  2278. TODO(OpGroupFMin)
  2279. TODO(OpGroupUMin)
  2280. TODO(OpGroupSMin)
  2281. TODO(OpGroupFMax)
  2282. TODO(OpGroupUMax)
  2283. TODO(OpGroupSMax)
  2284. TODO(OpEnqueueMarker)
  2285. TODO(OpEnqueueKernel)
  2286. TODO(OpGetKernelNDrangeSubGroupCount)
  2287. TODO(OpGetKernelNDrangeMaxSubGroupSize)
  2288. TODO(OpGetKernelWorkGroupSize)
  2289. TODO(OpGetKernelPreferredWorkGroupSizeMultiple)
  2290. TODO(OpRetainEvent)
  2291. TODO(OpReleaseEvent)
  2292. TODO(OpCreateUserEvent)
  2293. TODO(OpIsValidEvent)
  2294. TODO(OpSetUserEventStatus)
  2295. TODO(OpCaptureEventProfilingInfo)
  2296. TODO(OpGetDefaultQueue)
  2297. TODO(OpBuildNDRange)
  2298. TODO(OpReadPipe)
  2299. TODO(OpWritePipe)
  2300. TODO(OpReservedReadPipe)
  2301. TODO(OpReservedWritePipe)
  2302. TODO(OpReserveReadPipePackets)
  2303. TODO(OpReserveWritePipePackets)
  2304. TODO(OpCommitReadPipe)
  2305. TODO(OpCommitWritePipe)
  2306. TODO(OpIsValidReserveId)
  2307. TODO(OpGetNumPipePackets)
  2308. TODO(OpGetMaxPipePackets)
  2309. TODO(OpGroupReserveReadPipePackets)
  2310. TODO(OpGroupReserveWritePipePackets)
  2311. TODO(OpGroupCommitReadPipe)
  2312. TODO(OpGroupCommitWritePipe)
  2313. default:
  2314. return true;
  2315. }
  2316. #undef TODO
  2317. #undef CASE
  2318. }
  2319. bool idUsage::AreLayoutCompatibleStructs(const libspirv::Instruction* type1,
  2320. const libspirv::Instruction* type2) {
  2321. if (type1->opcode() != SpvOpTypeStruct) {
  2322. return false;
  2323. }
  2324. if (type2->opcode() != SpvOpTypeStruct) {
  2325. return false;
  2326. }
  2327. if (!HaveLayoutCompatibleMembers(type1, type2)) return false;
  2328. return HaveSameLayoutDecorations(type1, type2);
  2329. }
  2330. bool idUsage::HaveLayoutCompatibleMembers(const libspirv::Instruction* type1,
  2331. const libspirv::Instruction* type2) {
  2332. assert(type1->opcode() == SpvOpTypeStruct &&
  2333. "type1 must be and OpTypeStruct instruction.");
  2334. assert(type2->opcode() == SpvOpTypeStruct &&
  2335. "type2 must be and OpTypeStruct instruction.");
  2336. const auto& type1_operands = type1->operands();
  2337. const auto& type2_operands = type2->operands();
  2338. if (type1_operands.size() != type2_operands.size()) {
  2339. return false;
  2340. }
  2341. for (size_t operand = 2; operand < type1_operands.size(); ++operand) {
  2342. if (type1->word(operand) != type2->word(operand)) {
  2343. auto def1 = module_.FindDef(type1->word(operand));
  2344. auto def2 = module_.FindDef(type2->word(operand));
  2345. if (!AreLayoutCompatibleStructs(def1, def2)) {
  2346. return false;
  2347. }
  2348. }
  2349. }
  2350. return true;
  2351. }
  2352. bool idUsage::HaveSameLayoutDecorations(const libspirv::Instruction* type1,
  2353. const libspirv::Instruction* type2) {
  2354. assert(type1->opcode() == SpvOpTypeStruct &&
  2355. "type1 must be and OpTypeStruct instruction.");
  2356. assert(type2->opcode() == SpvOpTypeStruct &&
  2357. "type2 must be and OpTypeStruct instruction.");
  2358. const std::vector<Decoration>& type1_decorations =
  2359. module_.id_decorations(type1->id());
  2360. const std::vector<Decoration>& type2_decorations =
  2361. module_.id_decorations(type2->id());
  2362. // TODO: Will have to add other check for arrays an matricies if we want to
  2363. // handle them.
  2364. if (HasConflictingMemberOffsets(type1_decorations, type2_decorations)) {
  2365. return false;
  2366. }
  2367. return true;
  2368. }
  2369. bool idUsage::HasConflictingMemberOffsets(
  2370. const vector<Decoration>& type1_decorations,
  2371. const vector<Decoration>& type2_decorations) const {
  2372. {
  2373. // We are interested in conflicting decoration. If a decoration is in one
  2374. // list but not the other, then we will assume the code is correct. We are
  2375. // looking for things we know to be wrong.
  2376. //
  2377. // We do not have to traverse type2_decoration because, after traversing
  2378. // type1_decorations, anything new will not be found in
  2379. // type1_decoration. Therefore, it cannot lead to a conflict.
  2380. for (const Decoration& decoration : type1_decorations) {
  2381. switch (decoration.dec_type()) {
  2382. case SpvDecorationOffset: {
  2383. // Since these affect the layout of the struct, they must be present
  2384. // in both structs.
  2385. auto compare = [&decoration](const Decoration& rhs) {
  2386. if (rhs.dec_type() != SpvDecorationOffset) return false;
  2387. return decoration.struct_member_index() ==
  2388. rhs.struct_member_index();
  2389. };
  2390. auto i = find_if(type2_decorations.begin(), type2_decorations.end(),
  2391. compare);
  2392. if (i != type2_decorations.end() &&
  2393. decoration.params().front() != i->params().front()) {
  2394. return true;
  2395. }
  2396. } break;
  2397. default:
  2398. // This decoration does not affect the layout of the structure, so
  2399. // just moving on.
  2400. break;
  2401. }
  2402. }
  2403. }
  2404. return false;
  2405. }
  2406. } // anonymous namespace
  2407. namespace libspirv {
  2408. spv_result_t UpdateIdUse(ValidationState_t& _) {
  2409. for (const auto& inst : _.ordered_instructions()) {
  2410. for (auto& operand : inst.operands()) {
  2411. const spv_operand_type_t& type = operand.type;
  2412. const uint32_t operand_id = inst.word(operand.offset);
  2413. if (spvIsIdType(type) && type != SPV_OPERAND_TYPE_RESULT_ID) {
  2414. if (auto def = _.FindDef(operand_id))
  2415. def->RegisterUse(&inst, operand.offset);
  2416. }
  2417. }
  2418. }
  2419. return SPV_SUCCESS;
  2420. }
  2421. /// This function checks all ID definitions dominate their use in the CFG.
  2422. ///
  2423. /// This function will iterate over all ID definitions that are defined in the
  2424. /// functions of a module and make sure that the definitions appear in a
  2425. /// block that dominates their use.
  2426. ///
  2427. /// NOTE: This function does NOT check module scoped functions which are
  2428. /// checked during the initial binary parse in the IdPass below
  2429. spv_result_t CheckIdDefinitionDominateUse(const ValidationState_t& _) {
  2430. unordered_set<const Instruction*> phi_instructions;
  2431. for (const auto& definition : _.all_definitions()) {
  2432. // Check only those definitions defined in a function
  2433. if (const Function* func = definition.second->function()) {
  2434. if (const BasicBlock* block = definition.second->block()) {
  2435. if (!block->reachable()) continue;
  2436. // If the Id is defined within a block then make sure all references to
  2437. // that Id appear in a blocks that are dominated by the defining block
  2438. for (auto& use_index_pair : definition.second->uses()) {
  2439. const Instruction* use = use_index_pair.first;
  2440. if (const BasicBlock* use_block = use->block()) {
  2441. if (use_block->reachable() == false) continue;
  2442. if (use->opcode() == SpvOpPhi) {
  2443. phi_instructions.insert(use);
  2444. } else if (!block->dominates(*use->block())) {
  2445. return _.diag(SPV_ERROR_INVALID_ID)
  2446. << "ID " << _.getIdName(definition.first)
  2447. << " defined in block " << _.getIdName(block->id())
  2448. << " does not dominate its use in block "
  2449. << _.getIdName(use_block->id());
  2450. }
  2451. }
  2452. }
  2453. } else {
  2454. // If the Ids defined within a function but not in a block(i.e. function
  2455. // parameters, block ids), then make sure all references to that Id
  2456. // appear within the same function
  2457. for (auto use : definition.second->uses()) {
  2458. const Instruction* inst = use.first;
  2459. if (inst->function() && inst->function() != func) {
  2460. return _.diag(SPV_ERROR_INVALID_ID)
  2461. << "ID " << _.getIdName(definition.first)
  2462. << " used in function "
  2463. << _.getIdName(inst->function()->id())
  2464. << " is used outside of it's defining function "
  2465. << _.getIdName(func->id());
  2466. }
  2467. }
  2468. }
  2469. }
  2470. // NOTE: Ids defined outside of functions must appear before they are used
  2471. // This check is being performed in the IdPass function
  2472. }
  2473. // Check all OpPhi parent blocks are dominated by the variable's defining
  2474. // blocks
  2475. for (const Instruction* phi : phi_instructions) {
  2476. if (phi->block()->reachable() == false) continue;
  2477. for (size_t i = 3; i < phi->operands().size(); i += 2) {
  2478. const Instruction* variable = _.FindDef(phi->word(i));
  2479. const BasicBlock* parent =
  2480. phi->function()->GetBlock(phi->word(i + 1)).first;
  2481. if (variable->block() && parent->reachable() &&
  2482. !variable->block()->dominates(*parent)) {
  2483. return _.diag(SPV_ERROR_INVALID_ID)
  2484. << "In OpPhi instruction " << _.getIdName(phi->id()) << ", ID "
  2485. << _.getIdName(variable->id())
  2486. << " definition does not dominate its parent "
  2487. << _.getIdName(parent->id());
  2488. }
  2489. }
  2490. }
  2491. return SPV_SUCCESS;
  2492. }
  2493. // Performs SSA validation on the IDs of an instruction. The
  2494. // can_have_forward_declared_ids functor should return true if the
  2495. // instruction operand's ID can be forward referenced.
  2496. spv_result_t IdPass(ValidationState_t& _,
  2497. const spv_parsed_instruction_t* inst) {
  2498. auto can_have_forward_declared_ids =
  2499. spvOperandCanBeForwardDeclaredFunction(static_cast<SpvOp>(inst->opcode));
  2500. // Keep track of a result id defined by this instruction. 0 means it
  2501. // does not define an id.
  2502. uint32_t result_id = 0;
  2503. for (unsigned i = 0; i < inst->num_operands; i++) {
  2504. const spv_parsed_operand_t& operand = inst->operands[i];
  2505. const spv_operand_type_t& type = operand.type;
  2506. // We only care about Id operands, which are a single word.
  2507. const uint32_t operand_word = inst->words[operand.offset];
  2508. auto ret = SPV_ERROR_INTERNAL;
  2509. switch (type) {
  2510. case SPV_OPERAND_TYPE_RESULT_ID:
  2511. // NOTE: Multiple Id definitions are being checked by the binary parser.
  2512. //
  2513. // Defer undefined-forward-reference removal until after we've analyzed
  2514. // the remaining operands to this instruction. Deferral only matters
  2515. // for
  2516. // OpPhi since it's the only case where it defines its own forward
  2517. // reference. Other instructions that can have forward references
  2518. // either don't define a value or the forward reference is to a function
  2519. // Id (and hence defined outside of a function body).
  2520. result_id = operand_word;
  2521. // NOTE: The result Id is added (in RegisterInstruction) *after* all of
  2522. // the other Ids have been checked to avoid premature use in the same
  2523. // instruction.
  2524. ret = SPV_SUCCESS;
  2525. break;
  2526. case SPV_OPERAND_TYPE_ID:
  2527. case SPV_OPERAND_TYPE_TYPE_ID:
  2528. case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
  2529. case SPV_OPERAND_TYPE_SCOPE_ID:
  2530. if (_.IsDefinedId(operand_word)) {
  2531. ret = SPV_SUCCESS;
  2532. } else if (can_have_forward_declared_ids(i)) {
  2533. ret = _.ForwardDeclareId(operand_word);
  2534. } else {
  2535. ret = _.diag(SPV_ERROR_INVALID_ID)
  2536. << "ID " << _.getIdName(operand_word)
  2537. << " has not been defined";
  2538. }
  2539. break;
  2540. default:
  2541. ret = SPV_SUCCESS;
  2542. break;
  2543. }
  2544. if (SPV_SUCCESS != ret) {
  2545. return ret;
  2546. }
  2547. }
  2548. if (result_id) {
  2549. _.RemoveIfForwardDeclared(result_id);
  2550. }
  2551. _.RegisterInstruction(*inst);
  2552. return SPV_SUCCESS;
  2553. }
  2554. } // namespace libspirv
  2555. spv_result_t spvValidateInstructionIDs(const spv_instruction_t* pInsts,
  2556. const uint64_t instCount,
  2557. const libspirv::ValidationState_t& state,
  2558. spv_position position) {
  2559. idUsage idUsage(state.context(), pInsts, instCount, state.memory_model(),
  2560. state.addressing_model(), state, state.entry_points(),
  2561. position, state.context()->consumer);
  2562. for (uint64_t instIndex = 0; instIndex < instCount; ++instIndex) {
  2563. if (!idUsage.isValid(&pInsts[instIndex])) return SPV_ERROR_INVALID_ID;
  2564. position->index += pInsts[instIndex].words.size();
  2565. }
  2566. return SPV_SUCCESS;
  2567. }