transformation_propagate_instruction_down_test.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138
  1. // Copyright (c) 2020 Vasyl Teliman
  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_propagate_instruction_down.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(TransformationPropagateInstructionDownTest, BasicTest) {
  23. std::string shader = R"(
  24. OpCapability Shader
  25. %1 = OpExtInstImport "GLSL.std.450"
  26. OpMemoryModel Logical GLSL450
  27. OpEntryPoint Fragment %4 "main"
  28. OpExecutionMode %4 OriginUpperLeft
  29. OpSource ESSL 310
  30. %2 = OpTypeVoid
  31. %3 = OpTypeFunction %2
  32. %6 = OpTypeInt 32 1
  33. %7 = OpConstant %6 1
  34. %12 = OpTypeBool
  35. %13 = OpConstantTrue %12
  36. %9 = OpTypePointer Function %6
  37. %4 = OpFunction %2 None %3
  38. ; Has no instruction to propagate
  39. %5 = OpLabel
  40. %10 = OpVariable %9 Function
  41. %8 = OpCopyObject %6 %7
  42. OpStore %10 %8
  43. OpBranch %11
  44. ; Unreachable block
  45. %100 = OpLabel
  46. %101 = OpCopyObject %6 %7
  47. OpBranch %11
  48. ; Selection header
  49. ;
  50. ; One of acceptable successors has an OpPhi that uses propagated
  51. ; instruction's id
  52. %11 = OpLabel
  53. %19 = OpCopyObject %6 %7
  54. OpSelectionMerge %18 None
  55. OpBranchConditional %13 %14 %18
  56. ; %16 has no acceptable successors
  57. %14 = OpLabel
  58. %20 = OpPhi %6 %19 %11
  59. %15 = OpCopyObject %6 %7 ; dependency
  60. OpBranch %16
  61. %16 = OpLabel
  62. %17 = OpCopyObject %6 %15
  63. OpBranch %18
  64. ; Can be applied
  65. %18 = OpLabel
  66. %21 = OpCopyObject %6 %7
  67. OpSelectionMerge %24 None
  68. OpBranchConditional %13 %22 %23
  69. %22 = OpLabel
  70. %29 = OpPhi %6 %7 %18
  71. OpStore %10 %21
  72. OpBranch %24
  73. %23 = OpLabel
  74. OpStore %10 %21
  75. OpBranch %24
  76. %24 = OpLabel
  77. OpStore %10 %21
  78. OpBranch %32
  79. ; Can't replace all uses of the propagated instruction: %30 is
  80. ; propagated into %27.
  81. %32 = OpLabel
  82. OpLoopMerge %28 %27 None
  83. OpBranchConditional %13 %26 %28
  84. %26 = OpLabel
  85. %25 = OpCopyObject %6 %7
  86. %30 = OpCopyObject %6 %25
  87. OpBranchConditional %13 %27 %28
  88. %27 = OpLabel
  89. OpBranch %32
  90. %28 = OpLabel
  91. %31 = OpPhi %6 %30 %26 %7 %32 ; Can't replace this use
  92. OpReturn
  93. OpFunctionEnd
  94. )";
  95. const auto env = SPV_ENV_UNIVERSAL_1_3;
  96. const auto consumer = nullptr;
  97. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  98. spvtools::ValidatorOptions validator_options;
  99. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  100. kConsoleMessageConsumer));
  101. TransformationContext transformation_context(
  102. MakeUnique<FactManager>(context.get()), validator_options);
  103. // Invalid block id.
  104. ASSERT_FALSE(TransformationPropagateInstructionDown(200, 200, {{}})
  105. .IsApplicable(context.get(), transformation_context));
  106. ASSERT_FALSE(TransformationPropagateInstructionDown(101, 200, {{}})
  107. .IsApplicable(context.get(), transformation_context));
  108. // The block is unreachable.
  109. ASSERT_FALSE(TransformationPropagateInstructionDown(100, 200, {{}})
  110. .IsApplicable(context.get(), transformation_context));
  111. // The block has no instruction to propagate.
  112. ASSERT_FALSE(TransformationPropagateInstructionDown(5, 200, {{{11, 201}}})
  113. .IsApplicable(context.get(), transformation_context));
  114. // The block has no acceptable successors.
  115. ASSERT_FALSE(TransformationPropagateInstructionDown(16, 200, {{{18, 201}}})
  116. .IsApplicable(context.get(), transformation_context));
  117. // One of acceptable successors has an OpPhi that uses propagated
  118. // instruction's id.
  119. ASSERT_FALSE(
  120. TransformationPropagateInstructionDown(11, 200, {{{14, 201}, {18, 202}}})
  121. .IsApplicable(context.get(), transformation_context));
  122. #ifndef NDEBUG
  123. // Not all fresh ids are provided.
  124. ASSERT_DEATH(
  125. TransformationPropagateInstructionDown(18, 200, {{{22, 201}, {202, 203}}})
  126. .IsApplicable(context.get(), transformation_context),
  127. "Bad attempt to query whether overflow ids are available.");
  128. #endif
  129. // Not all fresh ids are fresh.
  130. ASSERT_FALSE(TransformationPropagateInstructionDown(
  131. 18, 18, {{{22, 201}, {23, 202}, {202, 203}}})
  132. .IsApplicable(context.get(), transformation_context));
  133. ASSERT_FALSE(TransformationPropagateInstructionDown(
  134. 18, 200, {{{22, 22}, {23, 202}, {202, 203}}})
  135. .IsApplicable(context.get(), transformation_context));
  136. ASSERT_FALSE(TransformationPropagateInstructionDown(
  137. 18, 18, {{{22, 22}, {23, 202}, {202, 203}}})
  138. .IsApplicable(context.get(), transformation_context));
  139. // Not all fresh ids are unique.
  140. ASSERT_FALSE(TransformationPropagateInstructionDown(
  141. 18, 200, {{{22, 200}, {23, 202}, {202, 200}}})
  142. .IsApplicable(context.get(), transformation_context));
  143. ASSERT_FALSE(TransformationPropagateInstructionDown(
  144. 18, 200, {{{22, 201}, {23, 202}, {202, 200}}})
  145. .IsApplicable(context.get(), transformation_context));
  146. ASSERT_FALSE(TransformationPropagateInstructionDown(
  147. 18, 200, {{{22, 201}, {23, 201}, {202, 203}}})
  148. .IsApplicable(context.get(), transformation_context));
  149. // Can't replace all uses of the propagated instruction: %30 is propagated
  150. // into %27.
  151. ASSERT_FALSE(TransformationPropagateInstructionDown(26, 200, {{{27, 201}}})
  152. .IsApplicable(context.get(), transformation_context));
  153. {
  154. TransformationPropagateInstructionDown transformation(
  155. 18, 200, {{{22, 201}, {23, 202}, {202, 203}}});
  156. ASSERT_TRUE(
  157. transformation.IsApplicable(context.get(), transformation_context));
  158. ApplyAndCheckFreshIds(transformation, context.get(),
  159. &transformation_context);
  160. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  161. context.get(), validator_options, kConsoleMessageConsumer));
  162. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
  163. MakeDataDescriptor(201, {}), MakeDataDescriptor(202, {})));
  164. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
  165. MakeDataDescriptor(201, {}), MakeDataDescriptor(200, {})));
  166. }
  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. %2 = OpTypeVoid
  175. %3 = OpTypeFunction %2
  176. %6 = OpTypeInt 32 1
  177. %7 = OpConstant %6 1
  178. %12 = OpTypeBool
  179. %13 = OpConstantTrue %12
  180. %9 = OpTypePointer Function %6
  181. %4 = OpFunction %2 None %3
  182. ; Has no instruction to propagate
  183. %5 = OpLabel
  184. %10 = OpVariable %9 Function
  185. %8 = OpCopyObject %6 %7
  186. OpStore %10 %8
  187. OpBranch %11
  188. ; Unreachable block
  189. %100 = OpLabel
  190. %101 = OpCopyObject %6 %7
  191. OpBranch %11
  192. ; Selection header
  193. ;
  194. ; One of acceptable successors has an OpPhi that uses propagated
  195. ; instruction's id
  196. %11 = OpLabel
  197. %19 = OpCopyObject %6 %7
  198. OpSelectionMerge %18 None
  199. OpBranchConditional %13 %14 %18
  200. ; %16 has no acceptable successors
  201. %14 = OpLabel
  202. %20 = OpPhi %6 %19 %11
  203. %15 = OpCopyObject %6 %7 ; dependency
  204. OpBranch %16
  205. %16 = OpLabel
  206. %17 = OpCopyObject %6 %15
  207. OpBranch %18
  208. ; Can be applied
  209. %18 = OpLabel
  210. OpSelectionMerge %24 None
  211. OpBranchConditional %13 %22 %23
  212. %22 = OpLabel
  213. %29 = OpPhi %6 %7 %18
  214. %201 = OpCopyObject %6 %7
  215. OpStore %10 %201
  216. OpBranch %24
  217. %23 = OpLabel
  218. %202 = OpCopyObject %6 %7
  219. OpStore %10 %202
  220. OpBranch %24
  221. %24 = OpLabel
  222. %200 = OpPhi %6 %201 %22 %202 %23
  223. OpStore %10 %200
  224. OpBranch %32
  225. ; Can't replace all uses of the propagated instruction: %30 is
  226. ; propagated into %27.
  227. %32 = OpLabel
  228. OpLoopMerge %28 %27 None
  229. OpBranchConditional %13 %26 %28
  230. %26 = OpLabel
  231. %25 = OpCopyObject %6 %7
  232. %30 = OpCopyObject %6 %25
  233. OpBranchConditional %13 %27 %28
  234. %27 = OpLabel
  235. OpBranch %32
  236. %28 = OpLabel
  237. %31 = OpPhi %6 %30 %26 %7 %32 ; Can't replace this use
  238. OpReturn
  239. OpFunctionEnd
  240. )";
  241. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  242. }
  243. TEST(TransformationPropagateInstructionDownTest, CantCreateOpPhiTest) {
  244. std::string shader = R"(
  245. OpCapability Shader
  246. %1 = OpExtInstImport "GLSL.std.450"
  247. OpMemoryModel Logical GLSL450
  248. OpEntryPoint Fragment %4 "main"
  249. OpExecutionMode %4 OriginUpperLeft
  250. OpSource ESSL 310
  251. %2 = OpTypeVoid
  252. %3 = OpTypeFunction %2
  253. %6 = OpTypeInt 32 1
  254. %7 = OpConstant %6 1
  255. %12 = OpTypeBool
  256. %13 = OpConstantTrue %12
  257. %4 = OpFunction %2 None %3
  258. ; %5 doesn't belong to any construct
  259. %5 = OpLabel
  260. %15 = OpCopyObject %6 %7
  261. OpBranch %16
  262. ; The merge block (%19) is unreachable
  263. %16 = OpLabel
  264. %17 = OpCopyObject %6 %7
  265. OpSelectionMerge %19 None
  266. OpBranchConditional %13 %18 %18
  267. ; %21 doesn't dominate the merge block - %20
  268. %18 = OpLabel
  269. OpSelectionMerge %20 None
  270. OpBranchConditional %13 %20 %21
  271. %21 = OpLabel
  272. %22 = OpCopyObject %6 %7
  273. OpBranch %20
  274. ; The merge block (%24) is an acceptable successor of the propagated
  275. ; instruction's block
  276. %20 = OpLabel
  277. %23 = OpCopyObject %6 %7
  278. OpSelectionMerge %24 None
  279. OpBranchConditional %13 %24 %30
  280. %30 = OpLabel
  281. OpBranch %24
  282. ; One of the predecessors of the merge block is not dominated by any
  283. ; successor of the propagated instruction's block
  284. %24 = OpLabel
  285. %26 = OpCopyObject %6 %7
  286. OpLoopMerge %29 %25 None
  287. OpBranch %25
  288. %25 = OpLabel
  289. OpBranchConditional %13 %24 %29
  290. %28 = OpLabel ; unreachable predecessor of %29
  291. OpBranch %29
  292. %29 = OpLabel
  293. OpReturn
  294. %19 = OpLabel
  295. OpReturn
  296. OpFunctionEnd
  297. )";
  298. const auto env = SPV_ENV_UNIVERSAL_1_3;
  299. const auto consumer = nullptr;
  300. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  301. spvtools::ValidatorOptions validator_options;
  302. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  303. kConsoleMessageConsumer));
  304. TransformationContext transformation_context(
  305. MakeUnique<FactManager>(context.get()), validator_options);
  306. TransformationPropagateInstructionDown transformations[] = {
  307. // %5 doesn't belong to any construct.
  308. {5, 200, {{{16, 201}}}},
  309. // The merge block (%19) is unreachable.
  310. {16, 200, {{{18, 202}}}},
  311. // %21 doesn't dominate the merge block - %20.
  312. {21, 200, {{{20, 203}}}},
  313. // The merge block (%24) is an acceptable successor of the propagated
  314. // instruction's block.
  315. {20, 200, {{{24, 204}, {30, 205}}}},
  316. // One of the predecessors of the merge block is not dominated by any
  317. // successor of the propagated instruction's block.
  318. {24, 200, {{{25, 206}}}},
  319. };
  320. for (const auto& transformation : transformations) {
  321. ASSERT_TRUE(
  322. transformation.IsApplicable(context.get(), transformation_context));
  323. ApplyAndCheckFreshIds(transformation, context.get(),
  324. &transformation_context);
  325. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  326. context.get(), validator_options, kConsoleMessageConsumer));
  327. }
  328. // No transformation has introduced an OpPhi instruction.
  329. ASSERT_FALSE(context->get_def_use_mgr()->GetDef(200));
  330. std::string after_transformation = R"(
  331. OpCapability Shader
  332. %1 = OpExtInstImport "GLSL.std.450"
  333. OpMemoryModel Logical GLSL450
  334. OpEntryPoint Fragment %4 "main"
  335. OpExecutionMode %4 OriginUpperLeft
  336. OpSource ESSL 310
  337. %2 = OpTypeVoid
  338. %3 = OpTypeFunction %2
  339. %6 = OpTypeInt 32 1
  340. %7 = OpConstant %6 1
  341. %12 = OpTypeBool
  342. %13 = OpConstantTrue %12
  343. %4 = OpFunction %2 None %3
  344. ; %5 doesn't belong to any construct
  345. %5 = OpLabel
  346. OpBranch %16
  347. ; The merge block (%19) is unreachable
  348. %16 = OpLabel
  349. %201 = OpCopyObject %6 %7
  350. OpSelectionMerge %19 None
  351. OpBranchConditional %13 %18 %18
  352. ; %21 doesn't dominate the merge block - %20
  353. %18 = OpLabel
  354. %202 = OpCopyObject %6 %7
  355. OpSelectionMerge %20 None
  356. OpBranchConditional %13 %20 %21
  357. %21 = OpLabel
  358. OpBranch %20
  359. ; The merge block (%24) is an acceptable successor of the propagated
  360. ; instruction's block
  361. %20 = OpLabel
  362. %203 = OpCopyObject %6 %7
  363. OpSelectionMerge %24 None
  364. OpBranchConditional %13 %24 %30
  365. %30 = OpLabel
  366. %205 = OpCopyObject %6 %7
  367. OpBranch %24
  368. ; One of the predecessors of the merge block is not dominated by any
  369. ; successor of the propagated instruction's block
  370. %24 = OpLabel
  371. %204 = OpCopyObject %6 %7
  372. OpLoopMerge %29 %25 None
  373. OpBranch %25
  374. %25 = OpLabel
  375. %206 = OpCopyObject %6 %7
  376. OpBranchConditional %13 %24 %29
  377. %28 = OpLabel ; unreachable predecessor of %29
  378. OpBranch %29
  379. %29 = OpLabel
  380. OpReturn
  381. %19 = OpLabel
  382. OpReturn
  383. OpFunctionEnd
  384. )";
  385. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  386. }
  387. TEST(TransformationPropagateInstructionDownTest, VariablePointersCapability) {
  388. std::string shader = R"(
  389. OpCapability Shader
  390. %1 = OpExtInstImport "GLSL.std.450"
  391. OpMemoryModel Logical GLSL450
  392. OpEntryPoint Fragment %4 "main"
  393. OpExecutionMode %4 OriginUpperLeft
  394. OpSource ESSL 310
  395. %2 = OpTypeVoid
  396. %3 = OpTypeFunction %2
  397. %6 = OpTypeInt 32 1
  398. %7 = OpConstant %6 1
  399. %12 = OpTypeBool
  400. %13 = OpConstantTrue %12
  401. %10 = OpTypePointer Workgroup %6
  402. %11 = OpVariable %10 Workgroup
  403. %4 = OpFunction %2 None %3
  404. %5 = OpLabel
  405. %18 = OpCopyObject %10 %11
  406. %14 = OpCopyObject %10 %11
  407. OpSelectionMerge %17 None
  408. OpBranchConditional %13 %15 %16
  409. %15 = OpLabel
  410. OpBranch %17
  411. %16 = OpLabel
  412. OpBranch %17
  413. %17 = OpLabel
  414. OpStore %18 %7
  415. OpReturn
  416. OpFunctionEnd
  417. )";
  418. const auto env = SPV_ENV_UNIVERSAL_1_3;
  419. const auto consumer = nullptr;
  420. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  421. spvtools::ValidatorOptions validator_options;
  422. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  423. kConsoleMessageConsumer));
  424. TransformationContext transformation_context(
  425. MakeUnique<FactManager>(context.get()), validator_options);
  426. {
  427. // Can propagate a pointer only if we don't have to create an OpPhi.
  428. TransformationPropagateInstructionDown transformation(
  429. 5, 200, {{{15, 201}, {16, 202}}});
  430. ASSERT_TRUE(
  431. transformation.IsApplicable(context.get(), transformation_context));
  432. ApplyAndCheckFreshIds(transformation, context.get(),
  433. &transformation_context);
  434. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  435. context.get(), validator_options, kConsoleMessageConsumer));
  436. ASSERT_FALSE(context->get_def_use_mgr()->GetDef(200));
  437. }
  438. {
  439. // Can't propagate a pointer if there is no VariablePointersStorageBuffer
  440. // capability and we need to create an OpPhi.
  441. TransformationPropagateInstructionDown transformation(
  442. 5, 200, {{{15, 203}, {16, 204}}});
  443. ASSERT_FALSE(context->get_feature_mgr()->HasCapability(
  444. spv::Capability::VariablePointersStorageBuffer));
  445. ASSERT_FALSE(
  446. transformation.IsApplicable(context.get(), transformation_context));
  447. context->AddCapability(spv::Capability::VariablePointers);
  448. ASSERT_TRUE(context->get_feature_mgr()->HasCapability(
  449. spv::Capability::VariablePointersStorageBuffer));
  450. ASSERT_TRUE(
  451. transformation.IsApplicable(context.get(), transformation_context));
  452. ApplyAndCheckFreshIds(transformation, context.get(),
  453. &transformation_context);
  454. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  455. context.get(), validator_options, kConsoleMessageConsumer));
  456. }
  457. std::string after_transformation = R"(
  458. OpCapability Shader
  459. OpCapability VariablePointers
  460. %1 = OpExtInstImport "GLSL.std.450"
  461. OpMemoryModel Logical GLSL450
  462. OpEntryPoint Fragment %4 "main"
  463. OpExecutionMode %4 OriginUpperLeft
  464. OpSource ESSL 310
  465. %2 = OpTypeVoid
  466. %3 = OpTypeFunction %2
  467. %6 = OpTypeInt 32 1
  468. %7 = OpConstant %6 1
  469. %12 = OpTypeBool
  470. %13 = OpConstantTrue %12
  471. %10 = OpTypePointer Workgroup %6
  472. %11 = OpVariable %10 Workgroup
  473. %4 = OpFunction %2 None %3
  474. %5 = OpLabel
  475. OpSelectionMerge %17 None
  476. OpBranchConditional %13 %15 %16
  477. %15 = OpLabel
  478. %203 = OpCopyObject %10 %11
  479. %201 = OpCopyObject %10 %11
  480. OpBranch %17
  481. %16 = OpLabel
  482. %204 = OpCopyObject %10 %11
  483. %202 = OpCopyObject %10 %11
  484. OpBranch %17
  485. %17 = OpLabel
  486. %200 = OpPhi %10 %203 %15 %204 %16
  487. OpStore %200 %7
  488. OpReturn
  489. OpFunctionEnd
  490. )";
  491. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  492. }
  493. TEST(TransformationPropagateInstructionDownTest, UseOverflowIdsTest) {
  494. std::string shader = R"(
  495. OpCapability Shader
  496. %1 = OpExtInstImport "GLSL.std.450"
  497. OpMemoryModel Logical GLSL450
  498. OpEntryPoint Fragment %4 "main"
  499. OpExecutionMode %4 OriginUpperLeft
  500. OpSource ESSL 310
  501. %2 = OpTypeVoid
  502. %3 = OpTypeFunction %2
  503. %6 = OpTypeInt 32 1
  504. %7 = OpConstant %6 1
  505. %12 = OpTypeBool
  506. %13 = OpConstantTrue %12
  507. %10 = OpTypePointer Private %6
  508. %11 = OpVariable %10 Private
  509. %4 = OpFunction %2 None %3
  510. %5 = OpLabel
  511. %20 = OpCopyObject %6 %7
  512. OpSelectionMerge %23 None
  513. OpBranchConditional %13 %21 %22
  514. %21 = OpLabel
  515. OpStore %11 %20
  516. OpBranch %23
  517. %22 = OpLabel
  518. OpStore %11 %20
  519. OpBranch %23
  520. %23 = OpLabel
  521. OpStore %11 %20
  522. OpReturn
  523. OpFunctionEnd
  524. )";
  525. const auto env = SPV_ENV_UNIVERSAL_1_3;
  526. const auto consumer = nullptr;
  527. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  528. spvtools::ValidatorOptions validator_options;
  529. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  530. kConsoleMessageConsumer));
  531. TransformationContext transformation_context(
  532. MakeUnique<FactManager>(context.get()), validator_options,
  533. MakeUnique<CounterOverflowIdSource>(300));
  534. TransformationPropagateInstructionDown transformation(5, 200, {{{21, 201}}});
  535. ASSERT_TRUE(
  536. transformation.IsApplicable(context.get(), transformation_context));
  537. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context,
  538. {300});
  539. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  540. kConsoleMessageConsumer));
  541. std::string after_transformation = R"(
  542. OpCapability Shader
  543. %1 = OpExtInstImport "GLSL.std.450"
  544. OpMemoryModel Logical GLSL450
  545. OpEntryPoint Fragment %4 "main"
  546. OpExecutionMode %4 OriginUpperLeft
  547. OpSource ESSL 310
  548. %2 = OpTypeVoid
  549. %3 = OpTypeFunction %2
  550. %6 = OpTypeInt 32 1
  551. %7 = OpConstant %6 1
  552. %12 = OpTypeBool
  553. %13 = OpConstantTrue %12
  554. %10 = OpTypePointer Private %6
  555. %11 = OpVariable %10 Private
  556. %4 = OpFunction %2 None %3
  557. %5 = OpLabel
  558. OpSelectionMerge %23 None
  559. OpBranchConditional %13 %21 %22
  560. %21 = OpLabel
  561. %201 = OpCopyObject %6 %7
  562. OpStore %11 %201
  563. OpBranch %23
  564. %22 = OpLabel
  565. %300 = OpCopyObject %6 %7
  566. OpStore %11 %300
  567. OpBranch %23
  568. %23 = OpLabel
  569. %200 = OpPhi %6 %201 %21 %300 %22
  570. OpStore %11 %200
  571. OpReturn
  572. OpFunctionEnd
  573. )";
  574. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  575. }
  576. TEST(TransformationPropagateInstructionDownTest, TestCreatedFacts) {
  577. std::string shader = R"(
  578. OpCapability VariablePointers
  579. %1 = OpExtInstImport "GLSL.std.450"
  580. OpMemoryModel Logical GLSL450
  581. OpEntryPoint Fragment %4 "main"
  582. OpExecutionMode %4 OriginUpperLeft
  583. OpSource ESSL 310
  584. %2 = OpTypeVoid
  585. %3 = OpTypeFunction %2
  586. %6 = OpTypeInt 32 1
  587. %7 = OpConstant %6 1
  588. %12 = OpTypeBool
  589. %13 = OpConstantTrue %12
  590. %10 = OpTypePointer Private %6
  591. %11 = OpVariable %10 Private
  592. %4 = OpFunction %2 None %3
  593. %5 = OpLabel
  594. %20 = OpCopyObject %6 %7
  595. %24 = OpCopyObject %6 %7 ; Irrelevant id
  596. %25 = OpCopyObject %10 %11 ; Pointee is irrelevant
  597. OpSelectionMerge %23 None
  598. OpBranchConditional %13 %21 %22
  599. %21 = OpLabel
  600. OpStore %25 %20
  601. OpBranch %23
  602. %22 = OpLabel ; Dead block
  603. OpStore %25 %20
  604. OpBranch %23
  605. %23 = OpLabel
  606. OpStore %25 %20
  607. OpReturn
  608. OpFunctionEnd
  609. )";
  610. const auto env = SPV_ENV_UNIVERSAL_1_3;
  611. const auto consumer = nullptr;
  612. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  613. spvtools::ValidatorOptions validator_options;
  614. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  615. kConsoleMessageConsumer));
  616. TransformationContext transformation_context(
  617. MakeUnique<FactManager>(context.get()), validator_options);
  618. transformation_context.GetFactManager()->AddFactBlockIsDead(22);
  619. transformation_context.GetFactManager()->AddFactIdIsIrrelevant(24);
  620. transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
  621. 25);
  622. {
  623. // Propagate pointer with PointeeIsIrrelevant fact.
  624. TransformationPropagateInstructionDown transformation(
  625. 5, 200, {{{21, 201}, {22, 202}}});
  626. ASSERT_TRUE(
  627. transformation.IsApplicable(context.get(), transformation_context));
  628. ApplyAndCheckFreshIds(transformation, context.get(),
  629. &transformation_context);
  630. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  631. context.get(), validator_options, kConsoleMessageConsumer));
  632. ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(201));
  633. ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(202));
  634. ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(200));
  635. ASSERT_TRUE(
  636. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(201));
  637. ASSERT_TRUE(
  638. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(202));
  639. ASSERT_TRUE(
  640. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(200));
  641. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
  642. MakeDataDescriptor(201, {}), MakeDataDescriptor(202, {})));
  643. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
  644. MakeDataDescriptor(201, {}), MakeDataDescriptor(200, {})));
  645. }
  646. {
  647. // Propagate an irrelevant id.
  648. TransformationPropagateInstructionDown transformation(
  649. 5, 203, {{{21, 204}, {22, 205}}});
  650. ASSERT_TRUE(
  651. transformation.IsApplicable(context.get(), transformation_context));
  652. ApplyAndCheckFreshIds(transformation, context.get(),
  653. &transformation_context);
  654. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  655. context.get(), validator_options, kConsoleMessageConsumer));
  656. ASSERT_TRUE(transformation_context.GetFactManager()->IdIsIrrelevant(203));
  657. ASSERT_TRUE(transformation_context.GetFactManager()->IdIsIrrelevant(204));
  658. ASSERT_TRUE(transformation_context.GetFactManager()->IdIsIrrelevant(205));
  659. ASSERT_FALSE(
  660. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(203));
  661. ASSERT_FALSE(
  662. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(204));
  663. ASSERT_FALSE(
  664. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(205));
  665. ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
  666. MakeDataDescriptor(204, {}), MakeDataDescriptor(205, {})));
  667. ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
  668. MakeDataDescriptor(204, {}), MakeDataDescriptor(203, {})));
  669. }
  670. {
  671. // Propagate a regular id.
  672. TransformationPropagateInstructionDown transformation(
  673. 5, 206, {{{21, 207}, {22, 208}}});
  674. ASSERT_TRUE(
  675. transformation.IsApplicable(context.get(), transformation_context));
  676. ApplyAndCheckFreshIds(transformation, context.get(),
  677. &transformation_context);
  678. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  679. context.get(), validator_options, kConsoleMessageConsumer));
  680. ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(206));
  681. ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(207));
  682. ASSERT_TRUE(transformation_context.GetFactManager()->IdIsIrrelevant(208));
  683. ASSERT_FALSE(
  684. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(206));
  685. ASSERT_FALSE(
  686. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(207));
  687. ASSERT_FALSE(
  688. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(208));
  689. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
  690. MakeDataDescriptor(206, {}), MakeDataDescriptor(207, {})));
  691. ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
  692. MakeDataDescriptor(206, {}), MakeDataDescriptor(208, {})));
  693. }
  694. std::string after_transformation = R"(
  695. OpCapability VariablePointers
  696. %1 = OpExtInstImport "GLSL.std.450"
  697. OpMemoryModel Logical GLSL450
  698. OpEntryPoint Fragment %4 "main"
  699. OpExecutionMode %4 OriginUpperLeft
  700. OpSource ESSL 310
  701. %2 = OpTypeVoid
  702. %3 = OpTypeFunction %2
  703. %6 = OpTypeInt 32 1
  704. %7 = OpConstant %6 1
  705. %12 = OpTypeBool
  706. %13 = OpConstantTrue %12
  707. %10 = OpTypePointer Private %6
  708. %11 = OpVariable %10 Private
  709. %4 = OpFunction %2 None %3
  710. %5 = OpLabel
  711. OpSelectionMerge %23 None
  712. OpBranchConditional %13 %21 %22
  713. %21 = OpLabel
  714. %207 = OpCopyObject %6 %7
  715. %204 = OpCopyObject %6 %7 ; Irrelevant id
  716. %201 = OpCopyObject %10 %11 ; Pointee is irrelevant
  717. OpStore %201 %207
  718. OpBranch %23
  719. %22 = OpLabel ; Dead block
  720. %208 = OpCopyObject %6 %7
  721. %205 = OpCopyObject %6 %7 ; Irrelevant id
  722. %202 = OpCopyObject %10 %11 ; Pointee is irrelevant
  723. OpStore %202 %208
  724. OpBranch %23
  725. %23 = OpLabel
  726. %206 = OpPhi %6 %207 %21 %208 %22
  727. %203 = OpPhi %6 %204 %21 %205 %22 ; Irrelevant id
  728. %200 = OpPhi %10 %201 %21 %202 %22 ; Pointee is irrelevant
  729. OpStore %200 %206
  730. OpReturn
  731. OpFunctionEnd
  732. )";
  733. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  734. }
  735. TEST(TransformationPropagateInstructionDownTest, TestLoops1) {
  736. std::string shader = R"(
  737. OpCapability Shader
  738. %1 = OpExtInstImport "GLSL.std.450"
  739. OpMemoryModel Logical GLSL450
  740. OpEntryPoint Fragment %4 "main"
  741. OpExecutionMode %4 OriginUpperLeft
  742. OpSource ESSL 310
  743. %2 = OpTypeVoid
  744. %3 = OpTypeFunction %2
  745. %6 = OpTypeInt 32 1
  746. %7 = OpConstant %6 1
  747. %12 = OpTypeBool
  748. %13 = OpConstantTrue %12
  749. %4 = OpFunction %2 None %3
  750. %5 = OpLabel
  751. OpBranch %20
  752. %20 = OpLabel
  753. OpLoopMerge %26 %25 None
  754. OpBranch %21
  755. %21 = OpLabel
  756. %22 = OpCopyObject %6 %7
  757. %31 = OpCopyObject %6 %7
  758. OpSelectionMerge %35 None
  759. OpBranchConditional %13 %23 %24
  760. %23 = OpLabel
  761. %27 = OpCopyObject %6 %22
  762. %32 = OpCopyObject %6 %31
  763. OpBranch %26
  764. %24 = OpLabel
  765. %28 = OpCopyObject %6 %22
  766. %33 = OpCopyObject %6 %31
  767. OpBranchConditional %13 %26 %25
  768. %35 = OpLabel
  769. OpBranch %25
  770. %25 = OpLabel
  771. %29 = OpCopyObject %6 %22
  772. %34 = OpCopyObject %6 %31
  773. OpBranch %20
  774. %26 = OpLabel
  775. %30 = OpCopyObject %6 %22
  776. OpReturn
  777. OpFunctionEnd
  778. )";
  779. const auto env = SPV_ENV_UNIVERSAL_1_3;
  780. const auto consumer = nullptr;
  781. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  782. spvtools::ValidatorOptions validator_options;
  783. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  784. kConsoleMessageConsumer));
  785. TransformationContext transformation_context(
  786. MakeUnique<FactManager>(context.get()), validator_options);
  787. {
  788. TransformationPropagateInstructionDown transformation(
  789. 21, 200, {{{23, 201}, {24, 202}}});
  790. ASSERT_TRUE(
  791. transformation.IsApplicable(context.get(), transformation_context));
  792. ApplyAndCheckFreshIds(transformation, context.get(),
  793. &transformation_context);
  794. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  795. context.get(), validator_options, kConsoleMessageConsumer));
  796. }
  797. // Can't replace usage of %22 in %26.
  798. ASSERT_FALSE(
  799. TransformationPropagateInstructionDown(21, 200, {{{23, 201}, {24, 202}}})
  800. .IsApplicable(context.get(), transformation_context));
  801. std::string after_transformation = R"(
  802. OpCapability Shader
  803. %1 = OpExtInstImport "GLSL.std.450"
  804. OpMemoryModel Logical GLSL450
  805. OpEntryPoint Fragment %4 "main"
  806. OpExecutionMode %4 OriginUpperLeft
  807. OpSource ESSL 310
  808. %2 = OpTypeVoid
  809. %3 = OpTypeFunction %2
  810. %6 = OpTypeInt 32 1
  811. %7 = OpConstant %6 1
  812. %12 = OpTypeBool
  813. %13 = OpConstantTrue %12
  814. %4 = OpFunction %2 None %3
  815. %5 = OpLabel
  816. OpBranch %20
  817. %20 = OpLabel
  818. OpLoopMerge %26 %25 None
  819. OpBranch %21
  820. %21 = OpLabel
  821. %22 = OpCopyObject %6 %7
  822. OpSelectionMerge %35 None
  823. OpBranchConditional %13 %23 %24
  824. %23 = OpLabel
  825. %201 = OpCopyObject %6 %7
  826. %27 = OpCopyObject %6 %22
  827. %32 = OpCopyObject %6 %201
  828. OpBranch %26
  829. %24 = OpLabel
  830. %202 = OpCopyObject %6 %7
  831. %28 = OpCopyObject %6 %22
  832. %33 = OpCopyObject %6 %202
  833. OpBranchConditional %13 %26 %25
  834. %35 = OpLabel
  835. OpBranch %25
  836. %25 = OpLabel
  837. %29 = OpCopyObject %6 %22
  838. %34 = OpCopyObject %6 %202
  839. OpBranch %20
  840. %26 = OpLabel
  841. %30 = OpCopyObject %6 %22
  842. OpReturn
  843. OpFunctionEnd
  844. )";
  845. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  846. }
  847. TEST(TransformationPropagateInstructionDownTest, TestLoops2) {
  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. %2 = OpTypeVoid
  856. %3 = OpTypeFunction %2
  857. %6 = OpTypeInt 32 1
  858. %7 = OpConstant %6 1
  859. %12 = OpTypeBool
  860. %13 = OpConstantTrue %12
  861. %4 = OpFunction %2 None %3
  862. %5 = OpLabel
  863. OpBranch %20
  864. %20 = OpLabel
  865. %23 = OpPhi %6 %7 %5 %24 %21
  866. OpLoopMerge %22 %21 None
  867. OpBranch %21
  868. %21 = OpLabel
  869. %24 = OpCopyObject %6 %23
  870. %25 = OpCopyObject %6 %7
  871. OpBranchConditional %13 %22 %20
  872. %22 = OpLabel
  873. OpReturn
  874. OpFunctionEnd
  875. )";
  876. const auto env = SPV_ENV_UNIVERSAL_1_3;
  877. const auto consumer = nullptr;
  878. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  879. spvtools::ValidatorOptions validator_options;
  880. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  881. kConsoleMessageConsumer));
  882. TransformationContext transformation_context(
  883. MakeUnique<FactManager>(context.get()), validator_options);
  884. {
  885. // Can propagate %25 from %21 into %20.
  886. TransformationPropagateInstructionDown transformation(
  887. 21, 200, {{{20, 201}, {22, 202}}});
  888. ASSERT_TRUE(
  889. transformation.IsApplicable(context.get(), transformation_context));
  890. ApplyAndCheckFreshIds(transformation, context.get(),
  891. &transformation_context);
  892. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  893. context.get(), validator_options, kConsoleMessageConsumer));
  894. }
  895. {
  896. // Can propagate %201 from %20 into %21.
  897. TransformationPropagateInstructionDown transformation(20, 200,
  898. {{{21, 203}}});
  899. ASSERT_TRUE(
  900. transformation.IsApplicable(context.get(), transformation_context));
  901. ApplyAndCheckFreshIds(transformation, context.get(),
  902. &transformation_context);
  903. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  904. context.get(), validator_options, kConsoleMessageConsumer));
  905. }
  906. // Can't propagate %24 from %21 into %20.
  907. ASSERT_FALSE(
  908. TransformationPropagateInstructionDown(21, 200, {{{20, 204}, {22, 205}}})
  909. .IsApplicable(context.get(), transformation_context));
  910. std::string after_transformation = R"(
  911. OpCapability Shader
  912. %1 = OpExtInstImport "GLSL.std.450"
  913. OpMemoryModel Logical GLSL450
  914. OpEntryPoint Fragment %4 "main"
  915. OpExecutionMode %4 OriginUpperLeft
  916. OpSource ESSL 310
  917. %2 = OpTypeVoid
  918. %3 = OpTypeFunction %2
  919. %6 = OpTypeInt 32 1
  920. %7 = OpConstant %6 1
  921. %12 = OpTypeBool
  922. %13 = OpConstantTrue %12
  923. %4 = OpFunction %2 None %3
  924. %5 = OpLabel
  925. OpBranch %20
  926. %20 = OpLabel
  927. %23 = OpPhi %6 %7 %5 %24 %21
  928. OpLoopMerge %22 %21 None
  929. OpBranch %21
  930. %21 = OpLabel
  931. %203 = OpCopyObject %6 %7
  932. %24 = OpCopyObject %6 %23
  933. OpBranchConditional %13 %22 %20
  934. %22 = OpLabel
  935. %200 = OpPhi %6 %203 %21
  936. %202 = OpCopyObject %6 %7
  937. OpReturn
  938. OpFunctionEnd
  939. )";
  940. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  941. }
  942. TEST(TransformationPropagateInstructionDownTest, TestLoops3) {
  943. std::string shader = R"(
  944. OpCapability Shader
  945. %1 = OpExtInstImport "GLSL.std.450"
  946. OpMemoryModel Logical GLSL450
  947. OpEntryPoint Fragment %4 "main"
  948. OpExecutionMode %4 OriginUpperLeft
  949. OpSource ESSL 310
  950. %2 = OpTypeVoid
  951. %3 = OpTypeFunction %2
  952. %6 = OpTypeInt 32 1
  953. %7 = OpConstant %6 1
  954. %12 = OpTypeBool
  955. %13 = OpConstantTrue %12
  956. %4 = OpFunction %2 None %3
  957. %5 = OpLabel
  958. OpBranch %20
  959. %20 = OpLabel
  960. %27 = OpPhi %6 %7 %5 %26 %20
  961. %25 = OpCopyObject %6 %7
  962. %26 = OpCopyObject %6 %7
  963. OpLoopMerge %22 %20 None
  964. OpBranchConditional %13 %20 %22
  965. %22 = OpLabel
  966. OpReturn
  967. OpFunctionEnd
  968. )";
  969. const auto env = SPV_ENV_UNIVERSAL_1_3;
  970. const auto consumer = nullptr;
  971. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  972. spvtools::ValidatorOptions validator_options;
  973. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  974. kConsoleMessageConsumer));
  975. TransformationContext transformation_context(
  976. MakeUnique<FactManager>(context.get()), validator_options);
  977. {
  978. // Propagate %25 into %20 and %22. Not that we are skipping %26 since not
  979. // all of its users are in different blocks (%27).h
  980. TransformationPropagateInstructionDown transformation(
  981. 20, 200, {{{20, 201}, {22, 202}}});
  982. ASSERT_TRUE(
  983. transformation.IsApplicable(context.get(), transformation_context));
  984. ApplyAndCheckFreshIds(transformation, context.get(),
  985. &transformation_context);
  986. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  987. context.get(), validator_options, kConsoleMessageConsumer));
  988. }
  989. std::string after_transformation = R"(
  990. OpCapability Shader
  991. %1 = OpExtInstImport "GLSL.std.450"
  992. OpMemoryModel Logical GLSL450
  993. OpEntryPoint Fragment %4 "main"
  994. OpExecutionMode %4 OriginUpperLeft
  995. OpSource ESSL 310
  996. %2 = OpTypeVoid
  997. %3 = OpTypeFunction %2
  998. %6 = OpTypeInt 32 1
  999. %7 = OpConstant %6 1
  1000. %12 = OpTypeBool
  1001. %13 = OpConstantTrue %12
  1002. %4 = OpFunction %2 None %3
  1003. %5 = OpLabel
  1004. OpBranch %20
  1005. %20 = OpLabel
  1006. %27 = OpPhi %6 %7 %5 %26 %20
  1007. %201 = OpCopyObject %6 %7
  1008. %26 = OpCopyObject %6 %7
  1009. OpLoopMerge %22 %20 None
  1010. OpBranchConditional %13 %20 %22
  1011. %22 = OpLabel
  1012. %202 = OpCopyObject %6 %7
  1013. OpReturn
  1014. OpFunctionEnd
  1015. )";
  1016. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  1017. }
  1018. } // namespace
  1019. } // namespace fuzz
  1020. } // namespace spvtools