transformation_move_instruction_down_test.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. // Copyright (c) 2020 Vasyl Teliman
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "source/fuzz/transformation_move_instruction_down.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(TransformationMoveInstructionDownTest, BasicTest) {
  23. std::string shader = R"(
  24. OpCapability Shader
  25. %1 = OpExtInstImport "GLSL.std.450"
  26. OpMemoryModel Logical GLSL450
  27. OpEntryPoint Fragment %4 "main"
  28. OpExecutionMode %4 OriginUpperLeft
  29. OpSource ESSL 310
  30. %2 = OpTypeVoid
  31. %3 = OpTypeFunction %2
  32. %6 = OpTypeInt 32 1
  33. %9 = OpConstant %6 0
  34. %16 = OpTypeBool
  35. %17 = OpConstantFalse %16
  36. %20 = OpUndef %6
  37. %13 = OpTypePointer Function %6
  38. %4 = OpFunction %2 None %3
  39. %5 = OpLabel
  40. %12 = OpVariable %13 Function
  41. %10 = OpIAdd %6 %9 %9
  42. %11 = OpISub %6 %9 %10
  43. OpStore %12 %10
  44. %14 = OpLoad %6 %12
  45. %15 = OpIMul %6 %9 %14
  46. OpSelectionMerge %19 None
  47. OpBranchConditional %17 %18 %19
  48. %18 = OpLabel
  49. OpBranch %19
  50. %19 = OpLabel
  51. %42 = OpFunctionCall %2 %40
  52. %22 = OpIAdd %6 %15 %15
  53. %21 = OpIAdd %6 %15 %15
  54. OpReturn
  55. OpFunctionEnd
  56. %40 = OpFunction %2 None %3
  57. %41 = OpLabel
  58. OpReturn
  59. OpFunctionEnd
  60. )";
  61. const auto env = SPV_ENV_UNIVERSAL_1_3;
  62. const auto consumer = nullptr;
  63. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  64. spvtools::ValidatorOptions validator_options;
  65. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  66. kConsoleMessageConsumer));
  67. TransformationContext transformation_context(
  68. MakeUnique<FactManager>(context.get()), validator_options);
  69. // Instruction descriptor is invalid.
  70. ASSERT_FALSE(TransformationMoveInstructionDown(
  71. MakeInstructionDescriptor(30, spv::Op::OpNop, 0))
  72. .IsApplicable(context.get(), transformation_context));
  73. // Opcode is not supported.
  74. ASSERT_FALSE(TransformationMoveInstructionDown(
  75. MakeInstructionDescriptor(5, spv::Op::OpLabel, 0))
  76. .IsApplicable(context.get(), transformation_context));
  77. ASSERT_FALSE(TransformationMoveInstructionDown(
  78. MakeInstructionDescriptor(12, spv::Op::OpVariable, 0))
  79. .IsApplicable(context.get(), transformation_context));
  80. ASSERT_FALSE(TransformationMoveInstructionDown(
  81. MakeInstructionDescriptor(42, spv::Op::OpFunctionCall, 0))
  82. .IsApplicable(context.get(), transformation_context));
  83. // Can't move the last instruction in the block.
  84. ASSERT_FALSE(
  85. TransformationMoveInstructionDown(
  86. MakeInstructionDescriptor(15, spv::Op::OpBranchConditional, 0))
  87. .IsApplicable(context.get(), transformation_context));
  88. // Can't move the instruction if the next instruction is the last one in the
  89. // block.
  90. ASSERT_FALSE(TransformationMoveInstructionDown(
  91. MakeInstructionDescriptor(21, spv::Op::OpIAdd, 0))
  92. .IsApplicable(context.get(), transformation_context));
  93. // Can't insert instruction's opcode after its successor.
  94. ASSERT_FALSE(TransformationMoveInstructionDown(
  95. MakeInstructionDescriptor(15, spv::Op::OpIMul, 0))
  96. .IsApplicable(context.get(), transformation_context));
  97. // Instruction's successor depends on the instruction.
  98. ASSERT_FALSE(TransformationMoveInstructionDown(
  99. MakeInstructionDescriptor(10, spv::Op::OpIAdd, 0))
  100. .IsApplicable(context.get(), transformation_context));
  101. {
  102. TransformationMoveInstructionDown transformation(
  103. MakeInstructionDescriptor(11, spv::Op::OpISub, 0));
  104. ASSERT_TRUE(
  105. transformation.IsApplicable(context.get(), transformation_context));
  106. ApplyAndCheckFreshIds(transformation, context.get(),
  107. &transformation_context);
  108. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  109. context.get(), validator_options, kConsoleMessageConsumer));
  110. }
  111. {
  112. TransformationMoveInstructionDown transformation(
  113. MakeInstructionDescriptor(22, spv::Op::OpIAdd, 0));
  114. ASSERT_TRUE(
  115. transformation.IsApplicable(context.get(), transformation_context));
  116. ApplyAndCheckFreshIds(transformation, context.get(),
  117. &transformation_context);
  118. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  119. context.get(), validator_options, kConsoleMessageConsumer));
  120. }
  121. std::string after_transformation = R"(
  122. OpCapability Shader
  123. %1 = OpExtInstImport "GLSL.std.450"
  124. OpMemoryModel Logical GLSL450
  125. OpEntryPoint Fragment %4 "main"
  126. OpExecutionMode %4 OriginUpperLeft
  127. OpSource ESSL 310
  128. %2 = OpTypeVoid
  129. %3 = OpTypeFunction %2
  130. %6 = OpTypeInt 32 1
  131. %9 = OpConstant %6 0
  132. %16 = OpTypeBool
  133. %17 = OpConstantFalse %16
  134. %20 = OpUndef %6
  135. %13 = OpTypePointer Function %6
  136. %4 = OpFunction %2 None %3
  137. %5 = OpLabel
  138. %12 = OpVariable %13 Function
  139. %10 = OpIAdd %6 %9 %9
  140. OpStore %12 %10
  141. %11 = OpISub %6 %9 %10
  142. %14 = OpLoad %6 %12
  143. %15 = OpIMul %6 %9 %14
  144. OpSelectionMerge %19 None
  145. OpBranchConditional %17 %18 %19
  146. %18 = OpLabel
  147. OpBranch %19
  148. %19 = OpLabel
  149. %42 = OpFunctionCall %2 %40
  150. %21 = OpIAdd %6 %15 %15
  151. %22 = OpIAdd %6 %15 %15
  152. OpReturn
  153. OpFunctionEnd
  154. %40 = OpFunction %2 None %3
  155. %41 = OpLabel
  156. OpReturn
  157. OpFunctionEnd
  158. )";
  159. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  160. }
  161. TEST(TransformationMoveInstructionDownTest, HandlesUnsupportedInstructions) {
  162. std::string shader = R"(
  163. OpCapability Shader
  164. %1 = OpExtInstImport "GLSL.std.450"
  165. OpMemoryModel Logical GLSL450
  166. OpEntryPoint GLCompute %4 "main"
  167. OpExecutionMode %4 LocalSize 16 1 1
  168. OpSource ESSL 320
  169. %2 = OpTypeVoid
  170. %3 = OpTypeFunction %2
  171. %6 = OpTypeInt 32 0
  172. %7 = OpConstant %6 2
  173. %20 = OpTypePointer Function %6
  174. %4 = OpFunction %2 None %3
  175. %5 = OpLabel
  176. %21 = OpVariable %20 Function %7
  177. ; can swap simple and not supported instructions
  178. %8 = OpCopyObject %6 %7
  179. %9 = OpFunctionCall %2 %12
  180. ; cannot swap memory and not supported instruction
  181. %22 = OpLoad %6 %21
  182. %23 = OpFunctionCall %2 %12
  183. ; cannot swap barrier and not supported instruction
  184. OpMemoryBarrier %7 %7
  185. %24 = OpFunctionCall %2 %12
  186. OpReturn
  187. OpFunctionEnd
  188. %12 = OpFunction %2 None %3
  189. %13 = OpLabel
  190. OpReturn
  191. OpFunctionEnd
  192. )";
  193. const auto env = SPV_ENV_UNIVERSAL_1_3;
  194. const auto consumer = nullptr;
  195. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  196. spvtools::ValidatorOptions validator_options;
  197. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  198. kConsoleMessageConsumer));
  199. TransformationContext transformation_context(
  200. MakeUnique<FactManager>(context.get()), validator_options);
  201. // Swap memory instruction with an unsupported one.
  202. ASSERT_FALSE(TransformationMoveInstructionDown(
  203. MakeInstructionDescriptor(22, spv::Op::OpLoad, 0))
  204. .IsApplicable(context.get(), transformation_context));
  205. // Swap memory barrier with an unsupported one.
  206. ASSERT_FALSE(TransformationMoveInstructionDown(
  207. MakeInstructionDescriptor(23, spv::Op::OpMemoryBarrier, 0))
  208. .IsApplicable(context.get(), transformation_context));
  209. // Swap simple instruction with an unsupported one.
  210. TransformationMoveInstructionDown transformation(
  211. MakeInstructionDescriptor(8, spv::Op::OpCopyObject, 0));
  212. ASSERT_TRUE(
  213. transformation.IsApplicable(context.get(), transformation_context));
  214. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  215. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  216. kConsoleMessageConsumer));
  217. std::string after_transformation = R"(
  218. OpCapability Shader
  219. %1 = OpExtInstImport "GLSL.std.450"
  220. OpMemoryModel Logical GLSL450
  221. OpEntryPoint GLCompute %4 "main"
  222. OpExecutionMode %4 LocalSize 16 1 1
  223. OpSource ESSL 320
  224. %2 = OpTypeVoid
  225. %3 = OpTypeFunction %2
  226. %6 = OpTypeInt 32 0
  227. %7 = OpConstant %6 2
  228. %20 = OpTypePointer Function %6
  229. %4 = OpFunction %2 None %3
  230. %5 = OpLabel
  231. %21 = OpVariable %20 Function %7
  232. ; can swap simple and not supported instructions
  233. %9 = OpFunctionCall %2 %12
  234. %8 = OpCopyObject %6 %7
  235. ; cannot swap memory and not supported instruction
  236. %22 = OpLoad %6 %21
  237. %23 = OpFunctionCall %2 %12
  238. ; cannot swap barrier and not supported instruction
  239. OpMemoryBarrier %7 %7
  240. %24 = OpFunctionCall %2 %12
  241. OpReturn
  242. OpFunctionEnd
  243. %12 = OpFunction %2 None %3
  244. %13 = OpLabel
  245. OpReturn
  246. OpFunctionEnd
  247. )";
  248. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  249. }
  250. TEST(TransformationMoveInstructionDownTest, HandlesBarrierInstructions) {
  251. std::string shader = R"(
  252. OpCapability Shader
  253. %1 = OpExtInstImport "GLSL.std.450"
  254. OpMemoryModel Logical GLSL450
  255. OpEntryPoint GLCompute %4 "main"
  256. OpExecutionMode %4 LocalSize 16 1 1
  257. OpSource ESSL 320
  258. %2 = OpTypeVoid
  259. %3 = OpTypeFunction %2
  260. %6 = OpTypeInt 32 0
  261. %7 = OpConstant %6 2
  262. %20 = OpTypePointer Function %6
  263. %4 = OpFunction %2 None %3
  264. %5 = OpLabel
  265. %21 = OpVariable %20 Function %7
  266. ; cannot swap two barrier instructions
  267. OpMemoryBarrier %7 %7
  268. OpMemoryBarrier %7 %7
  269. ; cannot swap barrier and memory instructions
  270. OpMemoryBarrier %7 %7
  271. %22 = OpLoad %6 %21
  272. OpMemoryBarrier %7 %7
  273. ; can swap barrier and simple instructions
  274. %23 = OpCopyObject %6 %7
  275. OpMemoryBarrier %7 %7
  276. OpReturn
  277. OpFunctionEnd
  278. %12 = OpFunction %2 None %3
  279. %13 = OpLabel
  280. OpReturn
  281. OpFunctionEnd
  282. )";
  283. const auto env = SPV_ENV_UNIVERSAL_1_3;
  284. const auto consumer = nullptr;
  285. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  286. spvtools::ValidatorOptions validator_options;
  287. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  288. kConsoleMessageConsumer));
  289. TransformationContext transformation_context(
  290. MakeUnique<FactManager>(context.get()), validator_options);
  291. // Swap two barrier instructions.
  292. ASSERT_FALSE(TransformationMoveInstructionDown(
  293. MakeInstructionDescriptor(21, spv::Op::OpMemoryBarrier, 0))
  294. .IsApplicable(context.get(), transformation_context));
  295. // Swap barrier and memory instructions.
  296. ASSERT_FALSE(TransformationMoveInstructionDown(
  297. MakeInstructionDescriptor(21, spv::Op::OpMemoryBarrier, 2))
  298. .IsApplicable(context.get(), transformation_context));
  299. ASSERT_FALSE(TransformationMoveInstructionDown(
  300. MakeInstructionDescriptor(22, spv::Op::OpLoad, 0))
  301. .IsApplicable(context.get(), transformation_context));
  302. // Swap barrier and simple instructions.
  303. {
  304. TransformationMoveInstructionDown transformation(
  305. MakeInstructionDescriptor(23, spv::Op::OpCopyObject, 0));
  306. ASSERT_TRUE(
  307. transformation.IsApplicable(context.get(), transformation_context));
  308. ApplyAndCheckFreshIds(transformation, context.get(),
  309. &transformation_context);
  310. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  311. context.get(), validator_options, kConsoleMessageConsumer));
  312. }
  313. {
  314. TransformationMoveInstructionDown transformation(
  315. MakeInstructionDescriptor(22, spv::Op::OpMemoryBarrier, 1));
  316. ASSERT_TRUE(
  317. transformation.IsApplicable(context.get(), transformation_context));
  318. ApplyAndCheckFreshIds(transformation, context.get(),
  319. &transformation_context);
  320. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  321. context.get(), validator_options, kConsoleMessageConsumer));
  322. }
  323. ASSERT_TRUE(IsEqual(env, shader, context.get()));
  324. }
  325. TEST(TransformationMoveInstructionDownTest, HandlesSimpleInstructions) {
  326. std::string shader = R"(
  327. OpCapability Shader
  328. %1 = OpExtInstImport "GLSL.std.450"
  329. OpMemoryModel Logical GLSL450
  330. OpEntryPoint GLCompute %4 "main"
  331. OpExecutionMode %4 LocalSize 16 1 1
  332. OpSource ESSL 320
  333. %2 = OpTypeVoid
  334. %3 = OpTypeFunction %2
  335. %6 = OpTypeInt 32 0
  336. %7 = OpConstant %6 2
  337. %20 = OpTypePointer Function %6
  338. %4 = OpFunction %2 None %3
  339. %5 = OpLabel
  340. %21 = OpVariable %20 Function %7
  341. ; can swap simple and barrier instructions
  342. %40 = OpCopyObject %6 %7
  343. OpMemoryBarrier %7 %7
  344. ; can swap simple and memory instructions
  345. %41 = OpCopyObject %6 %7
  346. %22 = OpLoad %6 %21
  347. ; can swap two simple instructions
  348. %23 = OpCopyObject %6 %7
  349. %42 = OpCopyObject %6 %7
  350. OpReturn
  351. OpFunctionEnd
  352. %12 = OpFunction %2 None %3
  353. %13 = OpLabel
  354. OpReturn
  355. OpFunctionEnd
  356. )";
  357. const auto env = SPV_ENV_UNIVERSAL_1_3;
  358. const auto consumer = nullptr;
  359. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  360. spvtools::ValidatorOptions validator_options;
  361. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  362. kConsoleMessageConsumer));
  363. TransformationContext transformation_context(
  364. MakeUnique<FactManager>(context.get()), validator_options);
  365. // Swap simple and barrier instructions.
  366. {
  367. TransformationMoveInstructionDown transformation(
  368. MakeInstructionDescriptor(40, spv::Op::OpCopyObject, 0));
  369. ASSERT_TRUE(
  370. transformation.IsApplicable(context.get(), transformation_context));
  371. ApplyAndCheckFreshIds(transformation, context.get(),
  372. &transformation_context);
  373. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  374. context.get(), validator_options, kConsoleMessageConsumer));
  375. }
  376. {
  377. TransformationMoveInstructionDown transformation(
  378. MakeInstructionDescriptor(21, spv::Op::OpMemoryBarrier, 0));
  379. ASSERT_TRUE(
  380. transformation.IsApplicable(context.get(), transformation_context));
  381. ApplyAndCheckFreshIds(transformation, context.get(),
  382. &transformation_context);
  383. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  384. context.get(), validator_options, kConsoleMessageConsumer));
  385. }
  386. // Swap simple and memory instructions.
  387. {
  388. TransformationMoveInstructionDown transformation(
  389. MakeInstructionDescriptor(41, spv::Op::OpCopyObject, 0));
  390. ASSERT_TRUE(
  391. transformation.IsApplicable(context.get(), transformation_context));
  392. ApplyAndCheckFreshIds(transformation, context.get(),
  393. &transformation_context);
  394. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  395. context.get(), validator_options, kConsoleMessageConsumer));
  396. }
  397. {
  398. TransformationMoveInstructionDown transformation(
  399. MakeInstructionDescriptor(22, spv::Op::OpLoad, 0));
  400. ASSERT_TRUE(
  401. transformation.IsApplicable(context.get(), transformation_context));
  402. ApplyAndCheckFreshIds(transformation, context.get(),
  403. &transformation_context);
  404. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  405. context.get(), validator_options, kConsoleMessageConsumer));
  406. }
  407. // Swap two simple instructions.
  408. {
  409. TransformationMoveInstructionDown transformation(
  410. MakeInstructionDescriptor(23, spv::Op::OpCopyObject, 0));
  411. ASSERT_TRUE(
  412. transformation.IsApplicable(context.get(), transformation_context));
  413. ApplyAndCheckFreshIds(transformation, context.get(),
  414. &transformation_context);
  415. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  416. context.get(), validator_options, kConsoleMessageConsumer));
  417. }
  418. std::string after_transformation = R"(
  419. OpCapability Shader
  420. %1 = OpExtInstImport "GLSL.std.450"
  421. OpMemoryModel Logical GLSL450
  422. OpEntryPoint GLCompute %4 "main"
  423. OpExecutionMode %4 LocalSize 16 1 1
  424. OpSource ESSL 320
  425. %2 = OpTypeVoid
  426. %3 = OpTypeFunction %2
  427. %6 = OpTypeInt 32 0
  428. %7 = OpConstant %6 2
  429. %20 = OpTypePointer Function %6
  430. %4 = OpFunction %2 None %3
  431. %5 = OpLabel
  432. %21 = OpVariable %20 Function %7
  433. ; can swap simple and barrier instructions
  434. %40 = OpCopyObject %6 %7
  435. OpMemoryBarrier %7 %7
  436. ; can swap simple and memory instructions
  437. %41 = OpCopyObject %6 %7
  438. %22 = OpLoad %6 %21
  439. ; can swap two simple instructions
  440. %42 = OpCopyObject %6 %7
  441. %23 = OpCopyObject %6 %7
  442. OpReturn
  443. OpFunctionEnd
  444. %12 = OpFunction %2 None %3
  445. %13 = OpLabel
  446. OpReturn
  447. OpFunctionEnd
  448. )";
  449. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  450. }
  451. TEST(TransformationMoveInstructionDownTest, HandlesMemoryInstructions) {
  452. std::string shader = R"(
  453. OpCapability Shader
  454. %1 = OpExtInstImport "GLSL.std.450"
  455. OpMemoryModel Logical GLSL450
  456. OpEntryPoint GLCompute %4 "main"
  457. OpExecutionMode %4 LocalSize 16 1 1
  458. OpSource ESSL 320
  459. %2 = OpTypeVoid
  460. %3 = OpTypeFunction %2
  461. %6 = OpTypeInt 32 0
  462. %7 = OpConstant %6 2
  463. %20 = OpTypePointer Function %6
  464. %4 = OpFunction %2 None %3
  465. %5 = OpLabel
  466. %21 = OpVariable %20 Function %7
  467. %22 = OpVariable %20 Function %7
  468. ; swap R and R instructions
  469. %23 = OpLoad %6 %21
  470. %24 = OpLoad %6 %22
  471. ; swap R and RW instructions
  472. ; can't swap
  473. %25 = OpLoad %6 %21
  474. OpCopyMemory %21 %22
  475. ; can swap
  476. %26 = OpLoad %6 %21
  477. OpCopyMemory %22 %21
  478. %27 = OpLoad %6 %22
  479. OpCopyMemory %21 %22
  480. %28 = OpLoad %6 %22
  481. OpCopyMemory %22 %21
  482. ; swap R and W instructions
  483. ; can't swap
  484. %29 = OpLoad %6 %21
  485. OpStore %21 %7
  486. ; can swap
  487. %30 = OpLoad %6 %22
  488. OpStore %21 %7
  489. %31 = OpLoad %6 %21
  490. OpStore %22 %7
  491. %32 = OpLoad %6 %22
  492. OpStore %22 %7
  493. ; swap RW and RW instructions
  494. ; can't swap
  495. OpCopyMemory %21 %21
  496. OpCopyMemory %21 %21
  497. OpCopyMemory %21 %22
  498. OpCopyMemory %21 %21
  499. OpCopyMemory %21 %21
  500. OpCopyMemory %21 %22
  501. ; can swap
  502. OpCopyMemory %22 %21
  503. OpCopyMemory %21 %22
  504. OpCopyMemory %22 %21
  505. OpCopyMemory %22 %21
  506. OpCopyMemory %21 %22
  507. OpCopyMemory %21 %22
  508. ; swap RW and W instructions
  509. ; can't swap
  510. OpCopyMemory %21 %21
  511. OpStore %21 %7
  512. OpStore %21 %7
  513. OpCopyMemory %21 %21
  514. ; can swap
  515. OpCopyMemory %22 %21
  516. OpStore %21 %7
  517. OpCopyMemory %21 %22
  518. OpStore %21 %7
  519. OpCopyMemory %21 %21
  520. OpStore %22 %7
  521. ; swap W and W instructions
  522. ; can't swap
  523. OpStore %21 %7
  524. OpStore %21 %7
  525. ; can swap
  526. OpStore %22 %7
  527. OpStore %21 %7
  528. OpStore %22 %7
  529. OpStore %22 %7
  530. OpReturn
  531. OpFunctionEnd
  532. )";
  533. const auto env = SPV_ENV_UNIVERSAL_1_3;
  534. const auto consumer = nullptr;
  535. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  536. spvtools::ValidatorOptions validator_options;
  537. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  538. kConsoleMessageConsumer));
  539. TransformationContext transformation_context(
  540. MakeUnique<FactManager>(context.get()), validator_options);
  541. transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
  542. 22);
  543. // Invalid swaps.
  544. protobufs::InstructionDescriptor invalid_swaps[] = {
  545. // R and RW
  546. MakeInstructionDescriptor(25, spv::Op::OpLoad, 0),
  547. // R and W
  548. MakeInstructionDescriptor(29, spv::Op::OpLoad, 0),
  549. // RW and RW
  550. MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 0),
  551. MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 2),
  552. MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 4),
  553. // RW and W
  554. MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 12),
  555. MakeInstructionDescriptor(32, spv::Op::OpStore, 1),
  556. // W and W
  557. MakeInstructionDescriptor(32, spv::Op::OpStore, 6),
  558. };
  559. for (const auto& descriptor : invalid_swaps) {
  560. ASSERT_FALSE(TransformationMoveInstructionDown(descriptor)
  561. .IsApplicable(context.get(), transformation_context));
  562. }
  563. // Valid swaps.
  564. protobufs::InstructionDescriptor valid_swaps[] = {
  565. // R and R
  566. MakeInstructionDescriptor(23, spv::Op::OpLoad, 0),
  567. MakeInstructionDescriptor(24, spv::Op::OpLoad, 0),
  568. // R and RW
  569. MakeInstructionDescriptor(26, spv::Op::OpLoad, 0),
  570. MakeInstructionDescriptor(25, spv::Op::OpCopyMemory, 1),
  571. MakeInstructionDescriptor(27, spv::Op::OpLoad, 0),
  572. MakeInstructionDescriptor(26, spv::Op::OpCopyMemory, 1),
  573. MakeInstructionDescriptor(28, spv::Op::OpLoad, 0),
  574. MakeInstructionDescriptor(27, spv::Op::OpCopyMemory, 1),
  575. // R and W
  576. MakeInstructionDescriptor(30, spv::Op::OpLoad, 0),
  577. MakeInstructionDescriptor(29, spv::Op::OpStore, 1),
  578. MakeInstructionDescriptor(31, spv::Op::OpLoad, 0),
  579. MakeInstructionDescriptor(30, spv::Op::OpStore, 1),
  580. MakeInstructionDescriptor(32, spv::Op::OpLoad, 0),
  581. MakeInstructionDescriptor(31, spv::Op::OpStore, 1),
  582. // RW and RW
  583. MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 6),
  584. MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 6),
  585. MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 8),
  586. MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 8),
  587. MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 10),
  588. MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 10),
  589. // RW and W
  590. MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 14),
  591. MakeInstructionDescriptor(32, spv::Op::OpStore, 3),
  592. MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 15),
  593. MakeInstructionDescriptor(32, spv::Op::OpStore, 4),
  594. MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 16),
  595. MakeInstructionDescriptor(32, spv::Op::OpStore, 5),
  596. // W and W
  597. MakeInstructionDescriptor(32, spv::Op::OpStore, 8),
  598. MakeInstructionDescriptor(32, spv::Op::OpStore, 8),
  599. MakeInstructionDescriptor(32, spv::Op::OpStore, 10),
  600. MakeInstructionDescriptor(32, spv::Op::OpStore, 10),
  601. };
  602. for (const auto& descriptor : valid_swaps) {
  603. TransformationMoveInstructionDown transformation(descriptor);
  604. ASSERT_TRUE(
  605. transformation.IsApplicable(context.get(), transformation_context));
  606. ApplyAndCheckFreshIds(transformation, context.get(),
  607. &transformation_context);
  608. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  609. context.get(), validator_options, kConsoleMessageConsumer));
  610. }
  611. ASSERT_TRUE(IsEqual(env, shader, context.get()));
  612. }
  613. } // namespace
  614. } // namespace fuzz
  615. } // namespace spvtools