spvtoolsfuzz.proto 81 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428
  1. // Copyright (c) 2019 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // This file is specifically named spvtools_fuzz.proto so that the string
  15. // 'spvtools_fuzz' appears in the names of global-scope symbols that protoc
  16. // generates when targeting C++. This is to reduce the potential for name
  17. // clashes with other globally-scoped symbols.
  18. syntax = "proto3";
  19. package spvtools.fuzz.protobufs;
  20. message UInt32Pair {
  21. // A pair of uint32s; useful for defining mappings.
  22. uint32 first = 1;
  23. uint32 second = 2;
  24. }
  25. message InstructionDescriptor {
  26. // Describes an instruction in some block of a function with respect to a
  27. // base instruction.
  28. // The id of an instruction after which the instruction being described is
  29. // believed to be located. It might be the using instruction itself.
  30. uint32 base_instruction_result_id = 1;
  31. // The opcode for the instruction being described.
  32. uint32 target_instruction_opcode = 2;
  33. // The number of matching opcodes to skip over when searching from the base
  34. // instruction to the instruction being described.
  35. uint32 num_opcodes_to_ignore = 3;
  36. }
  37. message IdUseDescriptor {
  38. // Describes a use of an id as an input operand to an instruction in some
  39. // block of a function.
  40. // Example:
  41. // - id_of_interest = 42
  42. // - enclosing_instruction = (
  43. // base_instruction_result_id = 50,
  44. // target_instruction_opcode = OpStore
  45. // num_opcodes_to_ignore = 7
  46. // )
  47. // - in_operand_index = 1
  48. // represents a use of id 42 as input operand 1 to an OpStore instruction,
  49. // such that the OpStore instruction can be found in the same basic block as
  50. // the instruction with result id 50, and in particular is the 8th OpStore
  51. // instruction found from instruction 50 onwards (i.e. 7 OpStore
  52. // instructions are skipped).
  53. // An id that we would like to be able to find a use of.
  54. uint32 id_of_interest = 1;
  55. // The input operand index at which the use is expected.
  56. InstructionDescriptor enclosing_instruction = 2;
  57. uint32 in_operand_index = 3;
  58. }
  59. message DataDescriptor {
  60. // Represents a data element that can be accessed from an id, by walking the
  61. // type hierarchy via a sequence of 0 or more indices.
  62. //
  63. // Very similar to a UniformBufferElementDescriptor, except that a
  64. // DataDescriptor is rooted at the id of a scalar or composite.
  65. // The object being accessed - a scalar or composite
  66. uint32 object = 1;
  67. // 0 or more indices, used to index into a composite object
  68. repeated uint32 index = 2;
  69. }
  70. message UniformBufferElementDescriptor {
  71. // Represents a data element inside a uniform buffer. The element is
  72. // specified via (a) the result id of a uniform variable in which the element
  73. // is contained, and (b) a series of indices that need to be followed to get
  74. // to the element (via fields and array/vector indices).
  75. //
  76. // Example: suppose there is a uniform variable with descriptor set 7 and
  77. // binding 9, and that the uniform variable has the following type (using
  78. // GLSL-like syntax):
  79. //
  80. // struct S {
  81. // float f;
  82. // vec3 g;
  83. // int4 h[10];
  84. // };
  85. //
  86. // Then:
  87. // - (7, 9, [0]) describes the 'f' field.
  88. // - (7, 9, [1,1]) describes the y component of the 'g' field.
  89. // - (7, 9, [2,7,3]) describes the w component of element 7 of the 'h' field
  90. // The descriptor set and binding associated with a uniform variable.
  91. uint32 descriptor_set = 1;
  92. uint32 binding = 2;
  93. // An ordered sequence of indices through composite structures in the
  94. // uniform buffer.
  95. repeated uint32 index = 3;
  96. }
  97. message InstructionOperand {
  98. // Represents an operand to a SPIR-V instruction.
  99. // The type of the operand.
  100. uint32 operand_type = 1;
  101. // The data associated with the operand. For most operands (e.g. ids,
  102. // storage classes and literals) this will be a single word.
  103. repeated uint32 operand_data = 2;
  104. }
  105. message Instruction {
  106. // Represents a SPIR-V instruction.
  107. // The instruction's opcode (e.g. OpLabel).
  108. uint32 opcode = 1;
  109. // The id of the instruction's result type; 0 if there is no result type.
  110. uint32 result_type_id = 2;
  111. // The id of the instruction's result; 0 if there is no result.
  112. uint32 result_id = 3;
  113. // Zero or more input operands.
  114. repeated InstructionOperand input_operand = 4;
  115. }
  116. message FactSequence {
  117. repeated Fact fact = 1;
  118. }
  119. message Fact {
  120. oneof fact {
  121. // Order the fact options by numeric id (rather than alphabetically).
  122. FactConstantUniform constant_uniform_fact = 1;
  123. FactDataSynonym data_synonym_fact = 2;
  124. FactBlockIsDead block_is_dead_fact = 3;
  125. FactFunctionIsLivesafe function_is_livesafe_fact = 4;
  126. FactPointeeValueIsIrrelevant pointee_value_is_irrelevant_fact = 5;
  127. FactIdEquation id_equation_fact = 6;
  128. FactIdIsIrrelevant id_is_irrelevant = 7;
  129. }
  130. }
  131. // Keep fact message types in alphabetical order:
  132. message FactBlockIsDead {
  133. // Records the fact that a block is guaranteed to be dynamically unreachable.
  134. // This is useful because it informs the fuzzer that rather arbitrary changes
  135. // can be made to this block.
  136. uint32 block_id = 1;
  137. }
  138. message FactConstantUniform {
  139. // Records the fact that a uniform buffer element is guaranteed to be equal
  140. // to a particular constant value. spirv-fuzz can use such guarantees to
  141. // obfuscate code, e.g. to manufacture an expression that will (due to the
  142. // guarantee) evaluate to a particular value at runtime but in a manner that
  143. // cannot be predicted at compile-time.
  144. // An element of a uniform buffer
  145. UniformBufferElementDescriptor uniform_buffer_element_descriptor = 1;
  146. // The words of the associated constant
  147. repeated uint32 constant_word = 2;
  148. }
  149. message FactDataSynonym {
  150. // Records the fact that the data held in two data descriptors are guaranteed
  151. // to be equal. spirv-fuzz can use this to replace uses of one piece of data
  152. // with a known-to-be-equal piece of data.
  153. // Data descriptors guaranteed to hold identical data.
  154. DataDescriptor data1 = 1;
  155. DataDescriptor data2 = 2;
  156. }
  157. message FactFunctionIsLivesafe {
  158. // Records the fact that a function is guaranteed to be "livesafe", meaning
  159. // that it will not make out-of-bounds accesses, does not contain reachable
  160. // OpKill or OpUnreachable instructions, does not contain loops that will
  161. // execute for large numbers of iterations, and only invokes other livesafe
  162. // functions.
  163. uint32 function_id = 1;
  164. }
  165. message FactIdEquation {
  166. // Records the fact that the equation:
  167. //
  168. // lhs_id = opcode rhs_id[0] rhs_id[1] ... rhs_id[N-1]
  169. //
  170. // holds; e.g. that the equation:
  171. //
  172. // %12 = OpIAdd %13 %14
  173. //
  174. // holds in the case where lhs_id is 12, rhs_id is [13, 14], and the opcode is
  175. // OpIAdd.
  176. // The left-hand-side of the equation.
  177. uint32 lhs_id = 1;
  178. // A SPIR-V opcode, from a restricted set of instructions for which equation
  179. // facts make sense.
  180. uint32 opcode = 2;
  181. // The operands to the right-hand-side of the equation.
  182. repeated uint32 rhs_id = 3;
  183. }
  184. message FactIdIsIrrelevant {
  185. // Records a fact that |result_id| is irrelevant (i.e. it's usage doesn't
  186. // change the semantics of the module). This implies that a use of this id
  187. // can later be replaced with some other id of the same type, or the
  188. // definition of |result_id| can be changed so that it yields a different value.
  189. // An irrelevant id.
  190. uint32 result_id = 1;
  191. }
  192. message FactPointeeValueIsIrrelevant {
  193. // Records the fact that value of the data pointed to by a pointer id does
  194. // not influence the observable behaviour of the module. This means that
  195. // arbitrary stores can be made through the pointer, and that nothing can be
  196. // guaranteed about the values that are loaded via the pointer.
  197. // A result id of pointer type
  198. uint32 pointer_id = 1;
  199. }
  200. message AccessChainClampingInfo {
  201. // When making a function livesafe it is necessary to clamp the indices that
  202. // occur as operands to access chain instructions so that they are guaranteed
  203. // to be in bounds. This message type allows an access chain instruction to
  204. // have an associated sequence of ids that are reserved for comparing an
  205. // access chain index with a bound (e.g. an array size), and selecting
  206. // between the access chain index (if it is within bounds) and the bound (if
  207. // it is not).
  208. //
  209. // This allows turning an instruction of the form:
  210. //
  211. // %result = OpAccessChain %type %object ... %index ...
  212. //
  213. // into:
  214. //
  215. // %t1 = OpULessThanEqual %bool %index %bound_minus_one
  216. // %t2 = OpSelect %int_type %t1 %index %bound_minus_one
  217. // %result = OpAccessChain %type %object ... %t2 ...
  218. // The result id of an OpAccessChain or OpInBoundsAccessChain instruction.
  219. uint32 access_chain_id = 1;
  220. // A series of pairs of fresh ids, one per access chain index, for the results
  221. // of a compare instruction and a select instruction, serving the roles of %t1
  222. // and %t2 in the above example.
  223. repeated UInt32Pair compare_and_select_ids = 2;
  224. }
  225. message SideEffectWrapperInfo {
  226. // When flattening a conditional branch, it is necessary to enclose
  227. // instructions that have side effects inside conditionals, so that
  228. // they are only executed if the condition holds. Otherwise, there
  229. // might be unintended changes in memory, or crashes that would not
  230. // originally happen.
  231. // For example, the instruction %id = OpLoad %type %ptr, found in
  232. // the true branch of the conditional, will be enclosed in a new
  233. // conditional (assuming that the block containing it can be split
  234. // around it) as follows:
  235. //
  236. // [previous instructions in the block]
  237. // OpSelectionMerge %merge_block_id None
  238. // OpBranchConditional %cond %execute_block_id %alternative_block_id
  239. // %execute_block_id = OpLabel
  240. // %actual_result_id = OpLoad %type %ptr
  241. // OpBranch %merge_block_id
  242. // %alternative_block_id = OpLabel
  243. // %placeholder_result_id = OpCopyObject %type %value_to_copy_id
  244. // OpBranch %merge_block_id
  245. // %merge_block_id = OpLabel
  246. // %id = OpPhi %type %actual_result_id %execute_block_id %placeholder_result_id %alternative_block_id
  247. // [following instructions from the original block]
  248. //
  249. // If the instruction does not have a result id, this is simplified.
  250. // For example, OpStore %ptr %value, found in the true branch of a
  251. // conditional, is enclosed as follows:
  252. //
  253. // [previous instructions in the block]
  254. // OpSelectionMerge %merge_block None
  255. // OpBranchConditional %cond %execute_block_id %merge_block_id
  256. // %execute_block_id = OpLabel
  257. // OpStore %ptr %value
  258. // OpBranch %merge_block_id
  259. // %merge_block_id = OpLabel
  260. // [following instructions from the original block]
  261. //
  262. // The same happens if the instruction is found in the false branch
  263. // of the conditional being flattened, except that the label ids in
  264. // the OpBranchConditional are swapped.
  265. // An instruction descriptor for identifying the instruction to be
  266. // enclosed inside a conditional. An instruction descriptor is
  267. // necessary because the instruction might not have a result id.
  268. InstructionDescriptor instruction = 1;
  269. // A fresh id for the new merge block.
  270. uint32 merge_block_id = 2;
  271. // A fresh id for the new block where the actual instruction is
  272. // executed.
  273. uint32 execute_block_id = 3;
  274. // The following fields are only needed if the original instruction has a
  275. // result id. They can be set to 0 if not needed.
  276. // A fresh id for the result id of the instruction (the original
  277. // one is used by the OpPhi instruction).
  278. uint32 actual_result_id = 4;
  279. // A fresh id for the new block where the placeholder instruction
  280. // is placed.
  281. uint32 alternative_block_id = 5;
  282. // A fresh id for the placeholder instruction.
  283. uint32 placeholder_result_id = 6;
  284. // An id present in the module, available to use at this point in
  285. // the program and with the same type as the original instruction,
  286. // that can be used to create a placeholder OpCopyObject
  287. // instruction.
  288. uint32 value_to_copy_id = 7;
  289. }
  290. message ReturnMergingInfo {
  291. // TransformationMergeFunctionReturns needs to modify each merge block of
  292. // loops containing return instructions, by:
  293. // - adding instructions to decide whether the function is returning
  294. // - adding instructions to pass on the return value of the function,
  295. // if it is returning
  296. // - changing the branch instruction (which must be an unconditional branch)
  297. // to a conditional branch that, if the function is returning, branches to
  298. // the merge block of the innermost loop that contains this merge block
  299. // (which can be the new merge block introduced by the transformation).
  300. //
  301. // One such merge block of the form:
  302. // %block = OpLabel
  303. // %phi1 = OpPhi %type1 %val1_1 %pred1 %val1_2 %pred2
  304. // %phi2 = OpPhi %type2 %val2_1 %pred1 %val2_2 %pred2
  305. // OpBranch %next
  306. //
  307. // is transformed into:
  308. // %block = OpLabel
  309. // %is_returning_id = OpPhi %bool %false %pred1 %false %pred2 %true %ret_bb1 %is_bb2_returning %mer_bb2
  310. // %maybe_return_val_id = OpPhi %return_type %any_returnable_val %pred1 %any_returnable_val %pred2
  311. // %ret_val1 %ret_bb1 %ret_val2 %mer_bb2
  312. // %phi1 = OpPhi %type1 %val1_1 %pred1 %val1_2 %pred2
  313. // %any_suitable_id_1 %ret_bb1 %any_suitable_id_1 %mer_bb2
  314. // %phi2 = OpPhi %type2 %val2_1 %pred1 %val2_2 %pred2
  315. // %any_suitable_id_1 %ret_bb1 %any_suitable_id_1 %mer_bb2
  316. // OpBranchConditional %is_returning_id %innermost_loop_merge %next
  317. //
  318. // where %ret_bb1 is a block that originally contains a return instruction and %mer_bb2 is the merge block of an inner
  319. // loop, from where the function might be returning.
  320. //
  321. // Note that the block is required to only have OpLabel, OpPhi or OpBranch instructions.
  322. // The id of the merge block that needs to be modified.
  323. uint32 merge_block_id = 1;
  324. // A fresh id for a boolean OpPhi whose value will be true iff the function
  325. // is returning. This will be used to decide whether to break out of the loop
  326. // or to use the original branch of the function. This value will also be
  327. // used by the merge block of the enclosing loop (if there is one) if the
  328. // function is returning from this block.
  329. uint32 is_returning_id = 2;
  330. // A fresh id that will get the value being returned, if the function is
  331. // returning. If the function return type is void, this is ignored.
  332. uint32 maybe_return_val_id = 3;
  333. // A mapping from each existing OpPhi id to a suitable id of the same type
  334. // available to use before the instruction.
  335. repeated UInt32Pair opphi_to_suitable_id = 4;
  336. }
  337. message LoopLimiterInfo {
  338. // Structure capturing the information required to manipulate a loop limiter
  339. // at a loop header.
  340. // The header for the loop.
  341. uint32 loop_header_id = 1;
  342. // A fresh id into which the loop limiter's current value can be loaded.
  343. uint32 load_id = 2;
  344. // A fresh id that can be used to increment the loaded value by 1.
  345. uint32 increment_id = 3;
  346. // A fresh id that can be used to compare the loaded value with the loop
  347. // limit.
  348. uint32 compare_id = 4;
  349. // A fresh id that can be used to compute the conjunction or disjunction of
  350. // an original loop exit condition with |compare_id|, if the loop's back edge
  351. // block can conditionally exit the loop.
  352. uint32 logical_op_id = 5;
  353. // A sequence of ids suitable for extending OpPhi instructions of the loop
  354. // merge block if it did not previously have an incoming edge from the loop
  355. // back edge block.
  356. repeated uint32 phi_id = 6;
  357. }
  358. message TransformationSequence {
  359. repeated Transformation transformation = 1;
  360. }
  361. message Transformation {
  362. oneof transformation {
  363. // Order the transformation options by numeric id (rather than
  364. // alphabetically).
  365. TransformationMoveBlockDown move_block_down = 1;
  366. TransformationSplitBlock split_block = 2;
  367. TransformationAddConstantBoolean add_constant_boolean = 3;
  368. TransformationAddConstantScalar add_constant_scalar = 4;
  369. TransformationAddTypeBoolean add_type_boolean = 5;
  370. TransformationAddTypeFloat add_type_float = 6;
  371. TransformationAddTypeInt add_type_int = 7;
  372. TransformationAddDeadBreak add_dead_break = 8;
  373. TransformationReplaceBooleanConstantWithConstantBinary
  374. replace_boolean_constant_with_constant_binary = 9;
  375. TransformationAddTypePointer add_type_pointer = 10;
  376. TransformationReplaceConstantWithUniform replace_constant_with_uniform = 11;
  377. TransformationAddDeadContinue add_dead_continue = 12;
  378. TransformationReplaceIdWithSynonym replace_id_with_synonym = 13;
  379. TransformationSetSelectionControl set_selection_control = 14;
  380. TransformationCompositeConstruct composite_construct = 15;
  381. TransformationSetLoopControl set_loop_control = 16;
  382. TransformationSetFunctionControl set_function_control = 17;
  383. TransformationAddNoContractionDecoration add_no_contraction_decoration = 18;
  384. TransformationSetMemoryOperandsMask set_memory_operands_mask = 19;
  385. TransformationCompositeExtract composite_extract = 20;
  386. TransformationVectorShuffle vector_shuffle = 21;
  387. TransformationOutlineFunction outline_function = 22;
  388. TransformationMergeBlocks merge_blocks = 23;
  389. TransformationAddTypeVector add_type_vector = 24;
  390. TransformationAddTypeArray add_type_array = 25;
  391. TransformationAddTypeMatrix add_type_matrix = 26;
  392. TransformationAddTypeStruct add_type_struct = 27;
  393. TransformationAddTypeFunction add_type_function = 28;
  394. TransformationAddConstantComposite add_constant_composite = 29;
  395. TransformationAddGlobalVariable add_global_variable = 30;
  396. TransformationAddGlobalUndef add_global_undef = 31;
  397. TransformationAddFunction add_function = 32;
  398. TransformationAddDeadBlock add_dead_block = 33;
  399. TransformationAddLocalVariable add_local_variable = 34;
  400. TransformationLoad load = 35;
  401. TransformationStore store = 36;
  402. TransformationFunctionCall function_call = 37;
  403. TransformationAccessChain access_chain = 38;
  404. TransformationEquationInstruction equation_instruction = 39;
  405. TransformationSwapCommutableOperands swap_commutable_operands = 40;
  406. TransformationPermuteFunctionParameters permute_function_parameters = 41;
  407. TransformationToggleAccessChainInstruction toggle_access_chain_instruction = 42;
  408. TransformationAddConstantNull add_constant_null = 43;
  409. TransformationComputeDataSynonymFactClosure compute_data_synonym_fact_closure = 44;
  410. TransformationAdjustBranchWeights adjust_branch_weights = 45;
  411. TransformationPushIdThroughVariable push_id_through_variable = 46;
  412. TransformationAddSpecConstantOp add_spec_constant_op = 47;
  413. TransformationReplaceLinearAlgebraInstruction replace_linear_algebra_instruction = 48;
  414. TransformationSwapConditionalBranchOperands swap_conditional_branch_operands = 49;
  415. TransformationPermutePhiOperands permute_phi_operands = 50;
  416. TransformationAddParameter add_parameter = 51;
  417. TransformationAddCopyMemory add_copy_memory = 52;
  418. TransformationInvertComparisonOperator invert_comparison_operator = 53;
  419. TransformationAddImageSampleUnusedComponents add_image_sample_unused_components = 54;
  420. TransformationReplaceParameterWithGlobal replace_parameter_with_global = 55;
  421. TransformationRecordSynonymousConstants record_synonymous_constants = 56;
  422. TransformationAddSynonym add_synonym = 57;
  423. TransformationAddRelaxedDecoration add_relaxed_decoration = 58;
  424. TransformationReplaceParamsWithStruct replace_params_with_struct = 59;
  425. TransformationReplaceCopyObjectWithStoreLoad replace_copy_object_with_store_load = 60;
  426. TransformationReplaceCopyMemoryWithLoadStore replace_copy_memory_with_load_store = 61;
  427. TransformationReplaceLoadStoreWithCopyMemory replace_load_store_with_copy_memory = 62;
  428. TransformationAddLoopPreheader add_loop_preheader = 63;
  429. TransformationMoveInstructionDown move_instruction_down = 64;
  430. TransformationMakeVectorOperationDynamic make_vector_operation_dynamic = 65;
  431. TransformationReplaceAddSubMulWithCarryingExtended replace_add_sub_mul_with_carrying_extended = 66;
  432. TransformationPropagateInstructionUp propagate_instruction_up = 67;
  433. TransformationCompositeInsert composite_insert = 68;
  434. TransformationInlineFunction inline_function = 69;
  435. TransformationAddOpPhiSynonym add_opphi_synonym = 70;
  436. TransformationMutatePointer mutate_pointer = 71;
  437. TransformationReplaceIrrelevantId replace_irrelevant_id = 72;
  438. TransformationReplaceOpPhiIdFromDeadPredecessor replace_opphi_id_from_dead_predecessor = 73;
  439. TransformationReplaceOpSelectWithConditionalBranch replace_opselect_with_conditional_branch = 74;
  440. TransformationDuplicateRegionWithSelection duplicate_region_with_selection = 75;
  441. TransformationFlattenConditionalBranch flatten_conditional_branch = 76;
  442. TransformationAddBitInstructionSynonym add_bit_instruction_synonym = 77;
  443. TransformationAddLoopToCreateIntConstantSynonym add_loop_to_create_int_constant_synonym = 78;
  444. TransformationWrapRegionInSelection wrap_region_in_selection = 79;
  445. TransformationAddEarlyTerminatorWrapper add_early_terminator_wrapper = 80;
  446. TransformationPropagateInstructionDown propagate_instruction_down = 81;
  447. TransformationReplaceBranchFromDeadBlockWithExit replace_branch_from_dead_block_with_exit = 82;
  448. TransformationWrapEarlyTerminatorInFunction wrap_early_terminator_in_function = 83;
  449. TransformationMergeFunctionReturns merge_function_returns = 84;
  450. TransformationExpandVectorReduction expand_vector_reduction = 85;
  451. TransformationSwapFunctionVariables swap_function_variables = 86;
  452. TransformationSwapTwoFunctions swap_two_functions = 87;
  453. TransformationWrapVectorSynonym wrap_vector_synonym = 88;
  454. // Add additional option using the next available number.
  455. }
  456. }
  457. // Keep transformation message types in alphabetical order:
  458. message TransformationAccessChain {
  459. // Adds an access chain instruction based on a given pointer and indices.
  460. // When accessing a struct, the corresponding indices must be 32-bit integer constants.
  461. // For any other composite, the indices can be any 32-bit integer, and the transformation
  462. // adds two instructions for each such index to clamp it to the bound, as follows:
  463. //
  464. // %t1 = OpULessThanEqual %bool %index %bound_minus_one
  465. // %t2 = OpSelect %int_type %t1 %index %bound_minus_one
  466. // Result id for the access chain
  467. uint32 fresh_id = 1;
  468. // The pointer from which the access chain starts
  469. uint32 pointer_id = 2;
  470. // Zero or more access chain indices
  471. repeated uint32 index_id = 3;
  472. // A descriptor for an instruction in a block before which the new
  473. // OpAccessChain instruction should be inserted
  474. InstructionDescriptor instruction_to_insert_before = 4;
  475. // Additional fresh ids, required to clamp index variables. A pair is needed
  476. // for each access to a non-struct composite.
  477. repeated UInt32Pair fresh_ids_for_clamping = 5;
  478. }
  479. message TransformationAddBitInstructionSynonym {
  480. // A transformation that adds synonyms for bit instructions by evaluating
  481. // each bit with the corresponding operation. There is a SPIR-V code example in the
  482. // header file of the transformation class that can help understand the transformation.
  483. // This transformation is only applicable if the described instruction has one of the following opcodes.
  484. // Supported:
  485. // OpBitwiseOr
  486. // OpBitwiseXor
  487. // OpBitwiseAnd
  488. // OpNot
  489. // To be supported in the future:
  490. // OpShiftRightLogical
  491. // OpShiftRightArithmetic
  492. // OpShiftLeftLogical
  493. // OpBitReverse
  494. // OpBitCount
  495. // The bit instruction result id.
  496. uint32 instruction_result_id = 1;
  497. // The fresh ids required to apply the transformation.
  498. repeated uint32 fresh_ids = 2;
  499. }
  500. message TransformationAddConstantBoolean {
  501. // Supports adding the constants true and false to a module, which may be
  502. // necessary in order to enable other transformations if they are not present.
  503. // Also, creates an IdIsIrrelevant fact about |fresh_id| if |is_irrelevant| is true.
  504. uint32 fresh_id = 1;
  505. bool is_true = 2;
  506. // If the constant should be marked as irrelevant.
  507. bool is_irrelevant = 3;
  508. }
  509. message TransformationAddConstantComposite {
  510. // Adds a constant of the given composite type to the module.
  511. // Also, creates an IdIsIrrelevant fact about |fresh_id| if
  512. // |is_irrelevant| is true.
  513. // Fresh id for the composite
  514. uint32 fresh_id = 1;
  515. // A composite type id
  516. uint32 type_id = 2;
  517. // Constituent ids for the composite
  518. repeated uint32 constituent_id = 3;
  519. // If the constant should be marked as irrelevant.
  520. bool is_irrelevant = 4;
  521. }
  522. message TransformationAddConstantNull {
  523. // Adds a null constant.
  524. // Id for the constant
  525. uint32 fresh_id = 1;
  526. // Type of the constant
  527. uint32 type_id = 2;
  528. }
  529. message TransformationAddConstantScalar {
  530. // Adds a constant of the given scalar type.
  531. // Also, creates an IdIsIrrelevant fact about
  532. // |fresh_id| if |is_irrelevant| is true.
  533. // Id for the constant
  534. uint32 fresh_id = 1;
  535. // Id for the scalar type of the constant
  536. uint32 type_id = 2;
  537. // Value of the constant
  538. repeated uint32 word = 3;
  539. // If the constant should be marked as irrelevant.
  540. bool is_irrelevant = 4;
  541. }
  542. message TransformationAddCopyMemory {
  543. // Adds an OpCopyMemory instruction into the module.
  544. // Creates either a global or a local variable (based on
  545. // |storage_class| field) to copy the target into.
  546. // OpCopyMemory will be inserted before this instruction.
  547. InstructionDescriptor instruction_descriptor = 1;
  548. // Fresh id to copy memory into.
  549. uint32 fresh_id = 2;
  550. // Source to copy memory from.
  551. uint32 source_id = 3;
  552. // Storage class for the target variable. Can be either Function or Private.
  553. uint32 storage_class = 4;
  554. // Result id for the variable's initializer operand. Its type must be equal to
  555. // variable's pointee type.
  556. uint32 initializer_id = 5;
  557. }
  558. message TransformationAddDeadBlock {
  559. // Adds a new block to the module that is statically reachable from an
  560. // existing block, but dynamically unreachable.
  561. // Fresh id for the dead block
  562. uint32 fresh_id = 1;
  563. // Id of an existing block terminated with OpBranch, such that this OpBranch
  564. // can be replaced with an OpBranchConditional to its exiting successor or
  565. // the dead block
  566. uint32 existing_block = 2;
  567. // Determines whether the condition associated with the OpBranchConditional
  568. // is true or false
  569. bool condition_value = 3;
  570. }
  571. message TransformationAddDeadBreak {
  572. // A transformation that turns a basic block that unconditionally branches to
  573. // its successor into a block that potentially breaks out of a structured
  574. // control flow construct, but in such a manner that the break cannot actually
  575. // be taken.
  576. // The block to break from
  577. uint32 from_block = 1;
  578. // The merge block to break to
  579. uint32 to_block = 2;
  580. // Determines whether the break condition is true or false
  581. bool break_condition_value = 3;
  582. // A sequence of ids suitable for extending OpPhi instructions as a result of
  583. // the new break edge
  584. repeated uint32 phi_id = 4;
  585. }
  586. message TransformationAddDeadContinue {
  587. // A transformation that turns a basic block appearing in a loop and that
  588. // unconditionally branches to its successor into a block that potentially
  589. // branches to the continue target of the loop, but in such a manner that the
  590. // continue branch cannot actually be taken.
  591. // The block to continue from
  592. uint32 from_block = 1;
  593. // Determines whether the continue condition is true or false
  594. bool continue_condition_value = 2;
  595. // A sequence of ids suitable for extending OpPhi instructions as a result of
  596. // the new break edge
  597. repeated uint32 phi_id = 3;
  598. }
  599. message TransformationAddEarlyTerminatorWrapper {
  600. // Adds a function to the module containing a single block with a single non-
  601. // label instruction that is either OpKill, OpUnreachable, or
  602. // OpTerminateInvocation. The purpose of this is to allow such instructions
  603. // to be subsequently replaced with wrapper functions, which can then enable
  604. // transformations (such as inlining) that are hard in the direct presence
  605. // of these instructions.
  606. // Fresh id for the function.
  607. uint32 function_fresh_id = 1;
  608. // Fresh id for the single basic block in the function.
  609. uint32 label_fresh_id = 2;
  610. // One of OpKill, OpUnreachable, OpTerminateInvocation. If additional early
  611. // termination instructions are added to SPIR-V they should also be handled
  612. // here.
  613. uint32 opcode = 3;
  614. }
  615. message TransformationAddFunction {
  616. // Adds a SPIR-V function to the module.
  617. // The series of instructions that comprise the function.
  618. repeated Instruction instruction = 1;
  619. // True if and only if the given function should be made livesafe (see
  620. // FactFunctionIsLivesafe for definition).
  621. bool is_livesafe = 2;
  622. // Fresh id for a new variable that will serve as a "loop limiter" for the
  623. // function; only relevant if |is_livesafe| holds.
  624. uint32 loop_limiter_variable_id = 3;
  625. // Id of an existing unsigned integer constant providing the maximum value
  626. // that the loop limiter can reach before the loop is broken from; only
  627. // relevant if |is_livesafe| holds.
  628. uint32 loop_limit_constant_id = 4;
  629. // Fresh ids for each loop in the function that allow the loop limiter to be
  630. // manipulated; only relevant if |is_livesafe| holds.
  631. repeated LoopLimiterInfo loop_limiter_info = 5;
  632. // Id of an existing global value with the same return type as the function
  633. // that can be used to replace OpKill and OpReachable instructions with
  634. // ReturnValue instructions. Ignored if the function has void return type.
  635. // Only relevant if |is_livesafe| holds.
  636. uint32 kill_unreachable_return_value_id = 6;
  637. // A mapping (represented as a sequence) from every access chain result id in
  638. // the function to the ids required to clamp its indices to ensure they are in
  639. // bounds; only relevant if |is_livesafe| holds.
  640. repeated AccessChainClampingInfo access_chain_clamping_info = 7;
  641. }
  642. message TransformationAddGlobalUndef {
  643. // Adds an undefined value of a given type to the module at global scope.
  644. // Fresh id for the undefined value
  645. uint32 fresh_id = 1;
  646. // The type of the undefined value
  647. uint32 type_id = 2;
  648. }
  649. message TransformationAddGlobalVariable {
  650. // Adds a global variable of the given type to the module, with Private or
  651. // Workgroup storage class, and optionally (for the Private case) with an
  652. // initializer.
  653. // Fresh id for the global variable
  654. uint32 fresh_id = 1;
  655. // The type of the global variable
  656. uint32 type_id = 2;
  657. uint32 storage_class = 3;
  658. // Initial value of the variable
  659. uint32 initializer_id = 4;
  660. // True if and only if the behaviour of the module should not depend on the
  661. // value of the variable, in which case stores to the variable can be
  662. // performed in an arbitrary fashion.
  663. bool value_is_irrelevant = 5;
  664. }
  665. message TransformationAddImageSampleUnusedComponents {
  666. // A transformation that adds unused components to an image sample coordinate.
  667. // An vector id with the original coordinate and the unused components.
  668. uint32 coordinate_with_unused_components_id = 1;
  669. // A descriptor for an image sample instruction.
  670. InstructionDescriptor instruction_descriptor = 2;
  671. }
  672. message TransformationAddLocalVariable {
  673. // Adds a local variable of the given type (which must be a pointer with
  674. // Function storage class) to the given function, initialized to the given
  675. // id.
  676. // Fresh id for the local variable
  677. uint32 fresh_id = 1;
  678. // The type of the local variable
  679. uint32 type_id = 2;
  680. // The id of the function to which the local variable should be added
  681. uint32 function_id = 3;
  682. // Initial value of the variable
  683. uint32 initializer_id = 4;
  684. // True if and only if the behaviour of the module should not depend on the
  685. // value of the variable, in which case stores to the variable can be
  686. // performed in an arbitrary fashion.
  687. bool value_is_irrelevant = 5;
  688. }
  689. message TransformationAddLoopPreheader {
  690. // A transformation that adds a loop preheader block before the given loop header.
  691. // The id of the loop header block
  692. uint32 loop_header_block = 1;
  693. // A fresh id for the preheader block
  694. uint32 fresh_id = 2;
  695. // Fresh ids for splitting the OpPhi instructions in the header.
  696. // A new OpPhi instruction in the preheader is needed for each OpPhi instruction in the header,
  697. // if the header has more than one predecessor outside of the loop.
  698. // This allows turning instructions of the form:
  699. //
  700. // %loop_header_block = OpLabel
  701. // %id1 = OpPhi %type %val1 %pred1_id %val2 %pred2_id %val3 %backedge_block_id
  702. //
  703. // into:
  704. // %fresh_id = OpLabel
  705. // %phi_id1 = OpPhi %type %val1 %pred1_id %val2 %pred2_id
  706. // OpBranch %header_id
  707. // %loop_header_block = OpLabel
  708. // %id1 = OpPhi %type %phi_id1 %fresh_id %val3 %backedge_block_id
  709. repeated uint32 phi_id = 3;
  710. }
  711. message TransformationAddLoopToCreateIntConstantSynonym {
  712. // A transformation that uses a loop to create a synonym for an integer
  713. // constant C (scalar or vector) using an initial value I, a step value S and
  714. // a number of iterations N such that C = I - N * S. For each iteration, S is
  715. // subtracted from the total.
  716. // The loop can be made up of one or two blocks, and it is inserted before a
  717. // block with a single predecessor. In the one-block case, it is of the form:
  718. //
  719. // %loop_id = OpLabel
  720. // %ctr_id = OpPhi %int %int_0 %pred %incremented_ctr_id %loop_id
  721. // %temp_id = OpPhi %type_of_I %I %pred %eventual_syn_id %loop_id
  722. // %eventual_syn_id = OpISub %type_of_I %temp_id %step_val_id
  723. // %incremented_ctr_id = OpIAdd %int %ctr_id %int_1
  724. // %cond_id = OpSLessThan %bool %incremented_ctr_id %num_iterations_id
  725. // OpLoopMerge %block_after_loop_id %loop_id None
  726. // OpBranchConditional %cond_id %loop_id %block_after_loop_id
  727. //
  728. // A new OpPhi instruction is then added to %block_after_loop_id, as follows:
  729. //
  730. // %block_after_loop_id = OpLabel
  731. // %syn_id = OpPhi %type_of_I %eventual_syn_id %loop_id
  732. //
  733. // This can be translated, assuming that N > 0, to:
  734. // int syn = I;
  735. // for (int ctr = 0; ctr < N; ctr++) syn = syn - S;
  736. //
  737. // All existing OpPhi instructions in %block_after_loop_id are also updated
  738. // to reflect the fact that its predecessor is now %loop_id.
  739. // The following are existing ids.
  740. // The id of the integer constant C that we want a synonym of.
  741. uint32 constant_id = 1;
  742. // The id of the initial value integer constant I.
  743. uint32 initial_val_id = 2;
  744. // The id of the step value integer constant S.
  745. uint32 step_val_id = 3;
  746. // The id of the integer scalar constant, its value being the number of
  747. // iterations N.
  748. uint32 num_iterations_id = 4;
  749. // The label id of the block before which the loop must be inserted.
  750. uint32 block_after_loop_id = 5;
  751. // The following are fresh ids.
  752. // A fresh id for the synonym.
  753. uint32 syn_id = 6;
  754. // A fresh id for the label of the loop,
  755. uint32 loop_id = 7;
  756. // A fresh id for the counter.
  757. uint32 ctr_id = 8;
  758. // A fresh id taking the value I - S * ctr at the ctr-th iteration.
  759. uint32 temp_id = 9;
  760. // A fresh id taking the value I - S * (ctr + 1) at the ctr-th iteration, and
  761. // thus I - S * N at the last iteration.
  762. uint32 eventual_syn_id = 10;
  763. // A fresh id for the incremented counter.
  764. uint32 incremented_ctr_id = 11;
  765. // A fresh id for the loop condition.
  766. uint32 cond_id = 12;
  767. // The instructions in the loop can also be laid out in two basic blocks, as follows:
  768. //
  769. // %loop_id = OpLabel
  770. // %ctr_id = OpPhi %int %int_0 %pred %incremented_ctr_id %loop_id
  771. // %temp_id = OpPhi %type_of_I %I %pred %eventual_syn_id %loop_id
  772. // OpLoopMerge %block_after_loop_id %additional_block_id None
  773. // OpBranch %additional_block_id
  774. //
  775. // %additional_block_id = OpLabel
  776. // %eventual_syn_id = OpISub %type_of_I %temp_id %step_val_id
  777. // %incremented_ctr_id = OpIAdd %int %ctr_id %int_1
  778. // %cond_id = OpSLessThan %bool %incremented_ctr_id %num_iterations_id
  779. // OpBranchConditional %cond_id %loop_id %block_after_loop_id
  780. // A fresh id for the additional block. If this is 0, it means that only one
  781. // block is to be created.
  782. uint32 additional_block_id = 13;
  783. }
  784. message TransformationAddNoContractionDecoration {
  785. // Applies OpDecorate NoContraction to the given result id
  786. // Result id to be decorated
  787. uint32 result_id = 1;
  788. }
  789. message TransformationAddOpPhiSynonym {
  790. // Adds an OpPhi instruction at the start of a block with n predecessors (pred_1, pred_2, ..., pred_n)
  791. // and n related ids (id_1, id_2, ..., id_n) which are pairwise synonymous.
  792. // The instruction will be of the form:
  793. // %fresh_id = OpPhi %type %id_1 %pred_1 %id_2 %pred_2 ... %id_n %pred_n
  794. // and fresh_id will be recorded as being synonymous with all the other ids.
  795. // Label id of the block
  796. uint32 block_id = 1;
  797. // Pairs (pred_i, id_i)
  798. repeated UInt32Pair pred_to_id = 2;
  799. // Fresh id for the new instruction
  800. uint32 fresh_id = 3;
  801. }
  802. message TransformationAddParameter {
  803. // Adds a new parameter into the function.
  804. // Result id of the function to add parameters to.
  805. uint32 function_id = 1;
  806. // Fresh id for a new parameter.
  807. uint32 parameter_fresh_id = 2;
  808. // Type id for a new parameter.
  809. uint32 parameter_type_id = 3;
  810. // A map that maps from the OpFunctionCall id to the id that will be passed as the new
  811. // parameter at that call site. It must have the same type as that of the new parameter.
  812. repeated UInt32Pair call_parameter_ids = 4;
  813. // A fresh id for a new function type. This might not be used
  814. // if a required function type already exists or if we can change
  815. // the old function type.
  816. uint32 function_type_fresh_id = 5;
  817. }
  818. message TransformationAddRelaxedDecoration {
  819. // Applies OpDecorate RelaxedPrecision to the given result id
  820. // Result id to be decorated
  821. uint32 result_id = 1;
  822. }
  823. message TransformationAddSpecConstantOp {
  824. // Adds OpSpecConstantOp into the module.
  825. // Result id for the new instruction.
  826. uint32 fresh_id = 1;
  827. // Type id for the new instruction.
  828. uint32 type_id = 2;
  829. // Opcode operand of the OpSpecConstantOp instruction.
  830. uint32 opcode = 3;
  831. // Operands of the |opcode| instruction.
  832. repeated InstructionOperand operand = 4;
  833. }
  834. message TransformationAddSynonym {
  835. // Adds a |synonymous_instruction| before |insert_before| instruction with
  836. // and creates a fact that |result_id| and the result id of |synonymous_instruction|
  837. // are synonymous.
  838. // Result id of the first synonym.
  839. uint32 result_id = 1;
  840. // Type of the synonym to apply. Some types might produce instructions
  841. // with commutative operands. Such types do not specify the order of the
  842. // operands since we have a special transformation to swap commutable operands.
  843. //
  844. // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3499):
  845. // Consider adding more types here.
  846. enum SynonymType {
  847. // New synonym is derived by adding zero to the |result_id|.
  848. ADD_ZERO = 0;
  849. // New synonym is derived by subtracting zero from the |result_id|.
  850. SUB_ZERO = 1;
  851. // New synonym is derived by multiplying |result_id| by one.
  852. MUL_ONE = 2;
  853. // New synonym is derived by applying OpCopyObject instruction to |result_id|.
  854. COPY_OBJECT = 3;
  855. // New synonym is derived by applying OpLogicalOr to |result_id| with the second
  856. // operand being 'false'.
  857. LOGICAL_OR = 4;
  858. // New synonym is derived by applying OpLogicalAnd to |result_id| with the second
  859. // operand being 'true'.
  860. LOGICAL_AND = 5;
  861. // New synonym is derived by applying OpBitwiseOr to |result_id| with the second
  862. // operand being 0 taken with the same bit length as |result_id|
  863. BITWISE_OR = 6;
  864. // New synonym is derived by applying OpBitwiseXor to |result_id| with the second
  865. // operand being 0 taken with the same bit length as |result_id|
  866. BITWISE_XOR = 7;
  867. }
  868. // Type of the synonym to create. See SynonymType for more details.
  869. SynonymType synonym_type = 2;
  870. // Fresh result id for a created synonym.
  871. uint32 synonym_fresh_id = 3;
  872. // An instruction to insert a new synonym before.
  873. InstructionDescriptor insert_before = 4;
  874. }
  875. message TransformationAddTypeArray {
  876. // Adds an array type of the given element type and size to the module
  877. // Fresh id for the array type
  878. uint32 fresh_id = 1;
  879. // The array's element type
  880. uint32 element_type_id = 2;
  881. // The array's size
  882. uint32 size_id = 3;
  883. }
  884. message TransformationAddTypeBoolean {
  885. // Adds OpTypeBool to the module
  886. // Id to be used for the type
  887. uint32 fresh_id = 1;
  888. }
  889. message TransformationAddTypeFloat {
  890. // Adds OpTypeFloat to the module with the given width
  891. // Id to be used for the type
  892. uint32 fresh_id = 1;
  893. // Floating-point width
  894. uint32 width = 2;
  895. }
  896. message TransformationAddTypeFunction {
  897. // Adds a function type to the module
  898. // Fresh id for the function type
  899. uint32 fresh_id = 1;
  900. // The function's return type
  901. uint32 return_type_id = 2;
  902. // The function's argument types
  903. repeated uint32 argument_type_id = 3;
  904. }
  905. message TransformationAddTypeInt {
  906. // Adds OpTypeInt to the module with the given width and signedness
  907. // Id to be used for the type
  908. uint32 fresh_id = 1;
  909. // Integer width
  910. uint32 width = 2;
  911. // True if and only if this is a signed type
  912. bool is_signed = 3;
  913. }
  914. message TransformationAddTypeMatrix {
  915. // Adds a matrix type to the module
  916. // Fresh id for the matrix type
  917. uint32 fresh_id = 1;
  918. // The matrix's column type, which must be a floating-point vector (as per
  919. // the "data rules" in the SPIR-V specification).
  920. uint32 column_type_id = 2;
  921. // The matrix's column count
  922. uint32 column_count = 3;
  923. }
  924. message TransformationAddTypePointer {
  925. // Adds OpTypePointer to the module, with the given storage class and base
  926. // type
  927. // Id to be used for the type
  928. uint32 fresh_id = 1;
  929. // Pointer storage class
  930. uint32 storage_class = 2;
  931. // Id of the base type for the pointer
  932. uint32 base_type_id = 3;
  933. }
  934. message TransformationAddTypeStruct {
  935. // Adds a struct type to the module
  936. // Fresh id for the struct type
  937. uint32 fresh_id = 1;
  938. // The struct's member types
  939. repeated uint32 member_type_id = 3;
  940. }
  941. message TransformationAddTypeVector {
  942. // Adds a vector type to the module
  943. // Fresh id for the vector type
  944. uint32 fresh_id = 1;
  945. // The vector's component type
  946. uint32 component_type_id = 2;
  947. // The vector's component count
  948. uint32 component_count = 3;
  949. }
  950. message TransformationAdjustBranchWeights {
  951. // A transformation that adjusts the branch weights
  952. // of a branch conditional instruction.
  953. // A descriptor for a branch conditional instruction.
  954. InstructionDescriptor instruction_descriptor = 1;
  955. // Branch weights of a branch conditional instruction.
  956. UInt32Pair branch_weights = 2;
  957. }
  958. message TransformationCompositeConstruct {
  959. // A transformation that introduces an OpCompositeConstruct instruction to
  960. // make a composite object.
  961. // Id of the type of the composite that is to be constructed
  962. uint32 composite_type_id = 1;
  963. // Ids of the objects that will form the components of the composite
  964. repeated uint32 component = 2;
  965. // A descriptor for an instruction in a block before which the new
  966. // OpCompositeConstruct instruction should be inserted
  967. InstructionDescriptor instruction_to_insert_before = 3;
  968. // A fresh id for the composite object
  969. uint32 fresh_id = 4;
  970. }
  971. message TransformationCompositeExtract {
  972. // A transformation that adds an instruction to extract an element from a
  973. // composite.
  974. // A descriptor for an instruction in a block before which the new
  975. // OpCompositeExtract instruction should be inserted
  976. InstructionDescriptor instruction_to_insert_before = 1;
  977. // Result id for the extract operation.
  978. uint32 fresh_id = 2;
  979. // Id of the composite from which data is to be extracted.
  980. uint32 composite_id = 3;
  981. // Indices that indicate which part of the composite should be extracted.
  982. repeated uint32 index = 4;
  983. }
  984. message TransformationCompositeInsert {
  985. // A transformation that adds an instruction OpCompositeInsert which creates
  986. // a new composite from an existing composite, with an element inserted.
  987. // A descriptor for an instruction before which the new instruction
  988. // OpCompositeInsert should be inserted.
  989. InstructionDescriptor instruction_to_insert_before = 1;
  990. // Result id of the inserted OpCompositeInsert instruction.
  991. uint32 fresh_id = 2;
  992. // Id of the composite used as the basis for the insertion.
  993. uint32 composite_id = 3;
  994. // Id of the object to be inserted.
  995. uint32 object_id = 4;
  996. // Indices that indicate which part of the composite should be inserted into.
  997. repeated uint32 index = 5;
  998. }
  999. message TransformationComputeDataSynonymFactClosure {
  1000. // A transformation that impacts the fact manager only, forcing a computation
  1001. // of the closure of data synonym facts, so that e.g. if the components of
  1002. // vectors v and w are known to be pairwise synonymous, it is deduced that v
  1003. // and w are themselves synonymous.
  1004. // When searching equivalence classes for implied facts, equivalence classes
  1005. // larger than this size will be skipped.
  1006. uint32 maximum_equivalence_class_size = 1;
  1007. }
  1008. message TransformationDuplicateRegionWithSelection {
  1009. // A transformation that inserts a conditional statement with a boolean expression
  1010. // of arbitrary value and duplicates a given single-entry, single-exit region, so
  1011. // that it is present in each conditional branch and will be executed regardless
  1012. // of which branch will be taken.
  1013. // Fresh id for a label of the new entry block.
  1014. uint32 new_entry_fresh_id = 1;
  1015. // Id for a boolean expression.
  1016. uint32 condition_id = 2;
  1017. // Fresh id for a label of the merge block of the conditional.
  1018. uint32 merge_label_fresh_id = 3;
  1019. // Block id of the entry block of the original region.
  1020. uint32 entry_block_id = 4;
  1021. // Block id of the exit block of the original region.
  1022. uint32 exit_block_id = 5;
  1023. // Map that maps from a label in the original region to the corresponding label
  1024. // in the duplicated region.
  1025. repeated UInt32Pair original_label_to_duplicate_label = 6;
  1026. // Map that maps from a result id in the original region to the corresponding
  1027. // result id in the duplicated region.
  1028. repeated UInt32Pair original_id_to_duplicate_id = 7;
  1029. // Map that maps from a result id in the original region to the result id of the
  1030. // corresponding OpPhi instruction.
  1031. repeated UInt32Pair original_id_to_phi_id = 8;
  1032. }
  1033. message TransformationEquationInstruction {
  1034. // A transformation that adds an instruction to the module that defines an
  1035. // equation between its result id and input operand ids, such that the
  1036. // equation is guaranteed to hold at any program point where all ids involved
  1037. // are available (i.e. at any program point dominated by the instruction).
  1038. // The result id of the new instruction
  1039. uint32 fresh_id = 1;
  1040. // The instruction's opcode
  1041. uint32 opcode = 2;
  1042. // The input operands to the instruction
  1043. repeated uint32 in_operand_id = 3;
  1044. // A descriptor for an instruction in a block before which the new
  1045. // instruction should be inserted
  1046. InstructionDescriptor instruction_to_insert_before = 4;
  1047. }
  1048. message TransformationExpandVectorReduction {
  1049. // A transformation that adds synonyms for OpAny and OpAll instructions by
  1050. // evaluating each vector component with the corresponding logical operation.
  1051. // There is a SPIR-V code example in the header file of the transformation
  1052. // class that can help understand the transformation.
  1053. // The OpAny or OpAll instruction result id.
  1054. uint32 instruction_result_id = 1;
  1055. // The fresh ids required to apply the transformation.
  1056. repeated uint32 fresh_ids = 2;
  1057. }
  1058. message TransformationFlattenConditionalBranch {
  1059. // A transformation that takes a selection construct with a header
  1060. // containing an OpBranchConditional instruction and flattens it.
  1061. // For example, something of the form:
  1062. //
  1063. // %1 = OpLabel
  1064. // [header instructions]
  1065. // OpSelectionMerge %4 None
  1066. // OpBranchConditional %cond %2 %3
  1067. // %2 = OpLabel
  1068. // [true branch instructions]
  1069. // OpBranch %4
  1070. // %3 = OpLabel
  1071. // [false branch instructions]
  1072. // OpBranch %4
  1073. // %4 = OpLabel
  1074. // ...
  1075. //
  1076. // becomes:
  1077. //
  1078. // %1 = OpLabel
  1079. // [header instructions]
  1080. // OpBranch %2
  1081. // %2 = OpLabel
  1082. // [true branch instructions]
  1083. // OpBranch %3
  1084. // %3 = OpLabel
  1085. // [false branch instructions]
  1086. // OpBranch %4
  1087. // %4 = OpLabel
  1088. // ...
  1089. //
  1090. // If all of the instructions in the true or false branches have
  1091. // no side effects, this is semantics-preserving.
  1092. // Side-effecting instructions will instead be enclosed by smaller
  1093. // conditionals. For more details, look at the definition for the
  1094. // SideEffectWrapperInfo message.
  1095. //
  1096. // Nested conditionals or loops are not supported. The false branch
  1097. // could also be executed before the true branch, depending on the
  1098. // |true_branch_first| field.
  1099. // The label id of the header block
  1100. uint32 header_block_id = 1;
  1101. // A boolean field deciding the order in which the original branches
  1102. // will be laid out: the true branch will be laid out first iff this
  1103. // field is true.
  1104. bool true_branch_first = 2;
  1105. // If the convergence block contains an OpPhi with bvec2 result type, it may
  1106. // be necessary to introduce a bvec2 with the selection construct's condition
  1107. // in both components in order to turn the OpPhi into an OpSelect. This
  1108. // this field provides a fresh id for an OpCompositeConstruct instruction for
  1109. // this purpose. It should be set to 0 if no such instruction is required.
  1110. uint32 fresh_id_for_bvec2_selector = 3;
  1111. // The same as |fresh_id_for_bvec2_selector| but for the bvec3 case.
  1112. uint32 fresh_id_for_bvec3_selector = 4;
  1113. // The same as |fresh_id_for_bvec2_selector| but for the bvec4 case.
  1114. uint32 fresh_id_for_bvec4_selector = 5;
  1115. // A list of instructions with side effects, which must be enclosed
  1116. // inside smaller conditionals before flattening the main one, and
  1117. // the corresponding fresh ids and module ids needed.
  1118. repeated SideEffectWrapperInfo side_effect_wrapper_info = 6;
  1119. }
  1120. message TransformationFunctionCall {
  1121. // A transformation that introduces an OpFunctionCall instruction. The call
  1122. // must not make the module's call graph cyclic. Beyond that, if the call
  1123. // is in a dead block it can be to any function with arbitrary suitably-typed
  1124. // arguments; otherwise it must be to a livesafe function, with injected
  1125. // variables as pointer arguments and arbitrary non-pointer arguments.
  1126. // A fresh id for the result of the call
  1127. uint32 fresh_id = 1;
  1128. // Id of the function to be called
  1129. uint32 callee_id = 2;
  1130. // Ids for arguments to the function
  1131. repeated uint32 argument_id = 3;
  1132. // A descriptor for an instruction in a block before which the new
  1133. // OpFunctionCall instruction should be inserted
  1134. InstructionDescriptor instruction_to_insert_before = 4;
  1135. }
  1136. message TransformationInlineFunction {
  1137. // This transformation inlines a function by mapping the function instructions to fresh ids.
  1138. // Result id of the function call instruction.
  1139. uint32 function_call_id = 1;
  1140. // For each result id defined by the called function,
  1141. // this map provides an associated fresh id that can
  1142. // be used in the inlined version of the function call.
  1143. repeated UInt32Pair result_id_map = 2;
  1144. }
  1145. message TransformationInvertComparisonOperator {
  1146. // For some instruction with result id |operator_id| that
  1147. // represents a binary comparison operator (e.g. <, >, <=), this transformation
  1148. // will replace that instruction's result id with |fresh_id|,
  1149. // invert the opcode (< will become >=) and insert OpLogicalNot
  1150. // instruction with result id |operator_id| below.
  1151. // Result id of the instruction to invert.
  1152. uint32 operator_id = 1;
  1153. // Fresh id that will be used by the operator after the inversion.
  1154. uint32 fresh_id = 2;
  1155. }
  1156. message TransformationLoad {
  1157. // Transformation that adds an OpLoad or OpAtomicLoad instruction from a pointer into an id.
  1158. // The result of the load instruction.
  1159. uint32 fresh_id = 1;
  1160. // The pointer to be loaded from.
  1161. uint32 pointer_id = 2;
  1162. // True if and only if the load should be atomic.
  1163. bool is_atomic = 3;
  1164. // The memory scope for the atomic load. Ignored unless |is_atomic| is true.
  1165. uint32 memory_scope_id = 4;
  1166. // The memory semantics for the atomic load. Ignored unless |is_atomic| is true.
  1167. uint32 memory_semantics_id = 5;
  1168. // A descriptor for an instruction in a block before which the new OpLoad
  1169. // instruction should be inserted.
  1170. InstructionDescriptor instruction_to_insert_before = 6;
  1171. }
  1172. message TransformationMakeVectorOperationDynamic {
  1173. // A transformation that replaces the OpCompositeExtract and OpCompositeInsert
  1174. // instructions with the OpVectorExtractDynamic and OpVectorInsertDynamic instructions.
  1175. // The composite instruction result id.
  1176. uint32 instruction_result_id = 1;
  1177. // The OpCompositeExtract/Insert instructions accept integer literals as indices to the composite object.
  1178. // However, the OpVectorInsert/ExtractDynamic instructions require its single index to be an integer instruction.
  1179. // This is the result id of the integer instruction.
  1180. uint32 constant_index_id = 2;
  1181. }
  1182. message TransformationMergeBlocks {
  1183. // A transformation that merges a block with its predecessor.
  1184. // The id of the block that is to be merged with its predecessor; the merged
  1185. // block will have the *predecessor's* id.
  1186. uint32 block_id = 1;
  1187. }
  1188. message TransformationMergeFunctionReturns {
  1189. // A transformation that modifies a function so that it does not return early,
  1190. // so it only has one return statement (ignoring unreachable blocks).
  1191. //
  1192. // The function is enclosed inside an outer loop, that is only executed once,
  1193. // and whose merge block is the new return block of the function.
  1194. //
  1195. // Each return instruction is replaced by:
  1196. // OpBranch %innermost_loop_merge
  1197. // where %innermost_loop_merge is the innermost loop containing the return
  1198. // instruction.
  1199. //
  1200. // Each merge block whose associated loop contains return instructions is
  1201. // changed so that it branches to the merge block of the loop containing it,
  1202. // as explained in the comments to the ReturnMergingInfo message.
  1203. //
  1204. // The new return block (the merge block of the new outer loop) will be of
  1205. // the following form (if the return type is not void):
  1206. // %outer_return_id = OpLabel
  1207. // %return_val_id = OpPhi %return_type %val1 %block_1 %val2 %block_2 ...
  1208. // OpReturnValue %return_val_id
  1209. // where %block_k is either a return block that, in the original function, is
  1210. // outside of any loops, or the merge block of a loop that contains return
  1211. // instructions and is not, originally, nested inside another loop, and
  1212. // %block_k is the corresponding return value.
  1213. // If the function has void type, there will be no OpPhi instruction and the
  1214. // last instruction will be OpReturn.
  1215. // The id of the function to which the transformation is being applied.
  1216. uint32 function_id = 1;
  1217. // A fresh id for the header of the new outer loop.
  1218. uint32 outer_header_id = 2;
  1219. // A fresh id for an unreachable continue construct for the new outer loop.
  1220. uint32 unreachable_continue_id = 7;
  1221. // A fresh id for the new return block of the function,
  1222. // i.e. the merge block of the new outer loop.
  1223. uint32 outer_return_id = 3;
  1224. // A fresh id for the value that will be returned.
  1225. // This is ignored if the function has void return type.
  1226. uint32 return_val_id = 4;
  1227. // An existing id of the same type as the return value, which is
  1228. // available to use at the end of the entry block.
  1229. // This is ignored if the function has void return type or if no
  1230. // loops in the function contain a return instruction.
  1231. // If the function is not void, the transformation will add an
  1232. // OpPhi instruction to each merge block whose associated loop
  1233. // contains at least a return instruction. The value associated
  1234. // with existing predecessors from which the function cannot be
  1235. // returning will be this id, used as a placeholder.
  1236. uint32 any_returnable_val_id = 5;
  1237. // The information needed to modify the merge blocks of
  1238. // loops containing return instructions.
  1239. repeated ReturnMergingInfo return_merging_info = 6;
  1240. }
  1241. message TransformationMoveBlockDown {
  1242. // A transformation that moves a basic block to be one position lower in
  1243. // program order.
  1244. // The id of the block to move down.
  1245. uint32 block_id = 1;
  1246. }
  1247. message TransformationMoveInstructionDown {
  1248. // Swaps |instruction| with the next instruction in the block.
  1249. // The instruction to move down.
  1250. InstructionDescriptor instruction = 1;
  1251. }
  1252. message TransformationMutatePointer {
  1253. // Backs up value of the pointer, writes into the pointer and
  1254. // restores the original value.
  1255. // Result id of the pointer instruction to mutate.
  1256. uint32 pointer_id = 1;
  1257. // Fresh id for the OpLoad instruction.
  1258. uint32 fresh_id = 2;
  1259. // Instruction to insert backup, mutation and restoration code before.
  1260. InstructionDescriptor insert_before = 3;
  1261. }
  1262. message TransformationOutlineFunction {
  1263. // A transformation that outlines a single-entry single-exit region of a
  1264. // control flow graph into a separate function, and replaces the region with
  1265. // a call to that function.
  1266. // Id of the entry block of the single-entry single-exit region to be outlined
  1267. uint32 entry_block = 1;
  1268. // Id of the exit block of the single-entry single-exit region to be outlined
  1269. uint32 exit_block = 2;
  1270. // Id of a struct that will store the return values of the new function
  1271. uint32 new_function_struct_return_type_id = 3;
  1272. // A fresh id for the type of the outlined function
  1273. uint32 new_function_type_id = 4;
  1274. // A fresh id for the outlined function itself
  1275. uint32 new_function_id = 5;
  1276. // A fresh id to represent the block in the outlined function that represents
  1277. // the first block of the outlined region.
  1278. uint32 new_function_region_entry_block = 6;
  1279. // A fresh id for the result of the OpFunctionCall instruction that will call
  1280. // the outlined function
  1281. uint32 new_caller_result_id = 7;
  1282. // A fresh id to capture the return value of the outlined function - the
  1283. // argument to OpReturn
  1284. uint32 new_callee_result_id = 8;
  1285. // Ids defined outside the region and used inside the region will become
  1286. // parameters to the outlined function. This is a mapping from used ids to
  1287. // fresh parameter ids.
  1288. repeated UInt32Pair input_id_to_fresh_id = 9;
  1289. // Ids defined inside the region and used outside the region will become
  1290. // fresh ids defined by the outlined function, which get copied into the
  1291. // function's struct return value and then copied into their destination ids
  1292. // by the caller. This is a mapping from original ids to corresponding fresh
  1293. // ids.
  1294. repeated UInt32Pair output_id_to_fresh_id = 10;
  1295. }
  1296. message TransformationPermuteFunctionParameters {
  1297. // A transformation that, given a non-entry-point function taking n
  1298. // parameters and a permutation of the set [0, n-1]:
  1299. // - Introduces a new function type that is the same as the original
  1300. // function's type but with the order of arguments permuted
  1301. // (only if it doesn't already exist)
  1302. // - Changes the type of the function to this type
  1303. // - Adjusts all calls to the function so that their arguments are permuted
  1304. // Function, whose parameters will be permuted
  1305. uint32 function_id = 1;
  1306. // Fresh id for a new type of the function. This might not be used
  1307. // if a required function type already exists or if we can change
  1308. // the old function type.
  1309. uint32 function_type_fresh_id = 2;
  1310. // An array of size |n|, where |n| is a number of arguments to a function
  1311. // with |function_id|. For each i: 0 <= permutation[i] < n.
  1312. //
  1313. // i-th element of this array contains a position for an i-th
  1314. // function's argument (i.e. i-th argument will be permutation[i]-th
  1315. // after running this transformation)
  1316. repeated uint32 permutation = 3;
  1317. }
  1318. message TransformationPermutePhiOperands {
  1319. // Permutes operands of some OpPhi instruction.
  1320. // Result id of the instruction to apply the transformation to.
  1321. uint32 result_id = 1;
  1322. // A sequence of numbers in the range [0, n/2 - 1] where |n| is the number
  1323. // of operands of the OpPhi instruction with |result_id|.
  1324. repeated uint32 permutation = 2;
  1325. }
  1326. message TransformationPropagateInstructionDown {
  1327. // Propagates an instruction from |block_id| into its successors.
  1328. // Concretely, the transformation clones the propagated instruction
  1329. // into some of the successors of |block_id| and removes the original
  1330. // instruction. Additionally, an OpPhi instruction may be added to make sure
  1331. // that the transformation can be applied in various scenarios.
  1332. //
  1333. // Note that the instruction might not be propagated down into every successor
  1334. // of |block_id| since it might make the module invalid.
  1335. // Id of the block to propagate an instruction from. The decision on what
  1336. // instruction to propagate is made based on whether the instruction interacts
  1337. // with memory, whether that instruction is used in its block etc (see the
  1338. // transformation class for more details).
  1339. uint32 block_id = 1;
  1340. // A fresh id for an OpPhi instruction. This might not be used by the
  1341. // transformation since an OpPhi instruction is created only if needed
  1342. // (e.g. an instruction is propagated into divergent blocks).
  1343. uint32 phi_fresh_id = 2;
  1344. // A map from the id of some successor of the |block_id| to the fresh id.
  1345. // The map contains a fresh id for at least every successor of the |block_id|.
  1346. // Every fresh id in the map corresponds to the result id of the clone,
  1347. // propagated into the corresponding successor block. This transformation
  1348. // might use overflow ids if they are available and this field doesn't account
  1349. // for every successor of |block_id|.
  1350. repeated UInt32Pair successor_id_to_fresh_id = 3;
  1351. }
  1352. message TransformationPropagateInstructionUp {
  1353. // Propagates an instruction in the block into the block's predecessors.
  1354. // Concretely, this transformation clones some particular instruction from
  1355. // the |block_id| into every block's predecessor and replaces the original
  1356. // instruction with OpPhi. Take a look at the transformation class to learn
  1357. // more about how we choose what instruction to propagate.
  1358. // Id of the block to propagate an instruction from.
  1359. uint32 block_id = 1;
  1360. // A map from the id of some predecessor of the |block_id| to the fresh id.
  1361. // The map contains a fresh id for at least every predecessor of the |block_id|.
  1362. // The instruction is propagated by creating a number of clones - one clone for
  1363. // each predecessor. Fresh ids from this field are used as result ids of cloned
  1364. // instructions.
  1365. repeated UInt32Pair predecessor_id_to_fresh_id = 2;
  1366. }
  1367. message TransformationPushIdThroughVariable {
  1368. // A transformation that makes |value_synonym_id| and |value_id| to be
  1369. // synonymous by storing |value_id| into |variable_id| and
  1370. // loading |variable_id| to |value_synonym_id|.
  1371. // The value to be stored.
  1372. uint32 value_id = 1;
  1373. // A fresh id for the result of the load instruction.
  1374. uint32 value_synonym_id = 2;
  1375. // A fresh id for the variable to be stored to.
  1376. uint32 variable_id = 3;
  1377. // Constant to initialize the variable from.
  1378. uint32 initializer_id = 4;
  1379. // The variable storage class (global or local).
  1380. uint32 variable_storage_class = 5;
  1381. // A descriptor for an instruction which the new OpStore
  1382. // and OpLoad instructions might be inserted before.
  1383. InstructionDescriptor instruction_descriptor = 6;
  1384. }
  1385. message TransformationRecordSynonymousConstants {
  1386. // A transformation that, given the IDs to two synonymous constants,
  1387. // records the fact that they are synonymous. The module is not changed.
  1388. // Two constants are synonymous if:
  1389. // - they have the same type (ignoring the presence of integer sign)
  1390. // - they have the same opcode (one of OpConstant, OpConstantTrue,
  1391. // OpConstantFalse, OpConstantNull)
  1392. // - they have the same value
  1393. // If the types are the same, OpConstantNull is equivalent to
  1394. // OpConstantFalse or OpConstant with value zero.
  1395. // The id of a constant
  1396. uint32 constant1_id = 1;
  1397. // The id of the synonym
  1398. uint32 constant2_id = 2;
  1399. }
  1400. message TransformationReplaceAddSubMulWithCarryingExtended {
  1401. // Replaces OpIAdd with OpIAddCarry, OpISub with OpISubBorrow, OpIMul
  1402. // with OpUMulExtended or OpSMulExtended (depending on the signedness
  1403. // of the operands) and stores the result into a |struct_fresh_id|.
  1404. // In the original instruction the result type id and the type ids of
  1405. // the operands must be the same. Then the transformation extracts
  1406. // the first element of the result into the original |result_id|.
  1407. // This value is the same as the result of the original instruction.
  1408. // The fresh id of the intermediate result.
  1409. uint32 struct_fresh_id = 1;
  1410. // The result id of the original instruction.
  1411. uint32 result_id = 2;
  1412. }
  1413. message TransformationReplaceBranchFromDeadBlockWithExit {
  1414. // Given a dead block that ends with OpBranch, replaces OpBranch with an
  1415. // "exit" instruction; one of OpReturn/OpReturnValue, OpKill (in a fragment
  1416. // shader) or OpUnreachable.
  1417. // The dead block whose terminator is to be replaced.
  1418. uint32 block_id = 1;
  1419. // The opcode of the new terminator.
  1420. uint32 opcode = 2;
  1421. // Ignored unless opcode is OpReturnValue, in which case this field provides
  1422. // a suitable result id to be returned.
  1423. uint32 return_value_id = 3;
  1424. }
  1425. message TransformationReplaceParameterWithGlobal {
  1426. // Removes parameter with result id |parameter_id| from its function
  1427. // and creates a global variable to pass its value to the function instead.
  1428. // Fresh id for a new function type. This might not be used if a required
  1429. // function type already exists or if we can change the old function type.
  1430. uint32 function_type_fresh_id = 2;
  1431. // Result id of the OpFunctionParameter instruction to remove.
  1432. uint32 parameter_id = 3;
  1433. // Fresh id of a global variable used to pass parameter's value to the function.
  1434. uint32 global_variable_fresh_id = 4;
  1435. }
  1436. message TransformationReplaceBooleanConstantWithConstantBinary {
  1437. // A transformation to capture replacing a use of a boolean constant with
  1438. // binary operation on two constant values
  1439. // A descriptor for the boolean constant id we would like to replace
  1440. IdUseDescriptor id_use_descriptor = 1;
  1441. // Id for the constant to be used on the LHS of the comparison
  1442. uint32 lhs_id = 2;
  1443. // Id for the constant to be used on the RHS of the comparison
  1444. uint32 rhs_id = 3;
  1445. // Opcode for binary operator
  1446. uint32 opcode = 4;
  1447. // Id that will store the result of the binary operation instruction
  1448. uint32 fresh_id_for_binary_operation = 5;
  1449. }
  1450. message TransformationReplaceConstantWithUniform {
  1451. // Replaces a use of a constant id with the result of a load from an
  1452. // element of uniform buffer known to hold the same value as the constant
  1453. // A descriptor for the id we would like to replace
  1454. IdUseDescriptor id_use_descriptor = 1;
  1455. // Uniform descriptor to identify which uniform value to choose
  1456. UniformBufferElementDescriptor uniform_descriptor = 2;
  1457. // Id that will store the result of an access chain
  1458. uint32 fresh_id_for_access_chain = 3;
  1459. // Id that will store the result of a load
  1460. uint32 fresh_id_for_load = 4;
  1461. }
  1462. message TransformationReplaceCopyMemoryWithLoadStore {
  1463. // A transformation that replaces instructions OpCopyMemory with loading
  1464. // the source variable to an intermediate value and storing this value into the
  1465. // target variable of the original OpCopyMemory instruction.
  1466. // The intermediate value.
  1467. uint32 fresh_id = 1;
  1468. // The instruction descriptor to OpCopyMemory. It is necessary, because
  1469. // OpCopyMemory doesn't have a result id.
  1470. InstructionDescriptor copy_memory_instruction_descriptor = 2;
  1471. }
  1472. message TransformationReplaceCopyObjectWithStoreLoad {
  1473. // A transformation that replaces instruction OpCopyObject with
  1474. // storing into a new variable and immediately loading from this
  1475. // variable to |result_id| of the original OpCopyObject instruction.
  1476. // The result id of initial OpCopyObject instruction
  1477. uint32 copy_object_result_id = 1;
  1478. // A fresh id for the variable to be stored to.
  1479. uint32 fresh_variable_id = 2;
  1480. // The variable storage class (Function or Private).
  1481. uint32 variable_storage_class = 3;
  1482. // Constant to initialize the variable with.
  1483. uint32 variable_initializer_id = 4;
  1484. }
  1485. message TransformationReplaceIdWithSynonym {
  1486. // Replaces a use of an id with an id that is known to be synonymous, e.g.
  1487. // because it was obtained via applying OpCopyObject
  1488. // The id use that is to be replaced
  1489. IdUseDescriptor id_use_descriptor = 1;
  1490. // The synonymous id
  1491. uint32 synonymous_id = 2;
  1492. }
  1493. message TransformationReplaceIrrelevantId {
  1494. // Replaces an irrelevant id with another id of the same type.
  1495. // The id use that is to be replaced
  1496. IdUseDescriptor id_use_descriptor = 1;
  1497. // The replacement id
  1498. uint32 replacement_id = 2;
  1499. }
  1500. message TransformationReplaceLinearAlgebraInstruction {
  1501. // Replaces a linear algebra instruction with its
  1502. // mathematical definition.
  1503. // The fresh ids needed to apply the transformation.
  1504. repeated uint32 fresh_ids = 1;
  1505. // A descriptor for a linear algebra instruction.
  1506. InstructionDescriptor instruction_descriptor = 2;
  1507. }
  1508. message TransformationReplaceLoadStoreWithCopyMemory {
  1509. // A transformation that takes a pair of instruction descriptors
  1510. // to OpLoad and OpStore that have the same intermediate value
  1511. // and replaces the OpStore with an equivalent OpCopyMemory.
  1512. // The instruction descriptor to OpLoad
  1513. InstructionDescriptor load_instruction_descriptor = 1;
  1514. // The instruction descriptor to OpStore
  1515. InstructionDescriptor store_instruction_descriptor = 2;
  1516. }
  1517. message TransformationReplaceOpPhiIdFromDeadPredecessor {
  1518. // Replaces one of the ids used by an OpPhi instruction, when
  1519. // the corresponding predecessor is dead, with any available id
  1520. // of the correct type.
  1521. // The result id of the OpPhi instruction.
  1522. uint32 opphi_id = 1;
  1523. // The label id of one of the predecessors of the block containing
  1524. // the OpPhi instruction, corresponding to the id that we want to
  1525. // replace.
  1526. uint32 pred_label_id = 2;
  1527. // The id that, after the transformation, will be associated with
  1528. // the given predecessor.
  1529. uint32 replacement_id = 3;
  1530. }
  1531. message TransformationReplaceOpSelectWithConditionalBranch {
  1532. // A transformation that takes an OpSelect instruction with a
  1533. // scalar boolean condition and replaces it with a conditional
  1534. // branch and an OpPhi instruction.
  1535. // The OpSelect instruction must be the first instruction in its
  1536. // block, which must have a unique predecessor. The block will
  1537. // become the merge block of a new construct, while its predecessor
  1538. // will become the header.
  1539. // Given the original OpSelect instruction:
  1540. // %id = OpSelect %type %cond %then %else
  1541. // The branching instruction of the header will be:
  1542. // OpBranchConditional %cond %true_block_id %false_block_id
  1543. // and the OpSelect instruction will be turned into:
  1544. // %id = OpPhi %type %then %true_block_id %else %false_block_id
  1545. // At most one of |true_block_id| and |false_block_id| can be zero. In
  1546. // that case, there will be no such block and all references to it
  1547. // will be replaced by %merge_block (where %merge_block is the
  1548. // block containing the OpSelect instruction).
  1549. // The result id of the OpSelect instruction.
  1550. uint32 select_id = 1;
  1551. // A fresh id for the new block that the predecessor of the block
  1552. // containing |select_id| will branch to if the condition holds.
  1553. uint32 true_block_id = 2;
  1554. // A fresh id for the new block that the predecessor of the block
  1555. // containing |select_id| will branch to if the condition does not
  1556. // hold.
  1557. uint32 false_block_id = 3;
  1558. }
  1559. message TransformationReplaceParamsWithStruct {
  1560. // Replaces parameters of the function with a struct containing
  1561. // values of those parameters.
  1562. // Result ids of parameters to replace.
  1563. repeated uint32 parameter_id = 1;
  1564. // Fresh id for a new function type. This might be unused if the required type
  1565. // already exists in the module or if we can change the old type.
  1566. uint32 fresh_function_type_id = 2;
  1567. // Fresh id for a new struct function parameter to be used as a replacement.
  1568. uint32 fresh_parameter_id = 3;
  1569. // Fresh ids for struct objects containing values of replaced parameters.
  1570. // This field contains a fresh id for at least every result id of a relevant
  1571. // OpFunctionCall instruction.
  1572. repeated UInt32Pair caller_id_to_fresh_composite_id = 4;
  1573. }
  1574. message TransformationSetFunctionControl {
  1575. // A transformation that sets the function control operand of an OpFunction
  1576. // instruction.
  1577. // The result id of an OpFunction instruction
  1578. uint32 function_id = 1;
  1579. // The value to which the 'function control' operand should be set.
  1580. uint32 function_control = 2;
  1581. }
  1582. message TransformationSetLoopControl {
  1583. // A transformation that sets the loop control operand of an OpLoopMerge
  1584. // instruction.
  1585. // The id of a basic block that should contain OpLoopMerge
  1586. uint32 block_id = 1;
  1587. // The value to which the 'loop control' operand should be set.
  1588. // This must be a legal loop control mask.
  1589. uint32 loop_control = 2;
  1590. // Provides a peel count value for the loop. Used if and only if the
  1591. // PeelCount bit is set. Must be zero if the PeelCount bit is not set (can
  1592. // still be zero if this bit is set).
  1593. uint32 peel_count = 3;
  1594. // Provides a partial count value for the loop. Used if and only if the
  1595. // PartialCount bit is set. Must be zero if the PartialCount bit is not set
  1596. // (can still be zero if this bit is set).
  1597. uint32 partial_count = 4;
  1598. }
  1599. message TransformationSetMemoryOperandsMask {
  1600. // A transformation that sets the memory operands mask of a memory access
  1601. // instruction.
  1602. // A descriptor for a memory access instruction, e.g. an OpLoad
  1603. InstructionDescriptor memory_access_instruction = 1;
  1604. // A mask of memory operands to be applied to the instruction. It must be the
  1605. // same as the original mask, except that Volatile can be added, and
  1606. // Nontemporal can be added or removed.
  1607. uint32 memory_operands_mask = 2;
  1608. // Some memory access instructions allow more than one mask to be specified;
  1609. // this field indicates which mask should be set
  1610. uint32 memory_operands_mask_index = 3;
  1611. }
  1612. message TransformationSetSelectionControl {
  1613. // A transformation that sets the selection control operand of an
  1614. // OpSelectionMerge instruction.
  1615. // The id of a basic block that should contain OpSelectionMerge
  1616. uint32 block_id = 1;
  1617. // The value to which the 'selection control' operand should be set.
  1618. // Although technically 'selection control' is a literal mask that can be
  1619. // some combination of 'None', 'Flatten' and 'DontFlatten', the combination
  1620. // 'Flatten | DontFlatten' does not make sense and is not allowed here.
  1621. uint32 selection_control = 2;
  1622. }
  1623. message TransformationSplitBlock {
  1624. // A transformation that splits a basic block into two basic blocks
  1625. // A descriptor for an instruction such that the block containing the
  1626. // described instruction should be split right before the instruction.
  1627. InstructionDescriptor instruction_to_split_before = 1;
  1628. // An id that must not yet be used by the module to which this transformation
  1629. // is applied. Rather than having the transformation choose a suitable id on
  1630. // application, we require the id to be given upfront in order to facilitate
  1631. // reducing fuzzed shaders by removing transformations. The reason is that
  1632. // future transformations may refer to the fresh id introduced by this
  1633. // transformation, and if we end up changing what that id is, due to removing
  1634. // earlier transformations, it may inhibit later transformations from
  1635. // applying.
  1636. uint32 fresh_id = 2;
  1637. }
  1638. message TransformationStore {
  1639. // Transformation that adds an OpStore or OpAtomicStore instruction of an id to a pointer.
  1640. // The pointer to be stored to.
  1641. uint32 pointer_id = 1;
  1642. // True if and only if the load should be atomic.
  1643. bool is_atomic = 2;
  1644. // The memory scope for the atomic load. Ignored unless |is_atomic| is true.
  1645. uint32 memory_scope_id = 3;
  1646. // The memory semantics for the atomic load. Ignored unless |is_atomic| is true.
  1647. uint32 memory_semantics_id = 4;
  1648. // The value to be stored.
  1649. uint32 value_id = 5;
  1650. // A descriptor for an instruction in a block before which the new OpStore
  1651. // instruction should be inserted.
  1652. InstructionDescriptor instruction_to_insert_before = 6;
  1653. }
  1654. message TransformationSwapCommutableOperands {
  1655. // A transformation that swaps the operands of a commutative instruction.
  1656. // A descriptor for a commutative instruction
  1657. InstructionDescriptor instruction_descriptor = 1;
  1658. }
  1659. message TransformationSwapConditionalBranchOperands {
  1660. // Swaps label ids in OpBranchConditional instruction.
  1661. // Additionally, inverts the guard and swaps branch weights
  1662. // if present.
  1663. // Descriptor of the instruction to swap operands of.
  1664. InstructionDescriptor instruction_descriptor = 1;
  1665. // Fresh result id for the OpLogicalNot instruction, used
  1666. // to invert the guard.
  1667. uint32 fresh_id = 2;
  1668. }
  1669. message TransformationSwapFunctionVariables {
  1670. // A transformation that swaps function variables
  1671. // Result id of the first variable.
  1672. uint32 result_id1 = 1;
  1673. // Result id of the second variable.
  1674. uint32 result_id2 = 2;
  1675. }
  1676. message TransformationSwapTwoFunctions {
  1677. // A transformation that swaps the position of two functions within the same module.
  1678. // the IDs for the two functions that are swapped.
  1679. uint32 function_id1 = 1;
  1680. uint32 function_id2 = 2;
  1681. }
  1682. message TransformationToggleAccessChainInstruction {
  1683. // A transformation that toggles an access chain instruction.
  1684. // A descriptor for an access chain instruction
  1685. InstructionDescriptor instruction_descriptor = 1;
  1686. }
  1687. message TransformationVectorShuffle {
  1688. // A transformation that adds a vector shuffle instruction.
  1689. // A descriptor for an instruction in a block before which the new
  1690. // OpVectorShuffle instruction should be inserted
  1691. InstructionDescriptor instruction_to_insert_before = 1;
  1692. // Result id for the shuffle operation.
  1693. uint32 fresh_id = 2;
  1694. // Id of the first vector operand.
  1695. uint32 vector1 = 3;
  1696. // Id of the second vector operand.
  1697. uint32 vector2 = 4;
  1698. // Indices that indicate which components of the input vectors should be used.
  1699. repeated uint32 component = 5;
  1700. }
  1701. message TransformationWrapEarlyTerminatorInFunction {
  1702. // Replaces an early terminator - OpKill, OpReachable or OpTerminateInvocation
  1703. // - with a call to a wrapper function for the terminator.
  1704. // A fresh id for a new OpFunctionCall instruction.
  1705. uint32 fresh_id = 1;
  1706. // A descriptor for an OpKill, OpUnreachable or OpTerminateInvocation
  1707. // instruction.
  1708. InstructionDescriptor early_terminator_instruction = 2;
  1709. // An id with the same type as the enclosing function's return type that is
  1710. // available at the early terminator. This is used to change the terminator
  1711. // to OpReturnValue. Ignored if the enclosing function has void return type,
  1712. // in which case OpReturn can be used as the new terminator.
  1713. uint32 returned_value_id = 3;
  1714. }
  1715. message TransformationWrapRegionInSelection {
  1716. // Transforms a single-entry-single-exit region R into
  1717. // if (|branch_condition|) { R } else { R }
  1718. // The entry block for R becomes a selection header and
  1719. // the exit block - a selection merge.
  1720. //
  1721. // Note that the region R is not duplicated. Thus, the effect of
  1722. // this transformation can be represented as follows:
  1723. // entry
  1724. // entry / \
  1725. // | \ /
  1726. // R --> R
  1727. // | |
  1728. // exit exit
  1729. // This behaviour is different from TransformationDuplicateRegionWithSelection
  1730. // that copies the blocks in R.
  1731. // The entry block for the region R.
  1732. uint32 region_entry_block_id = 1;
  1733. // The exit block for the region R.
  1734. uint32 region_exit_block_id = 2;
  1735. // Boolean value for the condition expression.
  1736. bool branch_condition = 3;
  1737. }
  1738. message TransformationWrapVectorSynonym {
  1739. // A transformation that wraps an arithmetic operation into a vector operation
  1740. // and get the result of the original operation from the corresponding index.
  1741. // For instance, for this transformation, an scalar operation between two scalars:
  1742. // define op ∈ {+, -, *}
  1743. // c = a op b
  1744. //
  1745. // requires the availability of two vectors:
  1746. //
  1747. // va = vector(..., a, ...)
  1748. // vb = vector(..., b, ...)
  1749. //
  1750. // where a and b are in the same position i in each of their corresponding vector
  1751. // and a is synonymous with va[i] and b is synonymous with vb[i].
  1752. //
  1753. // The transformation then add an instruction vc = va op vb where c is synonymous
  1754. // with vc[i].
  1755. // The result if of the original scalar operation instruction.
  1756. uint32 instruction_id = 1;
  1757. // The result id for the first vector that contains the first value of the scalar operation.
  1758. uint32 vector_operand1 = 2;
  1759. // The result id for the second vector that contains the second value of the scalar operation.
  1760. uint32 vector_operand2 = 3;
  1761. // A fresh id for the resulted vector from the addition of the first and second vector.
  1762. uint32 fresh_id = 4;
  1763. // The position in the vector where the value of original instruction is located. Must be in
  1764. // the corresponding vector range.
  1765. uint32 scalar_position = 5;
  1766. }