transformation_split_block_test.cpp 33 KB

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