transformation_split_block_test.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  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_split_block.h"
  15. #include "source/fuzz/instruction_descriptor.h"
  16. #include "test/fuzz/fuzz_test_util.h"
  17. namespace spvtools {
  18. namespace fuzz {
  19. namespace {
  20. TEST(TransformationSplitBlockTest, NotApplicable) {
  21. // The SPIR-V in this test came from the following fragment shader, with
  22. // local store elimination applied to get some OpPhi instructions.
  23. //
  24. // void main() {
  25. // int x;
  26. // int i;
  27. // for (i = 0; i < 100; i++) {
  28. // x += i;
  29. // }
  30. // }
  31. std::string shader = R"(
  32. OpCapability Shader
  33. %1 = OpExtInstImport "GLSL.std.450"
  34. OpMemoryModel Logical GLSL450
  35. OpEntryPoint Fragment %4 "main"
  36. OpExecutionMode %4 OriginUpperLeft
  37. OpSource ESSL 310
  38. OpName %4 "main"
  39. OpName %8 "i"
  40. OpName %19 "x"
  41. OpDecorate %8 RelaxedPrecision
  42. OpDecorate %19 RelaxedPrecision
  43. OpDecorate %22 RelaxedPrecision
  44. OpDecorate %25 RelaxedPrecision
  45. OpDecorate %26 RelaxedPrecision
  46. OpDecorate %27 RelaxedPrecision
  47. %2 = OpTypeVoid
  48. %3 = OpTypeFunction %2
  49. %6 = OpTypeInt 32 1
  50. %7 = OpTypePointer Function %6
  51. %9 = OpConstant %6 0
  52. %16 = OpConstant %6 100
  53. %17 = OpTypeBool
  54. %24 = OpConstant %6 1
  55. %28 = OpUndef %6
  56. %4 = OpFunction %2 None %3
  57. %5 = OpLabel
  58. %8 = OpVariable %7 Function
  59. %19 = OpVariable %7 Function
  60. OpStore %8 %9
  61. OpBranch %10
  62. %10 = OpLabel
  63. %27 = OpPhi %6 %28 %5 %22 %13
  64. %26 = OpPhi %6 %9 %5 %25 %13
  65. OpLoopMerge %12 %13 None
  66. OpBranch %14
  67. %14 = OpLabel
  68. %18 = OpSLessThan %17 %26 %16
  69. OpBranchConditional %18 %11 %12
  70. %11 = OpLabel
  71. %22 = OpIAdd %6 %27 %26
  72. OpStore %19 %22
  73. OpBranch %13
  74. %13 = OpLabel
  75. %25 = OpIAdd %6 %26 %24
  76. OpStore %8 %25
  77. OpBranch %10
  78. %12 = OpLabel
  79. OpReturn
  80. OpFunctionEnd
  81. )";
  82. const auto env = SPV_ENV_UNIVERSAL_1_3;
  83. const auto consumer = nullptr;
  84. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  85. FactManager fact_manager;
  86. // No split before OpVariable
  87. ASSERT_FALSE(TransformationSplitBlock(
  88. MakeInstructionDescriptor(8, SpvOpVariable, 0), 100)
  89. .IsApplicable(context.get(), fact_manager));
  90. ASSERT_FALSE(TransformationSplitBlock(
  91. MakeInstructionDescriptor(8, SpvOpVariable, 1), 100)
  92. .IsApplicable(context.get(), fact_manager));
  93. // No split before OpLabel
  94. ASSERT_FALSE(TransformationSplitBlock(
  95. MakeInstructionDescriptor(14, SpvOpLabel, 0), 100)
  96. .IsApplicable(context.get(), fact_manager));
  97. // No split if base instruction is outside a function
  98. ASSERT_FALSE(
  99. TransformationSplitBlock(MakeInstructionDescriptor(1, SpvOpLabel, 0), 100)
  100. .IsApplicable(context.get(), fact_manager));
  101. ASSERT_FALSE(TransformationSplitBlock(
  102. MakeInstructionDescriptor(1, SpvOpExecutionMode, 0), 100)
  103. .IsApplicable(context.get(), fact_manager));
  104. // No split if block is loop header
  105. ASSERT_FALSE(
  106. TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 0), 100)
  107. .IsApplicable(context.get(), fact_manager));
  108. ASSERT_FALSE(
  109. TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 1), 100)
  110. .IsApplicable(context.get(), fact_manager));
  111. // No split if base instruction does not exist
  112. ASSERT_FALSE(
  113. TransformationSplitBlock(MakeInstructionDescriptor(88, SpvOpIAdd, 0), 100)
  114. .IsApplicable(context.get(), fact_manager));
  115. ASSERT_FALSE(TransformationSplitBlock(
  116. MakeInstructionDescriptor(88, SpvOpIMul, 22), 100)
  117. .IsApplicable(context.get(), fact_manager));
  118. // No split if too many instructions with the desired opcode are skipped
  119. ASSERT_FALSE(
  120. TransformationSplitBlock(
  121. MakeInstructionDescriptor(18, SpvOpBranchConditional, 1), 100)
  122. .IsApplicable(context.get(), fact_manager));
  123. // No split if id in use
  124. ASSERT_FALSE(TransformationSplitBlock(
  125. MakeInstructionDescriptor(18, SpvOpSLessThan, 0), 27)
  126. .IsApplicable(context.get(), fact_manager));
  127. ASSERT_FALSE(TransformationSplitBlock(
  128. MakeInstructionDescriptor(18, SpvOpSLessThan, 0), 14)
  129. .IsApplicable(context.get(), fact_manager));
  130. }
  131. TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) {
  132. // The SPIR-V in this test came from the following fragment shader:
  133. //
  134. // void main() {
  135. // int a;
  136. // int b;
  137. // a = 1;
  138. // b = a;
  139. // a = b;
  140. // b = 2;
  141. // b++;
  142. // }
  143. std::string shader = R"(
  144. OpCapability Shader
  145. %1 = OpExtInstImport "GLSL.std.450"
  146. OpMemoryModel Logical GLSL450
  147. OpEntryPoint Fragment %4 "main"
  148. OpExecutionMode %4 OriginUpperLeft
  149. OpSource ESSL 310
  150. OpName %4 "main"
  151. OpName %8 "a"
  152. OpName %10 "b"
  153. OpDecorate %8 RelaxedPrecision
  154. OpDecorate %10 RelaxedPrecision
  155. OpDecorate %11 RelaxedPrecision
  156. OpDecorate %12 RelaxedPrecision
  157. OpDecorate %14 RelaxedPrecision
  158. OpDecorate %15 RelaxedPrecision
  159. %2 = OpTypeVoid
  160. %3 = OpTypeFunction %2
  161. %6 = OpTypeInt 32 1
  162. %7 = OpTypePointer Function %6
  163. %9 = OpConstant %6 1
  164. %13 = OpConstant %6 2
  165. %4 = OpFunction %2 None %3
  166. %5 = OpLabel
  167. %8 = OpVariable %7 Function
  168. %10 = OpVariable %7 Function
  169. OpStore %8 %9
  170. %11 = OpLoad %6 %8
  171. OpStore %10 %11
  172. %12 = OpLoad %6 %10
  173. OpStore %8 %12
  174. OpStore %10 %13
  175. %14 = OpLoad %6 %10
  176. %15 = OpIAdd %6 %14 %9
  177. OpStore %10 %15
  178. OpReturn
  179. OpFunctionEnd
  180. )";
  181. const auto env = SPV_ENV_UNIVERSAL_1_3;
  182. const auto consumer = nullptr;
  183. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  184. FactManager fact_manager;
  185. auto split_1 = TransformationSplitBlock(
  186. MakeInstructionDescriptor(5, SpvOpStore, 0), 100);
  187. ASSERT_TRUE(split_1.IsApplicable(context.get(), fact_manager));
  188. split_1.Apply(context.get(), &fact_manager);
  189. ASSERT_TRUE(IsValid(env, context.get()));
  190. std::string after_split_1 = R"(
  191. OpCapability Shader
  192. %1 = OpExtInstImport "GLSL.std.450"
  193. OpMemoryModel Logical GLSL450
  194. OpEntryPoint Fragment %4 "main"
  195. OpExecutionMode %4 OriginUpperLeft
  196. OpSource ESSL 310
  197. OpName %4 "main"
  198. OpName %8 "a"
  199. OpName %10 "b"
  200. OpDecorate %8 RelaxedPrecision
  201. OpDecorate %10 RelaxedPrecision
  202. OpDecorate %11 RelaxedPrecision
  203. OpDecorate %12 RelaxedPrecision
  204. OpDecorate %14 RelaxedPrecision
  205. OpDecorate %15 RelaxedPrecision
  206. %2 = OpTypeVoid
  207. %3 = OpTypeFunction %2
  208. %6 = OpTypeInt 32 1
  209. %7 = OpTypePointer Function %6
  210. %9 = OpConstant %6 1
  211. %13 = OpConstant %6 2
  212. %4 = OpFunction %2 None %3
  213. %5 = OpLabel
  214. %8 = OpVariable %7 Function
  215. %10 = OpVariable %7 Function
  216. OpBranch %100
  217. %100 = OpLabel
  218. OpStore %8 %9
  219. %11 = OpLoad %6 %8
  220. OpStore %10 %11
  221. %12 = OpLoad %6 %10
  222. OpStore %8 %12
  223. OpStore %10 %13
  224. %14 = OpLoad %6 %10
  225. %15 = OpIAdd %6 %14 %9
  226. OpStore %10 %15
  227. OpReturn
  228. OpFunctionEnd
  229. )";
  230. ASSERT_TRUE(IsEqual(env, after_split_1, context.get()));
  231. auto split_2 = TransformationSplitBlock(
  232. MakeInstructionDescriptor(11, SpvOpStore, 0), 101);
  233. ASSERT_TRUE(split_2.IsApplicable(context.get(), fact_manager));
  234. split_2.Apply(context.get(), &fact_manager);
  235. ASSERT_TRUE(IsValid(env, context.get()));
  236. std::string after_split_2 = R"(
  237. OpCapability Shader
  238. %1 = OpExtInstImport "GLSL.std.450"
  239. OpMemoryModel Logical GLSL450
  240. OpEntryPoint Fragment %4 "main"
  241. OpExecutionMode %4 OriginUpperLeft
  242. OpSource ESSL 310
  243. OpName %4 "main"
  244. OpName %8 "a"
  245. OpName %10 "b"
  246. OpDecorate %8 RelaxedPrecision
  247. OpDecorate %10 RelaxedPrecision
  248. OpDecorate %11 RelaxedPrecision
  249. OpDecorate %12 RelaxedPrecision
  250. OpDecorate %14 RelaxedPrecision
  251. OpDecorate %15 RelaxedPrecision
  252. %2 = OpTypeVoid
  253. %3 = OpTypeFunction %2
  254. %6 = OpTypeInt 32 1
  255. %7 = OpTypePointer Function %6
  256. %9 = OpConstant %6 1
  257. %13 = OpConstant %6 2
  258. %4 = OpFunction %2 None %3
  259. %5 = OpLabel
  260. %8 = OpVariable %7 Function
  261. %10 = OpVariable %7 Function
  262. OpBranch %100
  263. %100 = OpLabel
  264. OpStore %8 %9
  265. %11 = OpLoad %6 %8
  266. OpBranch %101
  267. %101 = OpLabel
  268. OpStore %10 %11
  269. %12 = OpLoad %6 %10
  270. OpStore %8 %12
  271. OpStore %10 %13
  272. %14 = OpLoad %6 %10
  273. %15 = OpIAdd %6 %14 %9
  274. OpStore %10 %15
  275. OpReturn
  276. OpFunctionEnd
  277. )";
  278. ASSERT_TRUE(IsEqual(env, after_split_2, context.get()));
  279. auto split_3 = TransformationSplitBlock(
  280. MakeInstructionDescriptor(14, SpvOpLoad, 0), 102);
  281. ASSERT_TRUE(split_3.IsApplicable(context.get(), fact_manager));
  282. split_3.Apply(context.get(), &fact_manager);
  283. ASSERT_TRUE(IsValid(env, context.get()));
  284. std::string after_split_3 = R"(
  285. OpCapability Shader
  286. %1 = OpExtInstImport "GLSL.std.450"
  287. OpMemoryModel Logical GLSL450
  288. OpEntryPoint Fragment %4 "main"
  289. OpExecutionMode %4 OriginUpperLeft
  290. OpSource ESSL 310
  291. OpName %4 "main"
  292. OpName %8 "a"
  293. OpName %10 "b"
  294. OpDecorate %8 RelaxedPrecision
  295. OpDecorate %10 RelaxedPrecision
  296. OpDecorate %11 RelaxedPrecision
  297. OpDecorate %12 RelaxedPrecision
  298. OpDecorate %14 RelaxedPrecision
  299. OpDecorate %15 RelaxedPrecision
  300. %2 = OpTypeVoid
  301. %3 = OpTypeFunction %2
  302. %6 = OpTypeInt 32 1
  303. %7 = OpTypePointer Function %6
  304. %9 = OpConstant %6 1
  305. %13 = OpConstant %6 2
  306. %4 = OpFunction %2 None %3
  307. %5 = OpLabel
  308. %8 = OpVariable %7 Function
  309. %10 = OpVariable %7 Function
  310. OpBranch %100
  311. %100 = OpLabel
  312. OpStore %8 %9
  313. %11 = OpLoad %6 %8
  314. OpBranch %101
  315. %101 = OpLabel
  316. OpStore %10 %11
  317. %12 = OpLoad %6 %10
  318. OpStore %8 %12
  319. OpStore %10 %13
  320. OpBranch %102
  321. %102 = OpLabel
  322. %14 = OpLoad %6 %10
  323. %15 = OpIAdd %6 %14 %9
  324. OpStore %10 %15
  325. OpReturn
  326. OpFunctionEnd
  327. )";
  328. ASSERT_TRUE(IsEqual(env, after_split_3, context.get()));
  329. }
  330. TEST(TransformationSplitBlockTest, SplitBlockBeforeSelectBranch) {
  331. // The SPIR-V in this test came from the following fragment shader:
  332. //
  333. // void main() {
  334. // int x, y;
  335. // x = 2;
  336. // if (x < y) {
  337. // y = 3;
  338. // } else {
  339. // y = 4;
  340. // }
  341. // }
  342. std::string shader = R"(
  343. OpCapability Shader
  344. %1 = OpExtInstImport "GLSL.std.450"
  345. OpMemoryModel Logical GLSL450
  346. OpEntryPoint Fragment %4 "main"
  347. OpExecutionMode %4 OriginUpperLeft
  348. OpSource ESSL 310
  349. OpName %4 "main"
  350. OpName %8 "x"
  351. OpName %11 "y"
  352. OpDecorate %8 RelaxedPrecision
  353. OpDecorate %10 RelaxedPrecision
  354. OpDecorate %11 RelaxedPrecision
  355. OpDecorate %12 RelaxedPrecision
  356. %2 = OpTypeVoid
  357. %3 = OpTypeFunction %2
  358. %6 = OpTypeInt 32 1
  359. %7 = OpTypePointer Function %6
  360. %9 = OpConstant %6 2
  361. %13 = OpTypeBool
  362. %17 = OpConstant %6 3
  363. %19 = OpConstant %6 4
  364. %4 = OpFunction %2 None %3
  365. %5 = OpLabel
  366. %8 = OpVariable %7 Function
  367. %11 = OpVariable %7 Function
  368. OpStore %8 %9
  369. %10 = OpLoad %6 %8
  370. %12 = OpLoad %6 %11
  371. %14 = OpSLessThan %13 %10 %12
  372. OpSelectionMerge %16 None
  373. OpBranchConditional %14 %15 %18
  374. %15 = OpLabel
  375. OpStore %11 %17
  376. OpBranch %16
  377. %18 = OpLabel
  378. OpStore %11 %19
  379. OpBranch %16
  380. %16 = OpLabel
  381. OpReturn
  382. OpFunctionEnd
  383. )";
  384. const auto env = SPV_ENV_UNIVERSAL_1_3;
  385. const auto consumer = nullptr;
  386. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  387. FactManager fact_manager;
  388. // Illegal to split between the merge and the conditional branch.
  389. ASSERT_FALSE(
  390. TransformationSplitBlock(
  391. MakeInstructionDescriptor(14, SpvOpBranchConditional, 0), 100)
  392. .IsApplicable(context.get(), fact_manager));
  393. ASSERT_FALSE(
  394. TransformationSplitBlock(
  395. MakeInstructionDescriptor(12, SpvOpBranchConditional, 0), 100)
  396. .IsApplicable(context.get(), fact_manager));
  397. auto split = TransformationSplitBlock(
  398. MakeInstructionDescriptor(14, SpvOpSelectionMerge, 0), 100);
  399. ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager));
  400. split.Apply(context.get(), &fact_manager);
  401. ASSERT_TRUE(IsValid(env, context.get()));
  402. std::string after_split = R"(
  403. OpCapability Shader
  404. %1 = OpExtInstImport "GLSL.std.450"
  405. OpMemoryModel Logical GLSL450
  406. OpEntryPoint Fragment %4 "main"
  407. OpExecutionMode %4 OriginUpperLeft
  408. OpSource ESSL 310
  409. OpName %4 "main"
  410. OpName %8 "x"
  411. OpName %11 "y"
  412. OpDecorate %8 RelaxedPrecision
  413. OpDecorate %10 RelaxedPrecision
  414. OpDecorate %11 RelaxedPrecision
  415. OpDecorate %12 RelaxedPrecision
  416. %2 = OpTypeVoid
  417. %3 = OpTypeFunction %2
  418. %6 = OpTypeInt 32 1
  419. %7 = OpTypePointer Function %6
  420. %9 = OpConstant %6 2
  421. %13 = OpTypeBool
  422. %17 = OpConstant %6 3
  423. %19 = OpConstant %6 4
  424. %4 = OpFunction %2 None %3
  425. %5 = OpLabel
  426. %8 = OpVariable %7 Function
  427. %11 = OpVariable %7 Function
  428. OpStore %8 %9
  429. %10 = OpLoad %6 %8
  430. %12 = OpLoad %6 %11
  431. %14 = OpSLessThan %13 %10 %12
  432. OpBranch %100
  433. %100 = OpLabel
  434. OpSelectionMerge %16 None
  435. OpBranchConditional %14 %15 %18
  436. %15 = OpLabel
  437. OpStore %11 %17
  438. OpBranch %16
  439. %18 = OpLabel
  440. OpStore %11 %19
  441. OpBranch %16
  442. %16 = OpLabel
  443. OpReturn
  444. OpFunctionEnd
  445. )";
  446. ASSERT_TRUE(IsEqual(env, after_split, context.get()));
  447. }
  448. TEST(TransformationSplitBlockTest, SplitBlockBeforeSwitchBranch) {
  449. // The SPIR-V in this test came from the following fragment shader:
  450. //
  451. // void main() {
  452. // int x, y;
  453. // switch (y) {
  454. // case 1:
  455. // x = 2;
  456. // case 2:
  457. // break;
  458. // case 3:
  459. // x = 4;
  460. // default:
  461. // x = 6;
  462. // }
  463. // }
  464. std::string shader = R"(
  465. OpCapability Shader
  466. %1 = OpExtInstImport "GLSL.std.450"
  467. OpMemoryModel Logical GLSL450
  468. OpEntryPoint Fragment %4 "main"
  469. OpExecutionMode %4 OriginUpperLeft
  470. OpSource ESSL 310
  471. OpName %4 "main"
  472. OpName %8 "y"
  473. OpName %15 "x"
  474. OpDecorate %8 RelaxedPrecision
  475. OpDecorate %9 RelaxedPrecision
  476. OpDecorate %15 RelaxedPrecision
  477. %2 = OpTypeVoid
  478. %3 = OpTypeFunction %2
  479. %6 = OpTypeInt 32 1
  480. %7 = OpTypePointer Function %6
  481. %16 = OpConstant %6 2
  482. %18 = OpConstant %6 4
  483. %19 = OpConstant %6 6
  484. %4 = OpFunction %2 None %3
  485. %5 = OpLabel
  486. %8 = OpVariable %7 Function
  487. %15 = OpVariable %7 Function
  488. %9 = OpLoad %6 %8
  489. OpSelectionMerge %14 None
  490. OpSwitch %9 %13 1 %10 2 %11 3 %12
  491. %13 = OpLabel
  492. OpStore %15 %19
  493. OpBranch %14
  494. %10 = OpLabel
  495. OpStore %15 %16
  496. OpBranch %11
  497. %11 = OpLabel
  498. OpBranch %14
  499. %12 = OpLabel
  500. OpStore %15 %18
  501. OpBranch %13
  502. %14 = OpLabel
  503. OpReturn
  504. OpFunctionEnd
  505. )";
  506. const auto env = SPV_ENV_UNIVERSAL_1_3;
  507. const auto consumer = nullptr;
  508. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  509. FactManager fact_manager;
  510. // Illegal to split between the merge and the conditional branch.
  511. ASSERT_FALSE(TransformationSplitBlock(
  512. MakeInstructionDescriptor(9, SpvOpSwitch, 0), 100)
  513. .IsApplicable(context.get(), fact_manager));
  514. ASSERT_FALSE(TransformationSplitBlock(
  515. MakeInstructionDescriptor(15, SpvOpSwitch, 0), 100)
  516. .IsApplicable(context.get(), fact_manager));
  517. auto split = TransformationSplitBlock(
  518. MakeInstructionDescriptor(9, SpvOpSelectionMerge, 0), 100);
  519. ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager));
  520. split.Apply(context.get(), &fact_manager);
  521. ASSERT_TRUE(IsValid(env, context.get()));
  522. std::string after_split = R"(
  523. OpCapability Shader
  524. %1 = OpExtInstImport "GLSL.std.450"
  525. OpMemoryModel Logical GLSL450
  526. OpEntryPoint Fragment %4 "main"
  527. OpExecutionMode %4 OriginUpperLeft
  528. OpSource ESSL 310
  529. OpName %4 "main"
  530. OpName %8 "y"
  531. OpName %15 "x"
  532. OpDecorate %8 RelaxedPrecision
  533. OpDecorate %9 RelaxedPrecision
  534. OpDecorate %15 RelaxedPrecision
  535. %2 = OpTypeVoid
  536. %3 = OpTypeFunction %2
  537. %6 = OpTypeInt 32 1
  538. %7 = OpTypePointer Function %6
  539. %16 = OpConstant %6 2
  540. %18 = OpConstant %6 4
  541. %19 = OpConstant %6 6
  542. %4 = OpFunction %2 None %3
  543. %5 = OpLabel
  544. %8 = OpVariable %7 Function
  545. %15 = OpVariable %7 Function
  546. %9 = OpLoad %6 %8
  547. OpBranch %100
  548. %100 = OpLabel
  549. OpSelectionMerge %14 None
  550. OpSwitch %9 %13 1 %10 2 %11 3 %12
  551. %13 = OpLabel
  552. OpStore %15 %19
  553. OpBranch %14
  554. %10 = OpLabel
  555. OpStore %15 %16
  556. OpBranch %11
  557. %11 = OpLabel
  558. OpBranch %14
  559. %12 = OpLabel
  560. OpStore %15 %18
  561. OpBranch %13
  562. %14 = OpLabel
  563. OpReturn
  564. OpFunctionEnd
  565. )";
  566. ASSERT_TRUE(IsEqual(env, after_split, context.get()));
  567. }
  568. TEST(TransformationSplitBlockTest, NoSplitDuringOpPhis) {
  569. // The SPIR-V in this test came from the following fragment shader, with
  570. // local store elimination applied to get some OpPhi instructions.
  571. //
  572. // void main() {
  573. // int x;
  574. // int i;
  575. // for (i = 0; i < 100; i++) {
  576. // x += i;
  577. // }
  578. // }
  579. std::string shader = R"(
  580. OpCapability Shader
  581. %1 = OpExtInstImport "GLSL.std.450"
  582. OpMemoryModel Logical GLSL450
  583. OpEntryPoint Fragment %4 "main"
  584. OpExecutionMode %4 OriginUpperLeft
  585. OpSource ESSL 310
  586. OpName %4 "main"
  587. OpName %8 "i"
  588. OpName %19 "x"
  589. OpDecorate %8 RelaxedPrecision
  590. OpDecorate %19 RelaxedPrecision
  591. OpDecorate %22 RelaxedPrecision
  592. OpDecorate %25 RelaxedPrecision
  593. OpDecorate %26 RelaxedPrecision
  594. OpDecorate %27 RelaxedPrecision
  595. %2 = OpTypeVoid
  596. %3 = OpTypeFunction %2
  597. %6 = OpTypeInt 32 1
  598. %7 = OpTypePointer Function %6
  599. %9 = OpConstant %6 0
  600. %16 = OpConstant %6 100
  601. %17 = OpTypeBool
  602. %24 = OpConstant %6 1
  603. %28 = OpUndef %6
  604. %4 = OpFunction %2 None %3
  605. %5 = OpLabel
  606. %8 = OpVariable %7 Function
  607. %19 = OpVariable %7 Function
  608. OpStore %8 %9
  609. OpBranch %10
  610. %10 = OpLabel
  611. %27 = OpPhi %6 %28 %5 %22 %13
  612. %26 = OpPhi %6 %9 %5 %25 %13
  613. OpBranch %50
  614. %50 = OpLabel
  615. OpLoopMerge %12 %13 None
  616. OpBranch %14
  617. %14 = OpLabel
  618. %18 = OpSLessThan %17 %26 %16
  619. OpBranchConditional %18 %11 %12
  620. %11 = OpLabel
  621. %22 = OpIAdd %6 %27 %26
  622. OpStore %19 %22
  623. OpBranch %13
  624. %13 = OpLabel
  625. %25 = OpIAdd %6 %26 %24
  626. OpStore %8 %25
  627. OpBranch %50
  628. %12 = OpLabel
  629. OpReturn
  630. OpFunctionEnd
  631. )";
  632. const auto env = SPV_ENV_UNIVERSAL_1_3;
  633. const auto consumer = nullptr;
  634. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  635. FactManager fact_manager;
  636. // We cannot split before OpPhi instructions, since the number of incoming
  637. // blocks may not appropriately match after splitting.
  638. ASSERT_FALSE(
  639. TransformationSplitBlock(MakeInstructionDescriptor(26, SpvOpPhi, 0), 100)
  640. .IsApplicable(context.get(), fact_manager));
  641. ASSERT_FALSE(
  642. TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 0), 100)
  643. .IsApplicable(context.get(), fact_manager));
  644. ASSERT_FALSE(
  645. TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 1), 100)
  646. .IsApplicable(context.get(), fact_manager));
  647. }
  648. TEST(TransformationSplitBlockTest, SplitOpPhiWithSinglePredecessor) {
  649. std::string shader = R"(
  650. OpCapability Shader
  651. %1 = OpExtInstImport "GLSL.std.450"
  652. OpMemoryModel Logical GLSL450
  653. OpEntryPoint Fragment %4 "main"
  654. OpExecutionMode %4 OriginUpperLeft
  655. OpSource ESSL 310
  656. OpName %4 "main"
  657. OpName %8 "x"
  658. OpName %10 "y"
  659. OpDecorate %8 RelaxedPrecision
  660. OpDecorate %10 RelaxedPrecision
  661. OpDecorate %11 RelaxedPrecision
  662. %2 = OpTypeVoid
  663. %3 = OpTypeFunction %2
  664. %6 = OpTypeInt 32 1
  665. %7 = OpTypePointer Function %6
  666. %9 = OpConstant %6 1
  667. %4 = OpFunction %2 None %3
  668. %5 = OpLabel
  669. %8 = OpVariable %7 Function
  670. %10 = OpVariable %7 Function
  671. OpStore %8 %9
  672. %11 = OpLoad %6 %8
  673. OpBranch %20
  674. %20 = OpLabel
  675. %21 = OpPhi %6 %11 %5
  676. OpStore %10 %21
  677. OpReturn
  678. OpFunctionEnd
  679. )";
  680. const auto env = SPV_ENV_UNIVERSAL_1_3;
  681. const auto consumer = nullptr;
  682. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  683. FactManager fact_manager;
  684. ASSERT_TRUE(
  685. TransformationSplitBlock(MakeInstructionDescriptor(21, SpvOpPhi, 0), 100)
  686. .IsApplicable(context.get(), fact_manager));
  687. // An equivalent transformation to the above, just described with respect to a
  688. // different base instruction.
  689. auto split =
  690. TransformationSplitBlock(MakeInstructionDescriptor(20, SpvOpPhi, 0), 100);
  691. ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager));
  692. split.Apply(context.get(), &fact_manager);
  693. ASSERT_TRUE(IsValid(env, context.get()));
  694. std::string after_split = R"(
  695. OpCapability Shader
  696. %1 = OpExtInstImport "GLSL.std.450"
  697. OpMemoryModel Logical GLSL450
  698. OpEntryPoint Fragment %4 "main"
  699. OpExecutionMode %4 OriginUpperLeft
  700. OpSource ESSL 310
  701. OpName %4 "main"
  702. OpName %8 "x"
  703. OpName %10 "y"
  704. OpDecorate %8 RelaxedPrecision
  705. OpDecorate %10 RelaxedPrecision
  706. OpDecorate %11 RelaxedPrecision
  707. %2 = OpTypeVoid
  708. %3 = OpTypeFunction %2
  709. %6 = OpTypeInt 32 1
  710. %7 = OpTypePointer Function %6
  711. %9 = OpConstant %6 1
  712. %4 = OpFunction %2 None %3
  713. %5 = OpLabel
  714. %8 = OpVariable %7 Function
  715. %10 = OpVariable %7 Function
  716. OpStore %8 %9
  717. %11 = OpLoad %6 %8
  718. OpBranch %20
  719. %20 = OpLabel
  720. OpBranch %100
  721. %100 = OpLabel
  722. %21 = OpPhi %6 %11 %20
  723. OpStore %10 %21
  724. OpReturn
  725. OpFunctionEnd
  726. )";
  727. ASSERT_TRUE(IsEqual(env, after_split, context.get()));
  728. }
  729. } // namespace
  730. } // namespace fuzz
  731. } // namespace spvtools