transformation_outline_function_test.cpp 118 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251
  1. // Copyright (c) 2019 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "source/fuzz/transformation_outline_function.h"
  15. #include "gtest/gtest.h"
  16. #include "source/fuzz/counter_overflow_id_source.h"
  17. #include "source/fuzz/fuzzer_util.h"
  18. #include "test/fuzz/fuzz_test_util.h"
  19. namespace spvtools {
  20. namespace fuzz {
  21. namespace {
  22. TEST(TransformationOutlineFunctionTest, TrivialOutline) {
  23. // This tests outlining of a single, empty basic block.
  24. std::string shader = R"(
  25. OpCapability Shader
  26. %1 = OpExtInstImport "GLSL.std.450"
  27. OpMemoryModel Logical GLSL450
  28. OpEntryPoint Fragment %4 "main"
  29. OpExecutionMode %4 OriginUpperLeft
  30. OpSource ESSL 310
  31. OpName %4 "main"
  32. %2 = OpTypeVoid
  33. %3 = OpTypeFunction %2
  34. %4 = OpFunction %2 None %3
  35. %5 = OpLabel
  36. OpReturn
  37. OpFunctionEnd
  38. )";
  39. const auto env = SPV_ENV_UNIVERSAL_1_4;
  40. const auto consumer = nullptr;
  41. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  42. spvtools::ValidatorOptions validator_options;
  43. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  44. kConsoleMessageConsumer));
  45. TransformationContext transformation_context(
  46. MakeUnique<FactManager>(context.get()), validator_options);
  47. TransformationOutlineFunction transformation(5, 5, /* not relevant */ 200,
  48. 100, 101, 102, 103,
  49. /* not relevant */ 201, {}, {});
  50. ASSERT_TRUE(
  51. transformation.IsApplicable(context.get(), transformation_context));
  52. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  53. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  54. kConsoleMessageConsumer));
  55. std::string after_transformation = R"(
  56. OpCapability Shader
  57. %1 = OpExtInstImport "GLSL.std.450"
  58. OpMemoryModel Logical GLSL450
  59. OpEntryPoint Fragment %4 "main"
  60. OpExecutionMode %4 OriginUpperLeft
  61. OpSource ESSL 310
  62. OpName %4 "main"
  63. %2 = OpTypeVoid
  64. %3 = OpTypeFunction %2
  65. %4 = OpFunction %2 None %3
  66. %5 = OpLabel
  67. %103 = OpFunctionCall %2 %101
  68. OpReturn
  69. OpFunctionEnd
  70. %101 = OpFunction %2 None %3
  71. %102 = OpLabel
  72. OpReturn
  73. OpFunctionEnd
  74. )";
  75. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  76. }
  77. TEST(TransformationOutlineFunctionTest,
  78. DoNotOutlineIfRegionStartsWithOpVariable) {
  79. // This checks that we do not outline the first block of a function if it
  80. // contains OpVariable.
  81. std::string shader = R"(
  82. OpCapability Shader
  83. %1 = OpExtInstImport "GLSL.std.450"
  84. OpMemoryModel Logical GLSL450
  85. OpEntryPoint Fragment %4 "main"
  86. OpExecutionMode %4 OriginUpperLeft
  87. OpSource ESSL 310
  88. OpName %4 "main"
  89. %2 = OpTypeVoid
  90. %3 = OpTypeFunction %2
  91. %7 = OpTypeBool
  92. %8 = OpTypePointer Function %7
  93. %4 = OpFunction %2 None %3
  94. %5 = OpLabel
  95. %6 = OpVariable %8 Function
  96. OpReturn
  97. OpFunctionEnd
  98. )";
  99. const auto env = SPV_ENV_UNIVERSAL_1_4;
  100. const auto consumer = nullptr;
  101. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  102. spvtools::ValidatorOptions validator_options;
  103. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  104. kConsoleMessageConsumer));
  105. TransformationContext transformation_context(
  106. MakeUnique<FactManager>(context.get()), validator_options);
  107. TransformationOutlineFunction transformation(5, 5, /* not relevant */ 200,
  108. 100, 101, 102, 103,
  109. /* not relevant */ 201, {}, {});
  110. ASSERT_FALSE(
  111. transformation.IsApplicable(context.get(), transformation_context));
  112. }
  113. TEST(TransformationOutlineFunctionTest, OutlineInterestingControlFlowNoState) {
  114. // This tests outlining of some non-trivial control flow, but such that the
  115. // basic blocks in the control flow do not actually do anything.
  116. std::string shader = R"(
  117. OpCapability Shader
  118. %1 = OpExtInstImport "GLSL.std.450"
  119. OpMemoryModel Logical GLSL450
  120. OpEntryPoint Fragment %4 "main"
  121. OpExecutionMode %4 OriginUpperLeft
  122. OpSource ESSL 310
  123. OpName %4 "main"
  124. %2 = OpTypeVoid
  125. %20 = OpTypeBool
  126. %21 = OpConstantTrue %20
  127. %3 = OpTypeFunction %2
  128. %4 = OpFunction %2 None %3
  129. %5 = OpLabel
  130. OpBranch %6
  131. %6 = OpLabel
  132. OpBranch %7
  133. %7 = OpLabel
  134. OpSelectionMerge %9 None
  135. OpBranchConditional %21 %8 %9
  136. %8 = OpLabel
  137. OpBranch %9
  138. %9 = OpLabel
  139. OpLoopMerge %12 %11 None
  140. OpBranch %10
  141. %10 = OpLabel
  142. OpBranchConditional %21 %11 %12
  143. %11 = OpLabel
  144. OpBranch %9
  145. %12 = OpLabel
  146. OpBranch %13
  147. %13 = OpLabel
  148. OpReturn
  149. OpFunctionEnd
  150. )";
  151. const auto env = SPV_ENV_UNIVERSAL_1_4;
  152. const auto consumer = nullptr;
  153. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  154. spvtools::ValidatorOptions validator_options;
  155. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  156. kConsoleMessageConsumer));
  157. TransformationContext transformation_context(
  158. MakeUnique<FactManager>(context.get()), validator_options);
  159. TransformationOutlineFunction transformation(6, 13, /* not relevant */
  160. 200, 100, 101, 102, 103,
  161. /* not relevant */ 201, {}, {});
  162. ASSERT_TRUE(
  163. transformation.IsApplicable(context.get(), transformation_context));
  164. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  165. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  166. kConsoleMessageConsumer));
  167. std::string after_transformation = R"(
  168. OpCapability Shader
  169. %1 = OpExtInstImport "GLSL.std.450"
  170. OpMemoryModel Logical GLSL450
  171. OpEntryPoint Fragment %4 "main"
  172. OpExecutionMode %4 OriginUpperLeft
  173. OpSource ESSL 310
  174. OpName %4 "main"
  175. %2 = OpTypeVoid
  176. %20 = OpTypeBool
  177. %21 = OpConstantTrue %20
  178. %3 = OpTypeFunction %2
  179. %4 = OpFunction %2 None %3
  180. %5 = OpLabel
  181. OpBranch %6
  182. %6 = OpLabel
  183. %103 = OpFunctionCall %2 %101
  184. OpReturn
  185. OpFunctionEnd
  186. %101 = OpFunction %2 None %3
  187. %102 = OpLabel
  188. OpBranch %7
  189. %7 = OpLabel
  190. OpSelectionMerge %9 None
  191. OpBranchConditional %21 %8 %9
  192. %8 = OpLabel
  193. OpBranch %9
  194. %9 = OpLabel
  195. OpLoopMerge %12 %11 None
  196. OpBranch %10
  197. %10 = OpLabel
  198. OpBranchConditional %21 %11 %12
  199. %11 = OpLabel
  200. OpBranch %9
  201. %12 = OpLabel
  202. OpBranch %13
  203. %13 = OpLabel
  204. OpReturn
  205. OpFunctionEnd
  206. )";
  207. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  208. }
  209. TEST(TransformationOutlineFunctionTest, OutlineCodeThatGeneratesUnusedIds) {
  210. // This tests outlining of a single basic block that does some computation,
  211. // but that does not use nor generate ids required outside of the outlined
  212. // region.
  213. std::string shader = R"(
  214. OpCapability Shader
  215. %1 = OpExtInstImport "GLSL.std.450"
  216. OpMemoryModel Logical GLSL450
  217. OpEntryPoint Fragment %4 "main"
  218. OpExecutionMode %4 OriginUpperLeft
  219. OpSource ESSL 310
  220. OpName %4 "main"
  221. %2 = OpTypeVoid
  222. %20 = OpTypeInt 32 1
  223. %21 = OpConstant %20 5
  224. %3 = OpTypeFunction %2
  225. %4 = OpFunction %2 None %3
  226. %5 = OpLabel
  227. OpBranch %6
  228. %6 = OpLabel
  229. %7 = OpCopyObject %20 %21
  230. %8 = OpCopyObject %20 %21
  231. %9 = OpIAdd %20 %7 %8
  232. OpReturn
  233. OpFunctionEnd
  234. )";
  235. const auto env = SPV_ENV_UNIVERSAL_1_4;
  236. const auto consumer = nullptr;
  237. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  238. spvtools::ValidatorOptions validator_options;
  239. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  240. kConsoleMessageConsumer));
  241. TransformationContext transformation_context(
  242. MakeUnique<FactManager>(context.get()), validator_options);
  243. TransformationOutlineFunction transformation(6, 6, /* not relevant */ 200,
  244. 100, 101, 102, 103,
  245. /* not relevant */ 201, {}, {});
  246. ASSERT_TRUE(
  247. transformation.IsApplicable(context.get(), transformation_context));
  248. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  249. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  250. kConsoleMessageConsumer));
  251. std::string after_transformation = R"(
  252. OpCapability Shader
  253. %1 = OpExtInstImport "GLSL.std.450"
  254. OpMemoryModel Logical GLSL450
  255. OpEntryPoint Fragment %4 "main"
  256. OpExecutionMode %4 OriginUpperLeft
  257. OpSource ESSL 310
  258. OpName %4 "main"
  259. %2 = OpTypeVoid
  260. %20 = OpTypeInt 32 1
  261. %21 = OpConstant %20 5
  262. %3 = OpTypeFunction %2
  263. %4 = OpFunction %2 None %3
  264. %5 = OpLabel
  265. OpBranch %6
  266. %6 = OpLabel
  267. %103 = OpFunctionCall %2 %101
  268. OpReturn
  269. OpFunctionEnd
  270. %101 = OpFunction %2 None %3
  271. %102 = OpLabel
  272. %7 = OpCopyObject %20 %21
  273. %8 = OpCopyObject %20 %21
  274. %9 = OpIAdd %20 %7 %8
  275. OpReturn
  276. OpFunctionEnd
  277. )";
  278. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  279. }
  280. TEST(TransformationOutlineFunctionTest, OutlineCodeThatGeneratesSingleUsedId) {
  281. // This tests outlining of a block that generates an id that is used in a
  282. // later block.
  283. std::string shader = R"(
  284. OpCapability Shader
  285. %1 = OpExtInstImport "GLSL.std.450"
  286. OpMemoryModel Logical GLSL450
  287. OpEntryPoint Fragment %4 "main"
  288. OpExecutionMode %4 OriginUpperLeft
  289. OpSource ESSL 310
  290. OpName %4 "main"
  291. %2 = OpTypeVoid
  292. %20 = OpTypeInt 32 1
  293. %21 = OpConstant %20 5
  294. %3 = OpTypeFunction %2
  295. %4 = OpFunction %2 None %3
  296. %5 = OpLabel
  297. OpBranch %6
  298. %6 = OpLabel
  299. %7 = OpCopyObject %20 %21
  300. %8 = OpCopyObject %20 %21
  301. %9 = OpIAdd %20 %7 %8
  302. OpBranch %10
  303. %10 = OpLabel
  304. %11 = OpCopyObject %20 %9
  305. OpReturn
  306. OpFunctionEnd
  307. )";
  308. const auto env = SPV_ENV_UNIVERSAL_1_4;
  309. const auto consumer = nullptr;
  310. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  311. spvtools::ValidatorOptions validator_options;
  312. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  313. kConsoleMessageConsumer));
  314. TransformationContext transformation_context(
  315. MakeUnique<FactManager>(context.get()), validator_options);
  316. TransformationOutlineFunction transformation(6, 6, 99, 100, 101, 102, 103,
  317. 105, {}, {{9, 104}});
  318. ASSERT_TRUE(
  319. transformation.IsApplicable(context.get(), transformation_context));
  320. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  321. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  322. kConsoleMessageConsumer));
  323. std::string after_transformation = R"(
  324. OpCapability Shader
  325. %1 = OpExtInstImport "GLSL.std.450"
  326. OpMemoryModel Logical GLSL450
  327. OpEntryPoint Fragment %4 "main"
  328. OpExecutionMode %4 OriginUpperLeft
  329. OpSource ESSL 310
  330. OpName %4 "main"
  331. %2 = OpTypeVoid
  332. %20 = OpTypeInt 32 1
  333. %21 = OpConstant %20 5
  334. %3 = OpTypeFunction %2
  335. %99 = OpTypeStruct %20
  336. %100 = OpTypeFunction %99
  337. %4 = OpFunction %2 None %3
  338. %5 = OpLabel
  339. OpBranch %6
  340. %6 = OpLabel
  341. %103 = OpFunctionCall %99 %101
  342. %9 = OpCompositeExtract %20 %103 0
  343. OpBranch %10
  344. %10 = OpLabel
  345. %11 = OpCopyObject %20 %9
  346. OpReturn
  347. OpFunctionEnd
  348. %101 = OpFunction %99 None %100
  349. %102 = OpLabel
  350. %7 = OpCopyObject %20 %21
  351. %8 = OpCopyObject %20 %21
  352. %104 = OpIAdd %20 %7 %8
  353. %105 = OpCompositeConstruct %99 %104
  354. OpReturnValue %105
  355. OpFunctionEnd
  356. )";
  357. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  358. }
  359. TEST(TransformationOutlineFunctionTest, OutlineDiamondThatGeneratesSeveralIds) {
  360. // This tests outlining of several blocks that generate a number of ids that
  361. // are used in later blocks.
  362. std::string shader = R"(
  363. OpCapability Shader
  364. %1 = OpExtInstImport "GLSL.std.450"
  365. OpMemoryModel Logical GLSL450
  366. OpEntryPoint Fragment %4 "main"
  367. OpExecutionMode %4 OriginUpperLeft
  368. OpSource ESSL 310
  369. OpName %4 "main"
  370. %2 = OpTypeVoid
  371. %20 = OpTypeInt 32 1
  372. %21 = OpConstant %20 5
  373. %22 = OpTypeBool
  374. %3 = OpTypeFunction %2
  375. %4 = OpFunction %2 None %3
  376. %5 = OpLabel
  377. OpBranch %6
  378. %6 = OpLabel
  379. %7 = OpCopyObject %20 %21
  380. %8 = OpCopyObject %20 %21
  381. %9 = OpSLessThan %22 %7 %8
  382. OpSelectionMerge %12 None
  383. OpBranchConditional %9 %10 %11
  384. %10 = OpLabel
  385. %13 = OpIAdd %20 %7 %8
  386. OpBranch %12
  387. %11 = OpLabel
  388. %14 = OpIAdd %20 %7 %7
  389. OpBranch %12
  390. %12 = OpLabel
  391. %15 = OpPhi %20 %13 %10 %14 %11
  392. OpBranch %80
  393. %80 = OpLabel
  394. OpBranch %16
  395. %16 = OpLabel
  396. %17 = OpCopyObject %20 %15
  397. %18 = OpCopyObject %22 %9
  398. %19 = OpIAdd %20 %7 %8
  399. OpReturn
  400. OpFunctionEnd
  401. )";
  402. const auto env = SPV_ENV_UNIVERSAL_1_4;
  403. const auto consumer = nullptr;
  404. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  405. spvtools::ValidatorOptions validator_options;
  406. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  407. kConsoleMessageConsumer));
  408. TransformationContext transformation_context(
  409. MakeUnique<FactManager>(context.get()), validator_options);
  410. TransformationOutlineFunction transformation(
  411. 6, 80, 100, 101, 102, 103, 104, 105, {},
  412. {{15, 106}, {9, 107}, {7, 108}, {8, 109}});
  413. ASSERT_TRUE(
  414. transformation.IsApplicable(context.get(), transformation_context));
  415. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  416. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  417. kConsoleMessageConsumer));
  418. std::string after_transformation = R"(
  419. OpCapability Shader
  420. %1 = OpExtInstImport "GLSL.std.450"
  421. OpMemoryModel Logical GLSL450
  422. OpEntryPoint Fragment %4 "main"
  423. OpExecutionMode %4 OriginUpperLeft
  424. OpSource ESSL 310
  425. OpName %4 "main"
  426. %2 = OpTypeVoid
  427. %20 = OpTypeInt 32 1
  428. %21 = OpConstant %20 5
  429. %22 = OpTypeBool
  430. %3 = OpTypeFunction %2
  431. %100 = OpTypeStruct %20 %20 %22 %20
  432. %101 = OpTypeFunction %100
  433. %4 = OpFunction %2 None %3
  434. %5 = OpLabel
  435. OpBranch %6
  436. %6 = OpLabel
  437. %104 = OpFunctionCall %100 %102
  438. %7 = OpCompositeExtract %20 %104 0
  439. %8 = OpCompositeExtract %20 %104 1
  440. %9 = OpCompositeExtract %22 %104 2
  441. %15 = OpCompositeExtract %20 %104 3
  442. OpBranch %16
  443. %16 = OpLabel
  444. %17 = OpCopyObject %20 %15
  445. %18 = OpCopyObject %22 %9
  446. %19 = OpIAdd %20 %7 %8
  447. OpReturn
  448. OpFunctionEnd
  449. %102 = OpFunction %100 None %101
  450. %103 = OpLabel
  451. %108 = OpCopyObject %20 %21
  452. %109 = OpCopyObject %20 %21
  453. %107 = OpSLessThan %22 %108 %109
  454. OpSelectionMerge %12 None
  455. OpBranchConditional %107 %10 %11
  456. %10 = OpLabel
  457. %13 = OpIAdd %20 %108 %109
  458. OpBranch %12
  459. %11 = OpLabel
  460. %14 = OpIAdd %20 %108 %108
  461. OpBranch %12
  462. %12 = OpLabel
  463. %106 = OpPhi %20 %13 %10 %14 %11
  464. OpBranch %80
  465. %80 = OpLabel
  466. %105 = OpCompositeConstruct %100 %108 %109 %107 %106
  467. OpReturnValue %105
  468. OpFunctionEnd
  469. )";
  470. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  471. }
  472. TEST(TransformationOutlineFunctionTest, OutlineCodeThatUsesASingleId) {
  473. // This tests outlining of a block that uses an id defined earlier.
  474. std::string shader = R"(
  475. OpCapability Shader
  476. %1 = OpExtInstImport "GLSL.std.450"
  477. OpMemoryModel Logical GLSL450
  478. OpEntryPoint Fragment %4 "main"
  479. OpExecutionMode %4 OriginUpperLeft
  480. OpSource ESSL 310
  481. OpName %4 "main"
  482. %2 = OpTypeVoid
  483. %20 = OpTypeInt 32 1
  484. %21 = OpConstant %20 5
  485. %3 = OpTypeFunction %2
  486. %4 = OpFunction %2 None %3
  487. %5 = OpLabel
  488. %7 = OpCopyObject %20 %21
  489. OpBranch %6
  490. %6 = OpLabel
  491. %8 = OpCopyObject %20 %7
  492. OpBranch %10
  493. %10 = OpLabel
  494. OpReturn
  495. OpFunctionEnd
  496. )";
  497. const auto env = SPV_ENV_UNIVERSAL_1_4;
  498. const auto consumer = nullptr;
  499. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  500. spvtools::ValidatorOptions validator_options;
  501. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  502. kConsoleMessageConsumer));
  503. TransformationContext transformation_context(
  504. MakeUnique<FactManager>(context.get()), validator_options);
  505. TransformationOutlineFunction transformation(6, 6, 100, 101, 102, 103, 104,
  506. 105, {{7, 106}}, {});
  507. ASSERT_TRUE(
  508. transformation.IsApplicable(context.get(), transformation_context));
  509. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  510. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  511. kConsoleMessageConsumer));
  512. std::string after_transformation = R"(
  513. OpCapability Shader
  514. %1 = OpExtInstImport "GLSL.std.450"
  515. OpMemoryModel Logical GLSL450
  516. OpEntryPoint Fragment %4 "main"
  517. OpExecutionMode %4 OriginUpperLeft
  518. OpSource ESSL 310
  519. OpName %4 "main"
  520. %2 = OpTypeVoid
  521. %20 = OpTypeInt 32 1
  522. %21 = OpConstant %20 5
  523. %3 = OpTypeFunction %2
  524. %101 = OpTypeFunction %2 %20
  525. %4 = OpFunction %2 None %3
  526. %5 = OpLabel
  527. %7 = OpCopyObject %20 %21
  528. OpBranch %6
  529. %6 = OpLabel
  530. %104 = OpFunctionCall %2 %102 %7
  531. OpBranch %10
  532. %10 = OpLabel
  533. OpReturn
  534. OpFunctionEnd
  535. %102 = OpFunction %2 None %101
  536. %106 = OpFunctionParameter %20
  537. %103 = OpLabel
  538. %8 = OpCopyObject %20 %106
  539. OpReturn
  540. OpFunctionEnd
  541. )";
  542. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  543. }
  544. TEST(TransformationOutlineFunctionTest, OutlineCodeThatUsesAVariable) {
  545. // This tests outlining of a block that uses a variable.
  546. std::string shader = R"(
  547. OpCapability Shader
  548. %1 = OpExtInstImport "GLSL.std.450"
  549. OpMemoryModel Logical GLSL450
  550. OpEntryPoint Fragment %4 "main"
  551. OpExecutionMode %4 OriginUpperLeft
  552. OpSource ESSL 310
  553. OpName %4 "main"
  554. %2 = OpTypeVoid
  555. %20 = OpTypeInt 32 1
  556. %21 = OpConstant %20 5
  557. %3 = OpTypeFunction %2
  558. %12 = OpTypePointer Function %20
  559. %4 = OpFunction %2 None %3
  560. %5 = OpLabel
  561. %13 = OpVariable %12 Function
  562. OpBranch %6
  563. %6 = OpLabel
  564. %8 = OpLoad %20 %13
  565. OpBranch %10
  566. %10 = OpLabel
  567. OpReturn
  568. OpFunctionEnd
  569. )";
  570. const auto env = SPV_ENV_UNIVERSAL_1_4;
  571. const auto consumer = nullptr;
  572. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  573. spvtools::ValidatorOptions validator_options;
  574. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  575. kConsoleMessageConsumer));
  576. TransformationContext transformation_context(
  577. MakeUnique<FactManager>(context.get()), validator_options);
  578. TransformationOutlineFunction transformation(6, 6, 100, 101, 102, 103, 104,
  579. 105, {{13, 106}}, {});
  580. ASSERT_TRUE(
  581. transformation.IsApplicable(context.get(), transformation_context));
  582. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  583. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  584. kConsoleMessageConsumer));
  585. std::string after_transformation = R"(
  586. OpCapability Shader
  587. %1 = OpExtInstImport "GLSL.std.450"
  588. OpMemoryModel Logical GLSL450
  589. OpEntryPoint Fragment %4 "main"
  590. OpExecutionMode %4 OriginUpperLeft
  591. OpSource ESSL 310
  592. OpName %4 "main"
  593. %2 = OpTypeVoid
  594. %20 = OpTypeInt 32 1
  595. %21 = OpConstant %20 5
  596. %3 = OpTypeFunction %2
  597. %12 = OpTypePointer Function %20
  598. %101 = OpTypeFunction %2 %12
  599. %4 = OpFunction %2 None %3
  600. %5 = OpLabel
  601. %13 = OpVariable %12 Function
  602. OpBranch %6
  603. %6 = OpLabel
  604. %104 = OpFunctionCall %2 %102 %13
  605. OpBranch %10
  606. %10 = OpLabel
  607. OpReturn
  608. OpFunctionEnd
  609. %102 = OpFunction %2 None %101
  610. %106 = OpFunctionParameter %12
  611. %103 = OpLabel
  612. %8 = OpLoad %20 %106
  613. OpReturn
  614. OpFunctionEnd
  615. )";
  616. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  617. }
  618. TEST(TransformationOutlineFunctionTest, OutlineCodeThatUsesAParameter) {
  619. // This tests outlining of a block that uses a function parameter.
  620. std::string shader = R"(
  621. OpCapability Shader
  622. %1 = OpExtInstImport "GLSL.std.450"
  623. OpMemoryModel Logical GLSL450
  624. OpEntryPoint Fragment %4 "main"
  625. OpExecutionMode %4 OriginUpperLeft
  626. OpSource ESSL 310
  627. OpName %4 "main"
  628. OpName %10 "foo(i1;"
  629. OpName %9 "x"
  630. OpName %18 "param"
  631. %2 = OpTypeVoid
  632. %3 = OpTypeFunction %2
  633. %6 = OpTypeInt 32 1
  634. %7 = OpTypePointer Function %6
  635. %8 = OpTypeFunction %6 %7
  636. %13 = OpConstant %6 1
  637. %17 = OpConstant %6 3
  638. %4 = OpFunction %2 None %3
  639. %5 = OpLabel
  640. %18 = OpVariable %7 Function
  641. OpStore %18 %17
  642. %19 = OpFunctionCall %6 %10 %18
  643. OpReturn
  644. OpFunctionEnd
  645. %10 = OpFunction %6 None %8
  646. %9 = OpFunctionParameter %7
  647. %11 = OpLabel
  648. %12 = OpLoad %6 %9
  649. %14 = OpIAdd %6 %12 %13
  650. OpReturnValue %14
  651. OpFunctionEnd
  652. )";
  653. const auto env = SPV_ENV_UNIVERSAL_1_4;
  654. const auto consumer = nullptr;
  655. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  656. spvtools::ValidatorOptions validator_options;
  657. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  658. kConsoleMessageConsumer));
  659. TransformationContext transformation_context(
  660. MakeUnique<FactManager>(context.get()), validator_options);
  661. TransformationOutlineFunction transformation(11, 11, 100, 101, 102, 103, 104,
  662. 105, {{9, 106}}, {{14, 107}});
  663. ASSERT_TRUE(
  664. transformation.IsApplicable(context.get(), transformation_context));
  665. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  666. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  667. kConsoleMessageConsumer));
  668. std::string after_transformation = R"(
  669. OpCapability Shader
  670. %1 = OpExtInstImport "GLSL.std.450"
  671. OpMemoryModel Logical GLSL450
  672. OpEntryPoint Fragment %4 "main"
  673. OpExecutionMode %4 OriginUpperLeft
  674. OpSource ESSL 310
  675. OpName %4 "main"
  676. OpName %10 "foo(i1;"
  677. OpName %9 "x"
  678. OpName %18 "param"
  679. %2 = OpTypeVoid
  680. %3 = OpTypeFunction %2
  681. %6 = OpTypeInt 32 1
  682. %7 = OpTypePointer Function %6
  683. %8 = OpTypeFunction %6 %7
  684. %13 = OpConstant %6 1
  685. %17 = OpConstant %6 3
  686. %100 = OpTypeStruct %6
  687. %101 = OpTypeFunction %100 %7
  688. %4 = OpFunction %2 None %3
  689. %5 = OpLabel
  690. %18 = OpVariable %7 Function
  691. OpStore %18 %17
  692. %19 = OpFunctionCall %6 %10 %18
  693. OpReturn
  694. OpFunctionEnd
  695. %10 = OpFunction %6 None %8
  696. %9 = OpFunctionParameter %7
  697. %11 = OpLabel
  698. %104 = OpFunctionCall %100 %102 %9
  699. %14 = OpCompositeExtract %6 %104 0
  700. OpReturnValue %14
  701. OpFunctionEnd
  702. %102 = OpFunction %100 None %101
  703. %106 = OpFunctionParameter %7
  704. %103 = OpLabel
  705. %12 = OpLoad %6 %106
  706. %107 = OpIAdd %6 %12 %13
  707. %105 = OpCompositeConstruct %100 %107
  708. OpReturnValue %105
  709. OpFunctionEnd
  710. )";
  711. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  712. }
  713. TEST(TransformationOutlineFunctionTest,
  714. DoNotOutlineIfLoopMergeIsOutsideRegion) {
  715. std::string shader = R"(
  716. OpCapability Shader
  717. %1 = OpExtInstImport "GLSL.std.450"
  718. OpMemoryModel Logical GLSL450
  719. OpEntryPoint Fragment %4 "main"
  720. OpExecutionMode %4 OriginUpperLeft
  721. OpSource ESSL 310
  722. OpName %4 "main"
  723. %2 = OpTypeVoid
  724. %3 = OpTypeFunction %2
  725. %9 = OpTypeBool
  726. %10 = OpConstantTrue %9
  727. %4 = OpFunction %2 None %3
  728. %5 = OpLabel
  729. OpBranch %6
  730. %6 = OpLabel
  731. OpLoopMerge %7 %8 None
  732. OpBranch %8
  733. %8 = OpLabel
  734. OpBranchConditional %10 %6 %7
  735. %7 = OpLabel
  736. OpReturn
  737. OpFunctionEnd
  738. )";
  739. const auto env = SPV_ENV_UNIVERSAL_1_4;
  740. const auto consumer = nullptr;
  741. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  742. spvtools::ValidatorOptions validator_options;
  743. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  744. kConsoleMessageConsumer));
  745. TransformationContext transformation_context(
  746. MakeUnique<FactManager>(context.get()), validator_options);
  747. TransformationOutlineFunction transformation(6, 8, 100, 101, 102, 103, 104,
  748. 105, {}, {});
  749. ASSERT_FALSE(
  750. transformation.IsApplicable(context.get(), transformation_context));
  751. }
  752. TEST(TransformationOutlineFunctionTest, DoNotOutlineIfRegionInvolvesReturn) {
  753. std::string shader = R"(
  754. OpCapability Shader
  755. %1 = OpExtInstImport "GLSL.std.450"
  756. OpMemoryModel Logical GLSL450
  757. OpEntryPoint Fragment %4 "main"
  758. OpExecutionMode %4 OriginUpperLeft
  759. OpSource ESSL 310
  760. OpName %4 "main"
  761. %2 = OpTypeVoid
  762. %20 = OpTypeBool
  763. %21 = OpConstantTrue %20
  764. %3 = OpTypeFunction %2
  765. %4 = OpFunction %2 None %3
  766. %5 = OpLabel
  767. OpBranch %6
  768. %6 = OpLabel
  769. OpBranch %7
  770. %7 = OpLabel
  771. OpSelectionMerge %10 None
  772. OpBranchConditional %21 %8 %9
  773. %8 = OpLabel
  774. OpReturn
  775. %9 = OpLabel
  776. OpBranch %10
  777. %10 = OpLabel
  778. OpBranch %11
  779. %11 = OpLabel
  780. OpBranch %12
  781. %12 = OpLabel
  782. OpReturn
  783. OpFunctionEnd
  784. )";
  785. const auto env = SPV_ENV_UNIVERSAL_1_4;
  786. const auto consumer = nullptr;
  787. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  788. spvtools::ValidatorOptions validator_options;
  789. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  790. kConsoleMessageConsumer));
  791. TransformationContext transformation_context(
  792. MakeUnique<FactManager>(context.get()), validator_options);
  793. TransformationOutlineFunction transformation(6, 11, /* not relevant */ 200,
  794. 100, 101, 102, 103,
  795. /* not relevant */ 201, {}, {});
  796. ASSERT_FALSE(
  797. transformation.IsApplicable(context.get(), transformation_context));
  798. }
  799. TEST(TransformationOutlineFunctionTest, DoNotOutlineIfRegionInvolvesKill) {
  800. std::string shader = R"(
  801. OpCapability Shader
  802. %1 = OpExtInstImport "GLSL.std.450"
  803. OpMemoryModel Logical GLSL450
  804. OpEntryPoint Fragment %4 "main"
  805. OpExecutionMode %4 OriginUpperLeft
  806. OpSource ESSL 310
  807. OpName %4 "main"
  808. %2 = OpTypeVoid
  809. %20 = OpTypeBool
  810. %21 = OpConstantTrue %20
  811. %3 = OpTypeFunction %2
  812. %4 = OpFunction %2 None %3
  813. %5 = OpLabel
  814. OpBranch %6
  815. %6 = OpLabel
  816. OpBranch %7
  817. %7 = OpLabel
  818. OpSelectionMerge %10 None
  819. OpBranchConditional %21 %8 %9
  820. %8 = OpLabel
  821. OpKill
  822. %9 = OpLabel
  823. OpBranch %10
  824. %10 = OpLabel
  825. OpBranch %11
  826. %11 = OpLabel
  827. OpBranch %12
  828. %12 = OpLabel
  829. OpReturn
  830. OpFunctionEnd
  831. )";
  832. const auto env = SPV_ENV_UNIVERSAL_1_4;
  833. const auto consumer = nullptr;
  834. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  835. spvtools::ValidatorOptions validator_options;
  836. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  837. kConsoleMessageConsumer));
  838. TransformationContext transformation_context(
  839. MakeUnique<FactManager>(context.get()), validator_options);
  840. TransformationOutlineFunction transformation(6, 11, /* not relevant */ 200,
  841. 100, 101, 102, 103,
  842. /* not relevant */ 201, {}, {});
  843. ASSERT_FALSE(
  844. transformation.IsApplicable(context.get(), transformation_context));
  845. }
  846. TEST(TransformationOutlineFunctionTest,
  847. DoNotOutlineIfRegionInvolvesUnreachable) {
  848. std::string shader = R"(
  849. OpCapability Shader
  850. %1 = OpExtInstImport "GLSL.std.450"
  851. OpMemoryModel Logical GLSL450
  852. OpEntryPoint Fragment %4 "main"
  853. OpExecutionMode %4 OriginUpperLeft
  854. OpSource ESSL 310
  855. OpName %4 "main"
  856. %2 = OpTypeVoid
  857. %20 = OpTypeBool
  858. %21 = OpConstantTrue %20
  859. %3 = OpTypeFunction %2
  860. %4 = OpFunction %2 None %3
  861. %5 = OpLabel
  862. OpBranch %6
  863. %6 = OpLabel
  864. OpBranch %7
  865. %7 = OpLabel
  866. OpSelectionMerge %10 None
  867. OpBranchConditional %21 %8 %9
  868. %8 = OpLabel
  869. OpBranch %10
  870. %9 = OpLabel
  871. OpUnreachable
  872. %10 = OpLabel
  873. OpBranch %11
  874. %11 = OpLabel
  875. OpBranch %12
  876. %12 = OpLabel
  877. OpReturn
  878. OpFunctionEnd
  879. )";
  880. const auto env = SPV_ENV_UNIVERSAL_1_4;
  881. const auto consumer = nullptr;
  882. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  883. spvtools::ValidatorOptions validator_options;
  884. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  885. kConsoleMessageConsumer));
  886. TransformationContext transformation_context(
  887. MakeUnique<FactManager>(context.get()), validator_options);
  888. TransformationOutlineFunction transformation(6, 11, /* not relevant */ 200,
  889. 100, 101, 102, 103,
  890. /* not relevant */ 201, {}, {});
  891. ASSERT_FALSE(
  892. transformation.IsApplicable(context.get(), transformation_context));
  893. }
  894. TEST(TransformationOutlineFunctionTest,
  895. DoNotOutlineIfSelectionMergeIsOutsideRegion) {
  896. std::string shader = R"(
  897. OpCapability Shader
  898. %1 = OpExtInstImport "GLSL.std.450"
  899. OpMemoryModel Logical GLSL450
  900. OpEntryPoint Fragment %4 "main"
  901. OpExecutionMode %4 OriginUpperLeft
  902. OpSource ESSL 310
  903. OpName %4 "main"
  904. %2 = OpTypeVoid
  905. %3 = OpTypeFunction %2
  906. %9 = OpTypeBool
  907. %10 = OpConstantTrue %9
  908. %4 = OpFunction %2 None %3
  909. %5 = OpLabel
  910. OpBranch %6
  911. %6 = OpLabel
  912. OpSelectionMerge %7 None
  913. OpBranchConditional %10 %8 %7
  914. %8 = OpLabel
  915. OpBranch %7
  916. %7 = OpLabel
  917. OpReturn
  918. OpFunctionEnd
  919. )";
  920. const auto env = SPV_ENV_UNIVERSAL_1_4;
  921. const auto consumer = nullptr;
  922. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  923. spvtools::ValidatorOptions validator_options;
  924. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  925. kConsoleMessageConsumer));
  926. TransformationContext transformation_context(
  927. MakeUnique<FactManager>(context.get()), validator_options);
  928. TransformationOutlineFunction transformation(6, 8, 100, 101, 102, 103, 104,
  929. 105, {}, {});
  930. ASSERT_FALSE(
  931. transformation.IsApplicable(context.get(), transformation_context));
  932. }
  933. TEST(TransformationOutlineFunctionTest, DoNotOutlineIfLoopHeadIsOutsideRegion) {
  934. std::string shader = R"(
  935. OpCapability Shader
  936. %1 = OpExtInstImport "GLSL.std.450"
  937. OpMemoryModel Logical GLSL450
  938. OpEntryPoint Fragment %4 "main"
  939. OpExecutionMode %4 OriginUpperLeft
  940. OpSource ESSL 310
  941. OpName %4 "main"
  942. %2 = OpTypeVoid
  943. %3 = OpTypeFunction %2
  944. %9 = OpTypeBool
  945. %10 = OpConstantTrue %9
  946. %4 = OpFunction %2 None %3
  947. %5 = OpLabel
  948. OpBranch %6
  949. %6 = OpLabel
  950. OpLoopMerge %8 %11 None
  951. OpBranch %7
  952. %7 = OpLabel
  953. OpBranchConditional %10 %11 %8
  954. %11 = OpLabel
  955. OpBranch %6
  956. %8 = OpLabel
  957. OpReturn
  958. OpFunctionEnd
  959. )";
  960. const auto env = SPV_ENV_UNIVERSAL_1_4;
  961. const auto consumer = nullptr;
  962. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  963. spvtools::ValidatorOptions validator_options;
  964. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  965. kConsoleMessageConsumer));
  966. TransformationContext transformation_context(
  967. MakeUnique<FactManager>(context.get()), validator_options);
  968. TransformationOutlineFunction transformation(7, 8, 100, 101, 102, 103, 104,
  969. 105, {}, {});
  970. ASSERT_FALSE(
  971. transformation.IsApplicable(context.get(), transformation_context));
  972. }
  973. TEST(TransformationOutlineFunctionTest,
  974. DoNotOutlineIfLoopContinueIsOutsideRegion) {
  975. std::string shader = R"(
  976. OpCapability Shader
  977. %1 = OpExtInstImport "GLSL.std.450"
  978. OpMemoryModel Logical GLSL450
  979. OpEntryPoint Fragment %4 "main"
  980. OpExecutionMode %4 OriginUpperLeft
  981. OpSource ESSL 310
  982. OpName %4 "main"
  983. %2 = OpTypeVoid
  984. %3 = OpTypeFunction %2
  985. %9 = OpTypeBool
  986. %10 = OpConstantTrue %9
  987. %4 = OpFunction %2 None %3
  988. %5 = OpLabel
  989. OpBranch %6
  990. %6 = OpLabel
  991. OpLoopMerge %7 %8 None
  992. OpBranch %7
  993. %8 = OpLabel
  994. OpBranch %6
  995. %7 = OpLabel
  996. OpReturn
  997. OpFunctionEnd
  998. )";
  999. const auto env = SPV_ENV_UNIVERSAL_1_4;
  1000. const auto consumer = nullptr;
  1001. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1002. spvtools::ValidatorOptions validator_options;
  1003. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1004. kConsoleMessageConsumer));
  1005. TransformationContext transformation_context(
  1006. MakeUnique<FactManager>(context.get()), validator_options);
  1007. TransformationOutlineFunction transformation(6, 7, 100, 101, 102, 103, 104,
  1008. 105, {}, {});
  1009. ASSERT_FALSE(
  1010. transformation.IsApplicable(context.get(), transformation_context));
  1011. }
  1012. TEST(TransformationOutlineFunctionTest,
  1013. DoNotOutlineWithLoopCarriedPhiDependence) {
  1014. std::string shader = R"(
  1015. OpCapability Shader
  1016. %1 = OpExtInstImport "GLSL.std.450"
  1017. OpMemoryModel Logical GLSL450
  1018. OpEntryPoint Fragment %4 "main"
  1019. OpExecutionMode %4 OriginUpperLeft
  1020. OpSource ESSL 310
  1021. OpName %4 "main"
  1022. %2 = OpTypeVoid
  1023. %3 = OpTypeFunction %2
  1024. %9 = OpTypeBool
  1025. %10 = OpConstantTrue %9
  1026. %4 = OpFunction %2 None %3
  1027. %5 = OpLabel
  1028. OpBranch %6
  1029. %6 = OpLabel
  1030. %12 = OpPhi %9 %10 %5 %13 %8
  1031. OpLoopMerge %7 %8 None
  1032. OpBranch %8
  1033. %8 = OpLabel
  1034. %13 = OpCopyObject %9 %10
  1035. OpBranchConditional %10 %6 %7
  1036. %7 = OpLabel
  1037. OpReturn
  1038. OpFunctionEnd
  1039. )";
  1040. const auto env = SPV_ENV_UNIVERSAL_1_4;
  1041. const auto consumer = nullptr;
  1042. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1043. spvtools::ValidatorOptions validator_options;
  1044. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1045. kConsoleMessageConsumer));
  1046. TransformationContext transformation_context(
  1047. MakeUnique<FactManager>(context.get()), validator_options);
  1048. TransformationOutlineFunction transformation(6, 7, 100, 101, 102, 103, 104,
  1049. 105, {}, {});
  1050. ASSERT_FALSE(
  1051. transformation.IsApplicable(context.get(), transformation_context));
  1052. }
  1053. TEST(TransformationOutlineFunctionTest,
  1054. DoNotOutlineSelectionHeaderNotInRegion) {
  1055. std::string shader = R"(
  1056. OpCapability Shader
  1057. %1 = OpExtInstImport "GLSL.std.450"
  1058. OpMemoryModel Logical GLSL450
  1059. OpEntryPoint Fragment %4 "main"
  1060. OpExecutionMode %4 OriginUpperLeft
  1061. OpSource ESSL 310
  1062. OpName %4 "main"
  1063. %2 = OpTypeVoid
  1064. %3 = OpTypeFunction %2
  1065. %6 = OpTypeBool
  1066. %7 = OpConstantTrue %6
  1067. %4 = OpFunction %2 None %3
  1068. %5 = OpLabel
  1069. OpSelectionMerge %10 None
  1070. OpBranchConditional %7 %8 %8
  1071. %8 = OpLabel
  1072. OpBranch %9
  1073. %9 = OpLabel
  1074. OpBranch %10
  1075. %10 = OpLabel
  1076. OpBranch %11
  1077. %11 = OpLabel
  1078. OpReturn
  1079. OpFunctionEnd
  1080. )";
  1081. const auto env = SPV_ENV_UNIVERSAL_1_4;
  1082. const auto consumer = nullptr;
  1083. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1084. spvtools::ValidatorOptions validator_options;
  1085. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1086. kConsoleMessageConsumer));
  1087. TransformationContext transformation_context(
  1088. MakeUnique<FactManager>(context.get()), validator_options);
  1089. TransformationOutlineFunction transformation(8, 11, 100, 101, 102, 103, 104,
  1090. 105, {}, {});
  1091. ASSERT_FALSE(
  1092. transformation.IsApplicable(context.get(), transformation_context));
  1093. }
  1094. TEST(TransformationOutlineFunctionTest, OutlineRegionEndingWithReturnVoid) {
  1095. std::string shader = R"(
  1096. OpCapability Shader
  1097. %1 = OpExtInstImport "GLSL.std.450"
  1098. OpMemoryModel Logical GLSL450
  1099. OpEntryPoint Fragment %4 "main"
  1100. OpExecutionMode %4 OriginUpperLeft
  1101. OpSource ESSL 310
  1102. %20 = OpTypeInt 32 0
  1103. %21 = OpConstant %20 1
  1104. %2 = OpTypeVoid
  1105. %3 = OpTypeFunction %2
  1106. %4 = OpFunction %2 None %3
  1107. %5 = OpLabel
  1108. %22 = OpCopyObject %20 %21
  1109. OpBranch %54
  1110. %54 = OpLabel
  1111. OpBranch %57
  1112. %57 = OpLabel
  1113. %23 = OpCopyObject %20 %22
  1114. OpBranch %58
  1115. %58 = OpLabel
  1116. OpReturn
  1117. OpFunctionEnd
  1118. )";
  1119. const auto env = SPV_ENV_UNIVERSAL_1_5;
  1120. const auto consumer = nullptr;
  1121. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1122. spvtools::ValidatorOptions validator_options;
  1123. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1124. kConsoleMessageConsumer));
  1125. TransformationContext transformation_context(
  1126. MakeUnique<FactManager>(context.get()), validator_options);
  1127. TransformationOutlineFunction transformation(
  1128. /*entry_block*/ 54,
  1129. /*exit_block*/ 58,
  1130. /*new_function_struct_return_type_id*/ 200,
  1131. /*new_function_type_id*/ 201,
  1132. /*new_function_id*/ 202,
  1133. /*new_function_region_entry_block*/ 203,
  1134. /*new_caller_result_id*/ 204,
  1135. /*new_callee_result_id*/ 205,
  1136. /*input_id_to_fresh_id*/ {{22, 206}},
  1137. /*output_id_to_fresh_id*/ {});
  1138. ASSERT_TRUE(
  1139. transformation.IsApplicable(context.get(), transformation_context));
  1140. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  1141. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1142. kConsoleMessageConsumer));
  1143. std::string after_transformation = R"(
  1144. OpCapability Shader
  1145. %1 = OpExtInstImport "GLSL.std.450"
  1146. OpMemoryModel Logical GLSL450
  1147. OpEntryPoint Fragment %4 "main"
  1148. OpExecutionMode %4 OriginUpperLeft
  1149. OpSource ESSL 310
  1150. %20 = OpTypeInt 32 0
  1151. %21 = OpConstant %20 1
  1152. %2 = OpTypeVoid
  1153. %3 = OpTypeFunction %2
  1154. %201 = OpTypeFunction %2 %20
  1155. %4 = OpFunction %2 None %3
  1156. %5 = OpLabel
  1157. %22 = OpCopyObject %20 %21
  1158. OpBranch %54
  1159. %54 = OpLabel
  1160. %204 = OpFunctionCall %2 %202 %22
  1161. OpReturn
  1162. OpFunctionEnd
  1163. %202 = OpFunction %2 None %201
  1164. %206 = OpFunctionParameter %20
  1165. %203 = OpLabel
  1166. OpBranch %57
  1167. %57 = OpLabel
  1168. %23 = OpCopyObject %20 %206
  1169. OpBranch %58
  1170. %58 = OpLabel
  1171. OpReturn
  1172. OpFunctionEnd
  1173. )";
  1174. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  1175. }
  1176. TEST(TransformationOutlineFunctionTest, OutlineRegionEndingWithReturnValue) {
  1177. std::string shader = R"(
  1178. OpCapability Shader
  1179. %1 = OpExtInstImport "GLSL.std.450"
  1180. OpMemoryModel Logical GLSL450
  1181. OpEntryPoint Fragment %4 "main"
  1182. OpExecutionMode %4 OriginUpperLeft
  1183. OpSource ESSL 310
  1184. %20 = OpTypeInt 32 0
  1185. %21 = OpConstant %20 1
  1186. %2 = OpTypeVoid
  1187. %3 = OpTypeFunction %2
  1188. %30 = OpTypeFunction %20
  1189. %4 = OpFunction %2 None %3
  1190. %5 = OpLabel
  1191. %6 = OpFunctionCall %20 %100
  1192. OpReturn
  1193. OpFunctionEnd
  1194. %100 = OpFunction %20 None %30
  1195. %8 = OpLabel
  1196. %31 = OpCopyObject %20 %21
  1197. OpBranch %9
  1198. %9 = OpLabel
  1199. %32 = OpCopyObject %20 %31
  1200. OpBranch %10
  1201. %10 = OpLabel
  1202. OpReturnValue %32
  1203. OpFunctionEnd
  1204. )";
  1205. const auto env = SPV_ENV_UNIVERSAL_1_5;
  1206. const auto consumer = nullptr;
  1207. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1208. spvtools::ValidatorOptions validator_options;
  1209. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1210. kConsoleMessageConsumer));
  1211. TransformationContext transformation_context(
  1212. MakeUnique<FactManager>(context.get()), validator_options);
  1213. TransformationOutlineFunction transformation(
  1214. /*entry_block*/ 9,
  1215. /*exit_block*/ 10,
  1216. /*new_function_struct_return_type_id*/ 200,
  1217. /*new_function_type_id*/ 201,
  1218. /*new_function_id*/ 202,
  1219. /*new_function_region_entry_block*/ 203,
  1220. /*new_caller_result_id*/ 204,
  1221. /*new_callee_result_id*/ 205,
  1222. /*input_id_to_fresh_id*/ {{31, 206}},
  1223. /*output_id_to_fresh_id*/ {{32, 207}});
  1224. ASSERT_TRUE(
  1225. transformation.IsApplicable(context.get(), transformation_context));
  1226. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  1227. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1228. kConsoleMessageConsumer));
  1229. std::string after_transformation = R"(
  1230. OpCapability Shader
  1231. %1 = OpExtInstImport "GLSL.std.450"
  1232. OpMemoryModel Logical GLSL450
  1233. OpEntryPoint Fragment %4 "main"
  1234. OpExecutionMode %4 OriginUpperLeft
  1235. OpSource ESSL 310
  1236. %20 = OpTypeInt 32 0
  1237. %21 = OpConstant %20 1
  1238. %2 = OpTypeVoid
  1239. %3 = OpTypeFunction %2
  1240. %30 = OpTypeFunction %20
  1241. %200 = OpTypeStruct %20
  1242. %201 = OpTypeFunction %200 %20
  1243. %4 = OpFunction %2 None %3
  1244. %5 = OpLabel
  1245. %6 = OpFunctionCall %20 %100
  1246. OpReturn
  1247. OpFunctionEnd
  1248. %100 = OpFunction %20 None %30
  1249. %8 = OpLabel
  1250. %31 = OpCopyObject %20 %21
  1251. OpBranch %9
  1252. %9 = OpLabel
  1253. %204 = OpFunctionCall %200 %202 %31
  1254. %32 = OpCompositeExtract %20 %204 0
  1255. OpReturnValue %32
  1256. OpFunctionEnd
  1257. %202 = OpFunction %200 None %201
  1258. %206 = OpFunctionParameter %20
  1259. %203 = OpLabel
  1260. %207 = OpCopyObject %20 %206
  1261. OpBranch %10
  1262. %10 = OpLabel
  1263. %205 = OpCompositeConstruct %200 %207
  1264. OpReturnValue %205
  1265. OpFunctionEnd
  1266. )";
  1267. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  1268. }
  1269. TEST(TransformationOutlineFunctionTest,
  1270. OutlineRegionEndingWithConditionalBranch) {
  1271. std::string shader = R"(
  1272. OpCapability Shader
  1273. %1 = OpExtInstImport "GLSL.std.450"
  1274. OpMemoryModel Logical GLSL450
  1275. OpEntryPoint Fragment %4 "main"
  1276. OpExecutionMode %4 OriginUpperLeft
  1277. OpSource ESSL 310
  1278. %20 = OpTypeBool
  1279. %21 = OpConstantTrue %20
  1280. %2 = OpTypeVoid
  1281. %3 = OpTypeFunction %2
  1282. %4 = OpFunction %2 None %3
  1283. %5 = OpLabel
  1284. OpBranch %54
  1285. %54 = OpLabel
  1286. %6 = OpCopyObject %20 %21
  1287. OpSelectionMerge %8 None
  1288. OpBranchConditional %6 %7 %8
  1289. %7 = OpLabel
  1290. OpBranch %8
  1291. %8 = OpLabel
  1292. OpReturn
  1293. OpFunctionEnd
  1294. )";
  1295. const auto env = SPV_ENV_UNIVERSAL_1_5;
  1296. const auto consumer = nullptr;
  1297. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1298. spvtools::ValidatorOptions validator_options;
  1299. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1300. kConsoleMessageConsumer));
  1301. TransformationContext transformation_context(
  1302. MakeUnique<FactManager>(context.get()), validator_options);
  1303. TransformationOutlineFunction transformation(
  1304. /*entry_block*/ 54,
  1305. /*exit_block*/ 54,
  1306. /*new_function_struct_return_type_id*/ 200,
  1307. /*new_function_type_id*/ 201,
  1308. /*new_function_id*/ 202,
  1309. /*new_function_region_entry_block*/ 203,
  1310. /*new_caller_result_id*/ 204,
  1311. /*new_callee_result_id*/ 205,
  1312. /*input_id_to_fresh_id*/ {{}},
  1313. /*output_id_to_fresh_id*/ {{6, 206}});
  1314. ASSERT_TRUE(
  1315. transformation.IsApplicable(context.get(), transformation_context));
  1316. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  1317. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1318. kConsoleMessageConsumer));
  1319. std::string after_transformation = R"(
  1320. OpCapability Shader
  1321. %1 = OpExtInstImport "GLSL.std.450"
  1322. OpMemoryModel Logical GLSL450
  1323. OpEntryPoint Fragment %4 "main"
  1324. OpExecutionMode %4 OriginUpperLeft
  1325. OpSource ESSL 310
  1326. %20 = OpTypeBool
  1327. %21 = OpConstantTrue %20
  1328. %2 = OpTypeVoid
  1329. %3 = OpTypeFunction %2
  1330. %200 = OpTypeStruct %20
  1331. %201 = OpTypeFunction %200
  1332. %4 = OpFunction %2 None %3
  1333. %5 = OpLabel
  1334. OpBranch %54
  1335. %54 = OpLabel
  1336. %204 = OpFunctionCall %200 %202
  1337. %6 = OpCompositeExtract %20 %204 0
  1338. OpSelectionMerge %8 None
  1339. OpBranchConditional %6 %7 %8
  1340. %7 = OpLabel
  1341. OpBranch %8
  1342. %8 = OpLabel
  1343. OpReturn
  1344. OpFunctionEnd
  1345. %202 = OpFunction %200 None %201
  1346. %203 = OpLabel
  1347. %206 = OpCopyObject %20 %21
  1348. %205 = OpCompositeConstruct %200 %206
  1349. OpReturnValue %205
  1350. OpFunctionEnd
  1351. )";
  1352. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  1353. }
  1354. TEST(TransformationOutlineFunctionTest,
  1355. OutlineRegionEndingWithConditionalBranch2) {
  1356. std::string shader = R"(
  1357. OpCapability Shader
  1358. %1 = OpExtInstImport "GLSL.std.450"
  1359. OpMemoryModel Logical GLSL450
  1360. OpEntryPoint Fragment %4 "main"
  1361. OpExecutionMode %4 OriginUpperLeft
  1362. OpSource ESSL 310
  1363. %20 = OpTypeBool
  1364. %21 = OpConstantTrue %20
  1365. %2 = OpTypeVoid
  1366. %3 = OpTypeFunction %2
  1367. %4 = OpFunction %2 None %3
  1368. %5 = OpLabel
  1369. %6 = OpCopyObject %20 %21
  1370. OpBranch %54
  1371. %54 = OpLabel
  1372. OpSelectionMerge %8 None
  1373. OpBranchConditional %6 %7 %8
  1374. %7 = OpLabel
  1375. OpBranch %8
  1376. %8 = OpLabel
  1377. OpReturn
  1378. OpFunctionEnd
  1379. )";
  1380. const auto env = SPV_ENV_UNIVERSAL_1_5;
  1381. const auto consumer = nullptr;
  1382. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1383. spvtools::ValidatorOptions validator_options;
  1384. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1385. kConsoleMessageConsumer));
  1386. TransformationContext transformation_context(
  1387. MakeUnique<FactManager>(context.get()), validator_options);
  1388. TransformationOutlineFunction transformation(
  1389. /*entry_block*/ 54,
  1390. /*exit_block*/ 54,
  1391. /*new_function_struct_return_type_id*/ 200,
  1392. /*new_function_type_id*/ 201,
  1393. /*new_function_id*/ 202,
  1394. /*new_function_region_entry_block*/ 203,
  1395. /*new_caller_result_id*/ 204,
  1396. /*new_callee_result_id*/ 205,
  1397. /*input_id_to_fresh_id*/ {},
  1398. /*output_id_to_fresh_id*/ {});
  1399. ASSERT_TRUE(
  1400. transformation.IsApplicable(context.get(), transformation_context));
  1401. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  1402. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1403. kConsoleMessageConsumer));
  1404. std::string after_transformation = R"(
  1405. OpCapability Shader
  1406. %1 = OpExtInstImport "GLSL.std.450"
  1407. OpMemoryModel Logical GLSL450
  1408. OpEntryPoint Fragment %4 "main"
  1409. OpExecutionMode %4 OriginUpperLeft
  1410. OpSource ESSL 310
  1411. %20 = OpTypeBool
  1412. %21 = OpConstantTrue %20
  1413. %2 = OpTypeVoid
  1414. %3 = OpTypeFunction %2
  1415. %4 = OpFunction %2 None %3
  1416. %5 = OpLabel
  1417. %6 = OpCopyObject %20 %21
  1418. OpBranch %54
  1419. %54 = OpLabel
  1420. %204 = OpFunctionCall %2 %202
  1421. OpSelectionMerge %8 None
  1422. OpBranchConditional %6 %7 %8
  1423. %7 = OpLabel
  1424. OpBranch %8
  1425. %8 = OpLabel
  1426. OpReturn
  1427. OpFunctionEnd
  1428. %202 = OpFunction %2 None %3
  1429. %203 = OpLabel
  1430. OpReturn
  1431. OpFunctionEnd
  1432. )";
  1433. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  1434. }
  1435. TEST(TransformationOutlineFunctionTest, DoNotOutlineRegionThatStartsWithOpPhi) {
  1436. std::string shader = R"(
  1437. OpCapability Shader
  1438. %1 = OpExtInstImport "GLSL.std.450"
  1439. OpMemoryModel Logical GLSL450
  1440. OpEntryPoint Fragment %4 "main"
  1441. OpExecutionMode %4 OriginUpperLeft
  1442. OpSource ESSL 310
  1443. OpName %4 "main"
  1444. %2 = OpTypeVoid
  1445. %3 = OpTypeFunction %2
  1446. %6 = OpTypeBool
  1447. %7 = OpConstantTrue %6
  1448. %4 = OpFunction %2 None %3
  1449. %5 = OpLabel
  1450. OpBranch %21
  1451. %21 = OpLabel
  1452. %22 = OpPhi %6 %7 %5
  1453. %23 = OpCopyObject %6 %22
  1454. OpBranch %24
  1455. %24 = OpLabel
  1456. %25 = OpCopyObject %6 %23
  1457. %26 = OpCopyObject %6 %22
  1458. OpReturn
  1459. OpFunctionEnd
  1460. )";
  1461. const auto env = SPV_ENV_UNIVERSAL_1_5;
  1462. const auto consumer = nullptr;
  1463. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1464. spvtools::ValidatorOptions validator_options;
  1465. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1466. kConsoleMessageConsumer));
  1467. TransformationContext transformation_context(
  1468. MakeUnique<FactManager>(context.get()), validator_options);
  1469. TransformationOutlineFunction transformation(
  1470. /*entry_block*/ 21,
  1471. /*exit_block*/ 21,
  1472. /*new_function_struct_return_type_id*/ 200,
  1473. /*new_function_type_id*/ 201,
  1474. /*new_function_id*/ 202,
  1475. /*new_function_region_entry_block*/ 204,
  1476. /*new_caller_result_id*/ 205,
  1477. /*new_callee_result_id*/ 206,
  1478. /*input_id_to_fresh_id*/ {{22, 207}},
  1479. /*output_id_to_fresh_id*/ {{23, 208}});
  1480. ASSERT_FALSE(
  1481. transformation.IsApplicable(context.get(), transformation_context));
  1482. }
  1483. TEST(TransformationOutlineFunctionTest,
  1484. DoNotOutlineRegionThatStartsWithLoopHeader) {
  1485. std::string shader = R"(
  1486. OpCapability Shader
  1487. %1 = OpExtInstImport "GLSL.std.450"
  1488. OpMemoryModel Logical GLSL450
  1489. OpEntryPoint Fragment %4 "main"
  1490. OpExecutionMode %4 OriginUpperLeft
  1491. OpSource ESSL 310
  1492. OpName %4 "main"
  1493. %2 = OpTypeVoid
  1494. %3 = OpTypeFunction %2
  1495. %6 = OpTypeBool
  1496. %7 = OpConstantTrue %6
  1497. %4 = OpFunction %2 None %3
  1498. %5 = OpLabel
  1499. OpBranch %21
  1500. %21 = OpLabel
  1501. OpLoopMerge %22 %23 None
  1502. OpBranch %24
  1503. %24 = OpLabel
  1504. OpBranchConditional %7 %22 %23
  1505. %23 = OpLabel
  1506. OpBranch %21
  1507. %22 = OpLabel
  1508. OpBranch %25
  1509. %25 = OpLabel
  1510. OpReturn
  1511. OpFunctionEnd
  1512. )";
  1513. const auto env = SPV_ENV_UNIVERSAL_1_5;
  1514. const auto consumer = nullptr;
  1515. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1516. spvtools::ValidatorOptions validator_options;
  1517. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1518. kConsoleMessageConsumer));
  1519. TransformationContext transformation_context(
  1520. MakeUnique<FactManager>(context.get()), validator_options);
  1521. TransformationOutlineFunction transformation(
  1522. /*entry_block*/ 21,
  1523. /*exit_block*/ 24,
  1524. /*new_function_struct_return_type_id*/ 200,
  1525. /*new_function_type_id*/ 201,
  1526. /*new_function_id*/ 202,
  1527. /*new_function_region_entry_block*/ 204,
  1528. /*new_caller_result_id*/ 205,
  1529. /*new_callee_result_id*/ 206,
  1530. /*input_id_to_fresh_id*/ {},
  1531. /*output_id_to_fresh_id*/ {});
  1532. ASSERT_FALSE(
  1533. transformation.IsApplicable(context.get(), transformation_context));
  1534. }
  1535. TEST(TransformationOutlineFunctionTest,
  1536. DoNotOutlineRegionThatEndsWithLoopMerge) {
  1537. std::string shader = R"(
  1538. OpCapability Shader
  1539. %1 = OpExtInstImport "GLSL.std.450"
  1540. OpMemoryModel Logical GLSL450
  1541. OpEntryPoint Fragment %4 "main"
  1542. OpExecutionMode %4 OriginUpperLeft
  1543. OpSource ESSL 310
  1544. OpName %4 "main"
  1545. %2 = OpTypeVoid
  1546. %3 = OpTypeFunction %2
  1547. %6 = OpTypeBool
  1548. %7 = OpConstantTrue %6
  1549. %4 = OpFunction %2 None %3
  1550. %5 = OpLabel
  1551. OpBranch %21
  1552. %21 = OpLabel
  1553. OpLoopMerge %22 %23 None
  1554. OpBranch %24
  1555. %24 = OpLabel
  1556. OpBranchConditional %7 %22 %23
  1557. %23 = OpLabel
  1558. OpBranch %21
  1559. %22 = OpLabel
  1560. OpBranch %25
  1561. %25 = OpLabel
  1562. OpReturn
  1563. OpFunctionEnd
  1564. )";
  1565. const auto env = SPV_ENV_UNIVERSAL_1_5;
  1566. const auto consumer = nullptr;
  1567. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1568. spvtools::ValidatorOptions validator_options;
  1569. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1570. kConsoleMessageConsumer));
  1571. TransformationContext transformation_context(
  1572. MakeUnique<FactManager>(context.get()), validator_options);
  1573. TransformationOutlineFunction transformation(
  1574. /*entry_block*/ 5,
  1575. /*exit_block*/ 22,
  1576. /*new_function_struct_return_type_id*/ 200,
  1577. /*new_function_type_id*/ 201,
  1578. /*new_function_id*/ 202,
  1579. /*new_function_region_entry_block*/ 204,
  1580. /*new_caller_result_id*/ 205,
  1581. /*new_callee_result_id*/ 206,
  1582. /*input_id_to_fresh_id*/ {},
  1583. /*output_id_to_fresh_id*/ {});
  1584. ASSERT_FALSE(
  1585. transformation.IsApplicable(context.get(), transformation_context));
  1586. }
  1587. TEST(TransformationOutlineFunctionTest, DoNotOutlineRegionThatUsesAccessChain) {
  1588. // An access chain result is a pointer, but it cannot be passed as a function
  1589. // parameter, as it is not a memory object.
  1590. std::string shader = R"(
  1591. OpCapability Shader
  1592. %1 = OpExtInstImport "GLSL.std.450"
  1593. OpMemoryModel Logical GLSL450
  1594. OpEntryPoint Fragment %4 "main"
  1595. OpExecutionMode %4 OriginUpperLeft
  1596. OpSource ESSL 310
  1597. OpName %4 "main"
  1598. %2 = OpTypeVoid
  1599. %3 = OpTypeFunction %2
  1600. %6 = OpTypeFloat 32
  1601. %7 = OpTypeVector %6 4
  1602. %8 = OpTypePointer Function %7
  1603. %9 = OpTypePointer Function %6
  1604. %18 = OpTypeInt 32 0
  1605. %19 = OpConstant %18 0
  1606. %4 = OpFunction %2 None %3
  1607. %5 = OpLabel
  1608. %10 = OpVariable %8 Function
  1609. OpBranch %11
  1610. %11 = OpLabel
  1611. %12 = OpAccessChain %9 %10 %19
  1612. OpBranch %13
  1613. %13 = OpLabel
  1614. %14 = OpLoad %6 %12
  1615. OpBranch %15
  1616. %15 = OpLabel
  1617. OpReturn
  1618. OpFunctionEnd
  1619. )";
  1620. const auto env = SPV_ENV_UNIVERSAL_1_5;
  1621. const auto consumer = nullptr;
  1622. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1623. spvtools::ValidatorOptions validator_options;
  1624. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1625. kConsoleMessageConsumer));
  1626. TransformationContext transformation_context(
  1627. MakeUnique<FactManager>(context.get()), validator_options);
  1628. TransformationOutlineFunction transformation(
  1629. /*entry_block*/ 13,
  1630. /*exit_block*/ 15,
  1631. /*new_function_struct_return_type_id*/ 200,
  1632. /*new_function_type_id*/ 201,
  1633. /*new_function_id*/ 202,
  1634. /*new_function_region_entry_block*/ 204,
  1635. /*new_caller_result_id*/ 205,
  1636. /*new_callee_result_id*/ 206,
  1637. /*input_id_to_fresh_id*/ {{12, 207}},
  1638. /*output_id_to_fresh_id*/ {});
  1639. ASSERT_FALSE(
  1640. transformation.IsApplicable(context.get(), transformation_context));
  1641. }
  1642. TEST(TransformationOutlineFunctionTest,
  1643. DoNotOutlineRegionThatUsesCopiedObject) {
  1644. // Copying a variable leads to a pointer, but one that cannot be passed as a
  1645. // function parameter, as it is not a memory object.
  1646. std::string shader = R"(
  1647. OpCapability Shader
  1648. %1 = OpExtInstImport "GLSL.std.450"
  1649. OpMemoryModel Logical GLSL450
  1650. OpEntryPoint Fragment %4 "main"
  1651. OpExecutionMode %4 OriginUpperLeft
  1652. OpSource ESSL 310
  1653. OpName %4 "main"
  1654. %2 = OpTypeVoid
  1655. %3 = OpTypeFunction %2
  1656. %6 = OpTypeFloat 32
  1657. %7 = OpTypeVector %6 4
  1658. %8 = OpTypePointer Function %7
  1659. %9 = OpTypePointer Function %6
  1660. %18 = OpTypeInt 32 0
  1661. %19 = OpConstant %18 0
  1662. %4 = OpFunction %2 None %3
  1663. %5 = OpLabel
  1664. %10 = OpVariable %8 Function
  1665. OpBranch %11
  1666. %11 = OpLabel
  1667. %20 = OpCopyObject %8 %10
  1668. OpBranch %13
  1669. %13 = OpLabel
  1670. %12 = OpAccessChain %9 %20 %19
  1671. %14 = OpLoad %6 %12
  1672. OpBranch %15
  1673. %15 = OpLabel
  1674. OpReturn
  1675. OpFunctionEnd
  1676. )";
  1677. const auto env = SPV_ENV_UNIVERSAL_1_5;
  1678. const auto consumer = nullptr;
  1679. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1680. spvtools::ValidatorOptions validator_options;
  1681. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1682. kConsoleMessageConsumer));
  1683. TransformationContext transformation_context(
  1684. MakeUnique<FactManager>(context.get()), validator_options);
  1685. TransformationOutlineFunction transformation(
  1686. /*entry_block*/ 13,
  1687. /*exit_block*/ 15,
  1688. /*new_function_struct_return_type_id*/ 200,
  1689. /*new_function_type_id*/ 201,
  1690. /*new_function_id*/ 202,
  1691. /*new_function_region_entry_block*/ 204,
  1692. /*new_caller_result_id*/ 205,
  1693. /*new_callee_result_id*/ 206,
  1694. /*input_id_to_fresh_id*/ {{20, 207}},
  1695. /*output_id_to_fresh_id*/ {});
  1696. ASSERT_FALSE(
  1697. transformation.IsApplicable(context.get(), transformation_context));
  1698. }
  1699. TEST(TransformationOutlineFunctionTest,
  1700. DoOutlineRegionThatUsesPointerParameter) {
  1701. // The region being outlined reads from a function parameter of pointer type.
  1702. // This is OK: the function parameter can itself be passed on as a function
  1703. // parameter.
  1704. std::string shader = R"(
  1705. OpCapability Shader
  1706. %1 = OpExtInstImport "GLSL.std.450"
  1707. OpMemoryModel Logical GLSL450
  1708. OpEntryPoint Fragment %4 "main"
  1709. OpExecutionMode %4 OriginUpperLeft
  1710. OpSource ESSL 310
  1711. %2 = OpTypeVoid
  1712. %3 = OpTypeFunction %2
  1713. %6 = OpTypeInt 32 1
  1714. %7 = OpTypePointer Function %6
  1715. %8 = OpTypeFunction %2 %7
  1716. %13 = OpConstant %6 2
  1717. %4 = OpFunction %2 None %3
  1718. %5 = OpLabel
  1719. %15 = OpVariable %7 Function
  1720. %16 = OpVariable %7 Function
  1721. %17 = OpLoad %6 %15
  1722. OpStore %16 %17
  1723. %18 = OpFunctionCall %2 %10 %16
  1724. %19 = OpLoad %6 %16
  1725. OpStore %15 %19
  1726. OpReturn
  1727. OpFunctionEnd
  1728. %10 = OpFunction %2 None %8
  1729. %9 = OpFunctionParameter %7
  1730. %11 = OpLabel
  1731. %12 = OpLoad %6 %9
  1732. %14 = OpIAdd %6 %12 %13
  1733. OpBranch %20
  1734. %20 = OpLabel
  1735. OpStore %9 %14
  1736. OpReturn
  1737. OpFunctionEnd
  1738. )";
  1739. const auto env = SPV_ENV_UNIVERSAL_1_5;
  1740. const auto consumer = nullptr;
  1741. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1742. spvtools::ValidatorOptions validator_options;
  1743. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1744. kConsoleMessageConsumer));
  1745. TransformationContext transformation_context(
  1746. MakeUnique<FactManager>(context.get()), validator_options);
  1747. TransformationOutlineFunction transformation(
  1748. /*entry_block*/ 11,
  1749. /*exit_block*/ 11,
  1750. /*new_function_struct_return_type_id*/ 200,
  1751. /*new_function_type_id*/ 201,
  1752. /*new_function_id*/ 202,
  1753. /*new_function_region_entry_block*/ 204,
  1754. /*new_caller_result_id*/ 205,
  1755. /*new_callee_result_id*/ 206,
  1756. /*input_id_to_fresh_id*/ {{9, 207}},
  1757. /*output_id_to_fresh_id*/ {{14, 208}});
  1758. ASSERT_TRUE(
  1759. transformation.IsApplicable(context.get(), transformation_context));
  1760. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  1761. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1762. kConsoleMessageConsumer));
  1763. std::string after_transformation = R"(
  1764. OpCapability Shader
  1765. %1 = OpExtInstImport "GLSL.std.450"
  1766. OpMemoryModel Logical GLSL450
  1767. OpEntryPoint Fragment %4 "main"
  1768. OpExecutionMode %4 OriginUpperLeft
  1769. OpSource ESSL 310
  1770. %2 = OpTypeVoid
  1771. %3 = OpTypeFunction %2
  1772. %6 = OpTypeInt 32 1
  1773. %7 = OpTypePointer Function %6
  1774. %8 = OpTypeFunction %2 %7
  1775. %13 = OpConstant %6 2
  1776. %200 = OpTypeStruct %6
  1777. %201 = OpTypeFunction %200 %7
  1778. %4 = OpFunction %2 None %3
  1779. %5 = OpLabel
  1780. %15 = OpVariable %7 Function
  1781. %16 = OpVariable %7 Function
  1782. %17 = OpLoad %6 %15
  1783. OpStore %16 %17
  1784. %18 = OpFunctionCall %2 %10 %16
  1785. %19 = OpLoad %6 %16
  1786. OpStore %15 %19
  1787. OpReturn
  1788. OpFunctionEnd
  1789. %10 = OpFunction %2 None %8
  1790. %9 = OpFunctionParameter %7
  1791. %11 = OpLabel
  1792. %205 = OpFunctionCall %200 %202 %9
  1793. %14 = OpCompositeExtract %6 %205 0
  1794. OpBranch %20
  1795. %20 = OpLabel
  1796. OpStore %9 %14
  1797. OpReturn
  1798. OpFunctionEnd
  1799. %202 = OpFunction %200 None %201
  1800. %207 = OpFunctionParameter %7
  1801. %204 = OpLabel
  1802. %12 = OpLoad %6 %207
  1803. %208 = OpIAdd %6 %12 %13
  1804. %206 = OpCompositeConstruct %200 %208
  1805. OpReturnValue %206
  1806. OpFunctionEnd
  1807. )";
  1808. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  1809. }
  1810. TEST(TransformationOutlineFunctionTest, OutlineLivesafe) {
  1811. // In the following, %30 is a livesafe function, with irrelevant parameter
  1812. // %200 and irrelevant local variable %201. Variable %100 is a loop limiter,
  1813. // which is not irrelevant. The test checks that the outlined function is
  1814. // livesafe, and that the parameters corresponding to %200 and %201 have the
  1815. // irrelevant fact associated with them.
  1816. std::string shader = R"(
  1817. OpCapability Shader
  1818. %1 = OpExtInstImport "GLSL.std.450"
  1819. OpMemoryModel Logical GLSL450
  1820. OpEntryPoint Fragment %4 "main"
  1821. OpExecutionMode %4 OriginUpperLeft
  1822. OpSource ESSL 310
  1823. %2 = OpTypeVoid
  1824. %3 = OpTypeFunction %2
  1825. %6 = OpTypeInt 32 0
  1826. %7 = OpTypePointer Function %6
  1827. %199 = OpTypeFunction %2 %7
  1828. %8 = OpConstant %6 0
  1829. %9 = OpConstant %6 1
  1830. %10 = OpConstant %6 5
  1831. %11 = OpTypeBool
  1832. %12 = OpConstantTrue %11
  1833. %4 = OpFunction %2 None %3
  1834. %5 = OpLabel
  1835. OpReturn
  1836. OpFunctionEnd
  1837. %30 = OpFunction %2 None %199
  1838. %200 = OpFunctionParameter %7
  1839. %31 = OpLabel
  1840. %100 = OpVariable %7 Function %8
  1841. %201 = OpVariable %7 Function %8
  1842. OpBranch %198
  1843. %198 = OpLabel
  1844. OpBranch %20
  1845. %20 = OpLabel
  1846. %101 = OpLoad %6 %100
  1847. %102 = OpIAdd %6 %101 %9
  1848. %202 = OpLoad %6 %200
  1849. OpStore %201 %202
  1850. OpStore %100 %102
  1851. %103 = OpUGreaterThanEqual %11 %101 %10
  1852. OpLoopMerge %21 %22 None
  1853. OpBranchConditional %103 %21 %104
  1854. %104 = OpLabel
  1855. OpBranchConditional %12 %23 %21
  1856. %23 = OpLabel
  1857. %105 = OpLoad %6 %100
  1858. %106 = OpIAdd %6 %105 %9
  1859. OpStore %100 %106
  1860. %107 = OpUGreaterThanEqual %11 %105 %10
  1861. OpLoopMerge %25 %26 None
  1862. OpBranchConditional %107 %25 %108
  1863. %108 = OpLabel
  1864. OpBranch %28
  1865. %28 = OpLabel
  1866. OpBranchConditional %12 %26 %25
  1867. %26 = OpLabel
  1868. OpBranch %23
  1869. %25 = OpLabel
  1870. %109 = OpLoad %6 %100
  1871. %110 = OpIAdd %6 %109 %9
  1872. OpStore %100 %110
  1873. %111 = OpUGreaterThanEqual %11 %109 %10
  1874. OpLoopMerge %24 %27 None
  1875. OpBranchConditional %111 %24 %112
  1876. %112 = OpLabel
  1877. OpBranchConditional %12 %24 %27
  1878. %27 = OpLabel
  1879. OpBranch %25
  1880. %24 = OpLabel
  1881. OpBranch %22
  1882. %22 = OpLabel
  1883. OpBranch %20
  1884. %21 = OpLabel
  1885. OpBranch %197
  1886. %197 = OpLabel
  1887. OpReturn
  1888. OpFunctionEnd
  1889. )";
  1890. const auto env = SPV_ENV_UNIVERSAL_1_5;
  1891. const auto consumer = nullptr;
  1892. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1893. spvtools::ValidatorOptions validator_options;
  1894. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1895. kConsoleMessageConsumer));
  1896. TransformationContext transformation_context(
  1897. MakeUnique<FactManager>(context.get()), validator_options);
  1898. transformation_context.GetFactManager()->AddFactFunctionIsLivesafe(30);
  1899. transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
  1900. 200);
  1901. transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
  1902. 201);
  1903. TransformationOutlineFunction transformation(
  1904. /*entry_block*/ 198,
  1905. /*exit_block*/ 197,
  1906. /*new_function_struct_return_type_id*/ 400,
  1907. /*new_function_type_id*/ 401,
  1908. /*new_function_id*/ 402,
  1909. /*new_function_region_entry_block*/ 404,
  1910. /*new_caller_result_id*/ 405,
  1911. /*new_callee_result_id*/ 406,
  1912. /*input_id_to_fresh_id*/ {{100, 407}, {200, 408}, {201, 409}},
  1913. /*output_id_to_fresh_id*/ {});
  1914. ASSERT_TRUE(
  1915. transformation.IsApplicable(context.get(), transformation_context));
  1916. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  1917. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1918. kConsoleMessageConsumer));
  1919. // The original function should still be livesafe.
  1920. ASSERT_TRUE(transformation_context.GetFactManager()->FunctionIsLivesafe(30));
  1921. // The outlined function should be livesafe.
  1922. ASSERT_TRUE(transformation_context.GetFactManager()->FunctionIsLivesafe(402));
  1923. // The variable and parameter that were originally irrelevant should still be.
  1924. ASSERT_TRUE(
  1925. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(200));
  1926. ASSERT_TRUE(
  1927. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(201));
  1928. // The loop limiter should still be non-irrelevant.
  1929. ASSERT_FALSE(
  1930. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(100));
  1931. // The parameters for the original irrelevant variables should be irrelevant.
  1932. ASSERT_TRUE(
  1933. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(408));
  1934. ASSERT_TRUE(
  1935. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(409));
  1936. // The parameter for the loop limiter should not be irrelevant.
  1937. ASSERT_FALSE(
  1938. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(407));
  1939. std::string after_transformation = R"(
  1940. OpCapability Shader
  1941. %1 = OpExtInstImport "GLSL.std.450"
  1942. OpMemoryModel Logical GLSL450
  1943. OpEntryPoint Fragment %4 "main"
  1944. OpExecutionMode %4 OriginUpperLeft
  1945. OpSource ESSL 310
  1946. %2 = OpTypeVoid
  1947. %3 = OpTypeFunction %2
  1948. %6 = OpTypeInt 32 0
  1949. %7 = OpTypePointer Function %6
  1950. %199 = OpTypeFunction %2 %7
  1951. %8 = OpConstant %6 0
  1952. %9 = OpConstant %6 1
  1953. %10 = OpConstant %6 5
  1954. %11 = OpTypeBool
  1955. %12 = OpConstantTrue %11
  1956. %401 = OpTypeFunction %2 %7 %7 %7
  1957. %4 = OpFunction %2 None %3
  1958. %5 = OpLabel
  1959. OpReturn
  1960. OpFunctionEnd
  1961. %30 = OpFunction %2 None %199
  1962. %200 = OpFunctionParameter %7
  1963. %31 = OpLabel
  1964. %100 = OpVariable %7 Function %8
  1965. %201 = OpVariable %7 Function %8
  1966. OpBranch %198
  1967. %198 = OpLabel
  1968. %405 = OpFunctionCall %2 %402 %200 %100 %201
  1969. OpReturn
  1970. OpFunctionEnd
  1971. %402 = OpFunction %2 None %401
  1972. %408 = OpFunctionParameter %7
  1973. %407 = OpFunctionParameter %7
  1974. %409 = OpFunctionParameter %7
  1975. %404 = OpLabel
  1976. OpBranch %20
  1977. %20 = OpLabel
  1978. %101 = OpLoad %6 %407
  1979. %102 = OpIAdd %6 %101 %9
  1980. %202 = OpLoad %6 %408
  1981. OpStore %409 %202
  1982. OpStore %407 %102
  1983. %103 = OpUGreaterThanEqual %11 %101 %10
  1984. OpLoopMerge %21 %22 None
  1985. OpBranchConditional %103 %21 %104
  1986. %104 = OpLabel
  1987. OpBranchConditional %12 %23 %21
  1988. %23 = OpLabel
  1989. %105 = OpLoad %6 %407
  1990. %106 = OpIAdd %6 %105 %9
  1991. OpStore %407 %106
  1992. %107 = OpUGreaterThanEqual %11 %105 %10
  1993. OpLoopMerge %25 %26 None
  1994. OpBranchConditional %107 %25 %108
  1995. %108 = OpLabel
  1996. OpBranch %28
  1997. %28 = OpLabel
  1998. OpBranchConditional %12 %26 %25
  1999. %26 = OpLabel
  2000. OpBranch %23
  2001. %25 = OpLabel
  2002. %109 = OpLoad %6 %407
  2003. %110 = OpIAdd %6 %109 %9
  2004. OpStore %407 %110
  2005. %111 = OpUGreaterThanEqual %11 %109 %10
  2006. OpLoopMerge %24 %27 None
  2007. OpBranchConditional %111 %24 %112
  2008. %112 = OpLabel
  2009. OpBranchConditional %12 %24 %27
  2010. %27 = OpLabel
  2011. OpBranch %25
  2012. %24 = OpLabel
  2013. OpBranch %22
  2014. %22 = OpLabel
  2015. OpBranch %20
  2016. %21 = OpLabel
  2017. OpBranch %197
  2018. %197 = OpLabel
  2019. OpReturn
  2020. OpFunctionEnd
  2021. )";
  2022. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  2023. }
  2024. TEST(TransformationOutlineFunctionTest, OutlineWithDeadBlocks1) {
  2025. // This checks that if all blocks in the region being outlined were dead, all
  2026. // blocks in the outlined function will be dead.
  2027. std::string shader = R"(
  2028. OpCapability Shader
  2029. %1 = OpExtInstImport "GLSL.std.450"
  2030. OpMemoryModel Logical GLSL450
  2031. OpEntryPoint Fragment %4 "main"
  2032. OpExecutionMode %4 OriginUpperLeft
  2033. OpSource ESSL 310
  2034. OpName %4 "main"
  2035. OpName %10 "foo(i1;"
  2036. OpName %9 "x"
  2037. OpName %12 "y"
  2038. OpName %21 "i"
  2039. OpName %46 "param"
  2040. %2 = OpTypeVoid
  2041. %3 = OpTypeFunction %2
  2042. %6 = OpTypeInt 32 1
  2043. %7 = OpTypePointer Function %6
  2044. %8 = OpTypeFunction %2 %7
  2045. %13 = OpConstant %6 2
  2046. %14 = OpTypeBool
  2047. %15 = OpConstantFalse %14
  2048. %22 = OpConstant %6 0
  2049. %29 = OpConstant %6 10
  2050. %41 = OpConstant %6 1
  2051. %4 = OpFunction %2 None %3
  2052. %5 = OpLabel
  2053. %46 = OpVariable %7 Function
  2054. OpStore %46 %13
  2055. %47 = OpFunctionCall %2 %10 %46
  2056. OpReturn
  2057. OpFunctionEnd
  2058. %10 = OpFunction %2 None %8
  2059. %9 = OpFunctionParameter %7
  2060. %11 = OpLabel
  2061. %12 = OpVariable %7 Function
  2062. %21 = OpVariable %7 Function
  2063. OpStore %12 %13
  2064. OpSelectionMerge %17 None
  2065. OpBranchConditional %15 %16 %17
  2066. %16 = OpLabel
  2067. %18 = OpLoad %6 %9
  2068. OpStore %12 %18
  2069. %19 = OpLoad %6 %9
  2070. %20 = OpIAdd %6 %19 %13
  2071. OpStore %9 %20
  2072. OpStore %21 %22
  2073. OpBranch %23
  2074. %23 = OpLabel
  2075. OpLoopMerge %25 %26 None
  2076. OpBranch %27
  2077. %27 = OpLabel
  2078. %28 = OpLoad %6 %21
  2079. %30 = OpSLessThan %14 %28 %29
  2080. OpBranchConditional %30 %24 %25
  2081. %24 = OpLabel
  2082. %31 = OpLoad %6 %9
  2083. %32 = OpLoad %6 %21
  2084. %33 = OpSGreaterThan %14 %31 %32
  2085. OpSelectionMerge %35 None
  2086. OpBranchConditional %33 %34 %35
  2087. %34 = OpLabel
  2088. OpBranch %26
  2089. %35 = OpLabel
  2090. %37 = OpLoad %6 %9
  2091. %38 = OpLoad %6 %12
  2092. %39 = OpIAdd %6 %38 %37
  2093. OpStore %12 %39
  2094. OpBranch %26
  2095. %26 = OpLabel
  2096. %40 = OpLoad %6 %21
  2097. %42 = OpIAdd %6 %40 %41
  2098. OpStore %21 %42
  2099. OpBranch %23
  2100. %25 = OpLabel
  2101. OpBranch %50
  2102. %50 = OpLabel
  2103. OpBranch %17
  2104. %17 = OpLabel
  2105. %43 = OpLoad %6 %9
  2106. %44 = OpLoad %6 %12
  2107. %45 = OpIAdd %6 %44 %43
  2108. OpStore %12 %45
  2109. OpReturn
  2110. OpFunctionEnd
  2111. )";
  2112. const auto env = SPV_ENV_UNIVERSAL_1_5;
  2113. const auto consumer = nullptr;
  2114. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2115. spvtools::ValidatorOptions validator_options;
  2116. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2117. kConsoleMessageConsumer));
  2118. TransformationContext transformation_context(
  2119. MakeUnique<FactManager>(context.get()), validator_options);
  2120. for (uint32_t block_id : {16u, 23u, 24u, 26u, 27u, 34u, 35u, 50u}) {
  2121. transformation_context.GetFactManager()->AddFactBlockIsDead(block_id);
  2122. }
  2123. TransformationOutlineFunction transformation(
  2124. /*entry_block*/ 16,
  2125. /*exit_block*/ 50,
  2126. /*new_function_struct_return_type_id*/ 200,
  2127. /*new_function_type_id*/ 201,
  2128. /*new_function_id*/ 202,
  2129. /*new_function_region_entry_block*/ 203,
  2130. /*new_caller_result_id*/ 204,
  2131. /*new_callee_result_id*/ 205,
  2132. /*input_id_to_fresh_id*/ {{9, 206}, {12, 207}, {21, 208}},
  2133. /*output_id_to_fresh_id*/ {});
  2134. ASSERT_TRUE(
  2135. transformation.IsApplicable(context.get(), transformation_context));
  2136. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  2137. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2138. kConsoleMessageConsumer));
  2139. // All the original blocks, plus the new function entry block, should be dead.
  2140. for (uint32_t block_id : {16u, 23u, 24u, 26u, 27u, 34u, 35u, 50u, 203u}) {
  2141. ASSERT_TRUE(transformation_context.GetFactManager()->BlockIsDead(block_id));
  2142. }
  2143. }
  2144. TEST(TransformationOutlineFunctionTest, OutlineWithDeadBlocks2) {
  2145. // This checks that if some, but not all, blocks in the outlined region are
  2146. // dead, those (but not others) will be dead in the outlined function.
  2147. std::string shader = R"(
  2148. OpCapability Shader
  2149. %1 = OpExtInstImport "GLSL.std.450"
  2150. OpMemoryModel Logical GLSL450
  2151. OpEntryPoint Fragment %4 "main" %8
  2152. OpExecutionMode %4 OriginUpperLeft
  2153. OpSource ESSL 310
  2154. %2 = OpTypeVoid
  2155. %3 = OpTypeFunction %2
  2156. %6 = OpTypeBool
  2157. %7 = OpTypePointer Private %6
  2158. %8 = OpVariable %7 Private
  2159. %9 = OpConstantFalse %6
  2160. %10 = OpTypePointer Function %6
  2161. %12 = OpConstantTrue %6
  2162. %4 = OpFunction %2 None %3
  2163. %5 = OpLabel
  2164. %11 = OpVariable %10 Function
  2165. OpBranch %30
  2166. %30 = OpLabel
  2167. OpStore %8 %9
  2168. OpBranch %31
  2169. %31 = OpLabel
  2170. OpStore %11 %12
  2171. OpSelectionMerge %36 None
  2172. OpBranchConditional %9 %32 %33
  2173. %32 = OpLabel
  2174. OpBranch %34
  2175. %33 = OpLabel
  2176. OpBranch %36
  2177. %34 = OpLabel
  2178. OpBranch %35
  2179. %35 = OpLabel
  2180. OpBranch %36
  2181. %36 = OpLabel
  2182. OpBranch %37
  2183. %37 = OpLabel
  2184. %13 = OpLoad %6 %8
  2185. OpStore %11 %13
  2186. %14 = OpLoad %6 %11
  2187. OpStore %8 %14
  2188. OpReturn
  2189. OpFunctionEnd
  2190. )";
  2191. const auto env = SPV_ENV_UNIVERSAL_1_5;
  2192. const auto consumer = nullptr;
  2193. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2194. spvtools::ValidatorOptions validator_options;
  2195. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2196. kConsoleMessageConsumer));
  2197. TransformationContext transformation_context(
  2198. MakeUnique<FactManager>(context.get()), validator_options);
  2199. for (uint32_t block_id : {32u, 34u, 35u}) {
  2200. transformation_context.GetFactManager()->AddFactBlockIsDead(block_id);
  2201. }
  2202. TransformationOutlineFunction transformation(
  2203. /*entry_block*/ 30,
  2204. /*exit_block*/ 37,
  2205. /*new_function_struct_return_type_id*/ 200,
  2206. /*new_function_type_id*/ 201,
  2207. /*new_function_id*/ 202,
  2208. /*new_function_region_entry_block*/ 203,
  2209. /*new_caller_result_id*/ 204,
  2210. /*new_callee_result_id*/ 205,
  2211. /*input_id_to_fresh_id*/ {{11, 206}},
  2212. /*output_id_to_fresh_id*/ {});
  2213. ASSERT_TRUE(
  2214. transformation.IsApplicable(context.get(), transformation_context));
  2215. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  2216. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2217. kConsoleMessageConsumer));
  2218. // The blocks that were originally dead, but not others, should be dead.
  2219. for (uint32_t block_id : {32u, 34u, 35u}) {
  2220. ASSERT_TRUE(transformation_context.GetFactManager()->BlockIsDead(block_id));
  2221. }
  2222. for (uint32_t block_id : {5u, 30u, 31u, 33u, 36u, 37u, 203u}) {
  2223. ASSERT_FALSE(
  2224. transformation_context.GetFactManager()->BlockIsDead(block_id));
  2225. }
  2226. }
  2227. TEST(TransformationOutlineFunctionTest,
  2228. OutlineWithIrrelevantVariablesAndParameters) {
  2229. // This checks that if the outlined region uses a mixture of irrelevant and
  2230. // non-irrelevant variables and parameters, these properties are preserved
  2231. // during outlining.
  2232. std::string shader = R"(
  2233. OpCapability Shader
  2234. %1 = OpExtInstImport "GLSL.std.450"
  2235. OpMemoryModel Logical GLSL450
  2236. OpEntryPoint Fragment %4 "main"
  2237. OpExecutionMode %4 OriginUpperLeft
  2238. OpSource ESSL 310
  2239. %2 = OpTypeVoid
  2240. %3 = OpTypeFunction %2
  2241. %6 = OpTypeInt 32 1
  2242. %7 = OpTypePointer Function %6
  2243. %8 = OpTypeFunction %2 %7 %7
  2244. %13 = OpConstant %6 2
  2245. %15 = OpConstant %6 3
  2246. %4 = OpFunction %2 None %3
  2247. %5 = OpLabel
  2248. OpReturn
  2249. OpFunctionEnd
  2250. %11 = OpFunction %2 None %8
  2251. %9 = OpFunctionParameter %7
  2252. %10 = OpFunctionParameter %7
  2253. %12 = OpLabel
  2254. %14 = OpVariable %7 Function
  2255. %20 = OpVariable %7 Function
  2256. OpBranch %50
  2257. %50 = OpLabel
  2258. OpStore %9 %13
  2259. OpStore %14 %15
  2260. %16 = OpLoad %6 %14
  2261. OpStore %10 %16
  2262. %17 = OpLoad %6 %9
  2263. %18 = OpLoad %6 %10
  2264. %19 = OpIAdd %6 %17 %18
  2265. OpStore %14 %19
  2266. %21 = OpLoad %6 %9
  2267. OpStore %20 %21
  2268. OpReturn
  2269. OpFunctionEnd
  2270. )";
  2271. const auto env = SPV_ENV_UNIVERSAL_1_5;
  2272. const auto consumer = nullptr;
  2273. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2274. spvtools::ValidatorOptions validator_options;
  2275. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2276. kConsoleMessageConsumer));
  2277. TransformationContext transformation_context(
  2278. MakeUnique<FactManager>(context.get()), validator_options);
  2279. transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(9);
  2280. transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
  2281. 14);
  2282. TransformationOutlineFunction transformation(
  2283. /*entry_block*/ 50,
  2284. /*exit_block*/ 50,
  2285. /*new_function_struct_return_type_id*/ 200,
  2286. /*new_function_type_id*/ 201,
  2287. /*new_function_id*/ 202,
  2288. /*new_function_region_entry_block*/ 203,
  2289. /*new_caller_result_id*/ 204,
  2290. /*new_callee_result_id*/ 205,
  2291. /*input_id_to_fresh_id*/ {{9, 206}, {10, 207}, {14, 208}, {20, 209}},
  2292. /*output_id_to_fresh_id*/ {});
  2293. ASSERT_TRUE(
  2294. transformation.IsApplicable(context.get(), transformation_context));
  2295. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  2296. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2297. kConsoleMessageConsumer));
  2298. // The variables that were originally irrelevant, plus input parameters
  2299. // corresponding to them, should be irrelevant. The rest should not be.
  2300. for (uint32_t variable_id : {9u, 14u, 206u, 208u}) {
  2301. ASSERT_TRUE(
  2302. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(
  2303. variable_id));
  2304. }
  2305. for (uint32_t variable_id : {10u, 20u, 207u, 209u}) {
  2306. ASSERT_FALSE(
  2307. transformation_context.GetFactManager()->BlockIsDead(variable_id));
  2308. }
  2309. }
  2310. TEST(TransformationOutlineFunctionTest,
  2311. DoNotOutlineCodeThatProducesUsedPointer) {
  2312. // This checks that we cannot outline a region of code if it produces a
  2313. // pointer result id that gets used outside the region. This avoids creating
  2314. // a struct with a pointer member.
  2315. std::string shader = R"(
  2316. OpCapability Shader
  2317. %1 = OpExtInstImport "GLSL.std.450"
  2318. OpMemoryModel Logical GLSL450
  2319. OpEntryPoint Fragment %6 "main"
  2320. OpExecutionMode %6 OriginUpperLeft
  2321. OpSource ESSL 310
  2322. %2 = OpTypeVoid
  2323. %3 = OpTypeFunction %2
  2324. %21 = OpTypeBool
  2325. %100 = OpTypeInt 32 0
  2326. %99 = OpConstant %100 0
  2327. %101 = OpTypeVector %100 2
  2328. %102 = OpTypePointer Function %100
  2329. %103 = OpTypePointer Function %101
  2330. %6 = OpFunction %2 None %3
  2331. %7 = OpLabel
  2332. %104 = OpVariable %103 Function
  2333. OpBranch %80
  2334. %80 = OpLabel
  2335. %105 = OpAccessChain %102 %104 %99
  2336. OpBranch %106
  2337. %106 = OpLabel
  2338. OpStore %105 %99
  2339. OpReturn
  2340. OpFunctionEnd
  2341. )";
  2342. const auto env = SPV_ENV_UNIVERSAL_1_5;
  2343. const auto consumer = nullptr;
  2344. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2345. spvtools::ValidatorOptions validator_options;
  2346. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2347. kConsoleMessageConsumer));
  2348. TransformationContext transformation_context(
  2349. MakeUnique<FactManager>(context.get()), validator_options);
  2350. TransformationOutlineFunction transformation(
  2351. /*entry_block*/ 80,
  2352. /*exit_block*/ 80,
  2353. /*new_function_struct_return_type_id*/ 300,
  2354. /*new_function_type_id*/ 301,
  2355. /*new_function_id*/ 302,
  2356. /*new_function_region_entry_block*/ 304,
  2357. /*new_caller_result_id*/ 305,
  2358. /*new_callee_result_id*/ 306,
  2359. /*input_id_to_fresh_id*/ {{104, 307}},
  2360. /*output_id_to_fresh_id*/ {{105, 308}});
  2361. ASSERT_FALSE(
  2362. transformation.IsApplicable(context.get(), transformation_context));
  2363. }
  2364. TEST(TransformationOutlineFunctionTest, ExitBlockHeadsLoop) {
  2365. // This checks that it is not possible outline a region that ends in a loop
  2366. // head.
  2367. std::string shader = R"(
  2368. OpCapability Shader
  2369. %1 = OpExtInstImport "GLSL.std.450"
  2370. OpMemoryModel Logical GLSL450
  2371. OpEntryPoint Fragment %4 "main"
  2372. OpExecutionMode %4 OriginUpperLeft
  2373. OpSource ESSL 310
  2374. %2 = OpTypeVoid
  2375. %3 = OpTypeFunction %2
  2376. %15 = OpTypeInt 32 1
  2377. %35 = OpTypeBool
  2378. %39 = OpConstant %15 1
  2379. %40 = OpConstantTrue %35
  2380. %4 = OpFunction %2 None %3
  2381. %5 = OpLabel
  2382. OpBranch %22
  2383. %22 = OpLabel
  2384. OpBranch %23
  2385. %23 = OpLabel
  2386. %24 = OpPhi %15 %39 %22 %39 %25
  2387. OpLoopMerge %26 %25 None
  2388. OpBranchConditional %40 %25 %26
  2389. %25 = OpLabel
  2390. OpBranch %23
  2391. %26 = OpLabel
  2392. OpReturn
  2393. OpFunctionEnd
  2394. )";
  2395. const auto env = SPV_ENV_UNIVERSAL_1_5;
  2396. const auto consumer = nullptr;
  2397. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2398. spvtools::ValidatorOptions validator_options;
  2399. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2400. kConsoleMessageConsumer));
  2401. TransformationContext transformation_context(
  2402. MakeUnique<FactManager>(context.get()), validator_options);
  2403. TransformationOutlineFunction transformation(
  2404. /*entry_block*/ 22,
  2405. /*exit_block*/ 23,
  2406. /*new_function_struct_return_type_id*/ 200,
  2407. /*new_function_type_id*/ 201,
  2408. /*new_function_id*/ 202,
  2409. /*new_function_region_entry_block*/ 203,
  2410. /*new_caller_result_id*/ 204,
  2411. /*new_callee_result_id*/ 205,
  2412. /*input_id_to_fresh_id*/ {},
  2413. /*output_id_to_fresh_id*/ {});
  2414. ASSERT_FALSE(
  2415. transformation.IsApplicable(context.get(), transformation_context));
  2416. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  2417. }
  2418. TEST(TransformationOutlineFunctionTest, Miscellaneous1) {
  2419. // This tests outlining of some non-trivial code, and also tests the way
  2420. // overflow ids are used by the transformation.
  2421. std::string reference_shader = R"(
  2422. OpCapability Shader
  2423. %1 = OpExtInstImport "GLSL.std.450"
  2424. OpMemoryModel Logical GLSL450
  2425. OpEntryPoint Fragment %4 "main" %85
  2426. OpExecutionMode %4 OriginUpperLeft
  2427. OpSource ESSL 310
  2428. OpName %4 "main"
  2429. OpName %28 "buf"
  2430. OpMemberName %28 0 "u1"
  2431. OpMemberName %28 1 "u2"
  2432. OpName %30 ""
  2433. OpName %85 "color"
  2434. OpMemberDecorate %28 0 Offset 0
  2435. OpMemberDecorate %28 1 Offset 4
  2436. OpDecorate %28 Block
  2437. OpDecorate %30 DescriptorSet 0
  2438. OpDecorate %30 Binding 0
  2439. OpDecorate %85 Location 0
  2440. %2 = OpTypeVoid
  2441. %3 = OpTypeFunction %2
  2442. %6 = OpTypeFloat 32
  2443. %7 = OpTypeVector %6 4
  2444. %10 = OpConstant %6 1
  2445. %11 = OpConstant %6 2
  2446. %12 = OpConstant %6 3
  2447. %13 = OpConstant %6 4
  2448. %14 = OpConstantComposite %7 %10 %11 %12 %13
  2449. %15 = OpTypeInt 32 1
  2450. %18 = OpConstant %15 0
  2451. %28 = OpTypeStruct %6 %6
  2452. %29 = OpTypePointer Uniform %28
  2453. %30 = OpVariable %29 Uniform
  2454. %31 = OpTypePointer Uniform %6
  2455. %35 = OpTypeBool
  2456. %39 = OpConstant %15 1
  2457. %84 = OpTypePointer Output %7
  2458. %85 = OpVariable %84 Output
  2459. %114 = OpConstant %15 8
  2460. %4 = OpFunction %2 None %3
  2461. %5 = OpLabel
  2462. OpBranch %22
  2463. %22 = OpLabel
  2464. %103 = OpPhi %15 %18 %5 %106 %43
  2465. %102 = OpPhi %7 %14 %5 %107 %43
  2466. %101 = OpPhi %15 %18 %5 %40 %43
  2467. %32 = OpAccessChain %31 %30 %18
  2468. %33 = OpLoad %6 %32
  2469. %34 = OpConvertFToS %15 %33
  2470. %36 = OpSLessThan %35 %101 %34
  2471. OpLoopMerge %24 %43 None
  2472. OpBranchConditional %36 %23 %24
  2473. %23 = OpLabel
  2474. %40 = OpIAdd %15 %101 %39
  2475. OpBranch %150
  2476. %150 = OpLabel
  2477. OpBranch %41
  2478. %41 = OpLabel
  2479. %107 = OpPhi %7 %102 %150 %111 %65
  2480. %106 = OpPhi %15 %103 %150 %110 %65
  2481. %104 = OpPhi %15 %40 %150 %81 %65
  2482. %47 = OpAccessChain %31 %30 %39
  2483. %48 = OpLoad %6 %47
  2484. %49 = OpConvertFToS %15 %48
  2485. %50 = OpSLessThan %35 %104 %49
  2486. OpLoopMerge %1000 %65 None
  2487. OpBranchConditional %50 %42 %1000
  2488. %42 = OpLabel
  2489. %60 = OpIAdd %15 %106 %114
  2490. %63 = OpSGreaterThan %35 %104 %60
  2491. OpBranchConditional %63 %64 %65
  2492. %64 = OpLabel
  2493. %71 = OpCompositeExtract %6 %107 0
  2494. %72 = OpFAdd %6 %71 %11
  2495. %97 = OpCompositeInsert %7 %72 %107 0
  2496. %76 = OpCompositeExtract %6 %107 3
  2497. %77 = OpConvertFToS %15 %76
  2498. %79 = OpIAdd %15 %60 %77
  2499. OpBranch %65
  2500. %65 = OpLabel
  2501. %111 = OpPhi %7 %107 %42 %97 %64
  2502. %110 = OpPhi %15 %60 %42 %79 %64
  2503. %81 = OpIAdd %15 %104 %39
  2504. OpBranch %41
  2505. %1000 = OpLabel
  2506. OpBranch %1001
  2507. %1001 = OpLabel
  2508. OpBranch %43
  2509. %43 = OpLabel
  2510. OpBranch %22
  2511. %24 = OpLabel
  2512. %87 = OpCompositeExtract %6 %102 0
  2513. %91 = OpConvertSToF %6 %103
  2514. %92 = OpCompositeConstruct %7 %87 %11 %91 %10
  2515. OpStore %85 %92
  2516. OpReturn
  2517. OpFunctionEnd
  2518. )";
  2519. const auto env = SPV_ENV_UNIVERSAL_1_3;
  2520. const auto consumer = nullptr;
  2521. spvtools::ValidatorOptions validator_options;
  2522. TransformationOutlineFunction transformation(
  2523. /*entry_block*/ 150,
  2524. /*exit_block*/ 1001,
  2525. /*new_function_struct_return_type_id*/ 200,
  2526. /*new_function_type_id*/ 201,
  2527. /*new_function_id*/ 202,
  2528. /*new_function_region_entry_block*/ 203,
  2529. /*new_caller_result_id*/ 204,
  2530. /*new_callee_result_id*/ 205,
  2531. /*input_id_to_fresh_id*/ {{102, 300}, {103, 301}, {40, 302}},
  2532. /*output_id_to_fresh_id*/ {{106, 400}, {107, 401}});
  2533. TransformationOutlineFunction transformation_with_missing_input_id(
  2534. /*entry_block*/ 150,
  2535. /*exit_block*/ 1001,
  2536. /*new_function_struct_return_type_id*/ 200,
  2537. /*new_function_type_id*/ 201,
  2538. /*new_function_id*/ 202,
  2539. /*new_function_region_entry_block*/ 203,
  2540. /*new_caller_result_id*/ 204,
  2541. /*new_callee_result_id*/ 205,
  2542. /*input_id_to_fresh_id*/ {{102, 300}, {40, 302}},
  2543. /*output_id_to_fresh_id*/ {{106, 400}, {107, 401}});
  2544. TransformationOutlineFunction transformation_with_missing_output_id(
  2545. /*entry_block*/ 150,
  2546. /*exit_block*/ 1001,
  2547. /*new_function_struct_return_type_id*/ 200,
  2548. /*new_function_type_id*/ 201,
  2549. /*new_function_id*/ 202,
  2550. /*new_function_region_entry_block*/ 203,
  2551. /*new_caller_result_id*/ 204,
  2552. /*new_callee_result_id*/ 205,
  2553. /*input_id_to_fresh_id*/ {{102, 300}, {103, 301}, {40, 302}},
  2554. /*output_id_to_fresh_id*/ {{106, 400}});
  2555. TransformationOutlineFunction
  2556. transformation_with_missing_input_and_output_ids(
  2557. /*entry_block*/ 150,
  2558. /*exit_block*/ 1001,
  2559. /*new_function_struct_return_type_id*/ 200,
  2560. /*new_function_type_id*/ 201,
  2561. /*new_function_id*/ 202,
  2562. /*new_function_region_entry_block*/ 203,
  2563. /*new_caller_result_id*/ 204,
  2564. /*new_callee_result_id*/ 205,
  2565. /*input_id_to_fresh_id*/ {{102, 300}, {40, 302}},
  2566. /*output_id_to_fresh_id*/ {{106, 400}});
  2567. {
  2568. const auto context =
  2569. BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
  2570. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  2571. context.get(), validator_options, kConsoleMessageConsumer));
  2572. TransformationContext transformation_context(
  2573. MakeUnique<FactManager>(context.get()), validator_options);
  2574. #ifndef NDEBUG
  2575. // We expect the following applicability checks to lead to assertion
  2576. // failures since the transformations are missing input or output ids, and
  2577. // the transformation context does not have a source of overflow ids.
  2578. ASSERT_DEATH(transformation_with_missing_input_id.IsApplicable(
  2579. context.get(), transformation_context),
  2580. "Bad attempt to query whether overflow ids are available.");
  2581. ASSERT_DEATH(transformation_with_missing_output_id.IsApplicable(
  2582. context.get(), transformation_context),
  2583. "Bad attempt to query whether overflow ids are available.");
  2584. ASSERT_DEATH(transformation_with_missing_input_and_output_ids.IsApplicable(
  2585. context.get(), transformation_context),
  2586. "Bad attempt to query whether overflow ids are available.");
  2587. #endif
  2588. ASSERT_TRUE(
  2589. transformation.IsApplicable(context.get(), transformation_context));
  2590. ApplyAndCheckFreshIds(transformation, context.get(),
  2591. &transformation_context);
  2592. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  2593. context.get(), validator_options, kConsoleMessageConsumer));
  2594. std::string variant_shader = R"(
  2595. OpCapability Shader
  2596. %1 = OpExtInstImport "GLSL.std.450"
  2597. OpMemoryModel Logical GLSL450
  2598. OpEntryPoint Fragment %4 "main" %85
  2599. OpExecutionMode %4 OriginUpperLeft
  2600. OpSource ESSL 310
  2601. OpName %4 "main"
  2602. OpName %28 "buf"
  2603. OpMemberName %28 0 "u1"
  2604. OpMemberName %28 1 "u2"
  2605. OpName %30 ""
  2606. OpName %85 "color"
  2607. OpMemberDecorate %28 0 Offset 0
  2608. OpMemberDecorate %28 1 Offset 4
  2609. OpDecorate %28 Block
  2610. OpDecorate %30 DescriptorSet 0
  2611. OpDecorate %30 Binding 0
  2612. OpDecorate %85 Location 0
  2613. %2 = OpTypeVoid
  2614. %3 = OpTypeFunction %2
  2615. %6 = OpTypeFloat 32
  2616. %7 = OpTypeVector %6 4
  2617. %10 = OpConstant %6 1
  2618. %11 = OpConstant %6 2
  2619. %12 = OpConstant %6 3
  2620. %13 = OpConstant %6 4
  2621. %14 = OpConstantComposite %7 %10 %11 %12 %13
  2622. %15 = OpTypeInt 32 1
  2623. %18 = OpConstant %15 0
  2624. %28 = OpTypeStruct %6 %6
  2625. %29 = OpTypePointer Uniform %28
  2626. %30 = OpVariable %29 Uniform
  2627. %31 = OpTypePointer Uniform %6
  2628. %35 = OpTypeBool
  2629. %39 = OpConstant %15 1
  2630. %84 = OpTypePointer Output %7
  2631. %85 = OpVariable %84 Output
  2632. %114 = OpConstant %15 8
  2633. %200 = OpTypeStruct %7 %15
  2634. %201 = OpTypeFunction %200 %15 %7 %15
  2635. %4 = OpFunction %2 None %3
  2636. %5 = OpLabel
  2637. OpBranch %22
  2638. %22 = OpLabel
  2639. %103 = OpPhi %15 %18 %5 %106 %43
  2640. %102 = OpPhi %7 %14 %5 %107 %43
  2641. %101 = OpPhi %15 %18 %5 %40 %43
  2642. %32 = OpAccessChain %31 %30 %18
  2643. %33 = OpLoad %6 %32
  2644. %34 = OpConvertFToS %15 %33
  2645. %36 = OpSLessThan %35 %101 %34
  2646. OpLoopMerge %24 %43 None
  2647. OpBranchConditional %36 %23 %24
  2648. %23 = OpLabel
  2649. %40 = OpIAdd %15 %101 %39
  2650. OpBranch %150
  2651. %150 = OpLabel
  2652. %204 = OpFunctionCall %200 %202 %103 %102 %40
  2653. %107 = OpCompositeExtract %7 %204 0
  2654. %106 = OpCompositeExtract %15 %204 1
  2655. OpBranch %43
  2656. %43 = OpLabel
  2657. OpBranch %22
  2658. %24 = OpLabel
  2659. %87 = OpCompositeExtract %6 %102 0
  2660. %91 = OpConvertSToF %6 %103
  2661. %92 = OpCompositeConstruct %7 %87 %11 %91 %10
  2662. OpStore %85 %92
  2663. OpReturn
  2664. OpFunctionEnd
  2665. %202 = OpFunction %200 None %201
  2666. %301 = OpFunctionParameter %15
  2667. %300 = OpFunctionParameter %7
  2668. %302 = OpFunctionParameter %15
  2669. %203 = OpLabel
  2670. OpBranch %41
  2671. %41 = OpLabel
  2672. %401 = OpPhi %7 %300 %203 %111 %65
  2673. %400 = OpPhi %15 %301 %203 %110 %65
  2674. %104 = OpPhi %15 %302 %203 %81 %65
  2675. %47 = OpAccessChain %31 %30 %39
  2676. %48 = OpLoad %6 %47
  2677. %49 = OpConvertFToS %15 %48
  2678. %50 = OpSLessThan %35 %104 %49
  2679. OpLoopMerge %1000 %65 None
  2680. OpBranchConditional %50 %42 %1000
  2681. %42 = OpLabel
  2682. %60 = OpIAdd %15 %400 %114
  2683. %63 = OpSGreaterThan %35 %104 %60
  2684. OpBranchConditional %63 %64 %65
  2685. %64 = OpLabel
  2686. %71 = OpCompositeExtract %6 %401 0
  2687. %72 = OpFAdd %6 %71 %11
  2688. %97 = OpCompositeInsert %7 %72 %401 0
  2689. %76 = OpCompositeExtract %6 %401 3
  2690. %77 = OpConvertFToS %15 %76
  2691. %79 = OpIAdd %15 %60 %77
  2692. OpBranch %65
  2693. %65 = OpLabel
  2694. %111 = OpPhi %7 %401 %42 %97 %64
  2695. %110 = OpPhi %15 %60 %42 %79 %64
  2696. %81 = OpIAdd %15 %104 %39
  2697. OpBranch %41
  2698. %1000 = OpLabel
  2699. OpBranch %1001
  2700. %1001 = OpLabel
  2701. %205 = OpCompositeConstruct %200 %401 %400
  2702. OpReturnValue %205
  2703. OpFunctionEnd
  2704. )";
  2705. ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
  2706. }
  2707. {
  2708. const auto context =
  2709. BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
  2710. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  2711. context.get(), validator_options, kConsoleMessageConsumer));
  2712. auto overflow_ids_unique_ptr = MakeUnique<CounterOverflowIdSource>(2000);
  2713. auto overflow_ids_ptr = overflow_ids_unique_ptr.get();
  2714. TransformationContext new_transformation_context(
  2715. MakeUnique<FactManager>(context.get()), validator_options,
  2716. std::move(overflow_ids_unique_ptr));
  2717. ASSERT_TRUE(transformation_with_missing_input_id.IsApplicable(
  2718. context.get(), new_transformation_context));
  2719. ASSERT_TRUE(transformation_with_missing_output_id.IsApplicable(
  2720. context.get(), new_transformation_context));
  2721. ASSERT_TRUE(transformation_with_missing_input_and_output_ids.IsApplicable(
  2722. context.get(), new_transformation_context));
  2723. ApplyAndCheckFreshIds(transformation_with_missing_input_and_output_ids,
  2724. context.get(), &new_transformation_context,
  2725. overflow_ids_ptr->GetIssuedOverflowIds());
  2726. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  2727. context.get(), validator_options, kConsoleMessageConsumer));
  2728. std::string variant_shader = R"(
  2729. OpCapability Shader
  2730. %1 = OpExtInstImport "GLSL.std.450"
  2731. OpMemoryModel Logical GLSL450
  2732. OpEntryPoint Fragment %4 "main" %85
  2733. OpExecutionMode %4 OriginUpperLeft
  2734. OpSource ESSL 310
  2735. OpName %4 "main"
  2736. OpName %28 "buf"
  2737. OpMemberName %28 0 "u1"
  2738. OpMemberName %28 1 "u2"
  2739. OpName %30 ""
  2740. OpName %85 "color"
  2741. OpMemberDecorate %28 0 Offset 0
  2742. OpMemberDecorate %28 1 Offset 4
  2743. OpDecorate %28 Block
  2744. OpDecorate %30 DescriptorSet 0
  2745. OpDecorate %30 Binding 0
  2746. OpDecorate %85 Location 0
  2747. %2 = OpTypeVoid
  2748. %3 = OpTypeFunction %2
  2749. %6 = OpTypeFloat 32
  2750. %7 = OpTypeVector %6 4
  2751. %10 = OpConstant %6 1
  2752. %11 = OpConstant %6 2
  2753. %12 = OpConstant %6 3
  2754. %13 = OpConstant %6 4
  2755. %14 = OpConstantComposite %7 %10 %11 %12 %13
  2756. %15 = OpTypeInt 32 1
  2757. %18 = OpConstant %15 0
  2758. %28 = OpTypeStruct %6 %6
  2759. %29 = OpTypePointer Uniform %28
  2760. %30 = OpVariable %29 Uniform
  2761. %31 = OpTypePointer Uniform %6
  2762. %35 = OpTypeBool
  2763. %39 = OpConstant %15 1
  2764. %84 = OpTypePointer Output %7
  2765. %85 = OpVariable %84 Output
  2766. %114 = OpConstant %15 8
  2767. %200 = OpTypeStruct %7 %15
  2768. %201 = OpTypeFunction %200 %15 %7 %15
  2769. %4 = OpFunction %2 None %3
  2770. %5 = OpLabel
  2771. OpBranch %22
  2772. %22 = OpLabel
  2773. %103 = OpPhi %15 %18 %5 %106 %43
  2774. %102 = OpPhi %7 %14 %5 %107 %43
  2775. %101 = OpPhi %15 %18 %5 %40 %43
  2776. %32 = OpAccessChain %31 %30 %18
  2777. %33 = OpLoad %6 %32
  2778. %34 = OpConvertFToS %15 %33
  2779. %36 = OpSLessThan %35 %101 %34
  2780. OpLoopMerge %24 %43 None
  2781. OpBranchConditional %36 %23 %24
  2782. %23 = OpLabel
  2783. %40 = OpIAdd %15 %101 %39
  2784. OpBranch %150
  2785. %150 = OpLabel
  2786. %204 = OpFunctionCall %200 %202 %103 %102 %40
  2787. %107 = OpCompositeExtract %7 %204 0
  2788. %106 = OpCompositeExtract %15 %204 1
  2789. OpBranch %43
  2790. %43 = OpLabel
  2791. OpBranch %22
  2792. %24 = OpLabel
  2793. %87 = OpCompositeExtract %6 %102 0
  2794. %91 = OpConvertSToF %6 %103
  2795. %92 = OpCompositeConstruct %7 %87 %11 %91 %10
  2796. OpStore %85 %92
  2797. OpReturn
  2798. OpFunctionEnd
  2799. %202 = OpFunction %200 None %201
  2800. %2000 = OpFunctionParameter %15
  2801. %300 = OpFunctionParameter %7
  2802. %302 = OpFunctionParameter %15
  2803. %203 = OpLabel
  2804. OpBranch %41
  2805. %41 = OpLabel
  2806. %2001 = OpPhi %7 %300 %203 %111 %65
  2807. %400 = OpPhi %15 %2000 %203 %110 %65
  2808. %104 = OpPhi %15 %302 %203 %81 %65
  2809. %47 = OpAccessChain %31 %30 %39
  2810. %48 = OpLoad %6 %47
  2811. %49 = OpConvertFToS %15 %48
  2812. %50 = OpSLessThan %35 %104 %49
  2813. OpLoopMerge %1000 %65 None
  2814. OpBranchConditional %50 %42 %1000
  2815. %42 = OpLabel
  2816. %60 = OpIAdd %15 %400 %114
  2817. %63 = OpSGreaterThan %35 %104 %60
  2818. OpBranchConditional %63 %64 %65
  2819. %64 = OpLabel
  2820. %71 = OpCompositeExtract %6 %2001 0
  2821. %72 = OpFAdd %6 %71 %11
  2822. %97 = OpCompositeInsert %7 %72 %2001 0
  2823. %76 = OpCompositeExtract %6 %2001 3
  2824. %77 = OpConvertFToS %15 %76
  2825. %79 = OpIAdd %15 %60 %77
  2826. OpBranch %65
  2827. %65 = OpLabel
  2828. %111 = OpPhi %7 %2001 %42 %97 %64
  2829. %110 = OpPhi %15 %60 %42 %79 %64
  2830. %81 = OpIAdd %15 %104 %39
  2831. OpBranch %41
  2832. %1000 = OpLabel
  2833. OpBranch %1001
  2834. %1001 = OpLabel
  2835. %205 = OpCompositeConstruct %200 %2001 %400
  2836. OpReturnValue %205
  2837. OpFunctionEnd
  2838. )";
  2839. ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
  2840. }
  2841. }
  2842. TEST(TransformationOutlineFunctionTest, Miscellaneous2) {
  2843. std::string shader = R"(
  2844. OpCapability Shader
  2845. %1 = OpExtInstImport "GLSL.std.450"
  2846. OpMemoryModel Logical GLSL450
  2847. OpEntryPoint Fragment %4 "main"
  2848. OpExecutionMode %4 OriginUpperLeft
  2849. OpSource ESSL 310
  2850. %2 = OpTypeVoid
  2851. %3 = OpTypeFunction %2
  2852. %21 = OpTypeBool
  2853. %167 = OpConstantTrue %21
  2854. %168 = OpConstantFalse %21
  2855. %4 = OpFunction %2 None %3
  2856. %5 = OpLabel
  2857. OpBranch %34
  2858. %34 = OpLabel
  2859. OpLoopMerge %36 %37 None
  2860. OpBranchConditional %168 %37 %38
  2861. %38 = OpLabel
  2862. OpBranchConditional %168 %37 %36
  2863. %37 = OpLabel
  2864. OpBranch %34
  2865. %36 = OpLabel
  2866. OpReturn
  2867. OpFunctionEnd
  2868. )";
  2869. const auto env = SPV_ENV_UNIVERSAL_1_5;
  2870. const auto consumer = nullptr;
  2871. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2872. spvtools::ValidatorOptions validator_options;
  2873. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2874. kConsoleMessageConsumer));
  2875. TransformationContext transformation_context(
  2876. MakeUnique<FactManager>(context.get()), validator_options);
  2877. TransformationOutlineFunction transformation(
  2878. /*entry_block*/ 38,
  2879. /*exit_block*/ 36,
  2880. /*new_function_struct_return_type_id*/ 200,
  2881. /*new_function_type_id*/ 201,
  2882. /*new_function_id*/ 202,
  2883. /*new_function_region_entry_block*/ 203,
  2884. /*new_caller_result_id*/ 204,
  2885. /*new_callee_result_id*/ 205,
  2886. /*input_id_to_fresh_id*/ {},
  2887. /*output_id_to_fresh_id*/ {});
  2888. ASSERT_FALSE(
  2889. transformation.IsApplicable(context.get(), transformation_context));
  2890. }
  2891. TEST(TransformationOutlineFunctionTest, Miscellaneous3) {
  2892. std::string shader = R"(
  2893. OpCapability Shader
  2894. %1 = OpExtInstImport "GLSL.std.450"
  2895. OpMemoryModel Logical GLSL450
  2896. OpEntryPoint Fragment %6 "main"
  2897. OpExecutionMode %6 OriginUpperLeft
  2898. OpSource ESSL 310
  2899. %2 = OpTypeVoid
  2900. %3 = OpTypeFunction %2
  2901. %21 = OpTypeBool
  2902. %167 = OpConstantTrue %21
  2903. %6 = OpFunction %2 None %3
  2904. %7 = OpLabel
  2905. OpBranch %80
  2906. %80 = OpLabel
  2907. OpBranch %14
  2908. %14 = OpLabel
  2909. OpLoopMerge %16 %17 None
  2910. OpBranch %18
  2911. %18 = OpLabel
  2912. OpBranchConditional %167 %15 %16
  2913. %15 = OpLabel
  2914. OpBranch %17
  2915. %16 = OpLabel
  2916. OpBranch %81
  2917. %81 = OpLabel
  2918. OpReturn
  2919. %17 = OpLabel
  2920. OpBranch %14
  2921. OpFunctionEnd
  2922. )";
  2923. const auto env = SPV_ENV_UNIVERSAL_1_5;
  2924. const auto consumer = nullptr;
  2925. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  2926. spvtools::ValidatorOptions validator_options;
  2927. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2928. kConsoleMessageConsumer));
  2929. TransformationContext transformation_context(
  2930. MakeUnique<FactManager>(context.get()), validator_options);
  2931. TransformationOutlineFunction transformation(
  2932. /*entry_block*/ 80,
  2933. /*exit_block*/ 81,
  2934. /*new_function_struct_return_type_id*/ 300,
  2935. /*new_function_type_id*/ 301,
  2936. /*new_function_id*/ 302,
  2937. /*new_function_region_entry_block*/ 304,
  2938. /*new_caller_result_id*/ 305,
  2939. /*new_callee_result_id*/ 306,
  2940. /*input_id_to_fresh_id*/ {},
  2941. /*output_id_to_fresh_id*/ {});
  2942. ASSERT_TRUE(
  2943. transformation.IsApplicable(context.get(), transformation_context));
  2944. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  2945. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  2946. kConsoleMessageConsumer));
  2947. std::string after_transformation = R"(
  2948. OpCapability Shader
  2949. %1 = OpExtInstImport "GLSL.std.450"
  2950. OpMemoryModel Logical GLSL450
  2951. OpEntryPoint Fragment %6 "main"
  2952. OpExecutionMode %6 OriginUpperLeft
  2953. OpSource ESSL 310
  2954. %2 = OpTypeVoid
  2955. %3 = OpTypeFunction %2
  2956. %21 = OpTypeBool
  2957. %167 = OpConstantTrue %21
  2958. %6 = OpFunction %2 None %3
  2959. %7 = OpLabel
  2960. OpBranch %80
  2961. %80 = OpLabel
  2962. %305 = OpFunctionCall %2 %302
  2963. OpReturn
  2964. OpFunctionEnd
  2965. %302 = OpFunction %2 None %3
  2966. %304 = OpLabel
  2967. OpBranch %14
  2968. %14 = OpLabel
  2969. OpLoopMerge %16 %17 None
  2970. OpBranch %18
  2971. %18 = OpLabel
  2972. OpBranchConditional %167 %15 %16
  2973. %15 = OpLabel
  2974. OpBranch %17
  2975. %16 = OpLabel
  2976. OpBranch %81
  2977. %81 = OpLabel
  2978. OpReturn
  2979. %17 = OpLabel
  2980. OpBranch %14
  2981. OpFunctionEnd
  2982. )";
  2983. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  2984. }
  2985. TEST(TransformationOutlineFunctionTest, Miscellaneous4) {
  2986. std::string shader = R"(
  2987. OpCapability Shader
  2988. %1 = OpExtInstImport "GLSL.std.450"
  2989. OpMemoryModel Logical GLSL450
  2990. OpEntryPoint Fragment %6 "main"
  2991. OpExecutionMode %6 OriginUpperLeft
  2992. OpSource ESSL 310
  2993. %2 = OpTypeVoid
  2994. %3 = OpTypeFunction %2
  2995. %21 = OpTypeBool
  2996. %100 = OpTypeInt 32 0
  2997. %101 = OpTypePointer Function %100
  2998. %102 = OpTypePointer Function %100
  2999. %103 = OpTypeFunction %2 %101
  3000. %6 = OpFunction %2 None %3
  3001. %7 = OpLabel
  3002. %104 = OpVariable %102 Function
  3003. OpBranch %80
  3004. %80 = OpLabel
  3005. %105 = OpLoad %100 %104
  3006. OpBranch %106
  3007. %106 = OpLabel
  3008. OpReturn
  3009. OpFunctionEnd
  3010. )";
  3011. const auto env = SPV_ENV_UNIVERSAL_1_5;
  3012. const auto consumer = nullptr;
  3013. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  3014. spvtools::ValidatorOptions validator_options;
  3015. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  3016. kConsoleMessageConsumer));
  3017. TransformationContext transformation_context(
  3018. MakeUnique<FactManager>(context.get()), validator_options);
  3019. TransformationOutlineFunction transformation(
  3020. /*entry_block*/ 80,
  3021. /*exit_block*/ 106,
  3022. /*new_function_struct_return_type_id*/ 300,
  3023. /*new_function_type_id*/ 301,
  3024. /*new_function_id*/ 302,
  3025. /*new_function_region_entry_block*/ 304,
  3026. /*new_caller_result_id*/ 305,
  3027. /*new_callee_result_id*/ 306,
  3028. /*input_id_to_fresh_id*/ {{104, 307}},
  3029. /*output_id_to_fresh_id*/ {});
  3030. ASSERT_TRUE(
  3031. transformation.IsApplicable(context.get(), transformation_context));
  3032. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  3033. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  3034. kConsoleMessageConsumer));
  3035. std::string after_transformation = R"(
  3036. OpCapability Shader
  3037. %1 = OpExtInstImport "GLSL.std.450"
  3038. OpMemoryModel Logical GLSL450
  3039. OpEntryPoint Fragment %6 "main"
  3040. OpExecutionMode %6 OriginUpperLeft
  3041. OpSource ESSL 310
  3042. %2 = OpTypeVoid
  3043. %3 = OpTypeFunction %2
  3044. %21 = OpTypeBool
  3045. %100 = OpTypeInt 32 0
  3046. %101 = OpTypePointer Function %100
  3047. %102 = OpTypePointer Function %100
  3048. %103 = OpTypeFunction %2 %101
  3049. %301 = OpTypeFunction %2 %102
  3050. %6 = OpFunction %2 None %3
  3051. %7 = OpLabel
  3052. %104 = OpVariable %102 Function
  3053. OpBranch %80
  3054. %80 = OpLabel
  3055. %305 = OpFunctionCall %2 %302 %104
  3056. OpReturn
  3057. OpFunctionEnd
  3058. %302 = OpFunction %2 None %301
  3059. %307 = OpFunctionParameter %102
  3060. %304 = OpLabel
  3061. %105 = OpLoad %100 %307
  3062. OpBranch %106
  3063. %106 = OpLabel
  3064. OpReturn
  3065. OpFunctionEnd
  3066. )";
  3067. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  3068. }
  3069. TEST(TransformationOutlineFunctionTest, NoOutlineWithUnreachableBlocks) {
  3070. // This checks that outlining will not be performed if a node in the region
  3071. // has an unreachable predecessor.
  3072. std::string shader = R"(
  3073. OpCapability Shader
  3074. %1 = OpExtInstImport "GLSL.std.450"
  3075. OpMemoryModel Logical GLSL450
  3076. OpEntryPoint Fragment %4 "main"
  3077. OpExecutionMode %4 OriginUpperLeft
  3078. OpSource ESSL 310
  3079. OpName %4 "main"
  3080. %2 = OpTypeVoid
  3081. %3 = OpTypeFunction %2
  3082. %4 = OpFunction %2 None %3
  3083. %7 = OpLabel
  3084. OpBranch %5
  3085. %5 = OpLabel
  3086. OpReturn
  3087. %6 = OpLabel
  3088. OpBranch %5
  3089. OpFunctionEnd
  3090. )";
  3091. const auto env = SPV_ENV_UNIVERSAL_1_4;
  3092. const auto consumer = nullptr;
  3093. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  3094. spvtools::ValidatorOptions validator_options;
  3095. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  3096. kConsoleMessageConsumer));
  3097. TransformationContext transformation_context(
  3098. MakeUnique<FactManager>(context.get()), validator_options);
  3099. TransformationOutlineFunction transformation(5, 5, /* not relevant */ 200,
  3100. 100, 101, 102, 103,
  3101. /* not relevant */ 201, {}, {});
  3102. ASSERT_FALSE(
  3103. transformation.IsApplicable(context.get(), transformation_context));
  3104. }
  3105. } // namespace
  3106. } // namespace fuzz
  3107. } // namespace spvtools