You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

0001-spirv-opt-Add-auto-inst-passes.patch 134 kB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188
  1. From 48520bd5e6344d792840aa37fe1ba5d564232788 Mon Sep 17 00:00:00 2001
  2. From: dpankratz <pankratz@ualberta.ca>
  3. Date: Wed, 27 Jan 2021 09:18:00 -0700
  4. Subject: [PATCH] spirv-opt: Add auto-inst passes
  5. ---
  6. Android.mk | 8 +
  7. include/spirv-tools/instrument.hpp | 39 +
  8. include/spirv-tools/optimizer.hpp | 98 ++
  9. source/opt/CMakeLists.txt | 18 +-
  10. source/opt/auto_inst_debug_pass.cpp | 68 ++
  11. source/opt/auto_inst_debug_pass.h | 106 ++
  12. ..._inst_divergence_characterization_pass.cpp | 134 +++
  13. ...to_inst_divergence_characterization_pass.h | 106 ++
  14. .../opt/auto_inst_dyn_shader_trace_pass.cpp | 52 +
  15. source/opt/auto_inst_dyn_shader_trace_pass.h | 103 ++
  16. .../auto_inst_dyn_trace_ray_trace_pass.cpp | 184 ++++
  17. .../opt/auto_inst_dyn_trace_ray_trace_pass.h | 135 +++
  18. source/opt/auto_inst_execution_trace_pass.cpp | 68 ++
  19. source/opt/auto_inst_execution_trace_pass.h | 122 +++
  20. source/opt/auto_inst_pass.cpp | 927 ++++++++++++++++++
  21. source/opt/auto_inst_pass.h | 322 ++++++
  22. source/opt/auto_inst_simt_efficiency_pass.cpp | 39 +
  23. source/opt/auto_inst_simt_efficiency_pass.h | 101 ++
  24. .../auto_inst_warp_entry_and_exit_pass.cpp | 43 +
  25. .../opt/auto_inst_warp_entry_and_exit_pass.h | 99 ++
  26. source/opt/instrument_pass.cpp | 5 +-
  27. source/opt/instrument_pass.h | 1 +
  28. source/opt/ir_builder.h | 26 +
  29. source/opt/ir_context.cpp | 13 +
  30. source/opt/optimizer.cpp | 60 ++
  31. source/opt/passes.h | 7 +
  32. 26 files changed, 2882 insertions(+), 2 deletions(-)
  33. create mode 100644 source/opt/auto_inst_debug_pass.cpp
  34. create mode 100644 source/opt/auto_inst_debug_pass.h
  35. create mode 100644 source/opt/auto_inst_divergence_characterization_pass.cpp
  36. create mode 100644 source/opt/auto_inst_divergence_characterization_pass.h
  37. create mode 100644 source/opt/auto_inst_dyn_shader_trace_pass.cpp
  38. create mode 100644 source/opt/auto_inst_dyn_shader_trace_pass.h
  39. create mode 100644 source/opt/auto_inst_dyn_trace_ray_trace_pass.cpp
  40. create mode 100644 source/opt/auto_inst_dyn_trace_ray_trace_pass.h
  41. create mode 100644 source/opt/auto_inst_execution_trace_pass.cpp
  42. create mode 100644 source/opt/auto_inst_execution_trace_pass.h
  43. create mode 100644 source/opt/auto_inst_pass.cpp
  44. create mode 100644 source/opt/auto_inst_pass.h
  45. create mode 100644 source/opt/auto_inst_simt_efficiency_pass.cpp
  46. create mode 100644 source/opt/auto_inst_simt_efficiency_pass.h
  47. create mode 100644 source/opt/auto_inst_warp_entry_and_exit_pass.cpp
  48. create mode 100644 source/opt/auto_inst_warp_entry_and_exit_pass.h
  49. diff --git a/Android.mk b/Android.mk
  50. index 0b64ea6d..46728c67 100644
  51. --- a/Android.mk
  52. +++ b/Android.mk
  53. @@ -73,6 +73,14 @@ SPVTOOLS_SRC_FILES := \
  54. source/val/validate_type.cpp
  55. SPVTOOLS_OPT_SRC_FILES := \
  56. + source/opt/auto_inst_pass.cpp \
  57. + source/opt/auto_inst_debug_pass.cpp \
  58. + source/opt/auto_inst_divergence_characterization_pass.cpp \
  59. + source/opt/auto_inst_dyn_trace_ray_trace_pass.cpp \
  60. + source/opt/auto_inst_dyn_shader_trace_pass.cpp \
  61. + source/opt/auto_inst_execution_trace_pass.cpp \
  62. + source/opt/auto_inst_simt_efficiency_pass.cpp \
  63. + source/opt/auto_inst_warp_entry_and_exit_pass.cpp \
  64. source/opt/aggressive_dead_code_elim_pass.cpp \
  65. source/opt/amd_ext_to_khr.cpp \
  66. source/opt/basic_block.cpp \
  67. diff --git a/include/spirv-tools/instrument.hpp b/include/spirv-tools/instrument.hpp
  68. index 2b47a564..5a2b00c9 100644
  69. --- a/include/spirv-tools/instrument.hpp
  70. +++ b/include/spirv-tools/instrument.hpp
  71. @@ -250,6 +250,45 @@ static const int kDebugInputBuffAddrPtrOffset = 1;
  72. // not a valid buffer, the length associated with the 0x0 address is zero.
  73. static const int kDebugInputBuffAddrLengthOffset = 0;
  74. +// Auto-Inst Bindings
  75. +//
  76. +// These bindings are used primarily to differentiate different instrumentation
  77. +// primitives which have meaning to the instrumentation generating them
  78. +// and the analysis parsing them.
  79. +//
  80. +// NOTE: do not set these values to 0 since, by default, the instrumentation
  81. +// buffer is 0 initialized and would cause pernicious bugs.
  82. +
  83. +static const int kAutoInstUniqueSubgroupId = 1;
  84. +
  85. +// auto_inst_divergence_characterization
  86. +// Primitive to track the beginning of a traceRay
  87. +static const uint32_t kAutoInstDivCharPreTraceRay = 2;
  88. +// Primitive to track the end of a traceRay
  89. +static const uint32_t kAutoInstDivCharPostTraceRay = 3;
  90. +// Primitive to get the active threads in a basic block
  91. +static const uint32_t kAutoInstDivCharActiveThreads = 4;
  92. +// Primtive to get the active threads at the
  93. +// beginning of a ray tracing shader
  94. +static const uint32_t kAutoInstDivCharShaderEntryPoint = 5;
  95. +// Primitive to track when threads have finished executing
  96. +// the pipeline.
  97. +static const uint32_t kAutoInstDivCharQuitPipeline = 6;
  98. +
  99. +// auto_inst_dyn_shader_trace
  100. +// Track when shader is executed
  101. +static const uint32_t kAutoInstDynShaderTraceEntryPoint = 2;
  102. +
  103. +// auto_inst_dyn_trace_ray_trace
  104. +// Track when traceRay call started
  105. +static const uint32_t kAutoInstTraceRayTracePreTraceRay = 2;
  106. +// Track when merge point after traceRay is executed
  107. +static const uint32_t kAutoInstTraceRayTraceMergePoint = 3;
  108. +
  109. +// auto_inst_warp_entry_and_exit
  110. +static const uint32_t kAutoInstWarpEntryAndExitBeginPipeline = 1;
  111. +static const uint32_t kAutoInstWarpEntryAndExitEndPipeline = 2;
  112. +
  113. } // namespace spvtools
  114. #endif // INCLUDE_SPIRV_TOOLS_INSTRUMENT_HPP_
  115. diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp
  116. index 27352b25..a8cc6d34 100644
  117. --- a/include/spirv-tools/optimizer.hpp
  118. +++ b/include/spirv-tools/optimizer.hpp
  119. @@ -15,8 +15,10 @@
  120. #ifndef INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_
  121. #define INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_
  122. +#include <functional>
  123. #include <memory>
  124. #include <ostream>
  125. +#include <set>
  126. #include <string>
  127. #include <unordered_map>
  128. #include <vector>
  129. @@ -792,6 +794,102 @@ Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set,
  130. Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set,
  131. uint32_t shader_id);
  132. +// Create a pass which will help debug problems with other autoinstrumentation
  133. +// passes.
  134. +//
  135. +// If |test_atomic_ops| is true, then an atomicAdd will be added to the shader
  136. +// and its result will be written to the buffer given by |desc_set|. If
  137. +// |test_subgroup_ops| is true, then a subgroupElect will be added to the shader
  138. +// and its result will be written to the buffer.
  139. +// If both are false then a constant will be written to the buffer.
  140. +Optimizer::PassToken CreateAutoInstDebugPass(uint32_t desc_set,
  141. + uint32_t shader_id,
  142. + bool test_atomic_ops,
  143. + bool test_subgroup_ops);
  144. +
  145. +// Create a pass which will automatically insert instrumentation to
  146. +// capture the extent of different contributors to divergence.
  147. +//
  148. +// The instrumentation will write buffers in debug descriptor set |desc_set|.
  149. +// It will write |shader_id| in each output record to identify the shader
  150. +// module which generated the record if necessary.
  151. +Optimizer::PassToken CreateAutoInstDivergenceCharacterizationPass(
  152. + uint32_t desc_set, uint32_t shader_id,
  153. + std::function<
  154. + void(std::unordered_map<uint32_t, uint32_t>&& inst_id2prim_id,
  155. + std::unordered_map<uint32_t, uint32_t>&& inst_id2inst_count)>
  156. + static_data_callback);
  157. +
  158. +// Create a pass which will automatically insert instrumentation to
  159. +// determine the runtime execution counts of each shader.
  160. +//
  161. +// The instrumentation will write buffers in debug descriptor set |desc_set|.
  162. +// It will write |shader_id| in each output record to identify the shader
  163. +// module which generated the record.
  164. +Optimizer::PassToken CreateAutoInstDynShaderTracePass(uint32_t desc_set,
  165. + uint32_t shader_id);
  166. +
  167. +// Create a pass which will automatically insert instrumentation to
  168. +// disambiguate runtime traceRay calls found within control-flow.
  169. +//
  170. +// The instrumentation will write buffers in debug descriptor set |desc_set|.
  171. +// It will write |shader_id| in each output record to identify the shader
  172. +// module which generated the record if necessary.
  173. +//
  174. +// The |static_data_callback| is called after the instrumentation pass has
  175. +// finished. It is populated with a mapping from instrumentation callsite id
  176. +// to instrumentation type. It is also populated with a mapping from merge point
  177. +// to all the traceRay calls sites that could have executed within the
  178. +// control-flow.
  179. +Optimizer::PassToken CreateAutoInstDynTraceRayTracePass(
  180. + uint32_t desc_set, uint32_t shader_id,
  181. + std::function<void(std::unordered_map<uint32_t, uint32_t>&&,
  182. + std::unordered_map<uint32_t, std::vector<uint32_t>>&&)>
  183. + static_data_callback);
  184. +
  185. +// Create a pass which will automatically insert instrumentation to
  186. +// compute the simt efficiency of the shader module.
  187. +//
  188. +// The instrumentation will write buffers in debug descriptor set |desc_set|.
  189. +// |reserved_words_count| is the number of lower words in the buffer that
  190. +// have a fixed function and are reserved.
  191. +//
  192. +// It will write |shader_id| in each output record to identify the shader
  193. +// module which generated the record if necessary.
  194. +Optimizer::PassToken CreateAutoInstSimtEfficiencyPass(
  195. + uint32_t desc_set, uint32_t shader_id, uint32_t reserved_words_count);
  196. +
  197. +// Create a pass which will automatically insert instrumentation to
  198. +// capture the number of times the ray tracing pipeline entrypoint is executed
  199. +// vs how many times the exit is executed. On architectures with a SIMD
  200. +// execution model #entries == #exits. On MIMD (or psuedo-MIMD) execution models
  201. +// #entries != #exits.
  202. +//
  203. +// The instrumentation will write buffers in debug descriptor set |desc_set|.
  204. +// It will write |shader_id| in each output record to identify the shader
  205. +// module which generated the record if necessary.
  206. +Optimizer::PassToken CreateAutoInstWarpEntryAndExitPass(uint32_t desc_set,
  207. + uint32_t shader_id);
  208. +
  209. +
  210. +// Create a pass which will automatically insert instrumentation to
  211. +// capture the execution trace of the pipeline.
  212. +//
  213. +// The instrumentation will write buffers in debug descriptor set |desc_set|.
  214. +// It will write |shader_id| in each output record to identify the shader
  215. +// module which generated the record.
  216. +//
  217. +// The |static_data_callback| is called after the instrumentation pass has
  218. +// finished. It is populated with a mapping from instrumentation callsite id
  219. +// to the other opcodes in the basic block. This data allows the analysis
  220. +// to develop complete dynamic instruction counts of the shader module without
  221. +// needing to transfer the data at runtime.
  222. +Optimizer::PassToken CreateAutoInstExecutionTracePass(
  223. + uint32_t desc_set, uint32_t shader_id,
  224. + std::function<void(std::unordered_map<uint32_t, std::set<uint32_t>>&&,
  225. + std::unordered_map<uint32_t, uint32_t>&&)>
  226. + static_data_callback);
  227. +
  228. // Create a pass to upgrade to the VulkanKHR memory model.
  229. // This pass upgrades the Logical GLSL450 memory model to Logical VulkanKHR.
  230. // Additionally, it modifies memory, image, atomic and barrier operations to
  231. diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt
  232. index f3ac5906..a59b18c8 100644
  233. --- a/source/opt/CMakeLists.txt
  234. +++ b/source/opt/CMakeLists.txt
  235. @@ -14,6 +14,14 @@
  236. set(SPIRV_TOOLS_OPT_SOURCES
  237. aggressive_dead_code_elim_pass.h
  238. amd_ext_to_khr.h
  239. + auto_inst_pass.h
  240. + auto_inst_debug_pass.h
  241. + auto_inst_divergence_characterization_pass.h
  242. + auto_inst_dyn_shader_trace_pass.h
  243. + auto_inst_dyn_trace_ray_trace_pass.h
  244. + auto_inst_execution_trace_pass.h
  245. + auto_inst_simt_efficiency_pass.h
  246. + auto_inst_warp_entry_and_exit_pass.h
  247. basic_block.h
  248. block_merge_pass.h
  249. block_merge_util.h
  250. @@ -122,6 +130,14 @@ set(SPIRV_TOOLS_OPT_SOURCES
  251. aggressive_dead_code_elim_pass.cpp
  252. amd_ext_to_khr.cpp
  253. + auto_inst_pass.cpp
  254. + auto_inst_debug_pass.cpp
  255. + auto_inst_divergence_characterization_pass.cpp
  256. + auto_inst_dyn_shader_trace_pass.cpp
  257. + auto_inst_dyn_trace_ray_trace_pass.cpp
  258. + auto_inst_execution_trace_pass.cpp
  259. + auto_inst_simt_efficiency_pass.cpp
  260. + auto_inst_warp_entry_and_exit_pass.cpp
  261. basic_block.cpp
  262. block_merge_pass.cpp
  263. block_merge_util.cpp
  264. @@ -167,7 +183,7 @@ set(SPIRV_TOOLS_OPT_SOURCES
  265. inline_pass.cpp
  266. inst_bindless_check_pass.cpp
  267. inst_buff_addr_check_pass.cpp
  268. - inst_debug_printf_pass.cpp
  269. + inst_debug_printf_pass.cpp
  270. instruction.cpp
  271. instruction_list.cpp
  272. instrument_pass.cpp
  273. diff --git a/source/opt/auto_inst_debug_pass.cpp b/source/opt/auto_inst_debug_pass.cpp
  274. new file mode 100644
  275. index 00000000..d4321e92
  276. --- /dev/null
  277. +++ b/source/opt/auto_inst_debug_pass.cpp
  278. @@ -0,0 +1,68 @@
  279. +// Copyright (c) 2021 The Khronos Group Inc.
  280. +//
  281. +// Licensed under the Apache License, Version 2.0 (the "License");
  282. +// you may not use this file except in compliance with the License.
  283. +// You may obtain a copy of the License at
  284. +//
  285. +// http://www.apache.org/licenses/LICENSE-2.0
  286. +//
  287. +// Unless required by applicable law or agreed to in writing, software
  288. +// distributed under the License is distributed on an "AS IS" BASIS,
  289. +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  290. +// See the License for the specific language governing permissions and
  291. +// limitations under the License.
  292. +
  293. +#include "auto_inst_debug_pass.h"
  294. +
  295. +namespace spvtools {
  296. +namespace opt {
  297. +
  298. +bool AutoInstDebugPass::PreEntryPointInstrument(InstructionBuilder* builder,
  299. + uint32_t stage_idx) {
  300. + (void)stage_idx;
  301. +
  302. + uint32_t buf_id = GetOutputBufferId();
  303. + uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
  304. +
  305. + if (test_atomic_ops_) {
  306. + Instruction* offset_ptr = builder->AddTernaryOp(
  307. + buf_uint_ptr_id, SpvOpAccessChain, buf_id,
  308. + builder->GetUintConstantId(kDebugOutputDataOffset),
  309. + builder->GetUintConstantId(0));
  310. + uint32_t mask_none_id = builder->GetUintConstantId(SpvMemoryAccessMaskNone);
  311. + uint32_t scope_invok_id = builder->GetUintConstantId(SpvScopeInvocation);
  312. + (void)builder->AddQuadOp(GetUintId(), SpvOpAtomicIAdd,
  313. + offset_ptr->result_id(), scope_invok_id,
  314. + mask_none_id, builder->GetUintConstantId(1));
  315. + } else if (test_subgroup_ops_) {
  316. + Instruction* subgroup_leader_cond =
  317. + builder->AddUnaryOp(GetBoolId(), SpvOpGroupNonUniformElect,
  318. + builder->GetUintConstantId(SpvScopeSubgroup));
  319. +
  320. + auto active_thread_mask =
  321. + GenSubgroupBallotId(builder, subgroup_leader_cond->result_id());
  322. +
  323. + Instruction* offset_ptr = builder->AddTernaryOp(
  324. + buf_uint_ptr_id, SpvOpAccessChain, buf_id,
  325. + builder->GetUintConstantId(kDebugOutputDataOffset),
  326. + builder->GetUintConstantId(0));
  327. + builder->AddStore(offset_ptr->result_id(), active_thread_mask);
  328. +
  329. + } else if (!test_atomic_ops_ && !test_subgroup_ops_) {
  330. + Instruction* buffer_capacity =
  331. + builder->AddIdLiteralOp(GetUintId(), SpvOpArrayLength,
  332. + GetOutputBufferId(), kDebugOutputDataOffset);
  333. +
  334. + Instruction* offset_ptr = builder->AddTernaryOp(
  335. + buf_uint_ptr_id, SpvOpAccessChain, buf_id,
  336. + builder->GetUintConstantId(kDebugOutputDataOffset),
  337. + builder->GetUintConstantId(0));
  338. +
  339. + builder->AddStore(offset_ptr->result_id(), buffer_capacity->result_id());
  340. + }
  341. +
  342. + return true;
  343. +}
  344. +
  345. +} // namespace opt
  346. +} // namespace spvtools
  347. diff --git a/source/opt/auto_inst_debug_pass.h b/source/opt/auto_inst_debug_pass.h
  348. new file mode 100644
  349. index 00000000..7fb59430
  350. --- /dev/null
  351. +++ b/source/opt/auto_inst_debug_pass.h
  352. @@ -0,0 +1,106 @@
  353. +// Copyright (c) 2021 The Khronos Group Inc.
  354. +
  355. +// Licensed under the Apache License, Version 2.0 (the "License");
  356. +// you may not use this file except in compliance with the License.
  357. +// You may obtain a copy of the License at
  358. +//
  359. +// http://www.apache.org/licenses/LICENSE-2.0
  360. +//
  361. +// Unless required by applicable law or agreed to in writing, software
  362. +// distributed under the License is distributed on an "AS IS" BASIS,
  363. +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  364. +// See the License for the specific language governing permissions and
  365. +// limitations under the License.
  366. +
  367. +#ifndef LIBSPIRV_OPT_AUTO_INST_DEBUG_PASS_H_
  368. +#define LIBSPIRV_OPT_AUTO_INST_DEBUG_PASS_H_
  369. +
  370. +#include "auto_inst_pass.h"
  371. +
  372. +namespace spvtools {
  373. +namespace opt {
  374. +
  375. +class AutoInstDebugPass : public AutoInstPass {
  376. + public:
  377. + AutoInstDebugPass(uint32_t desc_set, uint32_t shader_id, bool test_atomic_ops,
  378. + bool test_subgroup_ops)
  379. + : AutoInstPass(desc_set, shader_id, kDefaultReservedWordsCnt),
  380. + test_atomic_ops_(test_atomic_ops),
  381. + test_subgroup_ops_(test_subgroup_ops) {}
  382. +
  383. + const char* name() const override { return "auto-inst-debug-pass"; }
  384. +
  385. + protected:
  386. + const bool test_atomic_ops_;
  387. + const bool test_subgroup_ops_;
  388. +
  389. + private:
  390. + // Allows inheriting classes to initialize their knowledge
  391. + // of module before beginning instrumentation
  392. + void InitializeInstrumentation() override{};
  393. +
  394. + // Allows inheriting classes to finalize before
  395. + // the pass finishes executing.
  396. + void FinalizeInstrumentation() override{};
  397. +
  398. + // Any instructions added via |builder| will appear before |inst|
  399. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  400. + // This function is expected to return true if it added instructions to
  401. + // builder, otherwise false.
  402. + bool PreInstructionInstrument(Instruction* inst, InstructionBuilder* builder,
  403. + uint32_t stage_idx) override {
  404. + (void)inst;
  405. + (void)builder;
  406. + (void)stage_idx;
  407. + return false;
  408. + };
  409. +
  410. + // Any instructions added via |builder| will appear after |inst|.
  411. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  412. + // This function is expected to return true if it added instructions to
  413. + // builder, otherwise false.
  414. + bool PostInstructionInstrument(Instruction* inst, InstructionBuilder* builder,
  415. + uint32_t stage_idx) override {
  416. + (void)inst;
  417. + (void)builder;
  418. + (void)stage_idx;
  419. + return false;
  420. + };
  421. +
  422. + // Any instructions added via |builder| will appear before the content of
  423. + // |bb|. |stage_idx| contains the SpvExecutionModel that builder is operating
  424. + // in. This function is expected to return true if it added instructions to
  425. + // builder, otherwise false.
  426. + bool BasicBlockInstrument(BasicBlock* bb, InstructionBuilder* builder,
  427. + uint32_t stage_idx) override {
  428. + (void)bb;
  429. + (void)builder;
  430. + (void)stage_idx;
  431. + return false;
  432. + };
  433. +
  434. + // Any instructions added via |builder| will execute before the
  435. + // entrypoint function of the shader
  436. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  437. + // This function is expected to return true if it added instructions to
  438. + // builder, otherwise false.
  439. + bool PreEntryPointInstrument(InstructionBuilder* builder,
  440. + uint32_t stage_idx) override;
  441. +
  442. + // Any instructions added via |builder| will execute before the
  443. + // entrypoint function of the shader.
  444. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  445. + // This function is expected to return true if it added instructions to
  446. + // builder, otherwise false.
  447. + bool PostEntryPointInstrument(InstructionBuilder* builder,
  448. + uint32_t stage_idx) override {
  449. + (void)builder;
  450. + (void)stage_idx;
  451. + return false;
  452. + }
  453. +};
  454. +
  455. +} // namespace opt
  456. +} // namespace spvtools
  457. +
  458. +#endif // LIBSPIRV_OPT_AUTO_INST_DEBUG_PASS_H_
  459. diff --git a/source/opt/auto_inst_divergence_characterization_pass.cpp b/source/opt/auto_inst_divergence_characterization_pass.cpp
  460. new file mode 100644
  461. index 00000000..a462c05e
  462. --- /dev/null
  463. +++ b/source/opt/auto_inst_divergence_characterization_pass.cpp
  464. @@ -0,0 +1,134 @@
  465. +// Copyright (c) 2021 The Khronos Group Inc.
  466. +//
  467. +// Licensed under the Apache License, Version 2.0 (the "License");
  468. +// you may not use this file except in compliance with the License.
  469. +// You may obtain a copy of the License at
  470. +//
  471. +// http://www.apache.org/licenses/LICENSE-2.0
  472. +//
  473. +// Unless required by applicable law or agreed to in writing, software
  474. +// distributed under the License is distributed on an "AS IS" BASIS,
  475. +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  476. +// See the License for the specific language governing permissions and
  477. +// limitations under the License.
  478. +
  479. +#include "auto_inst_divergence_characterization_pass.h"
  480. +
  481. +namespace {
  482. +std::unordered_set<uint32_t> pseudo_ops = {
  483. + SpvOpPhi, SpvOpFunction, SpvOpFunctionParameter,
  484. + SpvOpFunctionEnd, SpvOpVariable, SpvOpLoopMerge};
  485. +
  486. +static const std::set<uint32_t> kAllRayTracingStages = {
  487. + SpvExecutionModelRayGenerationNV, SpvExecutionModelAnyHitNV,
  488. + SpvExecutionModelClosestHitNV, SpvExecutionModelMissNV,
  489. + SpvExecutionModelIntersectionNV, SpvExecutionModelCallableNV};
  490. +
  491. +} // namespace
  492. +
  493. +namespace spvtools {
  494. +namespace opt {
  495. +
  496. +void AutoInstDivergenceCharacterizationPass::GenInst(
  497. + InstructionBuilder* builder, Instruction* instruction, uint32_t prim_id,
  498. + uint32_t stage_idx) {
  499. + uint32_t inst_id = GenInstCallsiteId(instruction);
  500. +
  501. + auto flat_thread_id = GenFlatRtThreadId(builder, stage_idx);
  502. + auto active_thread_mask_id =
  503. + GenSubgroupBallotId(builder, builder->GetBoolConstant(true)->result_id());
  504. +
  505. + GenSubgroupUpdateCall(builder, {builder->GetUintConstantId(inst_id),
  506. + flat_thread_id, active_thread_mask_id});
  507. +
  508. + inst_id2prim_id_[inst_id] = prim_id;
  509. +}
  510. +
  511. +void AutoInstDivergenceCharacterizationPass::InitializeInstrumentation() {
  512. + inst_id2inst_count_.clear();
  513. + inst_id2prim_id_.clear();
  514. +}
  515. +
  516. +bool AutoInstDivergenceCharacterizationPass::PreInstructionInstrument(
  517. + Instruction* inst, InstructionBuilder* builder, uint32_t stage_idx) {
  518. + if (inst->opcode() == SpvOpTraceNV || inst->opcode() == SpvOpTraceRayKHR) {
  519. + // Record when threads begin a traceRay
  520. + GenInst(builder, &*builder->GetInsertPoint(), kAutoInstDivCharPreTraceRay,
  521. + stage_idx);
  522. + return true;
  523. + }
  524. +
  525. + return false;
  526. +};
  527. +
  528. +bool AutoInstDivergenceCharacterizationPass::PostInstructionInstrument(
  529. + Instruction* inst, InstructionBuilder* builder, uint32_t stage_idx) {
  530. + if (inst->opcode() == SpvOpTraceNV || inst->opcode() == SpvOpTraceRayKHR) {
  531. + // Record when threads end a traceRay
  532. + GenInst(builder, &*builder->GetInsertPoint(), kAutoInstDivCharPostTraceRay,
  533. + stage_idx);
  534. + return true;
  535. + }
  536. +
  537. + return false;
  538. +}
  539. +
  540. +bool AutoInstDivergenceCharacterizationPass::PreEntryPointInstrument(
  541. + InstructionBuilder* builder, uint32_t stage_idx) {
  542. + if (stage_idx == SpvExecutionModelRayGenerationKHR) {
  543. + inst_id2prim_id_[kAutoInstUniqueSubgroupId] = kAutoInstUniqueSubgroupId;
  544. + // Create an instrumentation id which will be used by the analysis
  545. + // to determine how the subsequent words should be understood.
  546. + auto unique_warp_id_inst_id =
  547. + builder->GetUintConstantId(kAutoInstUniqueSubgroupId);
  548. +
  549. + GenUniqueSubgroupIdFuncCall(builder, unique_warp_id_inst_id, stage_idx);
  550. +
  551. + return true;
  552. + } else if (kAllRayTracingStages.count(stage_idx) != 0) {
  553. + // Record when threads run a shader during a traceRay
  554. + GenInst(builder,
  555. + builder->GetIntConstant(kAutoInstDivCharShaderEntryPoint, false),
  556. + kAutoInstDivCharShaderEntryPoint, stage_idx);
  557. + return true;
  558. + }
  559. + return false;
  560. +}
  561. +
  562. +bool AutoInstDivergenceCharacterizationPass::PostEntryPointInstrument(
  563. + InstructionBuilder* builder, uint32_t stage_idx) {
  564. + if (stage_idx != SpvExecutionModelRayGenerationKHR) return false;
  565. +
  566. + // Record the threads that quit the pipeline
  567. + GenInst(builder, builder->GetIntConstant(kAutoInstDivCharQuitPipeline, false),
  568. + kAutoInstDivCharQuitPipeline, stage_idx);
  569. +
  570. + return true;
  571. +}
  572. +
  573. +bool AutoInstDivergenceCharacterizationPass::BasicBlockInstrument(
  574. + BasicBlock* bb, InstructionBuilder* builder, uint32_t stage_idx) {
  575. + if (kAllRayTracingStages.count(stage_idx) == 0) return false;
  576. +
  577. + auto inst = builder->GetInsertPoint();
  578. +
  579. + // Record active threads in each basic block execution
  580. + GenInst(builder, &*inst, kAutoInstDivCharActiveThreads, stage_idx);
  581. +
  582. + uint32_t count = 0;
  583. + for (auto& ii : *bb) {
  584. + if (pseudo_ops.count(ii.opcode()) != 0) count++;
  585. + }
  586. +
  587. + inst_id2inst_count_[GenInstCallsiteId(&*inst)] = count;
  588. +
  589. + return true;
  590. +}
  591. +
  592. +void AutoInstDivergenceCharacterizationPass::FinalizeInstrumentation() {
  593. + static_data_callback_(std::move(inst_id2prim_id_),
  594. + std::move(inst_id2inst_count_));
  595. +}
  596. +
  597. +} // namespace opt
  598. +} // namespace spvtools
  599. diff --git a/source/opt/auto_inst_divergence_characterization_pass.h b/source/opt/auto_inst_divergence_characterization_pass.h
  600. new file mode 100644
  601. index 00000000..54c967a9
  602. --- /dev/null
  603. +++ b/source/opt/auto_inst_divergence_characterization_pass.h
  604. @@ -0,0 +1,106 @@
  605. +// Copyright (c) 2021 The Khronos Group Inc.
  606. +
  607. +// Licensed under the Apache License, Version 2.0 (the "License");
  608. +// you may not use this file except in compliance with the License.
  609. +// You may obtain a copy of the License at
  610. +//
  611. +// http://www.apache.org/licenses/LICENSE-2.0
  612. +//
  613. +// Unless required by applicable law or agreed to in writing, software
  614. +// distributed under the License is distributed on an "AS IS" BASIS,
  615. +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  616. +// See the License for the specific language governing permissions and
  617. +// limitations under the License.
  618. +
  619. +#ifndef LIBSPIRV_OPT_AUTO_INST_DIVERGENCE_CHARACTERIZATION_PASS_H_
  620. +#define LIBSPIRV_OPT_AUTO_INST_DIVERGENCE_CHARACTERIZATION_PASS_H_
  621. +
  622. +#include <functional>
  623. +
  624. +#include "auto_inst_pass.h"
  625. +
  626. +namespace spvtools {
  627. +namespace opt {
  628. +
  629. +class AutoInstDivergenceCharacterizationPass : public AutoInstPass {
  630. + public:
  631. + AutoInstDivergenceCharacterizationPass(
  632. + uint32_t desc_set, uint32_t shader_id,
  633. + std::function<
  634. + void(std::unordered_map<uint32_t, uint32_t>&& inst_id2prim_id,
  635. + std::unordered_map<uint32_t, uint32_t>&& inst_id2inst_count)>
  636. + static_data_callback)
  637. + : AutoInstPass(desc_set, shader_id, kDefaultReservedWordsCnt),
  638. + static_data_callback_(static_data_callback) {}
  639. +
  640. + const char* name() const override {
  641. + return "auto-inst-divergence-characterization-pass";
  642. + }
  643. +
  644. + private:
  645. + // Mapping from inst callsite id to primitive id
  646. + std::unordered_map<AutoInstId, AutoInstId> inst_id2prim_id_;
  647. +
  648. + // Mapping from inst callsite id to the number of insts in the bb
  649. + std::unordered_map<AutoInstId, AutoInstId> inst_id2inst_count_;
  650. +
  651. + // Callback for sending static data
  652. + std::function<void(
  653. + std::unordered_map<AutoInstId, AutoInstId>&& inst_id2prim_id,
  654. + std::unordered_map<AutoInstId, AutoInstId>&& inst_id2inst_count)>
  655. + static_data_callback_;
  656. +
  657. + // Generate instrumentation for this pass
  658. + void GenInst(InstructionBuilder* builder, Instruction* inst,
  659. + AutoInstId prim_id, AutoInstId stage_idx);
  660. +
  661. + // Allows inheriting classes to initialize their knowledge
  662. + // of module before beginning instrumentation
  663. + void InitializeInstrumentation() override;
  664. +
  665. + // Allows inheriting classes to finalize before
  666. + // the pass finishes executing.
  667. + void FinalizeInstrumentation() override;
  668. +
  669. + // Any instructions added via |builder| will appear before |inst|
  670. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  671. + // This function is expected to return true if it added instructions to
  672. + // builder, otherwise false.
  673. + bool PreInstructionInstrument(Instruction* inst, InstructionBuilder* builder,
  674. + uint32_t stage_idx) override;
  675. +
  676. + // Any instructions added via |builder| will appear after |inst|.
  677. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  678. + // This function is expected to return true if it added instructions to
  679. + // builder, otherwise false.
  680. + bool PostInstructionInstrument(Instruction* inst, InstructionBuilder* builder,
  681. + uint32_t stage_idx) override;
  682. +
  683. + // Any instructions added via |builder| will appear before the content of
  684. + // |bb|. |stage_idx| contains the SpvExecutionModel that builder is operating
  685. + // in. This function is expected to return true if it added instructions to
  686. + // builder, otherwise false.
  687. + bool BasicBlockInstrument(BasicBlock* bb, InstructionBuilder* builder,
  688. + uint32_t stage_idx) override;
  689. +
  690. + // Any instructions added via |builder| will execute before the
  691. + // entrypoint function of the shader
  692. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  693. + // This function is expected to return true if it added instructions to
  694. + // builder, otherwise false.
  695. + bool PreEntryPointInstrument(InstructionBuilder* builder,
  696. + uint32_t stage_idx) override;
  697. +
  698. + // Any instructions added via |builder| will execute before the
  699. + // entrypoint function of the shader.
  700. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  701. + // This function is expected to return true if it added instructions to
  702. + // builder, otherwise false.
  703. + bool PostEntryPointInstrument(InstructionBuilder* builder,
  704. + uint32_t stage_idx) override;
  705. +};
  706. +
  707. +} // namespace opt
  708. +} // namespace spvtools
  709. +
  710. +#endif // LIBSPIRV_OPT_AUTO_INST_DIVERGENCE_CHARACTERIZATION_PASS_H_
  711. diff --git a/source/opt/auto_inst_dyn_shader_trace_pass.cpp b/source/opt/auto_inst_dyn_shader_trace_pass.cpp
  712. new file mode 100644
  713. index 00000000..74416f43
  714. --- /dev/null
  715. +++ b/source/opt/auto_inst_dyn_shader_trace_pass.cpp
  716. @@ -0,0 +1,52 @@
  717. +// Copyright (c) 2021 The Khronos Group Inc.
  718. +//
  719. +// Licensed under the Apache License, Version 2.0 (the "License");
  720. +// you may not use this file except in compliance with the License.
  721. +// You may obtain a copy of the License at
  722. +//
  723. +// http://www.apache.org/licenses/LICENSE-2.0
  724. +//
  725. +// Unless required by applicable law or agreed to in writing, software
  726. +// distributed under the License is distributed on an "AS IS" BASIS,
  727. +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  728. +// See the License for the specific language governing permissions and
  729. +// limitations under the License.
  730. +
  731. +
  732. +#include "auto_inst_dyn_shader_trace_pass.h"
  733. +
  734. +namespace {
  735. +
  736. +static const std::set<uint32_t> kAllRayTracingStages = {
  737. + SpvExecutionModelRayGenerationNV, SpvExecutionModelAnyHitNV,
  738. + SpvExecutionModelClosestHitNV, SpvExecutionModelMissNV,
  739. + SpvExecutionModelIntersectionNV, SpvExecutionModelCallableNV};
  740. +}
  741. +
  742. +namespace spvtools {
  743. +namespace opt {
  744. +
  745. +bool AutoInstDynShaderTracePass::PreEntryPointInstrument(
  746. + InstructionBuilder* builder, uint32_t stage_idx) {
  747. + // Ray Generation begins and ends the ray tracing pipeline
  748. + if (stage_idx == SpvExecutionModelRayGenerationNV) {
  749. + // Create an instrumentation id which will be used by the analysis
  750. + // to determine how the subsequent words should be understood.
  751. + auto unique_warp_id_inst_id =
  752. + builder->GetUintConstantId(kAutoInstUniqueSubgroupId);
  753. + GenUniqueSubgroupIdFuncCall(builder, unique_warp_id_inst_id, stage_idx);
  754. + }
  755. +
  756. + auto prim_id = builder->GetUintConstantId(kAutoInstDynShaderTraceEntryPoint);
  757. + auto flat_thread_id = GenFlatRtThreadId(builder, stage_idx);
  758. + auto shader_id = builder->GetUintConstantId(shader_id_);
  759. + auto active_thread_mask_id =
  760. + GenSubgroupBallotId(builder, builder->GetBoolConstant(true)->result_id());
  761. + GenSubgroupUpdateCall(
  762. + builder, {prim_id, flat_thread_id, shader_id, active_thread_mask_id});
  763. +
  764. + return true;
  765. +}
  766. +
  767. +} // namespace opt
  768. +} // namespace spvtools
  769. diff --git a/source/opt/auto_inst_dyn_shader_trace_pass.h b/source/opt/auto_inst_dyn_shader_trace_pass.h
  770. new file mode 100644
  771. index 00000000..840f8942
  772. --- /dev/null
  773. +++ b/source/opt/auto_inst_dyn_shader_trace_pass.h
  774. @@ -0,0 +1,103 @@
  775. +// Copyright (c) 2021 The Khronos Group Inc.
  776. +
  777. +// Licensed under the Apache License, Version 2.0 (the "License");
  778. +// you may not use this file except in compliance with the License.
  779. +// You may obtain a copy of the License at
  780. +//
  781. +// http://www.apache.org/licenses/LICENSE-2.0
  782. +//
  783. +// Unless required by applicable law or agreed to in writing, software
  784. +// distributed under the License is distributed on an "AS IS" BASIS,
  785. +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  786. +// See the License for the specific language governing permissions and
  787. +// limitations under the License.
  788. +
  789. +#ifndef LIBSPIRV_OPT_AUTO_INST_DYN_SHADER_TRACE_PASS_H_
  790. +#define LIBSPIRV_OPT_AUTO_INST_DYN_SHADER_TRACE_PASS_H_
  791. +
  792. +#include <functional>
  793. +
  794. +#include "auto_inst_pass.h"
  795. +
  796. +namespace spvtools {
  797. +namespace opt {
  798. +
  799. +class AutoInstDynShaderTracePass : public AutoInstPass {
  800. + public:
  801. + AutoInstDynShaderTracePass(uint32_t desc_set, uint32_t shader_id)
  802. + : AutoInstPass(desc_set, shader_id, kDefaultReservedWordsCnt) {}
  803. +
  804. + const char* name() const override {
  805. + return "auto-inst-dyn-shader-trace-pass";
  806. + }
  807. +
  808. + private:
  809. + // Allows inheriting classes to initialize their knowledge
  810. + // of module before beginning instrumentation
  811. + void InitializeInstrumentation() override{};
  812. +
  813. + // Allows inheriting classes to finalize before
  814. + // the pass finishes executing.
  815. + void FinalizeInstrumentation() override{};
  816. +
  817. + // Any instructions added via |builder| will appear before |inst|
  818. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  819. + // This function is expected to return true if it added instructions to
  820. + // builder, otherwise false.
  821. + bool PreInstructionInstrument(Instruction* inst, InstructionBuilder* builder,
  822. + uint32_t stage_idx) override {
  823. + (void)inst;
  824. + (void)builder;
  825. + (void)stage_idx;
  826. + return false;
  827. + };
  828. +
  829. + // Any instructions added via |builder| will appear after |inst|.
  830. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  831. + // This function is expected to return true if it added instructions to
  832. + // builder, otherwise false.
  833. + bool PostInstructionInstrument(Instruction* inst, InstructionBuilder* builder,
  834. + uint32_t stage_idx) override {
  835. + (void)inst;
  836. + (void)builder;
  837. + (void)stage_idx;
  838. + return false;
  839. + };
  840. +
  841. + // Any instructions added via |builder| will appear before the content of
  842. + // |bb|. |stage_idx| contains the SpvExecutionModel that builder is operating
  843. + // in. This function is expected to return true if it added instructions to
  844. + // builder, otherwise false.
  845. + bool BasicBlockInstrument(BasicBlock* bb, InstructionBuilder* builder,
  846. + uint32_t stage_idx) override {
  847. + (void)bb;
  848. + (void)builder;
  849. + (void)stage_idx;
  850. + return false;
  851. + }
  852. +
  853. + // Any instructions added via |builder| will execute before the
  854. + // entrypoint function of the shader
  855. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  856. + // This function is expected to return true if it added instructions to
  857. + // builder, otherwise false.
  858. + bool PreEntryPointInstrument(InstructionBuilder* builder,
  859. + uint32_t stage_idx) override;
  860. +
  861. + // Any instructions added via |builder| will execute before the
  862. + // entrypoint function of the shader.
  863. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  864. + // This function is expected to return true if it added instructions to
  865. + // builder, otherwise false.
  866. + bool PostEntryPointInstrument(InstructionBuilder* builder,
  867. + uint32_t stage_idx) override {
  868. + (void)builder;
  869. + (void)stage_idx;
  870. + return false;
  871. + }
  872. +};
  873. +
  874. +} // namespace opt
  875. +} // namespace spvtools
  876. +
  877. +#endif // LIBSPIRV_OPT_AUTO_INST_DYN_SHADER_TRACE_PASS_H_
  878. diff --git a/source/opt/auto_inst_dyn_trace_ray_trace_pass.cpp b/source/opt/auto_inst_dyn_trace_ray_trace_pass.cpp
  879. new file mode 100644
  880. index 00000000..edd63b34
  881. --- /dev/null
  882. +++ b/source/opt/auto_inst_dyn_trace_ray_trace_pass.cpp
  883. @@ -0,0 +1,184 @@
  884. +// Copyright (c) 2021 The Khronos Group Inc.
  885. +//
  886. +// Licensed under the Apache License, Version 2.0 (the "License");
  887. +// you may not use this file except in compliance with the License.
  888. +// You may obtain a copy of the License at
  889. +//
  890. +// http://www.apache.org/licenses/LICENSE-2.0
  891. +//
  892. +// Unless required by applicable law or agreed to in writing, software
  893. +// distributed under the License is distributed on an "AS IS" BASIS,
  894. +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  895. +// See the License for the specific language governing permissions and
  896. +// limitations under the License.
  897. +
  898. +
  899. +#include "auto_inst_dyn_trace_ray_trace_pass.h"
  900. +
  901. +namespace {
  902. +
  903. +static const std::set<uint32_t> kAllRayTracingStages = {
  904. + SpvExecutionModelRayGenerationNV, SpvExecutionModelAnyHitNV,
  905. + SpvExecutionModelClosestHitNV, SpvExecutionModelMissNV,
  906. + SpvExecutionModelIntersectionNV, SpvExecutionModelCallableNV};
  907. +
  908. +static const int kEntryPointFunctionIdInIdx = 1;
  909. +} // namespace
  910. +
  911. +namespace spvtools {
  912. +namespace opt {
  913. +
  914. +void AutoInstDynTraceRayTracePass::GenInst(InstructionBuilder* builder,
  915. + uint32_t inst_id, uint32_t prim_type,
  916. + uint32_t stage_idx) {
  917. + if (inst_id2prim_type_.count(inst_id) != 0) {
  918. + consumer()(SPV_MSG_ERROR, 0, {0, 0, 0},
  919. + "Multiple instrumentation sites with the same id detected!\n");
  920. + return;
  921. + }
  922. +
  923. + auto flat_thread_id = GenFlatRtThreadId(builder, stage_idx);
  924. + auto active_thread_mask_id =
  925. + GenSubgroupBallotId(builder, builder->GetBoolConstant(true)->result_id());
  926. +
  927. + GenSubgroupUpdateCall(builder, {builder->GetUintConstantId(inst_id),
  928. + flat_thread_id, active_thread_mask_id});
  929. +
  930. + inst_id2prim_type_[inst_id] = prim_type;
  931. +}
  932. +
  933. +void AutoInstDynTraceRayTracePass::InitializeInstrumentation() {
  934. + inst_id2prim_type_.clear();
  935. + fn_id_2_divergent_ids_.clear();
  936. + merge_id_2_divergent_ids_.clear();
  937. + loop_begin_bb_ids_.clear();
  938. +
  939. + Function* entry_point_func = nullptr;
  940. +
  941. + for (auto e : get_module()->entry_points()) {
  942. + auto func_id = e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx);
  943. + entry_point_func = id2function_[func_id];
  944. + }
  945. +
  946. + auto active_merge_ids = std::stack<uint32_t>();
  947. + PopulateDivergentLabelsInfo(entry_point_func, active_merge_ids);
  948. +}
  949. +
  950. +bool AutoInstDynTraceRayTracePass::PreEntryPointInstrument(
  951. + InstructionBuilder* builder, uint32_t stage_idx) {
  952. + if (stage_idx != SpvExecutionModelRayGenerationKHR) return false;
  953. +
  954. + // Create an instrumentation id which will be used by the analysis
  955. + // to determine how the subsequent words should be understood.
  956. + auto unique_warp_id_inst_id =
  957. + builder->GetUintConstantId(kAutoInstUniqueSubgroupId);
  958. +
  959. + // This instrumentation is unique across the pipeline so it is sufficient
  960. + // to choose an inst_id that can never alias with the other types of
  961. + // instrumentation.
  962. + inst_id2prim_type_[kAutoInstUniqueSubgroupId] = kAutoInstUniqueSubgroupId;
  963. +
  964. + GenUniqueSubgroupIdFuncCall(builder, unique_warp_id_inst_id, stage_idx);
  965. +
  966. + return true;
  967. +}
  968. +
  969. +bool AutoInstDynTraceRayTracePass::BasicBlockInstrument(
  970. + BasicBlock* bb, InstructionBuilder* builder, uint32_t stage_idx) {
  971. + if (kAllRayTracingStages.count(stage_idx) == 0) return false;
  972. +
  973. + if (merge_id_2_divergent_ids_.count(bb->id()) != 0) {
  974. + GenInst(builder, bb->id(), kAutoInstTraceRayTraceMergePoint, stage_idx);
  975. + return true;
  976. + }
  977. +
  978. + for (auto& ii : *bb) {
  979. + if (ii.opcode() == SpvOpTraceRayKHR || ii.opcode() == SpvOpTraceNV) {
  980. + builder->SetInsertPoint(&ii);
  981. + GenInst(builder, bb->id(), kAutoInstTraceRayTracePreTraceRay, stage_idx);
  982. + return true;
  983. + }
  984. + }
  985. +
  986. + return false;
  987. +}
  988. +
  989. +void AutoInstDynTraceRayTracePass::FinalizeInstrumentation() {
  990. + static_data_callback_(std::move(inst_id2prim_type_),
  991. + std::move(merge_id_2_divergent_ids_));
  992. +}
  993. +
  994. +void AutoInstDynTraceRayTracePass::PopulateDivergentLabelsInfo(
  995. + Function* func, std::stack<uint32_t>& active_merge_ids) {
  996. + if (fn_id_2_divergent_ids_.count(func->result_id()) > 0) return;
  997. +
  998. + bool is_divergent_control_flow = active_merge_ids.size() > 0;
  999. + std::vector<uint32_t> divergent_labels;
  1000. + std::stack<uint32_t> active_loop_ids;
  1001. +
  1002. + for (auto& blk : *func) {
  1003. + if (active_merge_ids.size() > 0 && blk.id() == active_merge_ids.top()) {
  1004. + // Need to move the merge label to the beginning of the loop
  1005. + // iteration in order to determine how many times the label was visited at
  1006. + // runtime
  1007. + if (active_loop_ids.size() > 0) {
  1008. + if (merge_id_2_divergent_ids_.count(active_merge_ids.top()) > 0) {
  1009. + loop_begin_bb_ids_.insert(active_loop_ids.top());
  1010. + }
  1011. + merge_id_2_divergent_ids_[active_loop_ids.top()] =
  1012. + merge_id_2_divergent_ids_[active_merge_ids.top()];
  1013. + merge_id_2_divergent_ids_.erase(active_merge_ids.top());
  1014. + active_loop_ids.pop();
  1015. + }
  1016. + active_merge_ids.pop();
  1017. + }
  1018. +
  1019. + for (auto& inst : blk) {
  1020. + // Determine divergent labels to track
  1021. + if (inst.opcode() == SpvOpTraceRayKHR || inst.opcode() == SpvOpTraceNV) {
  1022. + divergent_labels.push_back(blk.id());
  1023. + } else if (inst.opcode() == SpvOpFunctionCall) {
  1024. + // Add divergent labels according to func being called
  1025. + auto func_to_call_id = inst.GetSingleWordOperand(2);
  1026. + if (fn_id_2_divergent_ids_.count(func_to_call_id) == 0) {
  1027. + // recurse if fn not discovered yet
  1028. + PopulateDivergentLabelsInfo(id2function_[func_to_call_id],
  1029. + active_merge_ids);
  1030. + }
  1031. + divergent_labels = fn_id_2_divergent_ids_[func_to_call_id];
  1032. +
  1033. + } else if (inst.opcode() == SpvOpSelectionMerge ||
  1034. + inst.opcode() == SpvOpLoopMerge) {
  1035. + auto merge_id = inst.GetSingleWordOperand(0);
  1036. +
  1037. + if (active_merge_ids.size() == 0) {
  1038. + active_merge_ids.push(merge_id);
  1039. + } else if (inst.opcode() == SpvOpLoopMerge) {
  1040. + active_merge_ids.push(merge_id);
  1041. + active_loop_ids.push(inst.GetSingleWordOperand(1));
  1042. + }
  1043. + }
  1044. +
  1045. + // Update datastructures with divergent labels
  1046. + if (divergent_labels.size() > 0) {
  1047. + fn_id_2_divergent_ids_[func->result_id()].insert(
  1048. + fn_id_2_divergent_ids_[func->result_id()].end(),
  1049. + divergent_labels.begin(), divergent_labels.end());
  1050. +
  1051. + // Update all active to-be-merged labels
  1052. + if (active_merge_ids.size() > 0 && !is_divergent_control_flow) {
  1053. + auto id = active_merge_ids.top();
  1054. +
  1055. + merge_id_2_divergent_ids_[id].insert(
  1056. + merge_id_2_divergent_ids_[id].end(), divergent_labels.begin(),
  1057. + divergent_labels.end());
  1058. + }
  1059. +
  1060. + divergent_labels.clear();
  1061. + }
  1062. + }
  1063. + }
  1064. +}
  1065. +
  1066. +} // namespace opt
  1067. +} // namespace spvtools
  1068. diff --git a/source/opt/auto_inst_dyn_trace_ray_trace_pass.h b/source/opt/auto_inst_dyn_trace_ray_trace_pass.h
  1069. new file mode 100644
  1070. index 00000000..d095398d
  1071. --- /dev/null
  1072. +++ b/source/opt/auto_inst_dyn_trace_ray_trace_pass.h
  1073. @@ -0,0 +1,135 @@
  1074. +// Copyright (c) 2021 The Khronos Group Inc.
  1075. +
  1076. +// Licensed under the Apache License, Version 2.0 (the "License");
  1077. +// you may not use this file except in compliance with the License.
  1078. +// You may obtain a copy of the License at
  1079. +//
  1080. +// http://www.apache.org/licenses/LICENSE-2.0
  1081. +//
  1082. +// Unless required by applicable law or agreed to in writing, software
  1083. +// distributed under the License is distributed on an "AS IS" BASIS,
  1084. +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1085. +// See the License for the specific language governing permissions and
  1086. +// limitations under the License.
  1087. +
  1088. +#ifndef LIBSPIRV_OPT_AUTO_INST_DYN_TRACE_RAY_TRACE_PASS_H_
  1089. +#define LIBSPIRV_OPT_AUTO_INST_DYN_TRACE_RAY_TRACE_PASS_H_
  1090. +
  1091. +#include <functional>
  1092. +
  1093. +#include "auto_inst_pass.h"
  1094. +
  1095. +namespace spvtools {
  1096. +namespace opt {
  1097. +
  1098. +class AutoInstDynTraceRayTracePass : public AutoInstPass {
  1099. + public:
  1100. + AutoInstDynTraceRayTracePass(
  1101. + uint32_t desc_set, uint32_t shader_id,
  1102. + std::function<void(std::unordered_map<uint32_t, uint32_t>&&,
  1103. + std::unordered_map<uint32_t, std::vector<uint32_t>>&&)>
  1104. + static_data_callback)
  1105. + : AutoInstPass(desc_set, shader_id, kDefaultReservedWordsCnt),
  1106. + static_data_callback_(static_data_callback) {}
  1107. +
  1108. + const char* name() const override {
  1109. + return "auto-inst-dyn-trace-ray-trace-pass";
  1110. + }
  1111. +
  1112. + private:
  1113. + // Callback to transfer static data to creator of the pass.
  1114. + std::function<void(std::unordered_map<uint32_t, uint32_t>&&,
  1115. + std::unordered_map<uint32_t, std::vector<uint32_t>>&&)>
  1116. + static_data_callback_;
  1117. +
  1118. + // Static data which forms a mapping from instrumentation callsite id
  1119. + // to the instructions in the basic block.
  1120. + std::unordered_map<uint32_t, uint32_t> inst_id2prim_type_;
  1121. +
  1122. + // Static data which contains the mapping of MergePoint instrumentation
  1123. + // to all the traceRay callsites that must have executed.
  1124. + std::unordered_map<uint32_t, std::vector<uint32_t>> merge_id_2_divergent_ids_;
  1125. +
  1126. + // Memoization table for each function
  1127. + std::unordered_map<uint32_t, std::vector<uint32_t>> fn_id_2_divergent_ids_;
  1128. +
  1129. + // Which bbs to add instrumentation before to track loop iterations.
  1130. + std::set<uint32_t> loop_begin_bb_ids_;
  1131. +
  1132. + // Generate instrumentation for this pass
  1133. + void GenInst(InstructionBuilder* builder, uint32_t inst_id,
  1134. + uint32_t prim_type, uint32_t stage_idx);
  1135. +
  1136. + // Allows inheriting classes to initialize their knowledge
  1137. + // of module before beginning instrumentation
  1138. + void InitializeInstrumentation() override;
  1139. +
  1140. + // Allows inheriting classes to finalize before
  1141. + // the pass finishes executing.
  1142. + void FinalizeInstrumentation() override;
  1143. +
  1144. + // Any instructions added via |builder| will appear before |inst|
  1145. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  1146. + // This function is expected to return true if it added instructions to
  1147. + // builder, otherwise false.
  1148. + bool PreInstructionInstrument(Instruction* inst, InstructionBuilder* builder,
  1149. + uint32_t stage_idx) override {
  1150. + (void)inst;
  1151. + (void)builder;
  1152. + (void)stage_idx;
  1153. + return false;
  1154. + };
  1155. +
  1156. + // Any instructions added via |builder| will appear after |inst|.
  1157. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  1158. + // This function is expected to return true if it added instructions to
  1159. + // builder, otherwise false.
  1160. + bool PostInstructionInstrument(Instruction* inst, InstructionBuilder* builder,
  1161. + uint32_t stage_idx) override {
  1162. + (void)inst;
  1163. + (void)builder;
  1164. + (void)stage_idx;
  1165. + return false;
  1166. + }
  1167. +
  1168. + // Any instructions added via |builder| will appear before the content of
  1169. + // |bb|. |stage_idx| contains the SpvExecutionModel that builder is operating
  1170. + // in. This function is expected to return true if it added instructions to
  1171. + // builder, otherwise false.
  1172. + bool BasicBlockInstrument(BasicBlock* bb, InstructionBuilder* builder,
  1173. + uint32_t stage_idx) override;
  1174. +
  1175. + // Any instructions added via |builder| will execute before the
  1176. + // entrypoint function of the shader
  1177. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  1178. + // This function is expected to return true if it added instructions to
  1179. + // builder, otherwise false.
  1180. + bool PreEntryPointInstrument(InstructionBuilder* builder,
  1181. + uint32_t stage_idx) override;
  1182. +
  1183. + // Any instructions added via |builder| will execute before the
  1184. + // entrypoint function of the shader.
  1185. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  1186. + // This function is expected to return true if it added instructions to
  1187. + // builder, otherwise false.
  1188. + bool PostEntryPointInstrument(InstructionBuilder* builder,
  1189. + uint32_t stage_idx) override {
  1190. + (void)builder;
  1191. + (void)stage_idx;
  1192. + return false;
  1193. + };
  1194. +
  1195. + // This function generates an analysis of |func| to determine
  1196. + // 1) the SpvOpTraceRays that exist within control-flow.
  1197. + // 2) where to add instrumentation to detect loop iterations and
  1198. + // opportunities to execute traceRays.
  1199. + //
  1200. + // This allows runtime traceRay calls to be disambiguated.
  1201. + void PopulateDivergentLabelsInfo(Function* func,
  1202. + std::stack<uint32_t>& active_merge_ids);
  1203. +};
  1204. +
  1205. +} // namespace opt
  1206. +} // namespace spvtools
  1207. +
  1208. +#endif // LIBSPIRV_OPT_AUTO_INST_DYN_TRACE_RAY_TRACE_PASS_H_
  1209. diff --git a/source/opt/auto_inst_execution_trace_pass.cpp b/source/opt/auto_inst_execution_trace_pass.cpp
  1210. new file mode 100644
  1211. index 00000000..3eeff48e
  1212. --- /dev/null
  1213. +++ b/source/opt/auto_inst_execution_trace_pass.cpp
  1214. @@ -0,0 +1,68 @@
  1215. +// Copyright (c) 2021 The Khronos Group Inc.
  1216. +//
  1217. +// Licensed under the Apache License, Version 2.0 (the "License");
  1218. +// you may not use this file except in compliance with the License.
  1219. +// You may obtain a copy of the License at
  1220. +//
  1221. +// http://www.apache.org/licenses/LICENSE-2.0
  1222. +//
  1223. +// Unless required by applicable law or agreed to in writing, software
  1224. +// distributed under the License is distributed on an "AS IS" BASIS,
  1225. +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1226. +// See the License for the specific language governing permissions and
  1227. +// limitations under the License.
  1228. +
  1229. +#include "auto_inst_execution_trace_pass.h"
  1230. +
  1231. +namespace spvtools {
  1232. +namespace opt {
  1233. +
  1234. +void AutoInstExecutionTracePass::InitializeInstrumentation() {
  1235. + inst_id2bb_inst_ids_.clear();
  1236. + inst_id2opcode_.clear();
  1237. +}
  1238. +
  1239. +bool AutoInstExecutionTracePass::BasicBlockInstrument(
  1240. + BasicBlock* bb, InstructionBuilder* builder, uint32_t stage_idx) {
  1241. + (void)stage_idx;
  1242. + auto module_offset = uid2offset_[bb->begin()->unique_id()];
  1243. + if (shader_id_ >= (1 << 12) || module_offset >= (1 << 20)) {
  1244. + std::string message =
  1245. + "Shader id count or shader module size are too large!\n";
  1246. + consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
  1247. + return false;
  1248. + }
  1249. +
  1250. + // Create an instrumentation callsite id that is unique across
  1251. + // the whole pipeline by including the shader id in the upper bits.
  1252. + auto inst = &*builder->GetInsertPoint();
  1253. +
  1254. + uint32_t inst_id = GenInstCallsiteId(inst);
  1255. +
  1256. + for (auto inst_itr : *bb) {
  1257. + auto other_inst_id = GenInstCallsiteId(&inst_itr);
  1258. +
  1259. + // Create group of instructions which must execute
  1260. + // if the instrumentation executed.
  1261. + inst_id2bb_inst_ids_[inst_id].insert(other_inst_id);
  1262. + // Add opcode to the static metadata map so it can be added
  1263. + // to a dynamic opcode total.
  1264. + inst_id2opcode_[other_inst_id] = inst_itr.opcode();
  1265. + }
  1266. + // Write the same inst_id as in the static data so that when a
  1267. + // buffer entry is parsed, the inst_id can be used to look up
  1268. + // the other instructions that must have also been executed.
  1269. + auto active_thread_mask_id =
  1270. + GenSubgroupBallotId(builder, builder->GetBoolConstant(true)->result_id());
  1271. + GenSubgroupUpdateCall(
  1272. + builder, {builder->GetUintConstantId(inst_id), active_thread_mask_id});
  1273. + return true;
  1274. +}
  1275. +
  1276. +void AutoInstExecutionTracePass::FinalizeInstrumentation() {
  1277. + static_data_callback_(std::move(inst_id2bb_inst_ids_),
  1278. + std::move(inst_id2opcode_));
  1279. +}
  1280. +
  1281. +} // namespace opt
  1282. +} // namespace spvtools
  1283. diff --git a/source/opt/auto_inst_execution_trace_pass.h b/source/opt/auto_inst_execution_trace_pass.h
  1284. new file mode 100644
  1285. index 00000000..124f3ecd
  1286. --- /dev/null
  1287. +++ b/source/opt/auto_inst_execution_trace_pass.h
  1288. @@ -0,0 +1,122 @@
  1289. +// Copyright (c) 2021 The Khronos Group Inc.
  1290. +
  1291. +// Licensed under the Apache License, Version 2.0 (the "License");
  1292. +// you may not use this file except in compliance with the License.
  1293. +// You may obtain a copy of the License at
  1294. +//
  1295. +// http://www.apache.org/licenses/LICENSE-2.0
  1296. +//
  1297. +// Unless required by applicable law or agreed to in writing, software
  1298. +// distributed under the License is distributed on an "AS IS" BASIS,
  1299. +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1300. +// See the License for the specific language governing permissions and
  1301. +// limitations under the License.
  1302. +
  1303. +#ifndef LIBSPIRV_OPT_AUTO_INST_EXECUTION_TRACE_PASS_H_
  1304. +#define LIBSPIRV_OPT_AUTO_INST_EXECUTION_TRACE_PASS_H_
  1305. +
  1306. +#include <functional>
  1307. +
  1308. +#include "auto_inst_pass.h"
  1309. +
  1310. +namespace spvtools {
  1311. +namespace opt {
  1312. +
  1313. +class AutoInstExecutionTracePass : public AutoInstPass {
  1314. + public:
  1315. + AutoInstExecutionTracePass(
  1316. + uint32_t desc_set, uint32_t shader_id,
  1317. + std::function<
  1318. + void(std::unordered_map<uint32_t, std::set<uint32_t>>&&
  1319. + inst_id2bb_inst_ids,
  1320. + std::unordered_map<uint32_t, uint32_t>&& inst_id2opcode)>
  1321. + static_data_callback)
  1322. + : AutoInstPass(desc_set, shader_id, kDefaultReservedWordsCnt),
  1323. + static_data_callback_(static_data_callback) {}
  1324. +
  1325. + const char* name() const override { return "auto-inst-execution-trace-pass"; }
  1326. +
  1327. + private:
  1328. + // Callback to transfer static data to creator of the pass.
  1329. + const std::function<void(
  1330. + std::unordered_map<uint32_t, std::set<uint32_t>>&& inst_id2bb_inst_ids,
  1331. + std::unordered_map<uint32_t, uint32_t>&& inst_id2opcode)>
  1332. + static_data_callback_;
  1333. +
  1334. + // Static data which forms a mapping from instrumentation callsite id
  1335. + // to the ids of other instructions in the basic block.
  1336. + std::unordered_map<uint32_t, std::set<uint32_t>> inst_id2bb_inst_ids_;
  1337. +
  1338. + // Static data which forms a mappign from inst_id to opcode.
  1339. + // This together with |inst_id2bb_inst_ids_| gives the runtime
  1340. + // instruction mix.
  1341. + std::unordered_map<uint32_t, uint32_t> inst_id2opcode_;
  1342. +
  1343. + // Allows inheriting classes to initialize their knowledge
  1344. + // of module before beginning instrumentation
  1345. + void InitializeInstrumentation() override;
  1346. +
  1347. + // Allows inheriting classes to finalize before
  1348. + // the pass finishes executing.
  1349. + void FinalizeInstrumentation() override;
  1350. +
  1351. + // Any instructions added via |builder| will appear before |inst|
  1352. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  1353. + // This function is expected to return true if it added instructions to
  1354. + // builder, otherwise false.
  1355. + bool PreInstructionInstrument(Instruction* inst, InstructionBuilder* builder,
  1356. + uint32_t stage_idx) override {
  1357. + (void)inst;
  1358. + (void)builder;
  1359. + (void)stage_idx;
  1360. + return false;
  1361. + };
  1362. +
  1363. + // Any instructions added via |builder| will appear after |inst|.
  1364. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  1365. + // This function is expected to return true if it added instructions to
  1366. + // builder, otherwise false.
  1367. + bool PostInstructionInstrument(Instruction* inst, InstructionBuilder* builder,
  1368. + uint32_t stage_idx) override {
  1369. + (void)inst;
  1370. + (void)builder;
  1371. + (void)stage_idx;
  1372. + return false;
  1373. + };
  1374. +
  1375. + // Any instructions added via |builder| will appear before the content of
  1376. + // |bb|. |stage_idx| contains the SpvExecutionModel that builder is operating
  1377. + // in. This function is expected to return true if it added instructions to
  1378. + // builder, otherwise false.
  1379. + bool BasicBlockInstrument(BasicBlock* bb, InstructionBuilder* builder,
  1380. + uint32_t stage_idx) override;
  1381. +
  1382. + // Any instructions added via |builder| will execute before the
  1383. + // entrypoint function of the shader
  1384. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  1385. + // This function is expected to return true if it added instructions to
  1386. + // builder, otherwise false.
  1387. + bool PreEntryPointInstrument(InstructionBuilder* builder,
  1388. + uint32_t stage_idx) override {
  1389. + (void)builder;
  1390. + (void)stage_idx;
  1391. + return false;
  1392. + }
  1393. +
  1394. + // Any instructions added via |builder| will execute before the
  1395. + // entrypoint function of the shader.
  1396. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  1397. + // This function is expected to return true if it added instructions to
  1398. + // builder, otherwise false.
  1399. + bool PostEntryPointInstrument(InstructionBuilder* builder,
  1400. + uint32_t stage_idx) override {
  1401. + (void)builder;
  1402. + (void)stage_idx;
  1403. + return false;
  1404. + };
  1405. +};
  1406. +
  1407. +} // namespace opt
  1408. +} // namespace spvtools
  1409. +
  1410. +#endif // LIBSPIRV_OPT_AUTO_INST_EXECUTION_TRACE_PASS_H_
  1411. diff --git a/source/opt/auto_inst_pass.cpp b/source/opt/auto_inst_pass.cpp
  1412. new file mode 100644
  1413. index 00000000..6a5f7f60
  1414. --- /dev/null
  1415. +++ b/source/opt/auto_inst_pass.cpp
  1416. @@ -0,0 +1,927 @@
  1417. +// Copyright (c) 2021 The Khronos Group Inc.
  1418. +//
  1419. +// Licensed under the Apache License, Version 2.0 (the "License");
  1420. +// you may not use this file except in compliance with the License.
  1421. +// You may obtain a copy of the License at
  1422. +//
  1423. +// http://www.apache.org/licenses/LICENSE-2.0
  1424. +//
  1425. +// Unless required by applicable law or agreed to in writing, software
  1426. +// distributed under the License is distributed on an "AS IS" BASIS,
  1427. +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1428. +// See the License for the specific language governing permissions and
  1429. +// limitations under the License.
  1430. +
  1431. +
  1432. +#include "auto_inst_pass.h"
  1433. +
  1434. +namespace {
  1435. +
  1436. +// Operand indices of SpvOpEntryPoint
  1437. +static const int kEntryPointFunctionIdInIdx = 1;
  1438. +static const int kEntryPointExecutionModelInIdx = 0;
  1439. +
  1440. +// Type of function from OpFunction
  1441. +static const int kFunctionTypeIdx = 3;
  1442. +
  1443. +// UniqueSubgroupId function constants
  1444. +static const int kUniqueSubgroupIdParamCnt = 1;
  1445. +static const int kUniqueSubgroupIdParamInstIdIdx = 0;
  1446. +} // namespace
  1447. +
  1448. +namespace spvtools {
  1449. +namespace opt {
  1450. +
  1451. +bool AutoInstPass::HandleInstrumentHooks(
  1452. + BasicBlock::iterator ref_inst_itr,
  1453. + UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
  1454. + InstructionBuilder* builder) {
  1455. + bool is_instrumented = false;
  1456. +
  1457. + // Initialize instrumentation validity based on inst opcode.
  1458. + bool skip_pre_instrumentation =
  1459. + uninstrumentable_pre_ops.count(ref_inst_itr->opcode()) > 0;
  1460. + bool skip_post_instrumentation =
  1461. + uninstrumentable_post_ops.count(ref_inst_itr->opcode()) > 0;
  1462. +
  1463. + if (ref_block_itr->GetParent()->begin() == ref_block_itr) {
  1464. + // Despite the SPIR-V specification stating:
  1465. + // "All OpVariable instructions in a function must be in the first block in
  1466. + // the function. " The real restriction is as follows: "All OpVariable
  1467. + // instructions in a function must be the first instructions in the first
  1468. + // block." Therefore this check prevents instrumenting OpVariables in the
  1469. + // first block of a function.
  1470. + if (ref_inst_itr->opcode() == SpvOpVariable) {
  1471. + skip_pre_instrumentation = true;
  1472. + }
  1473. + if (std::next(ref_inst_itr) != ref_block_itr->end() &&
  1474. + std::next(ref_inst_itr)->opcode() == SpvOpVariable) {
  1475. + skip_post_instrumentation = true;
  1476. + }
  1477. + }
  1478. +
  1479. + if (skip_pre_instrumentation && skip_post_instrumentation) return false;
  1480. +
  1481. + if (!skip_pre_instrumentation) {
  1482. + // set insert point to immediately before current inst
  1483. + builder->SetInsertPoint(&*ref_inst_itr);
  1484. +
  1485. + if (instrumented_bb_ids.count(ref_block_itr->id()) == 0) {
  1486. + is_instrumented |=
  1487. + BasicBlockInstrument(&*ref_block_itr, builder, stage_idx);
  1488. + }
  1489. +
  1490. + if (instrumented_inst_ids.count(ref_inst_itr->unique_id()) == 0) {
  1491. + is_instrumented |=
  1492. + PreInstructionInstrument(&*ref_inst_itr, builder, stage_idx);
  1493. + }
  1494. + }
  1495. + if (!skip_post_instrumentation) {
  1496. + if (instrumented_inst_ids.count(ref_inst_itr->unique_id()) == 0) {
  1497. + // Before next inst is after this inst
  1498. + builder->SetInsertPoint(&*std::next(ref_inst_itr));
  1499. + is_instrumented |=
  1500. + PostInstructionInstrument(&*ref_inst_itr, builder, stage_idx);
  1501. + }
  1502. + }
  1503. +
  1504. + if (is_instrumented) {
  1505. + // Record the bb and inst that were just visited
  1506. + instrumented_bb_ids.insert(ref_block_itr->id());
  1507. + instrumented_inst_ids.insert(ref_inst_itr->unique_id());
  1508. + }
  1509. +
  1510. + return is_instrumented;
  1511. +}
  1512. +
  1513. +void AutoInstPass::GenInstProgrammableCode(
  1514. + BasicBlock::iterator ref_inst_itr,
  1515. + UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx) {
  1516. + // Initialize DefUse manager before dismantling module
  1517. + (void)get_def_use_mgr();
  1518. +
  1519. + InstructionBuilder builder(context(), &*ref_block_itr);
  1520. +
  1521. + bool is_instrumented =
  1522. + HandleInstrumentHooks(ref_inst_itr, ref_block_itr, stage_idx, &builder);
  1523. + if (!is_instrumented) return;
  1524. + has_added_instrumentation_ = true;
  1525. +}
  1526. +
  1527. +uint32_t AutoInstPass::GenSubgroupBallotId(InstructionBuilder* builder,
  1528. + uint32_t pred_id) {
  1529. + if (!get_feature_mgr()->HasExtension(kSPV_KHR_subgroup_vote)) {
  1530. + context()->AddExtension("SPV_KHR_subgroup_vote");
  1531. + }
  1532. +
  1533. + if (!get_feature_mgr()->HasCapability(SpvCapabilityGroupNonUniformBallot)) {
  1534. + context()->AddCapability(SpvCapabilityGroupNonUniformBallot);
  1535. + }
  1536. +
  1537. + uint32_t scope_ballot_idx = builder->GetUintConstantId(SpvScopeSubgroup);
  1538. + Instruction* ballot_inst = builder->AddBinaryOp(
  1539. + GetVec4UintId(), SpvOpGroupNonUniformBallot, scope_ballot_idx, pred_id);
  1540. +
  1541. + return builder
  1542. + ->AddIdLiteralOp(GetUintId(), SpvOpCompositeExtract,
  1543. + ballot_inst->result_id(), 0)
  1544. + ->result_id();
  1545. +}
  1546. +
  1547. +std::pair<uint32_t, uint32_t> AutoInstPass::GenReadClockIds(
  1548. + InstructionBuilder* builder) {
  1549. + if (!get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock)) {
  1550. + context()->AddExtension("SPV_KHR_shader_clock");
  1551. + }
  1552. +
  1553. + if (!get_feature_mgr()->HasCapability(SpvCapabilityShaderClockKHR)) {
  1554. + context()->AddCapability(SpvCapabilityShaderClockKHR);
  1555. + }
  1556. +
  1557. + auto time_inst =
  1558. + builder->AddUnaryOp(GetVecUintId(2u), SpvOpReadClockKHR,
  1559. + builder->GetUintConstantId(SpvScopeDevice));
  1560. + Instruction* time_lower = builder->AddIdLiteralOp(
  1561. + GetUintId(), SpvOpCompositeExtract, time_inst->result_id(), 0);
  1562. + Instruction* time_upper = builder->AddIdLiteralOp(
  1563. + GetUintId(), SpvOpCompositeExtract, time_inst->result_id(), 1);
  1564. + return std::make_pair(time_lower->result_id(), time_upper->result_id());
  1565. +}
  1566. +
  1567. +uint32_t AutoInstPass::GenFlatRtThreadId(InstructionBuilder* builder,
  1568. + uint32_t stage_idx) {
  1569. + switch (stage_idx) {
  1570. + case SpvExecutionModelRayGenerationNV:
  1571. + case SpvExecutionModelIntersectionNV:
  1572. + case SpvExecutionModelAnyHitNV:
  1573. + case SpvExecutionModelClosestHitNV:
  1574. + case SpvExecutionModelMissNV:
  1575. + case SpvExecutionModelCallableNV: {
  1576. + auto launch_id = GenVarLoad(
  1577. + context()->GetBuiltinInputVarId(SpvBuiltInLaunchIdKHR), builder);
  1578. + Instruction* launch_x = builder->AddIdLiteralOp(
  1579. + GetUintId(), SpvOpCompositeExtract, launch_id, 0);
  1580. + Instruction* launch_y = builder->AddIdLiteralOp(
  1581. + GetUintId(), SpvOpCompositeExtract, launch_id, 1);
  1582. + Instruction* launch_z = builder->AddIdLiteralOp(
  1583. + GetUintId(), SpvOpCompositeExtract, launch_id, 2);
  1584. +
  1585. + auto launch_size_id = GenVarLoad(
  1586. + context()->GetBuiltinInputVarId(SpvBuiltInLaunchSizeKHR), builder);
  1587. + Instruction* launch_size_x = builder->AddIdLiteralOp(
  1588. + GetUintId(), SpvOpCompositeExtract, launch_size_id, 0);
  1589. + Instruction* launch_size_y = builder->AddIdLiteralOp(
  1590. + GetUintId(), SpvOpCompositeExtract, launch_size_id, 1);
  1591. +
  1592. + auto xy_size = builder->AddBinaryOp(GetUintId(), SpvOpIMul,
  1593. + launch_size_x->result_id(),
  1594. + launch_size_y->result_id());
  1595. + auto z_term = builder->AddBinaryOp(
  1596. + GetUintId(), SpvOpIMul, launch_z->result_id(), xy_size->result_id());
  1597. +
  1598. + auto y_term =
  1599. + builder->AddBinaryOp(GetUintId(), SpvOpIMul, launch_y->result_id(),
  1600. + launch_size_x->result_id());
  1601. +
  1602. + auto flat_thread_id = builder->AddBinaryOp(
  1603. + GetUintId(), SpvOpIAdd, z_term->result_id(), y_term->result_id());
  1604. + flat_thread_id = builder->AddBinaryOp(GetUintId(), SpvOpIAdd,
  1605. + flat_thread_id->result_id(),
  1606. + launch_x->result_id());
  1607. + return flat_thread_id->result_id();
  1608. + }
  1609. +
  1610. + default:
  1611. + consumer()(
  1612. + SPV_MSG_ERROR, 0, {0, 0, 0},
  1613. + "Cannot create a flattened rt thread id for requested shader stage! "
  1614. + "Defaulting to 0.\n");
  1615. + return builder->GetUintConstantId(0);
  1616. + }
  1617. +}
  1618. +
  1619. +uint32_t AutoInstPass::GenFlatComputeThreadId(InstructionBuilder* builder,
  1620. + uint32_t stage_idx) {
  1621. + if (stage_idx != SpvExecutionModelGLCompute) {
  1622. + consumer()(SPV_MSG_ERROR, 0, {0, 0, 0},
  1623. + "Cannot create a flattened compute thread id for requested "
  1624. + "shader stage! "
  1625. + "Defaulting to 0.\n");
  1626. + return builder->GetUintConstantId(0);
  1627. + }
  1628. + auto invocation_id = GenVarLoad(
  1629. + context()->GetBuiltinInputVarId(SpvBuiltInGlobalInvocationId), builder);
  1630. + Instruction* invocation_x = builder->AddIdLiteralOp(
  1631. + GetUintId(), SpvOpCompositeExtract, invocation_id, 0);
  1632. + Instruction* invocation_y = builder->AddIdLiteralOp(
  1633. + GetUintId(), SpvOpCompositeExtract, invocation_id, 1);
  1634. + Instruction* invocation_z = builder->AddIdLiteralOp(
  1635. + GetUintId(), SpvOpCompositeExtract, invocation_id, 2);
  1636. +
  1637. + auto num_workgroups_id = GenVarLoad(
  1638. + context()->GetBuiltinInputVarId(SpvBuiltInNumWorkgroups), builder);
  1639. + Instruction* num_workgroups_x = builder->AddIdLiteralOp(
  1640. + GetUintId(), SpvOpCompositeExtract, num_workgroups_id, 0);
  1641. + Instruction* num_workgroups_y = builder->AddIdLiteralOp(
  1642. + GetUintId(), SpvOpCompositeExtract, num_workgroups_id, 1);
  1643. +
  1644. + auto workgroup_size_id = GenVarLoad(
  1645. + context()->GetBuiltinInputVarId(SpvBuiltInWorkgroupSize), builder);
  1646. +
  1647. + Instruction* workgroup_size_x = builder->AddIdLiteralOp(
  1648. + GetUintId(), SpvOpCompositeExtract, workgroup_size_id, 0);
  1649. + Instruction* workgroup_size_y = builder->AddIdLiteralOp(
  1650. + GetUintId(), SpvOpCompositeExtract, workgroup_size_id, 1);
  1651. +
  1652. + Instruction* global_size_x = builder->AddBinaryOp(
  1653. + GetUintId(), SpvOpIMul, num_workgroups_x->result_id(),
  1654. + workgroup_size_x->result_id());
  1655. +
  1656. + Instruction* global_size_y = builder->AddBinaryOp(
  1657. + GetUintId(), SpvOpIMul, num_workgroups_y->result_id(),
  1658. + workgroup_size_y->result_id());
  1659. +
  1660. + auto xy_size =
  1661. + builder->AddBinaryOp(GetUintId(), SpvOpIMul, global_size_x->result_id(),
  1662. + global_size_y->result_id());
  1663. + auto z_term = builder->AddBinaryOp(
  1664. + GetUintId(), SpvOpIMul, invocation_z->result_id(), xy_size->result_id());
  1665. +
  1666. + auto y_term =
  1667. + builder->AddBinaryOp(GetUintId(), SpvOpIMul, invocation_y->result_id(),
  1668. + global_size_x->result_id());
  1669. +
  1670. + auto flat_thread_id = builder->AddBinaryOp(
  1671. + GetUintId(), SpvOpIAdd, z_term->result_id(), y_term->result_id());
  1672. + flat_thread_id =
  1673. + builder->AddBinaryOp(GetUintId(), SpvOpIAdd, flat_thread_id->result_id(),
  1674. + invocation_x->result_id());
  1675. + return flat_thread_id->result_id();
  1676. +}
  1677. +
  1678. +std::vector<uint32_t> AutoInstPass::GenThreadId(InstructionBuilder* builder,
  1679. + uint32_t stage_idx) {
  1680. + switch (stage_idx) {
  1681. + case SpvExecutionModelVertex: {
  1682. + // Load and store VertexId and InstanceId
  1683. + auto vertex_id = GenVarLoad(
  1684. + context()->GetBuiltinInputVarId(SpvBuiltInVertexIndex), builder);
  1685. + auto instance_id = GenVarLoad(
  1686. + context()->GetBuiltinInputVarId(SpvBuiltInInstanceIndex), builder);
  1687. + return {vertex_id, instance_id};
  1688. + }
  1689. + case SpvExecutionModelGLCompute: {
  1690. + // Load and store GlobalInvocationId.
  1691. +
  1692. + uint32_t load_id = GenVarLoad(
  1693. + context()->GetBuiltinInputVarId(SpvBuiltInGlobalInvocationId),
  1694. + builder);
  1695. + Instruction* x_inst = builder->AddIdLiteralOp(
  1696. + GetUintId(), SpvOpCompositeExtract, load_id, 0);
  1697. + Instruction* y_inst = builder->AddIdLiteralOp(
  1698. + GetUintId(), SpvOpCompositeExtract, load_id, 1);
  1699. + Instruction* z_inst = builder->AddIdLiteralOp(
  1700. + GetUintId(), SpvOpCompositeExtract, load_id, 2);
  1701. + return {x_inst->result_id(), y_inst->result_id(), z_inst->result_id()};
  1702. + }
  1703. + case SpvExecutionModelTessellationControl:
  1704. + case SpvExecutionModelGeometry: {
  1705. + // Load and store PrimitiveId and InvocationId.
  1706. + auto primitive_id = GenVarLoad(
  1707. + context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId), builder);
  1708. + auto instance_id = GenVarLoad(
  1709. + context()->GetBuiltinInputVarId(SpvBuiltInInvocationId), builder);
  1710. + return {primitive_id, instance_id};
  1711. + }
  1712. +
  1713. + case SpvExecutionModelTessellationEvaluation: {
  1714. + // Load and store PrimitiveId and TessCoord.uv
  1715. + auto primitive_id = GenVarLoad(
  1716. + context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId), builder);
  1717. + uint32_t load_id = GenVarLoad(
  1718. + context()->GetBuiltinInputVarId(SpvBuiltInTessCoord), builder);
  1719. + Instruction* uvec3_cast_inst =
  1720. + builder->AddUnaryOp(GetVec3UintId(), SpvOpBitcast, load_id);
  1721. + uint32_t uvec3_cast_id = uvec3_cast_inst->result_id();
  1722. + Instruction* u_inst = builder->AddIdLiteralOp(
  1723. + GetUintId(), SpvOpCompositeExtract, uvec3_cast_id, 0);
  1724. + Instruction* v_inst = builder->AddIdLiteralOp(
  1725. + GetUintId(), SpvOpCompositeExtract, uvec3_cast_id, 1);
  1726. + return {primitive_id, u_inst->result_id(), v_inst->result_id()};
  1727. + }
  1728. + case SpvExecutionModelFragment: {
  1729. + // Load FragCoord and convert to Uint
  1730. + Instruction* frag_coord_inst = builder->AddUnaryOp(
  1731. + GetVec4FloatId(), SpvOpLoad,
  1732. + context()->GetBuiltinInputVarId(SpvBuiltInFragCoord));
  1733. + Instruction* uint_frag_coord_inst = builder->AddUnaryOp(
  1734. + GetVec4UintId(), SpvOpBitcast, frag_coord_inst->result_id());
  1735. + Instruction* x_inst =
  1736. + builder->AddIdLiteralOp(GetUintId(), SpvOpCompositeExtract,
  1737. + uint_frag_coord_inst->result_id(), 0);
  1738. + Instruction* y_inst =
  1739. + builder->AddIdLiteralOp(GetUintId(), SpvOpCompositeExtract,
  1740. + uint_frag_coord_inst->result_id(), 1);
  1741. + Instruction* z_inst =
  1742. + builder->AddIdLiteralOp(GetUintId(), SpvOpCompositeExtract,
  1743. + uint_frag_coord_inst->result_id(), 2);
  1744. + return {x_inst->result_id(), y_inst->result_id(), z_inst->result_id()};
  1745. + }
  1746. + case SpvExecutionModelRayGenerationNV:
  1747. + case SpvExecutionModelIntersectionNV:
  1748. + case SpvExecutionModelAnyHitNV:
  1749. + case SpvExecutionModelClosestHitNV:
  1750. + case SpvExecutionModelMissNV:
  1751. + case SpvExecutionModelCallableNV: {
  1752. + // Load and store LaunchIdNV.
  1753. + auto launch_id = GenVarLoad(
  1754. + context()->GetBuiltinInputVarId(SpvBuiltInLaunchIdKHR), builder);
  1755. + Instruction* launch_x = builder->AddIdLiteralOp(
  1756. + GetUintId(), SpvOpCompositeExtract, launch_id, 0);
  1757. + Instruction* launch_y = builder->AddIdLiteralOp(
  1758. + GetUintId(), SpvOpCompositeExtract, launch_id, 1);
  1759. + Instruction* launch_z = builder->AddIdLiteralOp(
  1760. + GetUintId(), SpvOpCompositeExtract, launch_id, 2);
  1761. +
  1762. + auto launch_size_id = GenVarLoad(
  1763. + context()->GetBuiltinInputVarId(SpvBuiltInLaunchSizeKHR), builder);
  1764. + Instruction* launch_size_x = builder->AddIdLiteralOp(
  1765. + GetUintId(), SpvOpCompositeExtract, launch_size_id, 0);
  1766. + Instruction* launch_size_y = builder->AddIdLiteralOp(
  1767. + GetUintId(), SpvOpCompositeExtract, launch_size_id, 1);
  1768. +
  1769. + auto xy_size = builder->AddBinaryOp(GetUintId(), SpvOpIMul,
  1770. + launch_size_x->result_id(),
  1771. + launch_size_y->result_id());
  1772. + auto z_term = builder->AddBinaryOp(
  1773. + GetUintId(), SpvOpIMul, launch_z->result_id(), xy_size->result_id());
  1774. +
  1775. + auto y_term =
  1776. + builder->AddBinaryOp(GetUintId(), SpvOpIMul, launch_y->result_id(),
  1777. + launch_size_x->result_id());
  1778. +
  1779. + auto flat_thread_id = builder->AddBinaryOp(
  1780. + GetUintId(), SpvOpIAdd, z_term->result_id(), y_term->result_id());
  1781. + flat_thread_id = builder->AddBinaryOp(GetUintId(), SpvOpIAdd,
  1782. + flat_thread_id->result_id(),
  1783. + launch_x->result_id());
  1784. + return {flat_thread_id->result_id()};
  1785. + }
  1786. + default: {
  1787. + consumer()(SPV_MSG_ERROR, 0, {0, 0, 0},
  1788. + "Cannot create a thread id for requested shader stage!\n");
  1789. + return {};
  1790. + }
  1791. + }
  1792. +}
  1793. +
  1794. +uint32_t AutoInstPass::GenInstCallsiteId(Instruction* inst) {
  1795. + auto module_offset = uid2offset_[inst->unique_id()];
  1796. + if (shader_id_ >= (1 << 12) || module_offset >= (1 << 20)) {
  1797. + std::string message =
  1798. + "Shader id count or shader module size are too large!\n";
  1799. + consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
  1800. + return 0;
  1801. + }
  1802. +
  1803. + // Create an instrumentation callsite id that is unique across
  1804. + // the whole pipeline by including the shader id in the upper bits.
  1805. + return (shader_id_ << 20) | module_offset;
  1806. +}
  1807. +
  1808. +uint32_t AutoInstPass::GenSubgroupLocalInvocationId(
  1809. + InstructionBuilder* builder) {
  1810. + if (!get_feature_mgr()->HasCapability(SpvCapabilityGroupNonUniform)) {
  1811. + context()->AddCapability(SpvCapabilityGroupNonUniform);
  1812. + }
  1813. + return GenVarLoad(
  1814. + context()->GetBuiltinInputVarId(SpvBuiltInSubgroupLocalInvocationId),
  1815. + builder);
  1816. +}
  1817. +
  1818. +std::unique_ptr<BasicBlock> AutoInstPass::GenIfStatement(
  1819. + uint32_t condition_id, std::unique_ptr<BasicBlock> curr_block,
  1820. + std::function<std::unique_ptr<BasicBlock>(InstructionBuilder* builder,
  1821. + std::unique_ptr<BasicBlock>)>
  1822. + inside_if_callback) {
  1823. + auto output_func = curr_block->GetParent();
  1824. + InstructionBuilder builder(
  1825. + context(), &*curr_block,
  1826. + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
  1827. + uint32_t merge_blk_id = TakeNextId();
  1828. + uint32_t inside_if_blk_id = TakeNextId();
  1829. + std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
  1830. + std::unique_ptr<Instruction> inside_if_label(NewLabel(inside_if_blk_id));
  1831. + (void)builder.AddConditionalBranch(condition_id, inside_if_blk_id,
  1832. + merge_blk_id, merge_blk_id,
  1833. + SpvSelectionControlMaskNone);
  1834. +
  1835. + output_func->AddBasicBlock(std::move(curr_block));
  1836. + curr_block = MakeUnique<BasicBlock>(std::move(inside_if_label));
  1837. + curr_block->SetParent(&*output_func);
  1838. +
  1839. + builder.SetInsertPoint(&*curr_block);
  1840. +
  1841. + curr_block = inside_if_callback(&builder, std::move(curr_block));
  1842. +
  1843. + builder.SetInsertPoint(&*curr_block);
  1844. + if (!curr_block->IsReturn()) (void)builder.AddBranch(merge_blk_id);
  1845. +
  1846. + output_func->AddBasicBlock(std::move(curr_block));
  1847. + curr_block = MakeUnique<BasicBlock>(std::move(merge_label));
  1848. + curr_block->SetParent(&*output_func);
  1849. + return curr_block;
  1850. +}
  1851. +
  1852. +std::unique_ptr<BasicBlock> AutoInstPass::GenThreadUpdate(
  1853. + InstructionBuilder* builder, std::unique_ptr<BasicBlock> curr_block,
  1854. + std::vector<uint32_t> element_ids) {
  1855. + uint32_t buf_id = GetOutputBufferId();
  1856. + uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
  1857. + if (element_ids.size() > 65535) {
  1858. + std::string message =
  1859. + "ThreadUpdate does not support more than 65535 elements in a single "
  1860. + "entry!";
  1861. + consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
  1862. + }
  1863. + // Compute size of entry that will be written to the buffer.
  1864. + uint32_t entry_size =
  1865. + builder->GetUintConstantId((uint32_t)element_ids.size());
  1866. +
  1867. + // Update number of words written
  1868. + uint32_t mask_none_id = builder->GetUintConstantId(SpvMemoryAccessMaskNone);
  1869. + uint32_t scope_invok_id = builder->GetUintConstantId(SpvScopeInvocation);
  1870. + Instruction* buffer_consumed_ptr =
  1871. + builder->AddBinaryOp(buf_uint_ptr_id, SpvOpAccessChain, buf_id,
  1872. + builder->GetUintConstantId(kDebugOutputSizeOffset));
  1873. + Instruction* write_offset = builder->AddQuadOp(
  1874. + GetUintId(), SpvOpAtomicIAdd, buffer_consumed_ptr->result_id(),
  1875. + scope_invok_id, mask_none_id, entry_size);
  1876. +
  1877. + Instruction* updated_consumed_value = builder->AddBinaryOp(
  1878. + GetUintId(), SpvOpIAdd, write_offset->result_id(), entry_size);
  1879. + updated_consumed_value = builder->AddBinaryOp(
  1880. + GetUintId(), SpvOpIAdd, updated_consumed_value->result_id(),
  1881. + builder->GetUintConstantId(reserved_words_count_));
  1882. + Instruction* buffer_capacity =
  1883. + builder->AddIdLiteralOp(GetUintId(), SpvOpArrayLength,
  1884. + GetOutputBufferId(), kDebugOutputDataOffset);
  1885. +
  1886. + Instruction* out_of_bounds_cond = builder->AddBinaryOp(
  1887. + GetBoolId(), SpvOpUGreaterThanEqual, updated_consumed_value->result_id(),
  1888. + buffer_capacity->result_id());
  1889. +
  1890. + curr_block =
  1891. + GenIfStatement(out_of_bounds_cond->result_id(), std::move(curr_block),
  1892. + [this](InstructionBuilder* ir_builder,
  1893. + std::unique_ptr<BasicBlock> block) {
  1894. + ir_builder->AddNullaryOp(0, SpvOpReturn);
  1895. + return block;
  1896. + });
  1897. + builder->SetInsertPoint(&*curr_block);
  1898. +
  1899. + uint32_t i = reserved_words_count_;
  1900. + for (auto it : element_ids) {
  1901. + Instruction* element_offset =
  1902. + builder->AddBinaryOp(GetUintId(), SpvOpIAdd, write_offset->result_id(),
  1903. + builder->GetUintConstantId(i));
  1904. + Instruction* offset_ptr = builder->AddTernaryOp(
  1905. + buf_uint_ptr_id, SpvOpAccessChain, buf_id,
  1906. + builder->GetUintConstantId(kDebugOutputDataOffset),
  1907. + element_offset->result_id());
  1908. + (void)builder->AddStore(offset_ptr->result_id(), it);
  1909. + i++;
  1910. + }
  1911. +
  1912. + return curr_block;
  1913. +}
  1914. +
  1915. +uint32_t AutoInstPass::GetThreadUpdateFuncId(uint32_t num_parameters) {
  1916. + if (param_cnt2thread_update_func_id_[num_parameters] == 0) {
  1917. + // Create function
  1918. + param_cnt2thread_update_func_id_[num_parameters] = TakeNextId();
  1919. + analysis::TypeManager* type_mgr = context()->get_type_mgr();
  1920. + std::vector<const analysis::Type*> param_types;
  1921. + for (uint32_t c = 0; c < num_parameters; ++c)
  1922. + param_types.push_back(type_mgr->GetType(GetUintId()));
  1923. + analysis::Function func_ty(type_mgr->GetType(GetVoidId()), param_types);
  1924. + analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
  1925. + std::unique_ptr<Instruction> func_inst(
  1926. + new Instruction(get_module()->context(), SpvOpFunction, GetVoidId(),
  1927. + param_cnt2thread_update_func_id_[num_parameters],
  1928. + {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
  1929. + {SpvFunctionControlMaskNone}},
  1930. + {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
  1931. + {type_mgr->GetTypeInstruction(reg_func_ty)}}}));
  1932. + get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
  1933. + std::unique_ptr<Function> output_func =
  1934. + MakeUnique<Function>(std::move(func_inst));
  1935. + // Add parameters
  1936. + std::vector<uint32_t> param_vec;
  1937. + for (uint32_t c = 0; c < num_parameters; ++c) {
  1938. + uint32_t pid = TakeNextId();
  1939. + param_vec.push_back(pid);
  1940. + std::unique_ptr<Instruction> param_inst(
  1941. + new Instruction(get_module()->context(), SpvOpFunctionParameter,
  1942. + GetUintId(), pid, {}));
  1943. + get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst);
  1944. + output_func->AddParameter(std::move(param_inst));
  1945. + }
  1946. +
  1947. + // Create first block
  1948. + uint32_t test_blk_id = TakeNextId();
  1949. + std::unique_ptr<Instruction> test_label(NewLabel(test_blk_id));
  1950. + std::unique_ptr<BasicBlock> new_blk_ptr =
  1951. + MakeUnique<BasicBlock>(std::move(test_label));
  1952. + new_blk_ptr->SetParent(&*output_func);
  1953. + InstructionBuilder builder(
  1954. + context(), &*new_blk_ptr,
  1955. + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
  1956. +
  1957. + builder.SetInsertPoint(&*new_blk_ptr);
  1958. +
  1959. + new_blk_ptr = GenThreadUpdate(&builder, std::move(new_blk_ptr), param_vec);
  1960. +
  1961. + builder.SetInsertPoint(&*new_blk_ptr);
  1962. +
  1963. + // Close merge block and function and add function to module
  1964. + (void)builder.AddNullaryOp(0, SpvOpReturn);
  1965. + new_blk_ptr->SetParent(&*output_func);
  1966. + output_func->AddBasicBlock(std::move(new_blk_ptr));
  1967. + std::unique_ptr<Instruction> func_end_inst(
  1968. + new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {}));
  1969. + get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
  1970. + output_func->SetFunctionEnd(std::move(func_end_inst));
  1971. + context()->AddFunction(std::move(output_func));
  1972. + }
  1973. + return param_cnt2thread_update_func_id_[num_parameters];
  1974. +}
  1975. +
  1976. +void AutoInstPass::GenThreadUpdateCall(InstructionBuilder* builder,
  1977. + std::vector<uint32_t> param_ids) {
  1978. + uint32_t func_id = GetThreadUpdateFuncId((uint32_t)param_ids.size());
  1979. +
  1980. + std::vector<uint32_t> operands = {func_id};
  1981. + operands.insert(operands.end(), param_ids.begin(), param_ids.end());
  1982. +
  1983. + (void)builder->AddNaryOp(GetVoidId(), SpvOpFunctionCall, operands);
  1984. +}
  1985. +
  1986. +std::unique_ptr<BasicBlock> AutoInstPass::GenSubgroupUpdate(
  1987. + InstructionBuilder* builder, std::unique_ptr<BasicBlock> curr_block,
  1988. + std::vector<uint32_t> element_ids) {
  1989. + Instruction* subgroup_leader_cond =
  1990. + builder->AddUnaryOp(GetBoolId(), SpvOpGroupNonUniformElect,
  1991. + builder->GetUintConstantId(SpvScopeSubgroup));
  1992. + curr_block = GenIfStatement(
  1993. + subgroup_leader_cond->result_id(), std::move(curr_block),
  1994. + [this, element_ids](InstructionBuilder* ir_builder,
  1995. + std::unique_ptr<BasicBlock> block) {
  1996. + block = GenThreadUpdate(ir_builder, std::move(block), element_ids);
  1997. + ir_builder->SetInsertPoint(&*block);
  1998. + return block;
  1999. + });
  2000. + builder->SetInsertPoint(&*curr_block);
  2001. +
  2002. + return curr_block;
  2003. +}
  2004. +
  2005. +uint32_t AutoInstPass::GetSubgroupUpdateFuncId(uint32_t num_parameters) {
  2006. + if (param_cnt2subgroup_update_func_id_[num_parameters] == 0) {
  2007. + // Create function
  2008. + param_cnt2subgroup_update_func_id_[num_parameters] = TakeNextId();
  2009. + analysis::TypeManager* type_mgr = context()->get_type_mgr();
  2010. + std::vector<const analysis::Type*> param_types;
  2011. + for (uint32_t c = 0; c < num_parameters; ++c)
  2012. + param_types.push_back(type_mgr->GetType(GetUintId()));
  2013. + analysis::Function func_ty(type_mgr->GetType(GetVoidId()), param_types);
  2014. + analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
  2015. + std::unique_ptr<Instruction> func_inst(
  2016. + new Instruction(get_module()->context(), SpvOpFunction, GetVoidId(),
  2017. + param_cnt2subgroup_update_func_id_[num_parameters],
  2018. + {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
  2019. + {SpvFunctionControlMaskNone}},
  2020. + {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
  2021. + {type_mgr->GetTypeInstruction(reg_func_ty)}}}));
  2022. + get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
  2023. + std::unique_ptr<Function> output_func =
  2024. + MakeUnique<Function>(std::move(func_inst));
  2025. + // Add parameters
  2026. + std::vector<uint32_t> param_vec;
  2027. + for (uint32_t c = 0; c < num_parameters; ++c) {
  2028. + uint32_t pid = TakeNextId();
  2029. + param_vec.push_back(pid);
  2030. + std::unique_ptr<Instruction> param_inst(
  2031. + new Instruction(get_module()->context(), SpvOpFunctionParameter,
  2032. + GetUintId(), pid, {}));
  2033. + get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst);
  2034. + output_func->AddParameter(std::move(param_inst));
  2035. + }
  2036. +
  2037. + // Create first block
  2038. + uint32_t test_blk_id = TakeNextId();
  2039. + std::unique_ptr<Instruction> test_label(NewLabel(test_blk_id));
  2040. + std::unique_ptr<BasicBlock> new_blk_ptr =
  2041. + MakeUnique<BasicBlock>(std::move(test_label));
  2042. + new_blk_ptr->SetParent(&*output_func);
  2043. + InstructionBuilder builder(
  2044. + context(), &*new_blk_ptr,
  2045. + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
  2046. +
  2047. + builder.SetInsertPoint(&*new_blk_ptr);
  2048. +
  2049. + new_blk_ptr = GenSubgroupUpdate(&builder, std::move(new_blk_ptr), param_vec);
  2050. +
  2051. + builder.SetInsertPoint(&*new_blk_ptr);
  2052. +
  2053. + // Close merge block and function and add function to module
  2054. + (void)builder.AddNullaryOp(0, SpvOpReturn);
  2055. + new_blk_ptr->SetParent(&*output_func);
  2056. + output_func->AddBasicBlock(std::move(new_blk_ptr));
  2057. + std::unique_ptr<Instruction> func_end_inst(
  2058. + new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {}));
  2059. + get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
  2060. + output_func->SetFunctionEnd(std::move(func_end_inst));
  2061. + context()->AddFunction(std::move(output_func));
  2062. + }
  2063. + return param_cnt2subgroup_update_func_id_[num_parameters];
  2064. +}
  2065. +
  2066. +void AutoInstPass::GenSubgroupUpdateCall(InstructionBuilder* builder,
  2067. + std::vector<uint32_t> param_ids) {
  2068. + uint32_t func_id = GetSubgroupUpdateFuncId((uint32_t)param_ids.size());
  2069. +
  2070. + std::vector<uint32_t> operands = {func_id};
  2071. + operands.insert(operands.end(), param_ids.begin(), param_ids.end());
  2072. +
  2073. + (void)builder->AddNaryOp(GetVoidId(), SpvOpFunctionCall, operands);
  2074. +}
  2075. +
  2076. +void AutoInstPass::GenUniqueSubgroupIdFuncCall(InstructionBuilder* builder,
  2077. + uint32_t inst_id,
  2078. + uint32_t stage_idx) {
  2079. + if (stage_idx != SpvExecutionModelRayGenerationNV &&
  2080. + stage_idx != SpvExecutionModelGLCompute) {
  2081. + std::string message =
  2082. + "Unique function id call cannot be generated unless the shader stage "
  2083. + "is compute or RayGeneration\n";
  2084. + consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
  2085. + return;
  2086. + }
  2087. +
  2088. + uint32_t output_func_id = GetUniqueSubgroupIdFunctionId(stage_idx);
  2089. + (void)builder->AddNaryOp(GetVoidId(), SpvOpFunctionCall,
  2090. + {output_func_id, inst_id});
  2091. +}
  2092. +
  2093. +uint32_t AutoInstPass::GetUniqueSubgroupIdFunctionId(uint32_t stage_idx) {
  2094. + if (unique_subgroup_id_function_id_ == 0) {
  2095. + // Create function
  2096. + unique_subgroup_id_function_id_ = TakeNextId();
  2097. + analysis::TypeManager* type_mgr = context()->get_type_mgr();
  2098. + std::vector<const analysis::Type*> param_types;
  2099. +
  2100. + for (uint32_t c = 0; c < kUniqueSubgroupIdParamCnt; ++c)
  2101. + param_types.push_back(type_mgr->GetType(GetUintId()));
  2102. +
  2103. + analysis::Function func_ty(type_mgr->GetType(GetVoidId()), param_types);
  2104. + analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
  2105. + std::unique_ptr<Instruction> func_inst(
  2106. + new Instruction(get_module()->context(), SpvOpFunction, GetVoidId(),
  2107. + unique_subgroup_id_function_id_,
  2108. + {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
  2109. + {SpvFunctionControlMaskNone}},
  2110. + {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
  2111. + {type_mgr->GetTypeInstruction(reg_func_ty)}}}));
  2112. + get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
  2113. + std::unique_ptr<Function> output_func =
  2114. + MakeUnique<Function>(std::move(func_inst));
  2115. +
  2116. + // Add parameters
  2117. + std::vector<uint32_t> param_vec;
  2118. + for (uint32_t c = 0; c < kUniqueSubgroupIdParamCnt; ++c) {
  2119. + uint32_t pid = TakeNextId();
  2120. + param_vec.push_back(pid);
  2121. + std::unique_ptr<Instruction> param_inst(
  2122. + new Instruction(get_module()->context(), SpvOpFunctionParameter,
  2123. + GetUintId(), pid, {}));
  2124. + get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst);
  2125. + output_func->AddParameter(std::move(param_inst));
  2126. + }
  2127. +
  2128. + // Create first block
  2129. + uint32_t test_blk_id = TakeNextId();
  2130. + std::unique_ptr<Instruction> test_label(NewLabel(test_blk_id));
  2131. + std::unique_ptr<BasicBlock> new_blk_ptr =
  2132. + MakeUnique<BasicBlock>(std::move(test_label));
  2133. + new_blk_ptr->SetParent(&*output_func);
  2134. + InstructionBuilder builder(
  2135. + context(), &*new_blk_ptr,
  2136. + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
  2137. +
  2138. + // Create variable to hold subgroup id computed by leader
  2139. +
  2140. + uint32_t varTyPtrId = context()->get_type_mgr()->FindPointerToType(
  2141. + GetUintId(), SpvStorageClassFunction);
  2142. + assert(varTyPtrId && "Cannot create uint ptr type.");
  2143. + auto zero = builder.GetUintConstantId(0);
  2144. +
  2145. + auto new_var_op =
  2146. + builder.AddUnaryOp(varTyPtrId, SpvOpVariable, SpvStorageClassFunction);
  2147. + auto unique_subgroup_ptr_id = new_var_op->result_id();
  2148. + builder.AddStore(new_var_op->result_id(), zero);
  2149. +
  2150. + Instruction* subgroup_leader_cond =
  2151. + builder.AddUnaryOp(GetBoolId(), SpvOpGroupNonUniformElect,
  2152. + builder.GetUintConstantId(SpvScopeSubgroup));
  2153. +
  2154. + new_blk_ptr = GenIfStatement(
  2155. + subgroup_leader_cond->result_id(), std::move(new_blk_ptr),
  2156. + [this, unique_subgroup_ptr_id](InstructionBuilder* ir_builder,
  2157. + std::unique_ptr<BasicBlock> block) {
  2158. + uint32_t mask_none_id =
  2159. + ir_builder->GetUintConstantId(SpvMemoryAccessMaskNone);
  2160. + uint32_t scope_invok_id =
  2161. + ir_builder->GetUintConstantId(SpvScopeInvocation);
  2162. + Instruction* unique_id_ptr = ir_builder->AddTernaryOp(
  2163. + GetOutputBufferPtrId(), SpvOpAccessChain, GetOutputBufferId(),
  2164. + ir_builder->GetUintConstantId(kDebugOutputDataOffset),
  2165. + ir_builder->GetUintConstantId(0));
  2166. + Instruction* unique_id = ir_builder->AddQuadOp(
  2167. + GetUintId(), SpvOpAtomicIAdd, unique_id_ptr->result_id(),
  2168. + scope_invok_id, mask_none_id, ir_builder->GetUintConstantId(1));
  2169. +
  2170. + ir_builder->AddStore(unique_subgroup_ptr_id, unique_id->result_id());
  2171. + return block;
  2172. + });
  2173. + builder.SetInsertPoint(&*new_blk_ptr);
  2174. + Instruction* broadcasted_id =
  2175. + builder.AddBinaryOp(GetUintId(), SpvOpGroupNonUniformBroadcastFirst,
  2176. + builder.GetUintConstantId(SpvScopeSubgroup),
  2177. + GenVarLoad(unique_subgroup_ptr_id, &builder));
  2178. +
  2179. + uint32_t intra_subgroup_id = GenSubgroupLocalInvocationId(&builder);
  2180. + // Shift the thread id in the subgroup in to the top log2(SUBGROUP_SIZE)=5 bits
  2181. + Instruction* shifted_subgroup_id = builder.AddBinaryOp(
  2182. + GetUintId(), SpvOpShiftLeftLogical, intra_subgroup_id,
  2183. + builder.GetUintConstantId(27 /*= 32 - log2(32) */));
  2184. + // Combine the unique subgroup id and intra subgroup id
  2185. + Instruction* joined_subgroup_ids = builder.AddBinaryOp(
  2186. + GetUintId(), SpvOpBitwiseOr, shifted_subgroup_id->result_id(),
  2187. + broadcasted_id->result_id());
  2188. +
  2189. + // Generate thread id which will be used to created thread_id -> subgroup_id
  2190. + // mapping
  2191. + auto flat_thread_id = (stage_idx == SpvExecutionModelRayGenerationNV)
  2192. + ? GenFlatRtThreadId(&builder, stage_idx)
  2193. + : GenFlatComputeThreadId(&builder, stage_idx);
  2194. +
  2195. + auto inst_id = param_vec[kUniqueSubgroupIdParamInstIdIdx];
  2196. +
  2197. + new_blk_ptr = GenThreadUpdate(
  2198. + &builder, std::move(new_blk_ptr),
  2199. + {inst_id, flat_thread_id, joined_subgroup_ids->result_id()});
  2200. +
  2201. + // Close merge block and function and add function to module
  2202. + (void)builder.AddNullaryOp(0, SpvOpReturn);
  2203. + new_blk_ptr->SetParent(&*output_func);
  2204. + output_func->AddBasicBlock(std::move(new_blk_ptr));
  2205. + std::unique_ptr<Instruction> func_end_inst(
  2206. + new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {}));
  2207. + get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
  2208. + output_func->SetFunctionEnd(std::move(func_end_inst));
  2209. + context()->AddFunction(std::move(output_func));
  2210. + }
  2211. + return unique_subgroup_id_function_id_;
  2212. +}
  2213. +
  2214. +void AutoInstPass::GenInstrumentedEntryPoints() {
  2215. + for (auto entry_point_inst : get_module()->entry_points()) {
  2216. + auto stage_idx =
  2217. + entry_point_inst.GetSingleWordInOperand(kEntryPointExecutionModelInIdx);
  2218. + auto entry_point_func_id =
  2219. + entry_point_inst.GetSingleWordInOperand(kEntryPointFunctionIdInIdx);
  2220. + Instruction* entry_point_func =
  2221. + get_def_use_mgr()->GetDef(entry_point_func_id);
  2222. +
  2223. + auto dummy_func_id = TakeNextId();
  2224. + analysis::TypeManager* type_mgr = context()->get_type_mgr();
  2225. + analysis::Function func_ty(type_mgr->GetType(GetVoidId()), {});
  2226. + analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty);
  2227. + auto expected_ty_id = type_mgr->GetId(reg_func_ty);
  2228. +
  2229. + auto entry_point_func_ty_id =
  2230. + entry_point_func->GetSingleWordOperand(kFunctionTypeIdx);
  2231. +
  2232. + if (expected_ty_id != entry_point_func_ty_id) {
  2233. + std::string message =
  2234. + "Could not generate dummy entrypoint due to an unexpected EntryPoint "
  2235. + "function signature.";
  2236. + consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str());
  2237. + return;
  2238. + }
  2239. +
  2240. + // Create dummy function to original entry point
  2241. + std::unique_ptr<Instruction> func_inst(new Instruction(
  2242. + get_module()->context(), SpvOpFunction, GetVoidId(), dummy_func_id,
  2243. + {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
  2244. + {SpvFunctionControlMaskNone}},
  2245. + {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
  2246. + {type_mgr->GetTypeInstruction(reg_func_ty)}}}));
  2247. + get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst);
  2248. +
  2249. + std::unique_ptr<Function> output_func =
  2250. + MakeUnique<Function>(std::move(func_inst));
  2251. +
  2252. + // Create first block
  2253. + uint32_t test_blk_id = TakeNextId();
  2254. + std::unique_ptr<Instruction> test_label(NewLabel(test_blk_id));
  2255. + std::unique_ptr<BasicBlock> new_blk_ptr =
  2256. + MakeUnique<BasicBlock>(std::move(test_label));
  2257. + new_blk_ptr->SetParent(&*output_func);
  2258. + InstructionBuilder builder(
  2259. + context(), &*new_blk_ptr,
  2260. + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
  2261. +
  2262. + builder.SetInsertPoint(&*new_blk_ptr);
  2263. +
  2264. + // Invoke instrumentation hook
  2265. + auto is_instrumented = PreEntryPointInstrument(&builder, stage_idx);
  2266. +
  2267. + // Call original entrypoint
  2268. + (void)builder.AddNaryOp(GetVoidId(), SpvOpFunctionCall,
  2269. + {entry_point_func_id});
  2270. +
  2271. + // Invoke instrumentation hook
  2272. + is_instrumented |= PostEntryPointInstrument(&builder, stage_idx);
  2273. +
  2274. + // Close merge block and function and add function to module
  2275. + (void)builder.AddNullaryOp(0, SpvOpReturn);
  2276. + new_blk_ptr->SetParent(&*output_func);
  2277. + output_func->AddBasicBlock(std::move(new_blk_ptr));
  2278. + std::unique_ptr<Instruction> func_end_inst(
  2279. + new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {}));
  2280. + get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst);
  2281. + output_func->SetFunctionEnd(std::move(func_end_inst));
  2282. +
  2283. + if (is_instrumented) {
  2284. + // If the instrumentation hooks insert code then
  2285. + // add dummy entrypoint and replace the original
  2286. + // EntryPoint with dummy entrypoint.
  2287. + context()->AddFunction(std::move(output_func));
  2288. + context()->ReplaceAllUsesWithPredicate(
  2289. + entry_point_func_id, dummy_func_id, [](Instruction* inst) {
  2290. + return inst->opcode() != SpvOpFunctionCall;
  2291. + });
  2292. + }
  2293. + }
  2294. +}
  2295. +
  2296. +Pass::Status AutoInstPass::ProcessImpl() {
  2297. + for (auto fii = get_module()->begin(); fii != get_module()->end(); ++fii) {
  2298. + auto bb = fii->begin();
  2299. + bb->IsLoopHeader();
  2300. + }
  2301. +
  2302. + InstProcessFunction pfn =
  2303. + [this](BasicBlock::iterator ref_inst_itr,
  2304. + UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
  2305. + std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
  2306. + (void)new_blocks;
  2307. + GenInstProgrammableCode(ref_inst_itr, ref_block_itr, stage_idx);
  2308. + };
  2309. + InstProcessEntryPointCallTree(pfn);
  2310. +
  2311. + // Add new entrypoint after other instrumentation to avoid it also being
  2312. + // instrumented.
  2313. + GenInstrumentedEntryPoints();
  2314. +
  2315. + context()->BuildInvalidAnalyses(IRContext::kAnalysisDefUse |
  2316. + IRContext::kAnalysisInstrToBlockMapping);
  2317. + return has_added_instrumentation_ ? Status::SuccessWithChange
  2318. + : Status::SuccessWithoutChange;
  2319. +}
  2320. +
  2321. +Pass::Status AutoInstPass::Process() {
  2322. + // Initialize base class
  2323. + InitializeInstrument();
  2324. +
  2325. + // init auto instrumentation metadata
  2326. + instrumented_bb_ids.clear();
  2327. + instrumented_inst_ids.clear();
  2328. + has_added_instrumentation_ = false;
  2329. +
  2330. + // initialize inheriting class
  2331. + InitializeInstrumentation();
  2332. +
  2333. + auto res = ProcessImpl();
  2334. +
  2335. + // finalize inheriting class
  2336. + FinalizeInstrumentation();
  2337. +
  2338. + // insert instrumentation
  2339. + return res;
  2340. +}
  2341. +
  2342. +} // namespace opt
  2343. +} // namespace spvtools
  2344. diff --git a/source/opt/auto_inst_pass.h b/source/opt/auto_inst_pass.h
  2345. new file mode 100644
  2346. index 00000000..ed91a44d
  2347. --- /dev/null
  2348. +++ b/source/opt/auto_inst_pass.h
  2349. @@ -0,0 +1,322 @@
  2350. +// Copyright (c) 2021 The Khronos Group Inc.
  2351. +
  2352. +// Licensed under the Apache License, Version 2.0 (the "License");
  2353. +// you may not use this file except in compliance with the License.
  2354. +// You may obtain a copy of the License at
  2355. +//
  2356. +// http://www.apache.org/licenses/LICENSE-2.0
  2357. +//
  2358. +// Unless required by applicable law or agreed to in writing, software
  2359. +// distributed under the License is distributed on an "AS IS" BASIS,
  2360. +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  2361. +// See the License for the specific language governing permissions and
  2362. +// limitations under the License.
  2363. +
  2364. +#ifndef LIBSPIRV_OPT_AUTO_INST_PASS_H_
  2365. +#define LIBSPIRV_OPT_AUTO_INST_PASS_H_
  2366. +
  2367. +#include <functional>
  2368. +
  2369. +#include "instrument_pass.h"
  2370. +
  2371. +namespace spvtools {
  2372. +namespace opt {
  2373. +
  2374. +class AutoInstPass : public InstrumentPass {
  2375. + public:
  2376. + AutoInstPass(uint32_t desc_set, uint32_t shader_id,
  2377. + uint32_t reserved_words_count)
  2378. + : InstrumentPass(desc_set, shader_id, kInstValidationIdAuto),
  2379. + reserved_words_count_(reserved_words_count) {}
  2380. +
  2381. + ~AutoInstPass() override = default;
  2382. +
  2383. + // See optimizer.hpp for pass user documentation.
  2384. + Status Process() override;
  2385. +
  2386. + const char* name() const override { return "auto-inst-pass"; }
  2387. +
  2388. + private:
  2389. + // Track whether any instrumentation occurred
  2390. + bool has_added_instrumentation_ = false;
  2391. +
  2392. + // Track the function ids created to support thread/subgroup update
  2393. + // accepting different numbers of parameters
  2394. + std::unordered_map<uint32_t, uint32_t> param_cnt2thread_update_func_id_;
  2395. + std::unordered_map<uint32_t, uint32_t> param_cnt2subgroup_update_func_id_;
  2396. +
  2397. + // Track the function id for creating unique subgroup ids.
  2398. + uint32_t unique_subgroup_id_function_id_ = 0;
  2399. +
  2400. + // Instructions whose semantics are destroyed by having instrumentation
  2401. + // inserted directly before them.
  2402. + const std::set<uint32_t> uninstrumentable_pre_ops = {SpvOpPhi,
  2403. + SpvOpUnreachable};
  2404. +
  2405. + // Instructions whose semantics are destroyed by having instrumentation
  2406. + // inserted directly after them.
  2407. + const std::set<uint32_t> uninstrumentable_post_ops = {
  2408. + SpvOpSelectionMerge, // Both merge instructions must precede a branch
  2409. + SpvOpLoopMerge,
  2410. + SpvOpBranch, // Branch instructions end a basic block which would put the
  2411. + // instrumentation in limbo
  2412. + SpvOpBranchConditional,
  2413. + SpvOpSwitch,
  2414. + SpvOpReturn, // Instrumenting after returns/unreachable would never
  2415. + // execute
  2416. + SpvOpReturnValue,
  2417. + SpvOpUnreachable,
  2418. + };
  2419. +
  2420. + // Add a function to the module that appends
  2421. + // an entry to the buffer containing |num_params| words
  2422. + // for every active thread invoking the function.
  2423. + uint32_t GetThreadUpdateFuncId(uint32_t num_params);
  2424. +
  2425. + // Generate a sequence of instructions in |builder| in function |function|
  2426. + // that write the value corresponding to the ids in |element_ids|. The
  2427. + // output buffer will be written to once by each thread.
  2428. + // The sequence of instructions will be inserted starting with |curr_block|.
  2429. + // |curr_block| will be consumed by this function call due to control flow.
  2430. + //
  2431. + // |element_ids| is a vector of uint32_t which contains the
  2432. + // id's of values that will be written to the output buffer.
  2433. + std::unique_ptr<BasicBlock> GenThreadUpdate(
  2434. + InstructionBuilder* builder, std::unique_ptr<BasicBlock> curr_block,
  2435. + std::vector<uint32_t> param_ids);
  2436. +
  2437. + // Add a function to the module that appends
  2438. + // an entry to the buffer containing |num_params| words
  2439. + // for every subgroup invoking the function.
  2440. + uint32_t GetSubgroupUpdateFuncId(uint32_t num_params);
  2441. +
  2442. + // Create function containing functionality for generating a
  2443. + // unique subgroup (or subgroup) id. This function should only
  2444. + // be called at the beginning of a shader in uniform control flow.
  2445. + //
  2446. + // The buffer entry created will be of the following form:
  2447. + // word 0: <inst id>
  2448. + // word 1: <flat thread id>
  2449. + // word 2: <unique subgroup id | (intra subgroup id << 27)>
  2450. + //
  2451. + // This information can be used by the analysis to create a mapping
  2452. + // from flattened thread id (available anywhere in the rt pipeline)
  2453. + // to subgroup id which allows for inter-shader subgroup tracking.
  2454. + // Furthermore, the intra-subgroup-id allows for attribution of subgroup-level
  2455. + // instrumentation to individual threads (i.e. for heatmap visualizations).
  2456. + uint32_t GetUniqueSubgroupIdFunctionId(uint32_t stage_idx);
  2457. +
  2458. + // Generate a sequence of instructions in |builder| in function |function|
  2459. + // that write the value corresponding to the ids in |element_ids|. The
  2460. + // output buffer will only be written to by the subgroup leader.
  2461. + // The sequence of instructions will be inserted starting with |curr_block|.
  2462. + // |curr_block| will be consumed by this function call due to control flow.
  2463. + //
  2464. + // |element_ids| is a vector of uint32_t which contains the
  2465. + // id's of values that will be written to the output buffer.
  2466. + std::unique_ptr<BasicBlock> GenSubgroupUpdate(
  2467. + InstructionBuilder* builder, std::unique_ptr<BasicBlock> curr_block,
  2468. + std::vector<uint32_t> param_ids);
  2469. +
  2470. + protected:
  2471. + // In this class it can be very confusing differentiating
  2472. + // between instruction SSA ids and ids for instrumentation.
  2473. + // This type is designed to make it explicit which type of id
  2474. + // it is when mixing and matching.
  2475. + using AutoInstId = uint32_t;
  2476. +
  2477. + // For some analyses keeping track of which threads belong
  2478. + // to which subgroups and also how many subgroups executed the shader stage
  2479. + // is interesting. Since saving 1 word is not important,
  2480. + // the default for this value is set to 1 so CreateUniquesubgroupIdCall
  2481. + // works out of the box.
  2482. + static const int kDefaultReservedWordsCnt = 1;
  2483. +
  2484. + // The number of lowers words in the instrumentation buffer that are reserved
  2485. + // for fixed functions (i.e. not dynamically appended runtime entries)
  2486. + // NOTE: this does not include the buffer size which is always tracked
  2487. + const uint32_t reserved_words_count_;
  2488. +
  2489. + // Track which basic blocks and instructions the pass has
  2490. + // given an opportunity to instrument to prevent reinstrumenting.
  2491. + std::set<uint32_t> instrumented_bb_ids;
  2492. + std::set<uint32_t> instrumented_inst_ids;
  2493. +
  2494. + // Apply GenDebugPrintfCode to every instruction in module.
  2495. + Pass::Status ProcessImpl();
  2496. +
  2497. + // Allows inheriting classes to initialize their knowledge
  2498. + // of module before beginning instrumentation
  2499. + virtual void InitializeInstrumentation() = 0;
  2500. +
  2501. + // Allows inheriting classes to finalize before
  2502. + // the pass finishes executing.
  2503. + virtual void FinalizeInstrumentation() = 0;
  2504. +
  2505. + // Any instructions added via |builder| will appear before |inst|.
  2506. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  2507. + // This function is expected to return true if it added instructions to
  2508. + // builder, otherwise false.
  2509. + virtual bool PreInstructionInstrument(Instruction* inst,
  2510. + InstructionBuilder* builder,
  2511. + uint32_t stage_idx) = 0;
  2512. +
  2513. + // Any instructions added via |builder| will appear after |inst|.
  2514. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  2515. + // This function is expected to return true if it added instructions to
  2516. + // builder, otherwise false.
  2517. + virtual bool PostInstructionInstrument(Instruction* inst,
  2518. + InstructionBuilder* builder,
  2519. + uint32_t stage_idx) = 0;
  2520. +
  2521. + // Any instructions added via |builder| will appear before the content of
  2522. + // |bb|. |stage_idx| contains the SpvExecutionModel that builder is operating
  2523. + // in. This function is expected to return true if it added instructions to
  2524. + // builder, otherwise false.
  2525. + virtual bool BasicBlockInstrument(BasicBlock* bb, InstructionBuilder* builder,
  2526. + uint32_t stage_idx) = 0;
  2527. +
  2528. + // Any instructions added via |builder| will execute before the
  2529. + // entrypoint function of the shader.
  2530. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  2531. + // This function is expected to return true if it added instructions to
  2532. + // builder, otherwise false.
  2533. + virtual bool PreEntryPointInstrument(InstructionBuilder* builder,
  2534. + uint32_t stage_idx) = 0;
  2535. +
  2536. + // Any instructions added via |builder| will execute before the
  2537. + // entrypoint function of the shader.
  2538. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  2539. + // This function is expected to return true if it added instructions to
  2540. + // builder, otherwise false.
  2541. + virtual bool PostEntryPointInstrument(InstructionBuilder* builder,
  2542. + uint32_t stage_idx) = 0;
  2543. +
  2544. + // If |ref_inst_itr| is selected as an instrumentation location,
  2545. + // return in |new_blocks| the result of adding instrumentation.
  2546. + // The instructions write a record to the output buffer stream
  2547. + // The block at |ref_block_itr| can just be replaced with the
  2548. + // block in |new_blocks|. Besides the buffer writes, this
  2549. + // block will comprise all instructions preceding and following
  2550. + // |ref_inst_itr|.
  2551. + //
  2552. + // This function is designed to be passed to
  2553. + // InstrumentPass::InstProcessEntryPointCallTree(), which applies the
  2554. + // function to each instruction in a module and replaces the instruction
  2555. + // if warranted.
  2556. + //
  2557. + void GenInstProgrammableCode(BasicBlock::iterator ref_inst_itr,
  2558. + UptrVectorIterator<BasicBlock> ref_block_itr,
  2559. + uint32_t stage_idx);
  2560. +
  2561. + // Generate a sequence of instructions in |builder| which
  2562. + // materialize the lower and upper 32 bits of from
  2563. + // OpReadClock.
  2564. + //
  2565. + // Returns std::pair<lower 32 bits,upper 32 bits>
  2566. + std::pair<uint32_t, uint32_t> GenReadClockIds(InstructionBuilder* builder);
  2567. +
  2568. + // Generate a sequence of instructions in |builder| which
  2569. + // materialize a 32-bit thread mask where each bit
  2570. + // is true if the thread is active and false otherwise.
  2571. + // The uint32_t value returned corresponds to the thread_mask.
  2572. + uint32_t GenSubgroupBallotId(InstructionBuilder* builder, uint32_t pred_id);
  2573. +
  2574. + // Generate a sequence of instructions in |builder| which
  2575. + // materialize the value of SpvBuiltinSubgroupLocalInvocationId.
  2576. + uint32_t GenSubgroupLocalInvocationId(InstructionBuilder* builder);
  2577. +
  2578. + // Returns an id corresponding to a uint created in |builder|
  2579. + // which contains a flattened thread id calculated from the
  2580. + // unique work id of the shader stage.
  2581. + //
  2582. + // This is primarily useful for tracking threads' execution between
  2583. + // shaders in the ray tracing pipeline.
  2584. + uint32_t GenFlatRtThreadId(InstructionBuilder* builder, uint32_t stage_idx);
  2585. +
  2586. + // Returns an id corresponding to a uint created in |builder|
  2587. + // which contains a flattened thread id calculated from the
  2588. + // GlobalSize and GlobalLaunchID
  2589. + //
  2590. + // This is primarily useful for tracking threads' execution between
  2591. + // different compute pipelines.
  2592. + uint32_t GenFlatComputeThreadId(InstructionBuilder* builder,
  2593. + uint32_t stage_idx);
  2594. +
  2595. + // Returns a vector of ids corresponding to a uint created in |builder|
  2596. + // which contains a unique work id of the shader stage.
  2597. + //
  2598. + // This is primarily useful for tracking threads' execution behaviour over
  2599. + // time.
  2600. + std::vector<uint32_t> GenThreadId(InstructionBuilder* builder,
  2601. + uint32_t stage_idx);
  2602. +
  2603. + // Returns an identifier
  2604. + // for an instrumentation callsite which is unique across the
  2605. + // whole ray-tracing pipeline.
  2606. + uint32_t GenInstCallsiteId(Instruction* inst);
  2607. +
  2608. + // Generate a sequence of instructions in function |function| that
  2609. + // create an if statement where the body is executed iff the value
  2610. + // corresponding to |condition_id| evaluates to true at runtime.
  2611. + // |old_block| will be closed by an OpBranchConditional
  2612. + //
  2613. + // The callback |inside_if_callback| will be invoked in the body
  2614. + // of the if statement. The |inside_if_callback| accepts an
  2615. + // InstructionBuilder |builder| at the beginning of the if body.
  2616. + // As well as a unique_ptr |curr_block| to the BasicBlock of the
  2617. + // if body. The |inside_if_callback| may add more basic blocks
  2618. + // but must return a unique_ptr to the basic block that ends the if
  2619. + // body.
  2620. + std::unique_ptr<BasicBlock> GenIfStatement(
  2621. + uint32_t condition_id, std::unique_ptr<BasicBlock> old_block,
  2622. + std::function<std::unique_ptr<BasicBlock>(
  2623. + InstructionBuilder* builder, std::unique_ptr<BasicBlock> curr_block)>
  2624. + inside_if_callback);
  2625. +
  2626. + // Generates a seuqence of instructions in |builder| which invoke the
  2627. + // ThreadUpdate function which writes the values that are identifier in
  2628. + // |param_ids| to the StorageBuffer for each thread that invokes the call.
  2629. + void GenThreadUpdateCall(InstructionBuilder* builder,
  2630. + std::vector<uint32_t> param_ids);
  2631. +
  2632. + // Generates a seuqence of instructions in |builder| which invoke the
  2633. + // subgroupUpdate function which writes the values that are identifier in
  2634. + // |param_ids| to the StorageBuffer for each subgroup that invokes the call.
  2635. + void GenSubgroupUpdateCall(InstructionBuilder* builder,
  2636. + std::vector<uint32_t> param_ids);
  2637. +
  2638. + // Generate a function call in a block which will be appended to |new_blocks|
  2639. + // This function should only bGe called at the beginning of a shader in
  2640. + // uniform control flow. This ensures that every thread in the subgroup
  2641. + // receives the value computed by the leader.
  2642. + //
  2643. + // |inst_offset_id| is used to report instrumentation metadata to validation
  2644. + // layer. |stage_idx| is the current SpvExecutionMode.
  2645. + void GenUniqueSubgroupIdFuncCall(InstructionBuilder* builder,
  2646. + uint32_t inst_offset_id, uint32_t stage_idx);
  2647. +
  2648. + // Pass the current context in terms of:
  2649. + // 1) instruction in |ref_inst_itr|
  2650. + // 2) BB in |ref_block_itr|
  2651. + // 3) shader stage in |stage_idx|
  2652. + //
  2653. + // This allows the instrumentation hooks to decide what
  2654. + // instrumentation to add to |builder|.
  2655. + // If instrumentation is added then this function returns true
  2656. + // otherwise false.
  2657. + //
  2658. + bool HandleInstrumentHooks(BasicBlock::iterator ref_inst_itr,
  2659. + UptrVectorIterator<BasicBlock> ref_block_itr,
  2660. + uint32_t stage_idx, InstructionBuilder* builder);
  2661. +
  2662. + // Generate dummy EntryPoints which invoke the PreEntryPointInstrument
  2663. + // and PostEntryPointInstrument hooks around a call to the original entrypoint
  2664. + // function.
  2665. + void GenInstrumentedEntryPoints();
  2666. +};
  2667. +
  2668. +} // namespace opt
  2669. +} // namespace spvtools
  2670. +
  2671. +#endif // LIBSPIRV_OPT_INST_PROGRAMMABLE_PASS_H_
  2672. diff --git a/source/opt/auto_inst_simt_efficiency_pass.cpp b/source/opt/auto_inst_simt_efficiency_pass.cpp
  2673. new file mode 100644
  2674. index 00000000..cfb7e38a
  2675. --- /dev/null
  2676. +++ b/source/opt/auto_inst_simt_efficiency_pass.cpp
  2677. @@ -0,0 +1,39 @@
  2678. +// Copyright (c) 2021 The Khronos Group Inc.
  2679. +//
  2680. +// Licensed under the Apache License, Version 2.0 (the "License");
  2681. +// you may not use this file except in compliance with the License.
  2682. +// You may obtain a copy of the License at
  2683. +//
  2684. +// http://www.apache.org/licenses/LICENSE-2.0
  2685. +//
  2686. +// Unless required by applicable law or agreed to in writing, software
  2687. +// distributed under the License is distributed on an "AS IS" BASIS,
  2688. +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  2689. +// See the License for the specific language governing permissions and
  2690. +// limitations under the License.
  2691. +
  2692. +
  2693. +#include "auto_inst_simt_efficiency_pass.h"
  2694. +
  2695. +namespace spvtools {
  2696. +namespace opt {
  2697. +
  2698. +bool AutoInstSimtEfficiencyPass::BasicBlockInstrument(
  2699. + BasicBlock* bb, InstructionBuilder* builder, uint32_t stage_idx) {
  2700. + // Suppress unused parameter warnings
  2701. + (void)bb;
  2702. + (void)stage_idx;
  2703. +
  2704. + Instruction* true_constant_op = builder->GetBoolConstant(true);
  2705. + uint32_t true_constant_id = true_constant_op->result_id();
  2706. + // Create active thread mask by having all threads vote true
  2707. + uint32_t active_thread_mask_id =
  2708. + GenSubgroupBallotId(builder, true_constant_id);
  2709. + // Write active thread mask
  2710. + GenSubgroupUpdateCall(builder, {active_thread_mask_id});
  2711. +
  2712. + return true;
  2713. +}
  2714. +
  2715. +} // namespace opt
  2716. +} // namespace spvtools
  2717. diff --git a/source/opt/auto_inst_simt_efficiency_pass.h b/source/opt/auto_inst_simt_efficiency_pass.h
  2718. new file mode 100644
  2719. index 00000000..3d2b58cf
  2720. --- /dev/null
  2721. +++ b/source/opt/auto_inst_simt_efficiency_pass.h
  2722. @@ -0,0 +1,101 @@
  2723. +// Copyright (c) 2021 The Khronos Group Inc.
  2724. +
  2725. +// Licensed under the Apache License, Version 2.0 (the "License");
  2726. +// you may not use this file except in compliance with the License.
  2727. +// You may obtain a copy of the License at
  2728. +//
  2729. +// http://www.apache.org/licenses/LICENSE-2.0
  2730. +//
  2731. +// Unless required by applicable law or agreed to in writing, software
  2732. +// distributed under the License is distributed on an "AS IS" BASIS,
  2733. +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  2734. +// See the License for the specific language governing permissions and
  2735. +// limitations under the License.
  2736. +
  2737. +#ifndef LIBSPIRV_OPT_AUTO_INST_SIMT_EFFICIENCY_PASS_H_
  2738. +#define LIBSPIRV_OPT_AUTO_INST_SIMT_EFFICIENCY_PASS_H_
  2739. +
  2740. +#include <functional>
  2741. +
  2742. +#include "auto_inst_pass.h"
  2743. +
  2744. +namespace spvtools {
  2745. +namespace opt {
  2746. +
  2747. +class AutoInstSimtEfficiencyPass : public AutoInstPass {
  2748. + public:
  2749. + AutoInstSimtEfficiencyPass(uint32_t desc_set, uint32_t shader_id,
  2750. + uint32_t reserved_words_count)
  2751. + : AutoInstPass(desc_set, shader_id, reserved_words_count) {}
  2752. +
  2753. + const char* name() const override { return "auto-inst-simt-efficiency-pass"; }
  2754. +
  2755. + private:
  2756. + // Allows inheriting classes to initialize their knowledge
  2757. + // of module before beginning instrumentation
  2758. + void InitializeInstrumentation() override{};
  2759. +
  2760. + // Allows inheriting classes to finalize before
  2761. + // the pass finishes executing.
  2762. + void FinalizeInstrumentation() override{};
  2763. +
  2764. + // Any instructions added via |builder| will appear before |inst|
  2765. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  2766. + // This function is expected to return true if it added instructions to
  2767. + // builder, otherwise false.
  2768. + bool PreInstructionInstrument(Instruction* inst, InstructionBuilder* builder,
  2769. + uint32_t stage_idx) override {
  2770. + (void)inst;
  2771. + (void)builder;
  2772. + (void)stage_idx;
  2773. + return false;
  2774. + };
  2775. +
  2776. + // Any instructions added via |builder| will appear after |inst|.
  2777. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  2778. + // This function is expected to return true if it added instructions to
  2779. + // builder, otherwise false.
  2780. + bool PostInstructionInstrument(Instruction* inst, InstructionBuilder* builder,
  2781. + uint32_t stage_idx) override {
  2782. + (void)inst;
  2783. + (void)builder;
  2784. + (void)stage_idx;
  2785. + return false;
  2786. + };
  2787. +
  2788. + // Any instructions added via |builder| will appear before the content of
  2789. + // |bb|. |stage_idx| contains the SpvExecutionModel that builder is operating
  2790. + // in. This function is expected to return true if it added instructions to
  2791. + // builder, otherwise false.
  2792. + bool BasicBlockInstrument(BasicBlock* bb, InstructionBuilder* builder,
  2793. + uint32_t stage_idx) override;
  2794. +
  2795. + // Any instructions added via |builder| will execute before the
  2796. + // entrypoint function of the shader
  2797. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  2798. + // This function is expected to return true if it added instructions to
  2799. + // builder, otherwise false.
  2800. + bool PreEntryPointInstrument(InstructionBuilder* builder,
  2801. + uint32_t stage_idx) override {
  2802. + (void)builder;
  2803. + (void)stage_idx;
  2804. + return false;
  2805. + }
  2806. +
  2807. + // Any instructions added via |builder| will execute before the
  2808. + // entrypoint function of the shader.
  2809. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  2810. + // This function is expected to return true if it added instructions to
  2811. + // builder, otherwise false.
  2812. + bool PostEntryPointInstrument(InstructionBuilder* builder,
  2813. + uint32_t stage_idx) override {
  2814. + (void)builder;
  2815. + (void)stage_idx;
  2816. + return false;
  2817. + };
  2818. +};
  2819. +
  2820. +} // namespace opt
  2821. +} // namespace spvtools
  2822. +
  2823. +#endif // LIBSPIRV_OPT_AUTO_INST_SIMT_EFFICIENCY_PASS_H_
  2824. diff --git a/source/opt/auto_inst_warp_entry_and_exit_pass.cpp b/source/opt/auto_inst_warp_entry_and_exit_pass.cpp
  2825. new file mode 100644
  2826. index 00000000..d985a70d
  2827. --- /dev/null
  2828. +++ b/source/opt/auto_inst_warp_entry_and_exit_pass.cpp
  2829. @@ -0,0 +1,43 @@
  2830. +// Copyright (c) 2021 The Khronos Group Inc.
  2831. +//
  2832. +// Licensed under the Apache License, Version 2.0 (the "License");
  2833. +// you may not use this file except in compliance with the License.
  2834. +// You may obtain a copy of the License at
  2835. +//
  2836. +// http://www.apache.org/licenses/LICENSE-2.0
  2837. +//
  2838. +// Unless required by applicable law or agreed to in writing, software
  2839. +// distributed under the License is distributed on an "AS IS" BASIS,
  2840. +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  2841. +// See the License for the specific language governing permissions and
  2842. +// limitations under the License.
  2843. +
  2844. +#include "auto_inst_warp_entry_and_exit_pass.h"
  2845. +
  2846. +namespace spvtools {
  2847. +namespace opt {
  2848. +
  2849. +bool AutoInstWarpEntryAndExitPass::PreEntryPointInstrument(
  2850. + InstructionBuilder* builder, uint32_t stage_idx) {
  2851. + if (stage_idx != SpvExecutionModelRayGenerationKHR) return false;
  2852. +
  2853. + // Record every warp that began the pipeline
  2854. + auto prim_id =
  2855. + builder->GetUintConstantId(kAutoInstWarpEntryAndExitBeginPipeline);
  2856. + GenSubgroupUpdateCall(builder, {prim_id});
  2857. + return true;
  2858. +}
  2859. +
  2860. +bool AutoInstWarpEntryAndExitPass::PostEntryPointInstrument(
  2861. + InstructionBuilder* builder, uint32_t stage_idx) {
  2862. + if (stage_idx != SpvExecutionModelRayGenerationKHR) return false;
  2863. +
  2864. + // Record every warp that completed the the pipeline
  2865. + auto prim_id =
  2866. + builder->GetUintConstantId(kAutoInstWarpEntryAndExitEndPipeline);
  2867. + GenSubgroupUpdateCall(builder, {prim_id});
  2868. + return true;
  2869. +}
  2870. +
  2871. +} // namespace opt
  2872. +} // namespace spvtools
  2873. diff --git a/source/opt/auto_inst_warp_entry_and_exit_pass.h b/source/opt/auto_inst_warp_entry_and_exit_pass.h
  2874. new file mode 100644
  2875. index 00000000..44a5d175
  2876. --- /dev/null
  2877. +++ b/source/opt/auto_inst_warp_entry_and_exit_pass.h
  2878. @@ -0,0 +1,99 @@
  2879. +// Copyright (c) 2021 The Khronos Group Inc.
  2880. +
  2881. +// Licensed under the Apache License, Version 2.0 (the "License");
  2882. +// you may not use this file except in compliance with the License.
  2883. +// You may obtain a copy of the License at
  2884. +//
  2885. +// http://www.apache.org/licenses/LICENSE-2.0
  2886. +//
  2887. +// Unless required by applicable law or agreed to in writing, software
  2888. +// distributed under the License is distributed on an "AS IS" BASIS,
  2889. +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  2890. +// See the License for the specific language governing permissions and
  2891. +// limitations under the License.
  2892. +
  2893. +#ifndef LIBSPIRV_OPT_AUTO_INST_WARP_ENTRY_AND_EXIT_PASS_H_
  2894. +#define LIBSPIRV_OPT_AUTO_INST_WARP_ENTRY_AND_EXIT_PASS_H_
  2895. +
  2896. +#include <functional>
  2897. +
  2898. +#include "auto_inst_pass.h"
  2899. +
  2900. +namespace spvtools {
  2901. +namespace opt {
  2902. +
  2903. +class AutoInstWarpEntryAndExitPass : public AutoInstPass {
  2904. + public:
  2905. + AutoInstWarpEntryAndExitPass(uint32_t desc_set, uint32_t shader_id)
  2906. + : AutoInstPass(desc_set, shader_id, kDefaultReservedWordsCnt) {}
  2907. +
  2908. + const char* name() const override {
  2909. + return "auto-inst-warp-entry-and-exit-pass";
  2910. + }
  2911. +
  2912. + private:
  2913. + // Allows inheriting classes to initialize their knowledge
  2914. + // of module before beginning instrumentation
  2915. + void InitializeInstrumentation() override{};
  2916. +
  2917. + // Allows inheriting classes to finalize before
  2918. + // the pass finishes executing.
  2919. + void FinalizeInstrumentation() override{};
  2920. +
  2921. + // Any instructions added via |builder| will appear before |inst|
  2922. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  2923. + // This function is expected to return true if it added instructions to
  2924. + // builder, otherwise false.
  2925. + bool PreInstructionInstrument(Instruction* inst, InstructionBuilder* builder,
  2926. + uint32_t stage_idx) override {
  2927. + (void)inst;
  2928. + (void)builder;
  2929. + (void)stage_idx;
  2930. + return false;
  2931. + };
  2932. +
  2933. + // Any instructions added via |builder| will appear after |inst|.
  2934. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  2935. + // This function is expected to return true if it added instructions to
  2936. + // builder, otherwise false.
  2937. + bool PostInstructionInstrument(Instruction* inst, InstructionBuilder* builder,
  2938. + uint32_t stage_idx) override {
  2939. + (void)inst;
  2940. + (void)builder;
  2941. + (void)stage_idx;
  2942. + return false;
  2943. + };
  2944. +
  2945. + // Any instructions added via |builder| will appear before the content of
  2946. + // |bb|. |stage_idx| contains the SpvExecutionModel that builder is operating
  2947. + // in. This function is expected to return true if it added instructions to
  2948. + // builder, otherwise false.
  2949. + bool BasicBlockInstrument(BasicBlock* bb, InstructionBuilder* builder,
  2950. + uint32_t stage_idx) override {
  2951. + (void)bb;
  2952. + (void)builder;
  2953. + (void)stage_idx;
  2954. + return false;
  2955. + };
  2956. +
  2957. + // Any instructions added via |builder| will execute before the
  2958. + // entrypoint function of the shader
  2959. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  2960. + // This function is expected to return true if it added instructions to
  2961. + // builder, otherwise false.
  2962. + bool PreEntryPointInstrument(InstructionBuilder* builder,
  2963. + uint32_t stage_idx) override;
  2964. +
  2965. + // Any instructions added via |builder| will execute before the
  2966. + // entrypoint function of the shader.
  2967. + // |stage_idx| contains the SpvExecutionModel that builder is operating in.
  2968. + // This function is expected to return true if it added instructions to
  2969. + // builder, otherwise false.
  2970. + bool PostEntryPointInstrument(InstructionBuilder* builder,
  2971. + uint32_t stage_idx) override;
  2972. +};
  2973. +
  2974. +} // namespace opt
  2975. +} // namespace spvtools
  2976. +
  2977. +#endif // LIBSPIRV_OPT_AUTO_INST_WARP_ENTRY_AND_EXIT_PASS_H_
  2978. diff --git a/source/opt/instrument_pass.cpp b/source/opt/instrument_pass.cpp
  2979. index ed34fb02..1a84a002 100644
  2980. --- a/source/opt/instrument_pass.cpp
  2981. +++ b/source/opt/instrument_pass.cpp
  2982. @@ -288,7 +288,9 @@ void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx,
  2983. GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdZ,
  2984. z_launch_inst->result_id(), builder);
  2985. } break;
  2986. - default: { assert(false && "unsupported stage"); } break;
  2987. + default: {
  2988. + assert(false && "unsupported stage");
  2989. + } break;
  2990. }
  2991. }
  2992. @@ -435,6 +437,7 @@ uint32_t InstrumentPass::GetOutputBufferBinding() {
  2993. case kInstValidationIdBuffAddr:
  2994. return kDebugOutputBindingStream;
  2995. case kInstValidationIdDebugPrintf:
  2996. + case kInstValidationIdAuto:
  2997. return kDebugOutputPrintfStream;
  2998. default:
  2999. assert(false && "unexpected validation id");
  3000. diff --git a/source/opt/instrument_pass.h b/source/opt/instrument_pass.h
  3001. index 12b939d4..5fb49f8b 100644
  3002. --- a/source/opt/instrument_pass.h
  3003. +++ b/source/opt/instrument_pass.h
  3004. @@ -62,6 +62,7 @@ namespace opt {
  3005. static const uint32_t kInstValidationIdBindless = 0;
  3006. static const uint32_t kInstValidationIdBuffAddr = 1;
  3007. static const uint32_t kInstValidationIdDebugPrintf = 2;
  3008. +static const uint32_t kInstValidationIdAuto = 3;
  3009. class InstrumentPass : public Pass {
  3010. using cbb_ptr = const BasicBlock*;
  3011. diff --git a/source/opt/ir_builder.h b/source/opt/ir_builder.h
  3012. index fe5feff5..b7c8e0c5 100644
  3013. --- a/source/opt/ir_builder.h
  3014. +++ b/source/opt/ir_builder.h
  3015. @@ -392,6 +392,10 @@ class InstructionBuilder {
  3016. return uint_inst->result_id();
  3017. }
  3018. + uint32_t GetIntConstantId(int value) {
  3019. + return GetIntConstant(value, true)->result_id();
  3020. + }
  3021. +
  3022. // Adds either a signed or unsigned 32 bit integer constant to the binary
  3023. // depedning on the |sign|. If |sign| is true then the value is added as a
  3024. // signed constant otherwise as an unsigned constant. If |sign| is false the
  3025. @@ -428,6 +432,28 @@ class InstructionBuilder {
  3026. return GetContext()->get_constant_mgr()->GetDefiningInstruction(constant);
  3027. }
  3028. + Instruction* GetBoolConstant(bool value) {
  3029. + analysis::Bool bool_type{};
  3030. +
  3031. + // Get or create the integer type. This rebuilds the type and manages the
  3032. + // memory for the rebuilt type.
  3033. + uint32_t type_id =
  3034. + GetContext()->get_type_mgr()->GetTypeInstruction(&bool_type);
  3035. +
  3036. + // Get the memory managed type so that it is safe to be stored by
  3037. + // GetConstant.
  3038. + analysis::Type* rebuilt_type =
  3039. + GetContext()->get_type_mgr()->GetType(type_id);
  3040. +
  3041. + // Create the constant value.
  3042. + const analysis::Constant* constant =
  3043. + GetContext()->get_constant_mgr()->GetConstant(rebuilt_type,
  3044. + {(uint32_t)value});
  3045. +
  3046. + // Create the OpConstant instruction using the type and the value.
  3047. + return GetContext()->get_constant_mgr()->GetDefiningInstruction(constant);
  3048. + }
  3049. +
  3050. Instruction* AddCompositeExtract(uint32_t type, uint32_t id_of_composite,
  3051. const std::vector<uint32_t>& index_list) {
  3052. std::vector<Operand> operands;
  3053. diff --git a/source/opt/ir_context.cpp b/source/opt/ir_context.cpp
  3054. index 82107b5c..094513c3 100644
  3055. --- a/source/opt/ir_context.cpp
  3056. +++ b/source/opt/ir_context.cpp
  3057. @@ -805,6 +805,15 @@ uint32_t IRContext::GetBuiltinInputVarId(uint32_t builtin) {
  3058. reg_type = type_mgr->GetRegisteredType(&v4float_ty);
  3059. break;
  3060. }
  3061. + case SpvBuiltInNumSubgroups:
  3062. + case SpvBuiltInWorkgroupId:
  3063. + case SpvBuiltInWarpIDNV:
  3064. + case SpvBuiltInWarpsPerSMNV:
  3065. + case SpvBuiltInSMIDNV:
  3066. + case SpvBuiltInSMCountNV:
  3067. + case SpvBuiltInSubgroupId:
  3068. + case SpvBuiltInLocalInvocationIndex:
  3069. + case SpvBuiltInSubgroupSize:
  3070. case SpvBuiltInVertexIndex:
  3071. case SpvBuiltInInstanceIndex:
  3072. case SpvBuiltInPrimitiveId:
  3073. @@ -814,7 +823,11 @@ uint32_t IRContext::GetBuiltinInputVarId(uint32_t builtin) {
  3074. reg_type = type_mgr->GetRegisteredType(&uint_ty);
  3075. break;
  3076. }
  3077. + case SpvBuiltInLocalInvocationId:
  3078. + case SpvBuiltInLaunchSizeNV:
  3079. case SpvBuiltInGlobalInvocationId:
  3080. + case SpvBuiltInNumWorkgroups:
  3081. + case SpvBuiltInWorkgroupSize:
  3082. case SpvBuiltInLaunchIdNV: {
  3083. analysis::Integer uint_ty(32, false);
  3084. analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
  3085. diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp
  3086. index 8726ff93..5497fab7 100644
  3087. --- a/source/opt/optimizer.cpp
  3088. +++ b/source/opt/optimizer.cpp
  3089. @@ -908,6 +908,66 @@ Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set,
  3090. MakeUnique<opt::InstDebugPrintfPass>(desc_set, shader_id));
  3091. }
  3092. +Optimizer::PassToken CreateAutoInstDebugPass(uint32_t desc_set,
  3093. + uint32_t shader_id,
  3094. + bool test_atomic_ops,
  3095. + bool test_subgroup_ops) {
  3096. + return MakeUnique<Optimizer::PassToken::Impl>(
  3097. + MakeUnique<opt::AutoInstDebugPass>(desc_set, shader_id, test_atomic_ops,
  3098. + test_subgroup_ops));
  3099. +}
  3100. +
  3101. +Optimizer::PassToken CreateAutoInstDivergenceCharacterizationPass(
  3102. + uint32_t desc_set, uint32_t shader_id,
  3103. + std::function<
  3104. + void(std::unordered_map<uint32_t, uint32_t>&& inst_id2prim_id,
  3105. + std::unordered_map<uint32_t, uint32_t>&& inst_id2inst_count)>
  3106. + static_data_callback) {
  3107. + return MakeUnique<Optimizer::PassToken::Impl>(
  3108. + MakeUnique<opt::AutoInstDivergenceCharacterizationPass>(
  3109. + desc_set, shader_id, static_data_callback));
  3110. +}
  3111. +
  3112. +Optimizer::PassToken CreateAutoInstDynShaderTracePass(uint32_t desc_set,
  3113. + uint32_t shader_id) {
  3114. + return MakeUnique<Optimizer::PassToken::Impl>(
  3115. + MakeUnique<opt::AutoInstDynShaderTracePass>(desc_set, shader_id));
  3116. +}
  3117. +
  3118. +Optimizer::PassToken CreateAutoInstDynTraceRayTracePass(
  3119. + uint32_t desc_set, uint32_t shader_id,
  3120. + std::function<void(std::unordered_map<uint32_t, uint32_t>&&,
  3121. + std::unordered_map<uint32_t, std::vector<uint32_t>>&&)>
  3122. + static_data_callback) {
  3123. + return MakeUnique<Optimizer::PassToken::Impl>(
  3124. + MakeUnique<opt::AutoInstDynTraceRayTracePass>(desc_set, shader_id,
  3125. + static_data_callback));
  3126. +}
  3127. +
  3128. +Optimizer::PassToken CreateAutoInstExecutionTracePass(
  3129. + uint32_t desc_set, uint32_t shader_id,
  3130. + std::function<
  3131. + void(std::unordered_map<uint32_t, std::set<uint32_t>>&&,
  3132. + std::unordered_map<uint32_t, uint32_t>&& inst_id2bb_opcodes)>
  3133. + static_data_callback) {
  3134. + return MakeUnique<Optimizer::PassToken::Impl>(
  3135. + MakeUnique<opt::AutoInstExecutionTracePass>(desc_set, shader_id,
  3136. + static_data_callback));
  3137. +}
  3138. +
  3139. +Optimizer::PassToken CreateAutoInstSimtEfficiencyPass(
  3140. + uint32_t desc_set, uint32_t shader_id, uint32_t reserved_words_count) {
  3141. + return MakeUnique<Optimizer::PassToken::Impl>(
  3142. + MakeUnique<opt::AutoInstSimtEfficiencyPass>(desc_set, shader_id,
  3143. + reserved_words_count));
  3144. +}
  3145. +
  3146. +Optimizer::PassToken CreateAutoInstWarpEntryAndExitPass(uint32_t desc_set,
  3147. + uint32_t shader_id) {
  3148. + return MakeUnique<Optimizer::PassToken::Impl>(
  3149. + MakeUnique<opt::AutoInstWarpEntryAndExitPass>(desc_set, shader_id));
  3150. +}
  3151. +
  3152. Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set,
  3153. uint32_t shader_id) {
  3154. return MakeUnique<Optimizer::PassToken::Impl>(
  3155. diff --git a/source/opt/passes.h b/source/opt/passes.h
  3156. index d47cc1ce..9a7c9c22 100644
  3157. --- a/source/opt/passes.h
  3158. +++ b/source/opt/passes.h
  3159. @@ -19,6 +19,13 @@
  3160. #include "source/opt/aggressive_dead_code_elim_pass.h"
  3161. #include "source/opt/amd_ext_to_khr.h"
  3162. +#include "source/opt/auto_inst_debug_pass.h"
  3163. +#include "source/opt/auto_inst_divergence_characterization_pass.h"
  3164. +#include "source/opt/auto_inst_dyn_trace_ray_trace_pass.h"
  3165. +#include "source/opt/auto_inst_dyn_shader_trace_pass.h"
  3166. +#include "source/opt/auto_inst_execution_trace_pass.h"
  3167. +#include "source/opt/auto_inst_simt_efficiency_pass.h"
  3168. +#include "source/opt/auto_inst_warp_entry_and_exit_pass.h"
  3169. #include "source/opt/block_merge_pass.h"
  3170. #include "source/opt/ccp_pass.h"
  3171. #include "source/opt/cfg_cleanup_pass.h"
  3172. --
  3173. 2.29.2.windows.2