transformation_composite_insert_test.cpp 38 KB

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