transformation_add_dead_continue_test.cpp 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616
  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_add_dead_continue.h"
  15. #include "gtest/gtest.h"
  16. #include "source/fuzz/fuzzer_util.h"
  17. #include "test/fuzz/fuzz_test_util.h"
  18. namespace spvtools {
  19. namespace fuzz {
  20. namespace {
  21. TEST(TransformationAddDeadContinueTest, SimpleExample) {
  22. // For a simple loop, checks that some dead continue scenarios are possible,
  23. // checks that some invalid scenarios are indeed not allowed, and then applies
  24. // a transformation.
  25. // The SPIR-V for this test is adapted from the following GLSL, by separating
  26. // some assignments into their own basic blocks, and adding constants for true
  27. // and false:
  28. //
  29. // void main() {
  30. // int x = 0;
  31. // for (int i = 0; i < 10; i++) {
  32. // x = x + i;
  33. // x = x + i;
  34. // }
  35. // }
  36. std::string shader = R"(
  37. OpCapability Shader
  38. %1 = OpExtInstImport "GLSL.std.450"
  39. OpMemoryModel Logical GLSL450
  40. OpEntryPoint Fragment %4 "main"
  41. OpExecutionMode %4 OriginUpperLeft
  42. OpSource ESSL 310
  43. OpName %4 "main"
  44. OpName %8 "x"
  45. OpName %10 "i"
  46. %2 = OpTypeVoid
  47. %3 = OpTypeFunction %2
  48. %6 = OpTypeInt 32 1
  49. %7 = OpTypePointer Function %6
  50. %9 = OpConstant %6 0
  51. %17 = OpConstant %6 10
  52. %18 = OpTypeBool
  53. %41 = OpConstantTrue %18
  54. %42 = OpConstantFalse %18
  55. %27 = OpConstant %6 1
  56. %4 = OpFunction %2 None %3
  57. %5 = OpLabel
  58. %8 = OpVariable %7 Function
  59. %10 = OpVariable %7 Function
  60. OpStore %8 %9
  61. OpStore %10 %9
  62. OpBranch %11
  63. %11 = OpLabel
  64. OpLoopMerge %13 %14 None
  65. OpBranch %15
  66. %15 = OpLabel
  67. %16 = OpLoad %6 %10
  68. %19 = OpSLessThan %18 %16 %17
  69. OpBranchConditional %19 %12 %13
  70. %12 = OpLabel
  71. %20 = OpLoad %6 %8
  72. %21 = OpLoad %6 %10
  73. %22 = OpIAdd %6 %20 %21
  74. OpStore %8 %22
  75. OpBranch %40
  76. %40 = OpLabel
  77. %23 = OpLoad %6 %8
  78. %24 = OpLoad %6 %10
  79. %25 = OpIAdd %6 %23 %24
  80. OpStore %8 %25
  81. OpBranch %14
  82. %14 = OpLabel
  83. %26 = OpLoad %6 %10
  84. %28 = OpIAdd %6 %26 %27
  85. OpStore %10 %28
  86. OpBranch %11
  87. %13 = OpLabel
  88. OpReturn
  89. OpFunctionEnd
  90. )";
  91. const auto env = SPV_ENV_UNIVERSAL_1_3;
  92. const auto consumer = nullptr;
  93. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  94. spvtools::ValidatorOptions validator_options;
  95. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  96. kConsoleMessageConsumer));
  97. TransformationContext transformation_context(
  98. MakeUnique<FactManager>(context.get()), validator_options);
  99. // These are all possibilities.
  100. ASSERT_TRUE(TransformationAddDeadContinue(11, true, {})
  101. .IsApplicable(context.get(), transformation_context));
  102. ASSERT_TRUE(TransformationAddDeadContinue(11, false, {})
  103. .IsApplicable(context.get(), transformation_context));
  104. ASSERT_TRUE(TransformationAddDeadContinue(12, true, {})
  105. .IsApplicable(context.get(), transformation_context));
  106. ASSERT_TRUE(TransformationAddDeadContinue(12, false, {})
  107. .IsApplicable(context.get(), transformation_context));
  108. ASSERT_TRUE(TransformationAddDeadContinue(40, true, {})
  109. .IsApplicable(context.get(), transformation_context));
  110. ASSERT_TRUE(TransformationAddDeadContinue(40, false, {})
  111. .IsApplicable(context.get(), transformation_context));
  112. // Inapplicable: 100 is not a block id.
  113. ASSERT_FALSE(TransformationAddDeadContinue(100, true, {})
  114. .IsApplicable(context.get(), transformation_context));
  115. // Inapplicable: 10 is not in a loop.
  116. ASSERT_FALSE(TransformationAddDeadContinue(10, true, {})
  117. .IsApplicable(context.get(), transformation_context));
  118. // Inapplicable: 15 does not branch unconditionally to a single successor.
  119. ASSERT_FALSE(TransformationAddDeadContinue(15, true, {})
  120. .IsApplicable(context.get(), transformation_context));
  121. // Inapplicable: 13 is not in a loop and has no successor.
  122. ASSERT_FALSE(TransformationAddDeadContinue(13, true, {})
  123. .IsApplicable(context.get(), transformation_context));
  124. // Inapplicable: 14 is the loop continue target, so it's not OK to jump to
  125. // the loop continue from there.
  126. ASSERT_FALSE(TransformationAddDeadContinue(14, false, {})
  127. .IsApplicable(context.get(), transformation_context));
  128. // These are the transformations we will apply.
  129. auto transformation1 = TransformationAddDeadContinue(11, true, {});
  130. auto transformation2 = TransformationAddDeadContinue(12, false, {});
  131. auto transformation3 = TransformationAddDeadContinue(40, true, {});
  132. ASSERT_TRUE(
  133. transformation1.IsApplicable(context.get(), transformation_context));
  134. ApplyAndCheckFreshIds(transformation1, context.get(),
  135. &transformation_context);
  136. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  137. kConsoleMessageConsumer));
  138. ASSERT_TRUE(
  139. transformation2.IsApplicable(context.get(), transformation_context));
  140. ApplyAndCheckFreshIds(transformation2, context.get(),
  141. &transformation_context);
  142. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  143. kConsoleMessageConsumer));
  144. ASSERT_TRUE(
  145. transformation3.IsApplicable(context.get(), transformation_context));
  146. ApplyAndCheckFreshIds(transformation3, context.get(),
  147. &transformation_context);
  148. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  149. kConsoleMessageConsumer));
  150. std::string after_transformation = R"(
  151. OpCapability Shader
  152. %1 = OpExtInstImport "GLSL.std.450"
  153. OpMemoryModel Logical GLSL450
  154. OpEntryPoint Fragment %4 "main"
  155. OpExecutionMode %4 OriginUpperLeft
  156. OpSource ESSL 310
  157. OpName %4 "main"
  158. OpName %8 "x"
  159. OpName %10 "i"
  160. %2 = OpTypeVoid
  161. %3 = OpTypeFunction %2
  162. %6 = OpTypeInt 32 1
  163. %7 = OpTypePointer Function %6
  164. %9 = OpConstant %6 0
  165. %17 = OpConstant %6 10
  166. %18 = OpTypeBool
  167. %41 = OpConstantTrue %18
  168. %42 = OpConstantFalse %18
  169. %27 = OpConstant %6 1
  170. %4 = OpFunction %2 None %3
  171. %5 = OpLabel
  172. %8 = OpVariable %7 Function
  173. %10 = OpVariable %7 Function
  174. OpStore %8 %9
  175. OpStore %10 %9
  176. OpBranch %11
  177. %11 = OpLabel
  178. OpLoopMerge %13 %14 None
  179. OpBranchConditional %41 %15 %14
  180. %15 = OpLabel
  181. %16 = OpLoad %6 %10
  182. %19 = OpSLessThan %18 %16 %17
  183. OpBranchConditional %19 %12 %13
  184. %12 = OpLabel
  185. %20 = OpLoad %6 %8
  186. %21 = OpLoad %6 %10
  187. %22 = OpIAdd %6 %20 %21
  188. OpStore %8 %22
  189. OpBranchConditional %42 %14 %40
  190. %40 = OpLabel
  191. %23 = OpLoad %6 %8
  192. %24 = OpLoad %6 %10
  193. %25 = OpIAdd %6 %23 %24
  194. OpStore %8 %25
  195. OpBranchConditional %41 %14 %14
  196. %14 = OpLabel
  197. %26 = OpLoad %6 %10
  198. %28 = OpIAdd %6 %26 %27
  199. OpStore %10 %28
  200. OpBranch %11
  201. %13 = OpLabel
  202. OpReturn
  203. OpFunctionEnd
  204. )";
  205. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  206. }
  207. TEST(TransformationAddDeadContinueTest, LoopNest) {
  208. // Checks some allowed and disallowed scenarios for a nest of loops, including
  209. // continuing a loop from an if or switch.
  210. // The SPIR-V for this test is adapted from the following GLSL:
  211. //
  212. // void main() {
  213. // int x, y;
  214. // do {
  215. // x++;
  216. // for (int j = 0; j < 100; j++) {
  217. // y++;
  218. // if (x == y) {
  219. // x++;
  220. // if (x == 2) {
  221. // y++;
  222. // }
  223. // switch (x) {
  224. // case 0:
  225. // x = 2;
  226. // default:
  227. // break;
  228. // }
  229. // }
  230. // }
  231. // } while (x > y);
  232. //
  233. // for (int i = 0; i < 100; i++) {
  234. // x++;
  235. // }
  236. // }
  237. std::string shader = R"(
  238. OpCapability Shader
  239. %1 = OpExtInstImport "GLSL.std.450"
  240. OpMemoryModel Logical GLSL450
  241. OpEntryPoint Fragment %4 "main"
  242. OpExecutionMode %4 OriginUpperLeft
  243. OpSource ESSL 310
  244. OpName %4 "main"
  245. OpName %12 "x"
  246. OpName %16 "j"
  247. OpName %27 "y"
  248. OpName %55 "i"
  249. %2 = OpTypeVoid
  250. %3 = OpTypeFunction %2
  251. %10 = OpTypeInt 32 1
  252. %11 = OpTypePointer Function %10
  253. %14 = OpConstant %10 1
  254. %17 = OpConstant %10 0
  255. %24 = OpConstant %10 100
  256. %25 = OpTypeBool
  257. %38 = OpConstant %10 2
  258. %67 = OpConstantTrue %25
  259. %68 = OpConstantFalse %25
  260. %4 = OpFunction %2 None %3
  261. %5 = OpLabel
  262. %12 = OpVariable %11 Function
  263. %16 = OpVariable %11 Function
  264. %27 = OpVariable %11 Function
  265. %55 = OpVariable %11 Function
  266. OpBranch %6
  267. %6 = OpLabel
  268. OpLoopMerge %8 %9 None
  269. OpBranch %7
  270. %7 = OpLabel
  271. %13 = OpLoad %10 %12
  272. %15 = OpIAdd %10 %13 %14
  273. OpStore %12 %15
  274. OpStore %16 %17
  275. OpBranch %18
  276. %18 = OpLabel
  277. OpLoopMerge %20 %21 None
  278. OpBranch %22
  279. %22 = OpLabel
  280. %23 = OpLoad %10 %16
  281. %26 = OpSLessThan %25 %23 %24
  282. OpBranchConditional %26 %19 %20
  283. %19 = OpLabel
  284. %28 = OpLoad %10 %27
  285. %29 = OpIAdd %10 %28 %14
  286. OpStore %27 %29
  287. %30 = OpLoad %10 %12
  288. %31 = OpLoad %10 %27
  289. %32 = OpIEqual %25 %30 %31
  290. OpSelectionMerge %34 None
  291. OpBranchConditional %32 %33 %34
  292. %33 = OpLabel
  293. %35 = OpLoad %10 %12
  294. %36 = OpIAdd %10 %35 %14
  295. OpStore %12 %36
  296. %37 = OpLoad %10 %12
  297. %39 = OpIEqual %25 %37 %38
  298. OpSelectionMerge %41 None
  299. OpBranchConditional %39 %40 %41
  300. %40 = OpLabel
  301. %42 = OpLoad %10 %27
  302. %43 = OpIAdd %10 %42 %14
  303. OpStore %27 %43
  304. OpBranch %41
  305. %41 = OpLabel
  306. %44 = OpLoad %10 %12
  307. OpSelectionMerge %47 None
  308. OpSwitch %44 %46 0 %45
  309. %46 = OpLabel
  310. OpBranch %47
  311. %45 = OpLabel
  312. OpStore %12 %38
  313. OpBranch %46
  314. %47 = OpLabel
  315. OpBranch %34
  316. %34 = OpLabel
  317. OpBranch %21
  318. %21 = OpLabel
  319. %50 = OpLoad %10 %16
  320. %51 = OpIAdd %10 %50 %14
  321. OpStore %16 %51
  322. OpBranch %18
  323. %20 = OpLabel
  324. OpBranch %9
  325. %9 = OpLabel
  326. %52 = OpLoad %10 %12
  327. %53 = OpLoad %10 %27
  328. %54 = OpSGreaterThan %25 %52 %53
  329. OpBranchConditional %54 %6 %8
  330. %8 = OpLabel
  331. OpStore %55 %17
  332. OpBranch %56
  333. %56 = OpLabel
  334. OpLoopMerge %58 %59 None
  335. OpBranch %60
  336. %60 = OpLabel
  337. %61 = OpLoad %10 %55
  338. %62 = OpSLessThan %25 %61 %24
  339. OpBranchConditional %62 %57 %58
  340. %57 = OpLabel
  341. %63 = OpLoad %10 %12
  342. %64 = OpIAdd %10 %63 %14
  343. OpStore %12 %64
  344. OpBranch %59
  345. %59 = OpLabel
  346. %65 = OpLoad %10 %55
  347. %66 = OpIAdd %10 %65 %14
  348. OpStore %55 %66
  349. OpBranch %56
  350. %58 = OpLabel
  351. OpReturn
  352. OpFunctionEnd
  353. )";
  354. const auto env = SPV_ENV_UNIVERSAL_1_3;
  355. const auto consumer = nullptr;
  356. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  357. spvtools::ValidatorOptions validator_options;
  358. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  359. kConsoleMessageConsumer));
  360. TransformationContext transformation_context(
  361. MakeUnique<FactManager>(context.get()), validator_options);
  362. std::vector<uint32_t> good = {6, 7, 18, 20, 34, 40, 45, 46, 47, 56, 57};
  363. std::vector<uint32_t> bad = {5, 8, 9, 19, 21, 22, 33, 41, 58, 59, 60};
  364. for (uint32_t from_block : bad) {
  365. ASSERT_FALSE(TransformationAddDeadContinue(from_block, true, {})
  366. .IsApplicable(context.get(), transformation_context));
  367. }
  368. for (uint32_t from_block : good) {
  369. const TransformationAddDeadContinue transformation(from_block, true, {});
  370. ASSERT_TRUE(
  371. transformation.IsApplicable(context.get(), transformation_context));
  372. ApplyAndCheckFreshIds(transformation, context.get(),
  373. &transformation_context);
  374. ASSERT_FALSE(
  375. transformation.IsApplicable(context.get(), transformation_context));
  376. }
  377. std::string after_transformation = R"(
  378. OpCapability Shader
  379. %1 = OpExtInstImport "GLSL.std.450"
  380. OpMemoryModel Logical GLSL450
  381. OpEntryPoint Fragment %4 "main"
  382. OpExecutionMode %4 OriginUpperLeft
  383. OpSource ESSL 310
  384. OpName %4 "main"
  385. OpName %12 "x"
  386. OpName %16 "j"
  387. OpName %27 "y"
  388. OpName %55 "i"
  389. %2 = OpTypeVoid
  390. %3 = OpTypeFunction %2
  391. %10 = OpTypeInt 32 1
  392. %11 = OpTypePointer Function %10
  393. %14 = OpConstant %10 1
  394. %17 = OpConstant %10 0
  395. %24 = OpConstant %10 100
  396. %25 = OpTypeBool
  397. %38 = OpConstant %10 2
  398. %67 = OpConstantTrue %25
  399. %68 = OpConstantFalse %25
  400. %4 = OpFunction %2 None %3
  401. %5 = OpLabel
  402. %12 = OpVariable %11 Function
  403. %16 = OpVariable %11 Function
  404. %27 = OpVariable %11 Function
  405. %55 = OpVariable %11 Function
  406. OpBranch %6
  407. %6 = OpLabel
  408. OpLoopMerge %8 %9 None
  409. OpBranchConditional %67 %7 %9
  410. %7 = OpLabel
  411. %13 = OpLoad %10 %12
  412. %15 = OpIAdd %10 %13 %14
  413. OpStore %12 %15
  414. OpStore %16 %17
  415. OpBranchConditional %67 %18 %9
  416. %18 = OpLabel
  417. OpLoopMerge %20 %21 None
  418. OpBranchConditional %67 %22 %21
  419. %22 = OpLabel
  420. %23 = OpLoad %10 %16
  421. %26 = OpSLessThan %25 %23 %24
  422. OpBranchConditional %26 %19 %20
  423. %19 = OpLabel
  424. %28 = OpLoad %10 %27
  425. %29 = OpIAdd %10 %28 %14
  426. OpStore %27 %29
  427. %30 = OpLoad %10 %12
  428. %31 = OpLoad %10 %27
  429. %32 = OpIEqual %25 %30 %31
  430. OpSelectionMerge %34 None
  431. OpBranchConditional %32 %33 %34
  432. %33 = OpLabel
  433. %35 = OpLoad %10 %12
  434. %36 = OpIAdd %10 %35 %14
  435. OpStore %12 %36
  436. %37 = OpLoad %10 %12
  437. %39 = OpIEqual %25 %37 %38
  438. OpSelectionMerge %41 None
  439. OpBranchConditional %39 %40 %41
  440. %40 = OpLabel
  441. %42 = OpLoad %10 %27
  442. %43 = OpIAdd %10 %42 %14
  443. OpStore %27 %43
  444. OpBranchConditional %67 %41 %21
  445. %41 = OpLabel
  446. %44 = OpLoad %10 %12
  447. OpSelectionMerge %47 None
  448. OpSwitch %44 %46 0 %45
  449. %46 = OpLabel
  450. OpBranchConditional %67 %47 %21
  451. %45 = OpLabel
  452. OpStore %12 %38
  453. OpBranchConditional %67 %46 %21
  454. %47 = OpLabel
  455. OpBranchConditional %67 %34 %21
  456. %34 = OpLabel
  457. OpBranchConditional %67 %21 %21
  458. %21 = OpLabel
  459. %50 = OpLoad %10 %16
  460. %51 = OpIAdd %10 %50 %14
  461. OpStore %16 %51
  462. OpBranch %18
  463. %20 = OpLabel
  464. OpBranchConditional %67 %9 %9
  465. %9 = OpLabel
  466. %52 = OpLoad %10 %12
  467. %53 = OpLoad %10 %27
  468. %54 = OpSGreaterThan %25 %52 %53
  469. OpBranchConditional %54 %6 %8
  470. %8 = OpLabel
  471. OpStore %55 %17
  472. OpBranch %56
  473. %56 = OpLabel
  474. OpLoopMerge %58 %59 None
  475. OpBranchConditional %67 %60 %59
  476. %60 = OpLabel
  477. %61 = OpLoad %10 %55
  478. %62 = OpSLessThan %25 %61 %24
  479. OpBranchConditional %62 %57 %58
  480. %57 = OpLabel
  481. %63 = OpLoad %10 %12
  482. %64 = OpIAdd %10 %63 %14
  483. OpStore %12 %64
  484. OpBranchConditional %67 %59 %59
  485. %59 = OpLabel
  486. %65 = OpLoad %10 %55
  487. %66 = OpIAdd %10 %65 %14
  488. OpStore %55 %66
  489. OpBranch %56
  490. %58 = OpLabel
  491. OpReturn
  492. OpFunctionEnd
  493. )";
  494. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  495. }
  496. TEST(TransformationAddDeadConditionalTest, LoopInContinueConstruct) {
  497. // Considers some scenarios where there is a loop in a loop's continue
  498. // construct.
  499. // The SPIR-V for this test is adapted from the following GLSL, with inlining
  500. // applied so that the loop from foo is in the main loop's continue construct:
  501. //
  502. // int foo() {
  503. // int result = 0;
  504. // for (int j = 0; j < 10; j++) {
  505. // result++;
  506. // }
  507. // return result;
  508. // }
  509. //
  510. // void main() {
  511. // for (int i = 0; i < 100; i += foo()) {
  512. // }
  513. // }
  514. std::string shader = R"(
  515. OpCapability Shader
  516. %1 = OpExtInstImport "GLSL.std.450"
  517. OpMemoryModel Logical GLSL450
  518. OpEntryPoint Fragment %4 "main"
  519. OpExecutionMode %4 OriginUpperLeft
  520. OpSource ESSL 310
  521. OpName %4 "main"
  522. OpName %31 "i"
  523. %2 = OpTypeVoid
  524. %3 = OpTypeFunction %2
  525. %6 = OpTypeInt 32 1
  526. %7 = OpTypeFunction %6
  527. %10 = OpTypePointer Function %6
  528. %12 = OpConstant %6 0
  529. %20 = OpConstant %6 10
  530. %21 = OpTypeBool
  531. %100 = OpConstantFalse %21
  532. %24 = OpConstant %6 1
  533. %38 = OpConstant %6 100
  534. %4 = OpFunction %2 None %3
  535. %5 = OpLabel
  536. %43 = OpVariable %10 Function
  537. %44 = OpVariable %10 Function
  538. %45 = OpVariable %10 Function
  539. %31 = OpVariable %10 Function
  540. OpStore %31 %12
  541. OpBranch %32
  542. %32 = OpLabel
  543. OpLoopMerge %34 %35 None
  544. OpBranch %36
  545. %36 = OpLabel
  546. %37 = OpLoad %6 %31
  547. %39 = OpSLessThan %21 %37 %38
  548. OpBranchConditional %39 %33 %34
  549. %33 = OpLabel
  550. OpBranch %35
  551. %35 = OpLabel
  552. OpStore %43 %12
  553. OpStore %44 %12
  554. OpBranch %46
  555. %46 = OpLabel
  556. OpLoopMerge %47 %48 None
  557. OpBranch %49
  558. %49 = OpLabel
  559. %50 = OpLoad %6 %44
  560. %51 = OpSLessThan %21 %50 %20
  561. OpBranchConditional %51 %52 %47
  562. %52 = OpLabel
  563. %53 = OpLoad %6 %43
  564. OpBranch %101
  565. %101 = OpLabel
  566. %54 = OpIAdd %6 %53 %24
  567. OpStore %43 %54
  568. OpBranch %48
  569. %48 = OpLabel
  570. %55 = OpLoad %6 %44
  571. %56 = OpIAdd %6 %55 %24
  572. OpStore %44 %56
  573. OpBranch %46
  574. %47 = OpLabel
  575. %57 = OpLoad %6 %43
  576. OpStore %45 %57
  577. %40 = OpLoad %6 %45
  578. %41 = OpLoad %6 %31
  579. %42 = OpIAdd %6 %41 %40
  580. OpStore %31 %42
  581. OpBranch %32
  582. %34 = OpLabel
  583. OpReturn
  584. OpFunctionEnd
  585. )";
  586. const auto env = SPV_ENV_UNIVERSAL_1_3;
  587. const auto consumer = nullptr;
  588. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  589. spvtools::ValidatorOptions validator_options;
  590. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  591. kConsoleMessageConsumer));
  592. TransformationContext transformation_context(
  593. MakeUnique<FactManager>(context.get()), validator_options);
  594. std::vector<uint32_t> good = {32, 33, 46, 52, 101};
  595. std::vector<uint32_t> bad = {5, 34, 36, 35, 47, 49, 48};
  596. for (uint32_t from_block : bad) {
  597. ASSERT_FALSE(TransformationAddDeadContinue(from_block, false, {})
  598. .IsApplicable(context.get(), transformation_context));
  599. }
  600. for (uint32_t from_block : good) {
  601. const TransformationAddDeadContinue transformation(from_block, false, {});
  602. ASSERT_TRUE(
  603. transformation.IsApplicable(context.get(), transformation_context));
  604. ApplyAndCheckFreshIds(transformation, context.get(),
  605. &transformation_context);
  606. ASSERT_FALSE(
  607. transformation.IsApplicable(context.get(), transformation_context));
  608. }
  609. std::string after_transformation = R"(
  610. OpCapability Shader
  611. %1 = OpExtInstImport "GLSL.std.450"
  612. OpMemoryModel Logical GLSL450
  613. OpEntryPoint Fragment %4 "main"
  614. OpExecutionMode %4 OriginUpperLeft
  615. OpSource ESSL 310
  616. OpName %4 "main"
  617. OpName %31 "i"
  618. %2 = OpTypeVoid
  619. %3 = OpTypeFunction %2
  620. %6 = OpTypeInt 32 1
  621. %7 = OpTypeFunction %6
  622. %10 = OpTypePointer Function %6
  623. %12 = OpConstant %6 0
  624. %20 = OpConstant %6 10
  625. %21 = OpTypeBool
  626. %100 = OpConstantFalse %21
  627. %24 = OpConstant %6 1
  628. %38 = OpConstant %6 100
  629. %4 = OpFunction %2 None %3
  630. %5 = OpLabel
  631. %43 = OpVariable %10 Function
  632. %44 = OpVariable %10 Function
  633. %45 = OpVariable %10 Function
  634. %31 = OpVariable %10 Function
  635. OpStore %31 %12
  636. OpBranch %32
  637. %32 = OpLabel
  638. OpLoopMerge %34 %35 None
  639. OpBranchConditional %100 %35 %36
  640. %36 = OpLabel
  641. %37 = OpLoad %6 %31
  642. %39 = OpSLessThan %21 %37 %38
  643. OpBranchConditional %39 %33 %34
  644. %33 = OpLabel
  645. OpBranchConditional %100 %35 %35
  646. %35 = OpLabel
  647. OpStore %43 %12
  648. OpStore %44 %12
  649. OpBranch %46
  650. %46 = OpLabel
  651. OpLoopMerge %47 %48 None
  652. OpBranchConditional %100 %48 %49
  653. %49 = OpLabel
  654. %50 = OpLoad %6 %44
  655. %51 = OpSLessThan %21 %50 %20
  656. OpBranchConditional %51 %52 %47
  657. %52 = OpLabel
  658. %53 = OpLoad %6 %43
  659. OpBranchConditional %100 %48 %101
  660. %101 = OpLabel
  661. %54 = OpIAdd %6 %53 %24
  662. OpStore %43 %54
  663. OpBranchConditional %100 %48 %48
  664. %48 = OpLabel
  665. %55 = OpLoad %6 %44
  666. %56 = OpIAdd %6 %55 %24
  667. OpStore %44 %56
  668. OpBranch %46
  669. %47 = OpLabel
  670. %57 = OpLoad %6 %43
  671. OpStore %45 %57
  672. %40 = OpLoad %6 %45
  673. %41 = OpLoad %6 %31
  674. %42 = OpIAdd %6 %41 %40
  675. OpStore %31 %42
  676. OpBranch %32
  677. %34 = OpLabel
  678. OpReturn
  679. OpFunctionEnd
  680. )";
  681. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  682. }
  683. TEST(TransformationAddDeadContinueTest, PhiInstructions) {
  684. // Checks that the transformation works in the presence of phi instructions.
  685. // The SPIR-V for this test is adapted from the following GLSL, with a bit of
  686. // extra and artificial work to get some interesting uses of OpPhi:
  687. //
  688. // void main() {
  689. // int x; int y;
  690. // float f;
  691. // x = 2;
  692. // f = 3.0;
  693. // if (x > y) {
  694. // x = 3;
  695. // f = 4.0;
  696. // } else {
  697. // x = x + 2;
  698. // f = f + 10.0;
  699. // }
  700. // while (x < y) {
  701. // x = x + 1;
  702. // f = f + 1.0;
  703. // }
  704. // y = x;
  705. // f = f + 3.0;
  706. // }
  707. std::string shader = R"(
  708. OpCapability Shader
  709. %1 = OpExtInstImport "GLSL.std.450"
  710. OpMemoryModel Logical GLSL450
  711. OpEntryPoint Fragment %4 "main"
  712. OpExecutionMode %4 OriginUpperLeft
  713. OpSource ESSL 310
  714. OpName %4 "main"
  715. OpName %8 "x"
  716. OpName %12 "f"
  717. OpName %15 "y"
  718. %2 = OpTypeVoid
  719. %3 = OpTypeFunction %2
  720. %6 = OpTypeInt 32 1
  721. %7 = OpTypePointer Function %6
  722. %9 = OpConstant %6 2
  723. %10 = OpTypeFloat 32
  724. %11 = OpTypePointer Function %10
  725. %13 = OpConstant %10 3
  726. %17 = OpTypeBool
  727. %80 = OpConstantTrue %17
  728. %21 = OpConstant %6 3
  729. %22 = OpConstant %10 4
  730. %27 = OpConstant %10 10
  731. %38 = OpConstant %6 1
  732. %41 = OpConstant %10 1
  733. %46 = OpUndef %6
  734. %4 = OpFunction %2 None %3
  735. %5 = OpLabel
  736. %8 = OpVariable %7 Function
  737. %12 = OpVariable %11 Function
  738. %15 = OpVariable %7 Function
  739. OpStore %8 %9
  740. OpStore %12 %13
  741. %18 = OpSGreaterThan %17 %9 %46
  742. OpSelectionMerge %20 None
  743. OpBranchConditional %18 %19 %23
  744. %19 = OpLabel
  745. OpStore %8 %21
  746. OpStore %12 %22
  747. OpBranch %20
  748. %23 = OpLabel
  749. %25 = OpIAdd %6 %9 %9
  750. OpStore %8 %25
  751. OpBranch %70
  752. %70 = OpLabel
  753. %28 = OpFAdd %10 %13 %27
  754. OpStore %12 %28
  755. OpBranch %20
  756. %20 = OpLabel
  757. %52 = OpPhi %10 %22 %19 %28 %70
  758. %48 = OpPhi %6 %21 %19 %25 %70
  759. OpBranch %29
  760. %29 = OpLabel
  761. %51 = OpPhi %10 %52 %20 %100 %32
  762. %47 = OpPhi %6 %48 %20 %101 %32
  763. OpLoopMerge %31 %32 None
  764. OpBranch %33
  765. %33 = OpLabel
  766. %36 = OpSLessThan %17 %47 %46
  767. OpBranchConditional %36 %30 %31
  768. %30 = OpLabel
  769. %39 = OpIAdd %6 %47 %38
  770. OpStore %8 %39
  771. OpBranch %75
  772. %75 = OpLabel
  773. %42 = OpFAdd %10 %51 %41
  774. OpStore %12 %42
  775. OpBranch %32
  776. %32 = OpLabel
  777. %100 = OpPhi %10 %42 %75
  778. %101 = OpPhi %6 %39 %75
  779. OpBranch %29
  780. %31 = OpLabel
  781. %71 = OpPhi %6 %47 %33
  782. %72 = OpPhi %10 %51 %33
  783. OpStore %15 %71
  784. %45 = OpFAdd %10 %72 %13
  785. OpStore %12 %45
  786. OpReturn
  787. OpFunctionEnd
  788. )";
  789. const auto env = SPV_ENV_UNIVERSAL_1_3;
  790. const auto consumer = nullptr;
  791. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  792. spvtools::ValidatorOptions validator_options;
  793. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  794. kConsoleMessageConsumer));
  795. TransformationContext transformation_context(
  796. MakeUnique<FactManager>(context.get()), validator_options);
  797. std::vector<uint32_t> bad = {5, 19, 20, 23, 31, 32, 33, 70};
  798. std::vector<uint32_t> good = {29, 30, 75};
  799. for (uint32_t from_block : bad) {
  800. ASSERT_FALSE(TransformationAddDeadContinue(from_block, true, {})
  801. .IsApplicable(context.get(), transformation_context));
  802. }
  803. auto transformation1 = TransformationAddDeadContinue(29, true, {13, 21});
  804. ASSERT_TRUE(
  805. transformation1.IsApplicable(context.get(), transformation_context));
  806. ApplyAndCheckFreshIds(transformation1, context.get(),
  807. &transformation_context);
  808. auto transformation2 = TransformationAddDeadContinue(30, true, {22, 46});
  809. ASSERT_TRUE(
  810. transformation2.IsApplicable(context.get(), transformation_context));
  811. ApplyAndCheckFreshIds(transformation2, context.get(),
  812. &transformation_context);
  813. // 75 already has the continue block as a successor, so we should not provide
  814. // phi ids.
  815. auto transformationBad = TransformationAddDeadContinue(75, true, {27, 46});
  816. ASSERT_FALSE(
  817. transformationBad.IsApplicable(context.get(), transformation_context));
  818. auto transformation3 = TransformationAddDeadContinue(75, true, {});
  819. ASSERT_TRUE(
  820. transformation3.IsApplicable(context.get(), transformation_context));
  821. ApplyAndCheckFreshIds(transformation3, context.get(),
  822. &transformation_context);
  823. std::string after_transformation = R"(
  824. OpCapability Shader
  825. %1 = OpExtInstImport "GLSL.std.450"
  826. OpMemoryModel Logical GLSL450
  827. OpEntryPoint Fragment %4 "main"
  828. OpExecutionMode %4 OriginUpperLeft
  829. OpSource ESSL 310
  830. OpName %4 "main"
  831. OpName %8 "x"
  832. OpName %12 "f"
  833. OpName %15 "y"
  834. %2 = OpTypeVoid
  835. %3 = OpTypeFunction %2
  836. %6 = OpTypeInt 32 1
  837. %7 = OpTypePointer Function %6
  838. %9 = OpConstant %6 2
  839. %10 = OpTypeFloat 32
  840. %11 = OpTypePointer Function %10
  841. %13 = OpConstant %10 3
  842. %17 = OpTypeBool
  843. %80 = OpConstantTrue %17
  844. %21 = OpConstant %6 3
  845. %22 = OpConstant %10 4
  846. %27 = OpConstant %10 10
  847. %38 = OpConstant %6 1
  848. %41 = OpConstant %10 1
  849. %46 = OpUndef %6
  850. %4 = OpFunction %2 None %3
  851. %5 = OpLabel
  852. %8 = OpVariable %7 Function
  853. %12 = OpVariable %11 Function
  854. %15 = OpVariable %7 Function
  855. OpStore %8 %9
  856. OpStore %12 %13
  857. %18 = OpSGreaterThan %17 %9 %46
  858. OpSelectionMerge %20 None
  859. OpBranchConditional %18 %19 %23
  860. %19 = OpLabel
  861. OpStore %8 %21
  862. OpStore %12 %22
  863. OpBranch %20
  864. %23 = OpLabel
  865. %25 = OpIAdd %6 %9 %9
  866. OpStore %8 %25
  867. OpBranch %70
  868. %70 = OpLabel
  869. %28 = OpFAdd %10 %13 %27
  870. OpStore %12 %28
  871. OpBranch %20
  872. %20 = OpLabel
  873. %52 = OpPhi %10 %22 %19 %28 %70
  874. %48 = OpPhi %6 %21 %19 %25 %70
  875. OpBranch %29
  876. %29 = OpLabel
  877. %51 = OpPhi %10 %52 %20 %100 %32
  878. %47 = OpPhi %6 %48 %20 %101 %32
  879. OpLoopMerge %31 %32 None
  880. OpBranchConditional %80 %33 %32
  881. %33 = OpLabel
  882. %36 = OpSLessThan %17 %47 %46
  883. OpBranchConditional %36 %30 %31
  884. %30 = OpLabel
  885. %39 = OpIAdd %6 %47 %38
  886. OpStore %8 %39
  887. OpBranchConditional %80 %75 %32
  888. %75 = OpLabel
  889. %42 = OpFAdd %10 %51 %41
  890. OpStore %12 %42
  891. OpBranchConditional %80 %32 %32
  892. %32 = OpLabel
  893. %100 = OpPhi %10 %42 %75 %13 %29 %22 %30
  894. %101 = OpPhi %6 %39 %75 %21 %29 %46 %30
  895. OpBranch %29
  896. %31 = OpLabel
  897. %71 = OpPhi %6 %47 %33
  898. %72 = OpPhi %10 %51 %33
  899. OpStore %15 %71
  900. %45 = OpFAdd %10 %72 %13
  901. OpStore %12 %45
  902. OpReturn
  903. OpFunctionEnd
  904. )";
  905. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  906. }
  907. TEST(TransformationAddDeadContinueTest, RespectDominanceRules1) {
  908. // Checks that a dead continue cannot be added if it would prevent a block
  909. // later in the loop from dominating the loop's continue construct, in the
  910. // case where said block defines and id that is used in the loop's continue
  911. // construct.
  912. std::string shader = R"(
  913. OpCapability Shader
  914. %1 = OpExtInstImport "GLSL.std.450"
  915. OpMemoryModel Logical GLSL450
  916. OpEntryPoint Fragment %4 "main"
  917. OpExecutionMode %4 OriginUpperLeft
  918. OpSource ESSL 310
  919. OpName %4 "main"
  920. %2 = OpTypeVoid
  921. %3 = OpTypeFunction %2
  922. %10 = OpTypeBool
  923. %11 = OpConstantFalse %10
  924. %4 = OpFunction %2 None %3
  925. %5 = OpLabel
  926. OpBranch %6
  927. %6 = OpLabel
  928. OpLoopMerge %8 %9 None
  929. OpBranch %7
  930. %7 = OpLabel
  931. %21 = OpCopyObject %10 %11
  932. OpBranch %9
  933. %9 = OpLabel
  934. %20 = OpPhi %10 %21 %7
  935. OpBranchConditional %11 %6 %8
  936. %8 = OpLabel
  937. OpBranch %12
  938. %12 = OpLabel
  939. OpLoopMerge %14 %15 None
  940. OpBranch %13
  941. %13 = OpLabel
  942. OpBranch %22
  943. %22 = OpLabel
  944. %23 = OpCopyObject %10 %11
  945. OpBranch %25
  946. %25 = OpLabel
  947. OpBranch %15
  948. %15 = OpLabel
  949. %26 = OpCopyObject %10 %23
  950. OpBranchConditional %11 %12 %14
  951. %14 = OpLabel
  952. OpReturn
  953. OpFunctionEnd
  954. )";
  955. const auto env = SPV_ENV_UNIVERSAL_1_3;
  956. const auto consumer = nullptr;
  957. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  958. spvtools::ValidatorOptions validator_options;
  959. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  960. kConsoleMessageConsumer));
  961. TransformationContext transformation_context(
  962. MakeUnique<FactManager>(context.get()), validator_options);
  963. // This transformation is not applicable because the dead continue from the
  964. // loop body prevents the definition of %23 later in the loop body from
  965. // dominating its use in the loop's continue target.
  966. auto bad_transformation = TransformationAddDeadContinue(13, false, {});
  967. ASSERT_FALSE(
  968. bad_transformation.IsApplicable(context.get(), transformation_context));
  969. auto good_transformation_1 = TransformationAddDeadContinue(7, false, {});
  970. ASSERT_TRUE(good_transformation_1.IsApplicable(context.get(),
  971. transformation_context));
  972. ApplyAndCheckFreshIds(good_transformation_1, context.get(),
  973. &transformation_context);
  974. auto good_transformation_2 = TransformationAddDeadContinue(22, false, {});
  975. ASSERT_TRUE(good_transformation_2.IsApplicable(context.get(),
  976. transformation_context));
  977. ApplyAndCheckFreshIds(good_transformation_2, context.get(),
  978. &transformation_context);
  979. // This transformation is OK, because the definition of %21 in the loop body
  980. // is only used in an OpPhi in the loop's continue target.
  981. auto good_transformation_3 = TransformationAddDeadContinue(6, false, {11});
  982. ASSERT_TRUE(good_transformation_3.IsApplicable(context.get(),
  983. transformation_context));
  984. ApplyAndCheckFreshIds(good_transformation_3, context.get(),
  985. &transformation_context);
  986. std::string after_transformations = R"(
  987. OpCapability Shader
  988. %1 = OpExtInstImport "GLSL.std.450"
  989. OpMemoryModel Logical GLSL450
  990. OpEntryPoint Fragment %4 "main"
  991. OpExecutionMode %4 OriginUpperLeft
  992. OpSource ESSL 310
  993. OpName %4 "main"
  994. %2 = OpTypeVoid
  995. %3 = OpTypeFunction %2
  996. %10 = OpTypeBool
  997. %11 = OpConstantFalse %10
  998. %4 = OpFunction %2 None %3
  999. %5 = OpLabel
  1000. OpBranch %6
  1001. %6 = OpLabel
  1002. OpLoopMerge %8 %9 None
  1003. OpBranchConditional %11 %9 %7
  1004. %7 = OpLabel
  1005. %21 = OpCopyObject %10 %11
  1006. OpBranchConditional %11 %9 %9
  1007. %9 = OpLabel
  1008. %20 = OpPhi %10 %21 %7 %11 %6
  1009. OpBranchConditional %11 %6 %8
  1010. %8 = OpLabel
  1011. OpBranch %12
  1012. %12 = OpLabel
  1013. OpLoopMerge %14 %15 None
  1014. OpBranch %13
  1015. %13 = OpLabel
  1016. OpBranch %22
  1017. %22 = OpLabel
  1018. %23 = OpCopyObject %10 %11
  1019. OpBranchConditional %11 %15 %25
  1020. %25 = OpLabel
  1021. OpBranch %15
  1022. %15 = OpLabel
  1023. %26 = OpCopyObject %10 %23
  1024. OpBranchConditional %11 %12 %14
  1025. %14 = OpLabel
  1026. OpReturn
  1027. OpFunctionEnd
  1028. )";
  1029. ASSERT_TRUE(IsEqual(env, after_transformations, context.get()));
  1030. }
  1031. TEST(TransformationAddDeadContinueTest, RespectDominanceRules2) {
  1032. // Checks that a dead continue cannot be added if it would lead to a use after
  1033. // the loop failing to be dominated by its definition.
  1034. std::string shader = R"(
  1035. OpCapability Shader
  1036. %1 = OpExtInstImport "GLSL.std.450"
  1037. OpMemoryModel Logical GLSL450
  1038. OpEntryPoint Fragment %4 "main"
  1039. OpExecutionMode %4 OriginUpperLeft
  1040. OpSource ESSL 310
  1041. OpName %4 "main"
  1042. %2 = OpTypeVoid
  1043. %3 = OpTypeFunction %2
  1044. %10 = OpTypeBool
  1045. %11 = OpConstantFalse %10
  1046. %4 = OpFunction %2 None %3
  1047. %5 = OpLabel
  1048. OpBranch %100
  1049. %100 = OpLabel
  1050. OpLoopMerge %101 %102 None
  1051. OpBranch %103
  1052. %103 = OpLabel
  1053. %200 = OpCopyObject %10 %11
  1054. OpBranch %104
  1055. %104 = OpLabel
  1056. OpBranch %102
  1057. %102 = OpLabel
  1058. OpBranchConditional %11 %100 %101
  1059. %101 = OpLabel
  1060. %201 = OpCopyObject %10 %200
  1061. OpReturn
  1062. OpFunctionEnd
  1063. )";
  1064. const auto env = SPV_ENV_UNIVERSAL_1_3;
  1065. const auto consumer = nullptr;
  1066. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1067. spvtools::ValidatorOptions validator_options;
  1068. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1069. kConsoleMessageConsumer));
  1070. TransformationContext transformation_context(
  1071. MakeUnique<FactManager>(context.get()), validator_options);
  1072. // This transformation would shortcut the part of the loop body that defines
  1073. // an id used after the loop.
  1074. auto bad_transformation = TransformationAddDeadContinue(100, false, {});
  1075. ASSERT_FALSE(
  1076. bad_transformation.IsApplicable(context.get(), transformation_context));
  1077. }
  1078. TEST(TransformationAddDeadContinueTest, RespectDominanceRules3) {
  1079. // Checks that a dead continue cannot be added if it would lead to a dominance
  1080. // problem with an id used in an OpPhi after the loop.
  1081. std::string shader = R"(
  1082. OpCapability Shader
  1083. %1 = OpExtInstImport "GLSL.std.450"
  1084. OpMemoryModel Logical GLSL450
  1085. OpEntryPoint Fragment %4 "main"
  1086. OpExecutionMode %4 OriginUpperLeft
  1087. OpSource ESSL 310
  1088. OpName %4 "main"
  1089. %2 = OpTypeVoid
  1090. %3 = OpTypeFunction %2
  1091. %10 = OpTypeBool
  1092. %11 = OpConstantFalse %10
  1093. %4 = OpFunction %2 None %3
  1094. %5 = OpLabel
  1095. OpBranch %100
  1096. %100 = OpLabel
  1097. OpLoopMerge %101 %102 None
  1098. OpBranch %103
  1099. %103 = OpLabel
  1100. %200 = OpCopyObject %10 %11
  1101. OpBranch %104
  1102. %104 = OpLabel
  1103. OpBranch %102
  1104. %102 = OpLabel
  1105. OpBranchConditional %11 %100 %101
  1106. %101 = OpLabel
  1107. %201 = OpPhi %10 %200 %102
  1108. OpReturn
  1109. OpFunctionEnd
  1110. )";
  1111. const auto env = SPV_ENV_UNIVERSAL_1_3;
  1112. const auto consumer = nullptr;
  1113. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1114. spvtools::ValidatorOptions validator_options;
  1115. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1116. kConsoleMessageConsumer));
  1117. TransformationContext transformation_context(
  1118. MakeUnique<FactManager>(context.get()), validator_options);
  1119. // This transformation would shortcut the part of the loop body that defines
  1120. // an id used after the loop.
  1121. auto bad_transformation = TransformationAddDeadContinue(100, false, {});
  1122. ASSERT_FALSE(
  1123. bad_transformation.IsApplicable(context.get(), transformation_context));
  1124. }
  1125. TEST(TransformationAddDeadContinueTest, Miscellaneous1) {
  1126. // A miscellaneous test that exposed a bug in spirv-fuzz.
  1127. std::string shader = R"(
  1128. OpCapability Shader
  1129. %1 = OpExtInstImport "GLSL.std.450"
  1130. OpMemoryModel Logical GLSL450
  1131. OpEntryPoint Fragment %4 "main" %586 %623
  1132. OpExecutionMode %4 OriginUpperLeft
  1133. OpSource ESSL 310
  1134. OpMemberDecorate %34 0 Offset 0
  1135. OpDecorate %34 Block
  1136. OpDecorate %36 DescriptorSet 0
  1137. OpDecorate %36 Binding 0
  1138. OpDecorate %586 BuiltIn FragCoord
  1139. OpMemberDecorate %591 0 Offset 0
  1140. OpDecorate %591 Block
  1141. OpDecorate %593 DescriptorSet 0
  1142. OpDecorate %593 Binding 1
  1143. OpDecorate %623 Location 0
  1144. %2 = OpTypeVoid
  1145. %3 = OpTypeFunction %2
  1146. %6 = OpTypeInt 32 1
  1147. %7 = OpTypePointer Function %6
  1148. %9 = OpConstant %6 0
  1149. %16 = OpConstant %6 2
  1150. %17 = OpTypeBool
  1151. %27 = OpTypeFloat 32
  1152. %28 = OpTypeVector %27 2
  1153. %29 = OpTypeMatrix %28 2
  1154. %30 = OpTypePointer Private %29
  1155. %31 = OpVariable %30 Private
  1156. %34 = OpTypeStruct %27
  1157. %35 = OpTypePointer Uniform %34
  1158. %36 = OpVariable %35 Uniform
  1159. %37 = OpTypePointer Uniform %27
  1160. %40 = OpTypePointer Private %27
  1161. %43 = OpConstant %6 1
  1162. %62 = OpConstant %6 3
  1163. %64 = OpTypeVector %27 3
  1164. %65 = OpTypeMatrix %64 2
  1165. %66 = OpTypePointer Private %65
  1166. %67 = OpVariable %66 Private
  1167. %92 = OpConstant %6 4
  1168. %94 = OpTypeVector %27 4
  1169. %95 = OpTypeMatrix %94 2
  1170. %96 = OpTypePointer Private %95
  1171. %97 = OpVariable %96 Private
  1172. %123 = OpTypeMatrix %28 3
  1173. %124 = OpTypePointer Private %123
  1174. %125 = OpVariable %124 Private
  1175. %151 = OpTypeMatrix %64 3
  1176. %152 = OpTypePointer Private %151
  1177. %153 = OpVariable %152 Private
  1178. %179 = OpTypeMatrix %94 3
  1179. %180 = OpTypePointer Private %179
  1180. %181 = OpVariable %180 Private
  1181. %207 = OpTypeMatrix %28 4
  1182. %208 = OpTypePointer Private %207
  1183. %209 = OpVariable %208 Private
  1184. %235 = OpTypeMatrix %64 4
  1185. %236 = OpTypePointer Private %235
  1186. %237 = OpVariable %236 Private
  1187. %263 = OpTypeMatrix %94 4
  1188. %264 = OpTypePointer Private %263
  1189. %265 = OpVariable %264 Private
  1190. %275 = OpTypeInt 32 0
  1191. %276 = OpConstant %275 9
  1192. %277 = OpTypeArray %27 %276
  1193. %278 = OpTypePointer Function %277
  1194. %280 = OpConstant %27 0
  1195. %281 = OpTypePointer Function %27
  1196. %311 = OpConstant %27 16
  1197. %448 = OpConstant %6 5
  1198. %482 = OpConstant %6 6
  1199. %516 = OpConstant %6 7
  1200. %550 = OpConstant %6 8
  1201. %585 = OpTypePointer Input %94
  1202. %586 = OpVariable %585 Input
  1203. %587 = OpConstant %275 0
  1204. %588 = OpTypePointer Input %27
  1205. %591 = OpTypeStruct %28
  1206. %592 = OpTypePointer Uniform %591
  1207. %593 = OpVariable %592 Uniform
  1208. %596 = OpConstant %27 3
  1209. %601 = OpConstant %275 1
  1210. %617 = OpConstant %6 9
  1211. %622 = OpTypePointer Output %94
  1212. %623 = OpVariable %622 Output
  1213. %628 = OpConstant %27 1
  1214. %634 = OpConstantComposite %94 %280 %280 %280 %628
  1215. %635 = OpUndef %6
  1216. %636 = OpUndef %17
  1217. %637 = OpUndef %27
  1218. %638 = OpUndef %64
  1219. %639 = OpUndef %94
  1220. %640 = OpConstantTrue %17
  1221. %736 = OpConstantFalse %17
  1222. %642 = OpVariable %37 Uniform
  1223. %643 = OpVariable %40 Private
  1224. %4 = OpFunction %2 None %3
  1225. %5 = OpLabel
  1226. OpBranch %164
  1227. %164 = OpLabel
  1228. OpLoopMerge %166 %167 None
  1229. OpBranch %165
  1230. %165 = OpLabel
  1231. OpBranch %172
  1232. %172 = OpLabel
  1233. OpSelectionMerge %174 None
  1234. OpBranchConditional %640 %174 %174
  1235. %174 = OpLabel
  1236. %785 = OpCopyObject %6 %43
  1237. OpBranch %167
  1238. %167 = OpLabel
  1239. %190 = OpIAdd %6 %9 %785
  1240. OpBranchConditional %640 %164 %166
  1241. %166 = OpLabel
  1242. OpBranch %196
  1243. %196 = OpLabel
  1244. OpBranch %194
  1245. %194 = OpLabel
  1246. OpReturn
  1247. OpFunctionEnd
  1248. )";
  1249. const auto env = SPV_ENV_UNIVERSAL_1_3;
  1250. const auto consumer = nullptr;
  1251. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1252. spvtools::ValidatorOptions validator_options;
  1253. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1254. kConsoleMessageConsumer));
  1255. TransformationContext transformation_context(
  1256. MakeUnique<FactManager>(context.get()), validator_options);
  1257. // This transformation would shortcut the part of the loop body that defines
  1258. // an id used in the continue target.
  1259. auto bad_transformation = TransformationAddDeadContinue(165, false, {});
  1260. ASSERT_FALSE(
  1261. bad_transformation.IsApplicable(context.get(), transformation_context));
  1262. }
  1263. TEST(TransformationAddDeadContinueTest, Miscellaneous2) {
  1264. // A miscellaneous test that exposed a bug in spirv-fuzz.
  1265. std::string shader = R"(
  1266. OpCapability Shader
  1267. %1 = OpExtInstImport "GLSL.std.450"
  1268. OpMemoryModel Logical GLSL450
  1269. OpEntryPoint Fragment %4 "main"
  1270. OpExecutionMode %4 OriginUpperLeft
  1271. OpSource ESSL 310
  1272. %2 = OpTypeVoid
  1273. %3 = OpTypeFunction %2
  1274. %51 = OpTypeBool
  1275. %395 = OpConstantTrue %51
  1276. %4 = OpFunction %2 None %3
  1277. %5 = OpLabel
  1278. OpBranch %389
  1279. %389 = OpLabel
  1280. OpLoopMerge %388 %391 None
  1281. OpBranch %339
  1282. %339 = OpLabel
  1283. OpSelectionMerge %396 None
  1284. OpBranchConditional %395 %388 %396
  1285. %396 = OpLabel
  1286. OpBranch %1552
  1287. %1552 = OpLabel
  1288. OpLoopMerge %1553 %1554 None
  1289. OpBranch %1556
  1290. %1556 = OpLabel
  1291. OpLoopMerge %1557 %1570 None
  1292. OpBranchConditional %395 %1562 %1557
  1293. %1562 = OpLabel
  1294. OpBranchConditional %395 %1571 %1570
  1295. %1571 = OpLabel
  1296. OpBranch %1557
  1297. %1570 = OpLabel
  1298. OpBranch %1556
  1299. %1557 = OpLabel
  1300. OpSelectionMerge %1586 None
  1301. OpBranchConditional %395 %1553 %1586
  1302. %1586 = OpLabel
  1303. OpBranch %1553
  1304. %1554 = OpLabel
  1305. OpBranch %1552
  1306. %1553 = OpLabel
  1307. OpBranch %388
  1308. %391 = OpLabel
  1309. OpBranch %389
  1310. %388 = OpLabel
  1311. OpReturn
  1312. OpFunctionEnd
  1313. )";
  1314. const auto env = SPV_ENV_UNIVERSAL_1_3;
  1315. const auto consumer = nullptr;
  1316. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1317. spvtools::ValidatorOptions validator_options;
  1318. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1319. kConsoleMessageConsumer));
  1320. TransformationContext transformation_context(
  1321. MakeUnique<FactManager>(context.get()), validator_options);
  1322. // This transformation would introduce a branch from a continue target to
  1323. // itself.
  1324. auto bad_transformation = TransformationAddDeadContinue(1554, true, {});
  1325. ASSERT_FALSE(
  1326. bad_transformation.IsApplicable(context.get(), transformation_context));
  1327. }
  1328. TEST(TransformationAddDeadContinueTest, Miscellaneous3) {
  1329. // A miscellaneous test that exposed a bug in spirv-fuzz.
  1330. std::string shader = R"(
  1331. OpCapability Shader
  1332. %1 = OpExtInstImport "GLSL.std.450"
  1333. OpMemoryModel Logical GLSL450
  1334. OpEntryPoint Fragment %4 "main"
  1335. OpExecutionMode %4 OriginUpperLeft
  1336. OpSource ESSL 310
  1337. %2 = OpTypeVoid
  1338. %3 = OpTypeFunction %2
  1339. %85 = OpTypeBool
  1340. %434 = OpConstantFalse %85
  1341. %4 = OpFunction %2 None %3
  1342. %5 = OpLabel
  1343. OpBranch %234
  1344. %234 = OpLabel
  1345. OpLoopMerge %235 %236 None
  1346. OpBranch %259
  1347. %259 = OpLabel
  1348. OpLoopMerge %260 %274 None
  1349. OpBranchConditional %434 %265 %260
  1350. %265 = OpLabel
  1351. OpBranch %275
  1352. %275 = OpLabel
  1353. OpBranch %260
  1354. %274 = OpLabel
  1355. OpBranch %259
  1356. %260 = OpLabel
  1357. OpSelectionMerge %298 None
  1358. OpBranchConditional %434 %299 %300
  1359. %300 = OpLabel
  1360. OpBranch %235
  1361. %298 = OpLabel
  1362. OpUnreachable
  1363. %236 = OpLabel
  1364. OpBranch %234
  1365. %299 = OpLabel
  1366. OpBranch %235
  1367. %235 = OpLabel
  1368. OpReturn
  1369. OpFunctionEnd
  1370. )";
  1371. const auto env = SPV_ENV_UNIVERSAL_1_3;
  1372. const auto consumer = nullptr;
  1373. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1374. spvtools::ValidatorOptions validator_options;
  1375. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1376. kConsoleMessageConsumer));
  1377. TransformationContext transformation_context(
  1378. MakeUnique<FactManager>(context.get()), validator_options);
  1379. auto bad_transformation = TransformationAddDeadContinue(299, false, {});
  1380. // The continue edge would connect %299 to the previously-unreachable %236,
  1381. // making %299 dominate %236, and breaking the rule that block ordering must
  1382. // respect dominance.
  1383. ASSERT_FALSE(
  1384. bad_transformation.IsApplicable(context.get(), transformation_context));
  1385. }
  1386. TEST(TransformationAddDeadContinueTest, Miscellaneous4) {
  1387. // A miscellaneous test that exposed a bug in spirv-fuzz.
  1388. std::string shader = R"(
  1389. OpCapability Shader
  1390. %1 = OpExtInstImport "GLSL.std.450"
  1391. OpMemoryModel Logical GLSL450
  1392. OpEntryPoint Fragment %4 "main"
  1393. OpExecutionMode %4 OriginUpperLeft
  1394. OpSource ESSL 310
  1395. OpName %4 "main"
  1396. OpName %8 "i"
  1397. %2 = OpTypeVoid
  1398. %3 = OpTypeFunction %2
  1399. %6 = OpTypeInt 32 1
  1400. %7 = OpTypePointer Function %6
  1401. %9 = OpConstant %6 0
  1402. %16 = OpConstant %6 100
  1403. %17 = OpTypeBool
  1404. %100 = OpConstantFalse %17
  1405. %21 = OpConstant %6 1
  1406. %4 = OpFunction %2 None %3
  1407. %5 = OpLabel
  1408. %8 = OpVariable %7 Function
  1409. OpStore %8 %9
  1410. OpBranch %10
  1411. %13 = OpLabel
  1412. %20 = OpLoad %6 %8
  1413. %22 = OpIAdd %6 %20 %21
  1414. OpStore %8 %22
  1415. OpBranch %10
  1416. %10 = OpLabel
  1417. OpLoopMerge %12 %13 None
  1418. OpBranch %14
  1419. %14 = OpLabel
  1420. %15 = OpLoad %6 %8
  1421. %18 = OpSLessThan %17 %15 %16
  1422. OpBranchConditional %18 %11 %12
  1423. %11 = OpLabel
  1424. OpBranch %12
  1425. %12 = OpLabel
  1426. OpReturn
  1427. OpFunctionEnd
  1428. )";
  1429. const auto env = SPV_ENV_UNIVERSAL_1_3;
  1430. const auto consumer = nullptr;
  1431. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1432. spvtools::ValidatorOptions validator_options;
  1433. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1434. kConsoleMessageConsumer));
  1435. TransformationContext transformation_context(
  1436. MakeUnique<FactManager>(context.get()), validator_options);
  1437. auto bad_transformation = TransformationAddDeadContinue(10, false, {});
  1438. // The continue edge would connect %10 to the previously-unreachable %13,
  1439. // making %10 dominate %13, and breaking the rule that block ordering must
  1440. // respect dominance.
  1441. ASSERT_FALSE(
  1442. bad_transformation.IsApplicable(context.get(), transformation_context));
  1443. }
  1444. TEST(TransformationAddDeadContinueTest, Miscellaneous5) {
  1445. // A miscellaneous test that exposed a bug in spirv-fuzz.
  1446. std::string shader = R"(
  1447. OpCapability Shader
  1448. %1 = OpExtInstImport "GLSL.std.450"
  1449. OpMemoryModel Logical GLSL450
  1450. OpEntryPoint Fragment %4 "main"
  1451. OpExecutionMode %4 OriginUpperLeft
  1452. OpSource ESSL 310
  1453. %2 = OpTypeVoid
  1454. %3 = OpTypeFunction %2
  1455. %6 = OpTypeBool
  1456. %7 = OpTypePointer Function %6
  1457. %9 = OpConstantTrue %6
  1458. %4 = OpFunction %2 None %3
  1459. %5 = OpLabel
  1460. OpBranch %98
  1461. %98 = OpLabel
  1462. OpLoopMerge %100 %101 None
  1463. OpBranch %99
  1464. %99 = OpLabel
  1465. OpSelectionMerge %111 None
  1466. OpBranchConditional %9 %110 %111
  1467. %110 = OpLabel
  1468. OpBranch %100
  1469. %111 = OpLabel
  1470. %200 = OpCopyObject %6 %9
  1471. OpBranch %101
  1472. %101 = OpLabel
  1473. %201 = OpCopyObject %6 %200
  1474. OpBranchConditional %9 %98 %100
  1475. %100 = OpLabel
  1476. OpReturn
  1477. OpFunctionEnd
  1478. )";
  1479. const auto env = SPV_ENV_UNIVERSAL_1_3;
  1480. const auto consumer = nullptr;
  1481. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1482. spvtools::ValidatorOptions validator_options;
  1483. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1484. kConsoleMessageConsumer));
  1485. TransformationContext transformation_context(
  1486. MakeUnique<FactManager>(context.get()), validator_options);
  1487. auto bad_transformation = TransformationAddDeadContinue(110, true, {});
  1488. // The continue edge would lead to the use of %200 in block %101 no longer
  1489. // being dominated by its definition in block %111.
  1490. ASSERT_FALSE(
  1491. bad_transformation.IsApplicable(context.get(), transformation_context));
  1492. }
  1493. TEST(TransformationAddDeadContinueTest, Miscellaneous6) {
  1494. // A miscellaneous test that exposed a bug in spirv-fuzz.
  1495. std::string shader = R"(
  1496. OpCapability Shader
  1497. %1 = OpExtInstImport "GLSL.std.450"
  1498. OpMemoryModel Logical GLSL450
  1499. OpEntryPoint Fragment %4 "main"
  1500. OpExecutionMode %4 OriginUpperLeft
  1501. OpSource ESSL 310
  1502. %2 = OpTypeVoid
  1503. %3 = OpTypeFunction %2
  1504. %6 = OpTypeBool
  1505. %9 = OpConstantTrue %6
  1506. %4 = OpFunction %2 None %3
  1507. %5 = OpLabel
  1508. OpBranch %10
  1509. %10 = OpLabel
  1510. OpLoopMerge %13 %12 None
  1511. OpBranch %11
  1512. %11 = OpLabel
  1513. %20 = OpCopyObject %6 %9
  1514. OpBranch %12
  1515. %12 = OpLabel
  1516. OpBranchConditional %9 %10 %13
  1517. %13 = OpLabel
  1518. %21 = OpCopyObject %6 %20
  1519. OpReturn
  1520. OpFunctionEnd
  1521. )";
  1522. const auto env = SPV_ENV_UNIVERSAL_1_3;
  1523. const auto consumer = nullptr;
  1524. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  1525. spvtools::ValidatorOptions validator_options;
  1526. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1527. kConsoleMessageConsumer));
  1528. TransformationContext transformation_context(
  1529. MakeUnique<FactManager>(context.get()), validator_options);
  1530. auto bad_transformation = TransformationAddDeadContinue(10, true, {});
  1531. ASSERT_FALSE(
  1532. bad_transformation.IsApplicable(context.get(), transformation_context));
  1533. }
  1534. } // namespace
  1535. } // namespace fuzz
  1536. } // namespace spvtools