transformation_add_opphi_synonym_test.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. // Copyright (c) 2020 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "source/fuzz/transformation_add_opphi_synonym.h"
  15. #include "gtest/gtest.h"
  16. #include "source/fuzz/fuzzer_util.h"
  17. #include "test/fuzz/fuzz_test_util.h"
  18. namespace spvtools {
  19. namespace fuzz {
  20. namespace {
  21. protobufs::Fact MakeSynonymFact(uint32_t first, uint32_t second) {
  22. protobufs::FactDataSynonym data_synonym_fact;
  23. *data_synonym_fact.mutable_data1() = MakeDataDescriptor(first, {});
  24. *data_synonym_fact.mutable_data2() = MakeDataDescriptor(second, {});
  25. protobufs::Fact result;
  26. *result.mutable_data_synonym_fact() = data_synonym_fact;
  27. return result;
  28. }
  29. // Adds synonym facts to the fact manager.
  30. void SetUpIdSynonyms(FactManager* fact_manager) {
  31. fact_manager->MaybeAddFact(MakeSynonymFact(11, 9));
  32. fact_manager->MaybeAddFact(MakeSynonymFact(13, 9));
  33. fact_manager->MaybeAddFact(MakeSynonymFact(14, 9));
  34. fact_manager->MaybeAddFact(MakeSynonymFact(19, 9));
  35. fact_manager->MaybeAddFact(MakeSynonymFact(20, 9));
  36. fact_manager->MaybeAddFact(MakeSynonymFact(10, 21));
  37. }
  38. TEST(TransformationAddOpPhiSynonymTest, Inapplicable) {
  39. std::string shader = R"(
  40. OpCapability Shader
  41. %1 = OpExtInstImport "GLSL.std.450"
  42. OpMemoryModel Logical GLSL450
  43. OpEntryPoint Fragment %2 "main"
  44. OpExecutionMode %2 OriginUpperLeft
  45. OpSource ESSL 310
  46. OpName %2 "main"
  47. %3 = OpTypeVoid
  48. %4 = OpTypeFunction %3
  49. %5 = OpTypeBool
  50. %6 = OpConstantTrue %5
  51. %7 = OpTypeInt 32 1
  52. %8 = OpTypeInt 32 0
  53. %22 = OpTypePointer Function %7
  54. %9 = OpConstant %7 1
  55. %10 = OpConstant %7 2
  56. %11 = OpConstant %8 1
  57. %2 = OpFunction %3 None %4
  58. %12 = OpLabel
  59. %23 = OpVariable %22 Function
  60. %13 = OpCopyObject %7 %9
  61. %14 = OpCopyObject %8 %11
  62. OpBranch %15
  63. %15 = OpLabel
  64. OpSelectionMerge %16 None
  65. OpBranchConditional %6 %17 %18
  66. %17 = OpLabel
  67. %19 = OpCopyObject %7 %13
  68. %20 = OpCopyObject %8 %14
  69. %21 = OpCopyObject %7 %10
  70. OpBranch %16
  71. %18 = OpLabel
  72. %24 = OpCopyObject %22 %23
  73. OpBranch %16
  74. %16 = OpLabel
  75. OpReturn
  76. OpFunctionEnd
  77. )";
  78. const auto env = SPV_ENV_UNIVERSAL_1_5;
  79. const auto consumer = nullptr;
  80. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  81. spvtools::ValidatorOptions validator_options;
  82. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  83. kConsoleMessageConsumer));
  84. TransformationContext transformation_context(
  85. MakeUnique<FactManager>(context.get()), validator_options);
  86. SetUpIdSynonyms(transformation_context.GetFactManager());
  87. transformation_context.GetFactManager()->MaybeAddFact(
  88. MakeSynonymFact(23, 24));
  89. // %13 is not a block label.
  90. ASSERT_FALSE(TransformationAddOpPhiSynonym(13, {{}}, 100)
  91. .IsApplicable(context.get(), transformation_context));
  92. // Block %12 does not have a predecessor.
  93. ASSERT_FALSE(TransformationAddOpPhiSynonym(12, {{}}, 100)
  94. .IsApplicable(context.get(), transformation_context));
  95. // Not all predecessors of %16 (%17 and %18) are considered in the map.
  96. ASSERT_FALSE(TransformationAddOpPhiSynonym(16, {{{17, 19}}}, 100)
  97. .IsApplicable(context.get(), transformation_context));
  98. // %30 does not exist in the module.
  99. ASSERT_FALSE(TransformationAddOpPhiSynonym(16, {{{30, 19}}}, 100)
  100. .IsApplicable(context.get(), transformation_context));
  101. // %20 is not a block label.
  102. ASSERT_FALSE(TransformationAddOpPhiSynonym(16, {{{20, 19}}}, 100)
  103. .IsApplicable(context.get(), transformation_context));
  104. // %15 is not the id of one of the predecessors of the block.
  105. ASSERT_FALSE(TransformationAddOpPhiSynonym(16, {{{15, 19}}}, 100)
  106. .IsApplicable(context.get(), transformation_context));
  107. // %30 does not exist in the module.
  108. ASSERT_FALSE(TransformationAddOpPhiSynonym(16, {{{17, 30}, {18, 13}}}, 100)
  109. .IsApplicable(context.get(), transformation_context));
  110. // %19 and %10 are not synonymous.
  111. ASSERT_FALSE(TransformationAddOpPhiSynonym(16, {{{17, 19}, {18, 10}}}, 100)
  112. .IsApplicable(context.get(), transformation_context));
  113. // %19 and %14 do not have the same type.
  114. ASSERT_FALSE(TransformationAddOpPhiSynonym(16, {{{17, 19}, {18, 14}}}, 100)
  115. .IsApplicable(context.get(), transformation_context));
  116. // %19 is not available at the end of %18.
  117. ASSERT_FALSE(TransformationAddOpPhiSynonym(16, {{{17, 9}, {18, 19}}}, 100)
  118. .IsApplicable(context.get(), transformation_context));
  119. // %21 is not a fresh id.
  120. ASSERT_FALSE(TransformationAddOpPhiSynonym(16, {{{17, 9}, {18, 9}}}, 21)
  121. .IsApplicable(context.get(), transformation_context));
  122. // %23 and %24 have pointer id.
  123. ASSERT_FALSE(TransformationAddOpPhiSynonym(16, {{{17, 23}, {18, 24}}}, 100)
  124. .IsApplicable(context.get(), transformation_context));
  125. }
  126. TEST(TransformationAddOpPhiSynonymTest, Apply) {
  127. std::string shader = R"(
  128. OpCapability Shader
  129. %1 = OpExtInstImport "GLSL.std.450"
  130. OpMemoryModel Logical GLSL450
  131. OpEntryPoint Fragment %2 "main"
  132. OpExecutionMode %2 OriginUpperLeft
  133. OpSource ESSL 310
  134. OpName %2 "main"
  135. %3 = OpTypeVoid
  136. %4 = OpTypeFunction %3
  137. %5 = OpTypeBool
  138. %6 = OpConstantTrue %5
  139. %7 = OpTypeInt 32 1
  140. %8 = OpTypeInt 32 0
  141. %9 = OpConstant %7 1
  142. %10 = OpConstant %7 2
  143. %11 = OpConstant %8 1
  144. %2 = OpFunction %3 None %4
  145. %12 = OpLabel
  146. %13 = OpCopyObject %7 %9
  147. %14 = OpCopyObject %8 %11
  148. OpBranch %15
  149. %15 = OpLabel
  150. OpSelectionMerge %16 None
  151. OpBranchConditional %6 %17 %18
  152. %17 = OpLabel
  153. %19 = OpCopyObject %7 %13
  154. %20 = OpCopyObject %8 %14
  155. %21 = OpCopyObject %7 %10
  156. OpBranch %16
  157. %18 = OpLabel
  158. OpBranch %16
  159. %16 = OpLabel
  160. OpBranch %22
  161. %22 = OpLabel
  162. OpLoopMerge %23 %24 None
  163. OpBranchConditional %6 %25 %23
  164. %25 = OpLabel
  165. OpSelectionMerge %26 None
  166. OpBranchConditional %6 %27 %26
  167. %27 = OpLabel
  168. %28 = OpCopyObject %7 %13
  169. OpBranch %23
  170. %26 = OpLabel
  171. OpSelectionMerge %29 None
  172. OpBranchConditional %6 %29 %24
  173. %29 = OpLabel
  174. %30 = OpCopyObject %7 %13
  175. OpBranch %23
  176. %24 = OpLabel
  177. OpBranch %22
  178. %23 = OpLabel
  179. OpSelectionMerge %31 None
  180. OpBranchConditional %6 %31 %31
  181. %31 = OpLabel
  182. OpReturn
  183. OpFunctionEnd
  184. )";
  185. const auto env = SPV_ENV_UNIVERSAL_1_5;
  186. const auto consumer = nullptr;
  187. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  188. spvtools::ValidatorOptions validator_options;
  189. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  190. kConsoleMessageConsumer));
  191. TransformationContext transformation_context(
  192. MakeUnique<FactManager>(context.get()), validator_options);
  193. SetUpIdSynonyms(transformation_context.GetFactManager());
  194. // Add some further synonym facts.
  195. transformation_context.GetFactManager()->MaybeAddFact(MakeSynonymFact(28, 9));
  196. transformation_context.GetFactManager()->MaybeAddFact(MakeSynonymFact(30, 9));
  197. auto transformation1 = TransformationAddOpPhiSynonym(17, {{{15, 13}}}, 100);
  198. ASSERT_TRUE(
  199. transformation1.IsApplicable(context.get(), transformation_context));
  200. ApplyAndCheckFreshIds(transformation1, context.get(),
  201. &transformation_context);
  202. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
  203. MakeDataDescriptor(100, {}), MakeDataDescriptor(9, {})));
  204. auto transformation2 =
  205. TransformationAddOpPhiSynonym(16, {{{17, 19}, {18, 13}}}, 101);
  206. ASSERT_TRUE(
  207. transformation2.IsApplicable(context.get(), transformation_context));
  208. ApplyAndCheckFreshIds(transformation2, context.get(),
  209. &transformation_context);
  210. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
  211. MakeDataDescriptor(101, {}), MakeDataDescriptor(9, {})));
  212. auto transformation3 =
  213. TransformationAddOpPhiSynonym(23, {{{22, 13}, {27, 28}, {29, 30}}}, 102);
  214. ASSERT_TRUE(
  215. transformation3.IsApplicable(context.get(), transformation_context));
  216. ApplyAndCheckFreshIds(transformation3, context.get(),
  217. &transformation_context);
  218. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
  219. MakeDataDescriptor(102, {}), MakeDataDescriptor(9, {})));
  220. auto transformation4 = TransformationAddOpPhiSynonym(31, {{{23, 13}}}, 103);
  221. ASSERT_TRUE(
  222. transformation4.IsApplicable(context.get(), transformation_context));
  223. ApplyAndCheckFreshIds(transformation4, context.get(),
  224. &transformation_context);
  225. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
  226. MakeDataDescriptor(103, {}), MakeDataDescriptor(9, {})));
  227. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  228. kConsoleMessageConsumer));
  229. std::string after_transformations = R"(
  230. OpCapability Shader
  231. %1 = OpExtInstImport "GLSL.std.450"
  232. OpMemoryModel Logical GLSL450
  233. OpEntryPoint Fragment %2 "main"
  234. OpExecutionMode %2 OriginUpperLeft
  235. OpSource ESSL 310
  236. OpName %2 "main"
  237. %3 = OpTypeVoid
  238. %4 = OpTypeFunction %3
  239. %5 = OpTypeBool
  240. %6 = OpConstantTrue %5
  241. %7 = OpTypeInt 32 1
  242. %8 = OpTypeInt 32 0
  243. %9 = OpConstant %7 1
  244. %10 = OpConstant %7 2
  245. %11 = OpConstant %8 1
  246. %2 = OpFunction %3 None %4
  247. %12 = OpLabel
  248. %13 = OpCopyObject %7 %9
  249. %14 = OpCopyObject %8 %11
  250. OpBranch %15
  251. %15 = OpLabel
  252. OpSelectionMerge %16 None
  253. OpBranchConditional %6 %17 %18
  254. %17 = OpLabel
  255. %100 = OpPhi %7 %13 %15
  256. %19 = OpCopyObject %7 %13
  257. %20 = OpCopyObject %8 %14
  258. %21 = OpCopyObject %7 %10
  259. OpBranch %16
  260. %18 = OpLabel
  261. OpBranch %16
  262. %16 = OpLabel
  263. %101 = OpPhi %7 %19 %17 %13 %18
  264. OpBranch %22
  265. %22 = OpLabel
  266. OpLoopMerge %23 %24 None
  267. OpBranchConditional %6 %25 %23
  268. %25 = OpLabel
  269. OpSelectionMerge %26 None
  270. OpBranchConditional %6 %27 %26
  271. %27 = OpLabel
  272. %28 = OpCopyObject %7 %13
  273. OpBranch %23
  274. %26 = OpLabel
  275. OpSelectionMerge %29 None
  276. OpBranchConditional %6 %29 %24
  277. %29 = OpLabel
  278. %30 = OpCopyObject %7 %13
  279. OpBranch %23
  280. %24 = OpLabel
  281. OpBranch %22
  282. %23 = OpLabel
  283. %102 = OpPhi %7 %13 %22 %28 %27 %30 %29
  284. OpSelectionMerge %31 None
  285. OpBranchConditional %6 %31 %31
  286. %31 = OpLabel
  287. %103 = OpPhi %7 %13 %23
  288. OpReturn
  289. OpFunctionEnd
  290. )";
  291. ASSERT_TRUE(IsEqual(env, after_transformations, context.get()));
  292. }
  293. TEST(TransformationAddOpPhiSynonymTest, VariablePointers) {
  294. std::string shader = R"(
  295. OpCapability Shader
  296. OpCapability VariablePointers
  297. %1 = OpExtInstImport "GLSL.std.450"
  298. OpMemoryModel Logical GLSL450
  299. OpEntryPoint Fragment %2 "main" %3
  300. OpExecutionMode %2 OriginUpperLeft
  301. OpSource ESSL 310
  302. %4 = OpTypeVoid
  303. %5 = OpTypeFunction %4
  304. %6 = OpTypeBool
  305. %7 = OpConstantTrue %6
  306. %8 = OpTypeInt 32 1
  307. %9 = OpTypePointer Function %8
  308. %10 = OpTypePointer Workgroup %8
  309. %3 = OpVariable %10 Workgroup
  310. %2 = OpFunction %4 None %5
  311. %11 = OpLabel
  312. %12 = OpVariable %9 Function
  313. OpSelectionMerge %13 None
  314. OpBranchConditional %7 %14 %13
  315. %14 = OpLabel
  316. %15 = OpCopyObject %10 %3
  317. %16 = OpCopyObject %9 %12
  318. OpBranch %13
  319. %13 = OpLabel
  320. OpReturn
  321. OpFunctionEnd
  322. )";
  323. const auto env = SPV_ENV_UNIVERSAL_1_5;
  324. const auto consumer = nullptr;
  325. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  326. spvtools::ValidatorOptions validator_options;
  327. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  328. kConsoleMessageConsumer));
  329. TransformationContext transformation_context(
  330. MakeUnique<FactManager>(context.get()), validator_options);
  331. // Declare synonyms
  332. transformation_context.GetFactManager()->MaybeAddFact(MakeSynonymFact(3, 15));
  333. transformation_context.GetFactManager()->MaybeAddFact(
  334. MakeSynonymFact(12, 16));
  335. // Remove the VariablePointers capability.
  336. context.get()->RemoveCapability(spv::Capability::VariablePointers);
  337. // The VariablePointers capability is required to add an OpPhi instruction of
  338. // pointer type.
  339. ASSERT_FALSE(TransformationAddOpPhiSynonym(13, {{{11, 3}, {14, 15}}}, 100)
  340. .IsApplicable(context.get(), transformation_context));
  341. // Add the VariablePointers capability back.
  342. context.get()->AddCapability(spv::Capability::VariablePointers);
  343. // If the ids have pointer type, the storage class must be Workgroup or
  344. // StorageBuffer, but it is Function in this case.
  345. ASSERT_FALSE(TransformationAddOpPhiSynonym(13, {{{11, 12}, {14, 16}}}, 100)
  346. .IsApplicable(context.get(), transformation_context));
  347. auto transformation =
  348. TransformationAddOpPhiSynonym(13, {{{11, 3}, {14, 15}}}, 100);
  349. ASSERT_TRUE(
  350. transformation.IsApplicable(context.get(), transformation_context));
  351. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  352. std::string after_transformation = R"(
  353. OpCapability Shader
  354. OpCapability VariablePointers
  355. %1 = OpExtInstImport "GLSL.std.450"
  356. OpMemoryModel Logical GLSL450
  357. OpEntryPoint Fragment %2 "main" %3
  358. OpExecutionMode %2 OriginUpperLeft
  359. OpSource ESSL 310
  360. %4 = OpTypeVoid
  361. %5 = OpTypeFunction %4
  362. %6 = OpTypeBool
  363. %7 = OpConstantTrue %6
  364. %8 = OpTypeInt 32 1
  365. %9 = OpTypePointer Function %8
  366. %10 = OpTypePointer Workgroup %8
  367. %3 = OpVariable %10 Workgroup
  368. %2 = OpFunction %4 None %5
  369. %11 = OpLabel
  370. %12 = OpVariable %9 Function
  371. OpSelectionMerge %13 None
  372. OpBranchConditional %7 %14 %13
  373. %14 = OpLabel
  374. %15 = OpCopyObject %10 %3
  375. %16 = OpCopyObject %9 %12
  376. OpBranch %13
  377. %13 = OpLabel
  378. %100 = OpPhi %10 %3 %11 %15 %14
  379. OpReturn
  380. OpFunctionEnd
  381. )";
  382. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  383. }
  384. TEST(TransformationAddOpPhiSynonymTest, DeadBlock) {
  385. std::string shader = R"(
  386. OpCapability Shader
  387. %1 = OpExtInstImport "GLSL.std.450"
  388. OpMemoryModel Logical GLSL450
  389. OpEntryPoint Fragment %4 "main"
  390. OpExecutionMode %4 OriginUpperLeft
  391. OpSource ESSL 320
  392. %2 = OpTypeVoid
  393. %3 = OpTypeFunction %2
  394. %6 = OpTypeInt 32 1
  395. %7 = OpTypePointer Function %6
  396. %9 = OpConstant %6 2
  397. %10 = OpTypeBool
  398. %11 = OpConstantFalse %10
  399. %15 = OpConstant %6 0
  400. %50 = OpConstant %6 0
  401. %4 = OpFunction %2 None %3
  402. %5 = OpLabel
  403. %8 = OpVariable %7 Function
  404. OpStore %8 %9
  405. OpSelectionMerge %13 None
  406. OpBranchConditional %11 %12 %13
  407. %12 = OpLabel
  408. %14 = OpLoad %6 %8
  409. %16 = OpIEqual %10 %14 %15
  410. OpSelectionMerge %18 None
  411. OpBranchConditional %16 %17 %40
  412. %17 = OpLabel
  413. OpBranch %18
  414. %40 = OpLabel
  415. OpBranch %18
  416. %18 = OpLabel
  417. OpBranch %13
  418. %13 = OpLabel
  419. OpReturn
  420. OpFunctionEnd
  421. )";
  422. const auto env = SPV_ENV_UNIVERSAL_1_5;
  423. const auto consumer = nullptr;
  424. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  425. spvtools::ValidatorOptions validator_options;
  426. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  427. kConsoleMessageConsumer));
  428. TransformationContext transformation_context(
  429. MakeUnique<FactManager>(context.get()), validator_options);
  430. // Dead blocks
  431. transformation_context.GetFactManager()->AddFactBlockIsDead(12);
  432. transformation_context.GetFactManager()->AddFactBlockIsDead(17);
  433. transformation_context.GetFactManager()->AddFactBlockIsDead(18);
  434. // Declare synonym
  435. ASSERT_TRUE(transformation_context.GetFactManager()->MaybeAddFact(
  436. MakeSynonymFact(15, 50)));
  437. // Bad because the block 18 is dead.
  438. ASSERT_FALSE(TransformationAddOpPhiSynonym(18, {{{17, 15}, {40, 50}}}, 100)
  439. .IsApplicable(context.get(), transformation_context));
  440. }
  441. } // namespace
  442. } // namespace fuzz
  443. } // namespace spvtools