transformation_swap_commutable_operands_test.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. // Copyright (c) 2020 André Perez Maselco
  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_swap_commutable_operands.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(TransformationSwapCommutableOperandsTest, IsApplicableTest) {
  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. OpName %4 "main"
  31. %2 = OpTypeVoid
  32. %3 = OpTypeFunction %2
  33. %6 = OpTypeInt 32 1
  34. %7 = OpTypeInt 32 0
  35. %8 = OpConstant %7 2
  36. %9 = OpTypeArray %6 %8
  37. %10 = OpTypePointer Function %9
  38. %12 = OpConstant %6 1
  39. %13 = OpConstant %6 2
  40. %14 = OpConstantComposite %9 %12 %13
  41. %15 = OpTypePointer Function %6
  42. %17 = OpConstant %6 0
  43. %29 = OpTypeFloat 32
  44. %30 = OpTypeArray %29 %8
  45. %31 = OpTypePointer Function %30
  46. %33 = OpConstant %29 1
  47. %34 = OpConstant %29 2
  48. %35 = OpConstantComposite %30 %33 %34
  49. %36 = OpTypePointer Function %29
  50. %49 = OpTypeVector %29 3
  51. %50 = OpTypeArray %49 %8
  52. %51 = OpTypePointer Function %50
  53. %53 = OpConstant %29 3
  54. %54 = OpConstantComposite %49 %33 %34 %53
  55. %55 = OpConstant %29 4
  56. %56 = OpConstant %29 5
  57. %57 = OpConstant %29 6
  58. %58 = OpConstantComposite %49 %55 %56 %57
  59. %59 = OpConstantComposite %50 %54 %58
  60. %61 = OpTypePointer Function %49
  61. %4 = OpFunction %2 None %3
  62. %5 = OpLabel
  63. %11 = OpVariable %10 Function
  64. %16 = OpVariable %15 Function
  65. %23 = OpVariable %15 Function
  66. %32 = OpVariable %31 Function
  67. %37 = OpVariable %36 Function
  68. %43 = OpVariable %36 Function
  69. %52 = OpVariable %51 Function
  70. %60 = OpVariable %36 Function
  71. OpStore %11 %14
  72. %18 = OpAccessChain %15 %11 %17
  73. %19 = OpLoad %6 %18
  74. %20 = OpAccessChain %15 %11 %12
  75. %21 = OpLoad %6 %20
  76. %22 = OpIAdd %6 %19 %21
  77. OpStore %16 %22
  78. %24 = OpAccessChain %15 %11 %17
  79. %25 = OpLoad %6 %24
  80. %26 = OpAccessChain %15 %11 %12
  81. %27 = OpLoad %6 %26
  82. %28 = OpIMul %6 %25 %27
  83. OpStore %23 %28
  84. OpStore %32 %35
  85. %38 = OpAccessChain %36 %32 %17
  86. %39 = OpLoad %29 %38
  87. %40 = OpAccessChain %36 %32 %12
  88. %41 = OpLoad %29 %40
  89. %42 = OpFAdd %29 %39 %41
  90. OpStore %37 %42
  91. %44 = OpAccessChain %36 %32 %17
  92. %45 = OpLoad %29 %44
  93. %46 = OpAccessChain %36 %32 %12
  94. %47 = OpLoad %29 %46
  95. %48 = OpFMul %29 %45 %47
  96. OpStore %43 %48
  97. OpStore %52 %59
  98. %62 = OpAccessChain %61 %52 %17
  99. %63 = OpLoad %49 %62
  100. %64 = OpAccessChain %61 %52 %12
  101. %65 = OpLoad %49 %64
  102. %66 = OpDot %29 %63 %65
  103. OpStore %60 %66
  104. OpReturn
  105. OpFunctionEnd
  106. )";
  107. const auto env = SPV_ENV_UNIVERSAL_1_5;
  108. const auto consumer = nullptr;
  109. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  110. spvtools::ValidatorOptions validator_options;
  111. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  112. kConsoleMessageConsumer));
  113. TransformationContext transformation_context(
  114. MakeUnique<FactManager>(context.get()), validator_options);
  115. // Tests existing commutative instructions
  116. auto instructionDescriptor =
  117. MakeInstructionDescriptor(22, spv::Op::OpIAdd, 0);
  118. auto transformation =
  119. TransformationSwapCommutableOperands(instructionDescriptor);
  120. ASSERT_TRUE(
  121. transformation.IsApplicable(context.get(), transformation_context));
  122. instructionDescriptor = MakeInstructionDescriptor(28, spv::Op::OpIMul, 0);
  123. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  124. ASSERT_TRUE(
  125. transformation.IsApplicable(context.get(), transformation_context));
  126. instructionDescriptor = MakeInstructionDescriptor(42, spv::Op::OpFAdd, 0);
  127. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  128. ASSERT_TRUE(
  129. transformation.IsApplicable(context.get(), transformation_context));
  130. instructionDescriptor = MakeInstructionDescriptor(48, spv::Op::OpFMul, 0);
  131. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  132. ASSERT_TRUE(
  133. transformation.IsApplicable(context.get(), transformation_context));
  134. instructionDescriptor = MakeInstructionDescriptor(66, spv::Op::OpDot, 0);
  135. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  136. ASSERT_TRUE(
  137. transformation.IsApplicable(context.get(), transformation_context));
  138. // Tests existing non-commutative instructions
  139. instructionDescriptor =
  140. MakeInstructionDescriptor(1, spv::Op::OpExtInstImport, 0);
  141. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  142. ASSERT_FALSE(
  143. transformation.IsApplicable(context.get(), transformation_context));
  144. instructionDescriptor = MakeInstructionDescriptor(5, spv::Op::OpLabel, 0);
  145. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  146. ASSERT_FALSE(
  147. transformation.IsApplicable(context.get(), transformation_context));
  148. instructionDescriptor = MakeInstructionDescriptor(8, spv::Op::OpConstant, 0);
  149. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  150. ASSERT_FALSE(
  151. transformation.IsApplicable(context.get(), transformation_context));
  152. instructionDescriptor = MakeInstructionDescriptor(11, spv::Op::OpVariable, 0);
  153. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  154. ASSERT_FALSE(
  155. transformation.IsApplicable(context.get(), transformation_context));
  156. instructionDescriptor =
  157. MakeInstructionDescriptor(14, spv::Op::OpConstantComposite, 0);
  158. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  159. ASSERT_FALSE(
  160. transformation.IsApplicable(context.get(), transformation_context));
  161. // Tests the base instruction id not existing
  162. instructionDescriptor =
  163. MakeInstructionDescriptor(67, spv::Op::OpIAddCarry, 0);
  164. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  165. ASSERT_FALSE(
  166. transformation.IsApplicable(context.get(), transformation_context));
  167. instructionDescriptor = MakeInstructionDescriptor(68, spv::Op::OpIEqual, 0);
  168. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  169. ASSERT_FALSE(
  170. transformation.IsApplicable(context.get(), transformation_context));
  171. instructionDescriptor =
  172. MakeInstructionDescriptor(69, spv::Op::OpINotEqual, 0);
  173. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  174. ASSERT_FALSE(
  175. transformation.IsApplicable(context.get(), transformation_context));
  176. instructionDescriptor =
  177. MakeInstructionDescriptor(70, spv::Op::OpFOrdEqual, 0);
  178. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  179. ASSERT_FALSE(
  180. transformation.IsApplicable(context.get(), transformation_context));
  181. instructionDescriptor = MakeInstructionDescriptor(71, spv::Op::OpPtrEqual, 0);
  182. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  183. ASSERT_FALSE(
  184. transformation.IsApplicable(context.get(), transformation_context));
  185. // Tests there being no instruction with the desired opcode after the base
  186. // instruction id
  187. instructionDescriptor = MakeInstructionDescriptor(24, spv::Op::OpIAdd, 0);
  188. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  189. ASSERT_FALSE(
  190. transformation.IsApplicable(context.get(), transformation_context));
  191. instructionDescriptor = MakeInstructionDescriptor(38, spv::Op::OpIMul, 0);
  192. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  193. ASSERT_FALSE(
  194. transformation.IsApplicable(context.get(), transformation_context));
  195. instructionDescriptor = MakeInstructionDescriptor(45, spv::Op::OpFAdd, 0);
  196. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  197. ASSERT_FALSE(
  198. transformation.IsApplicable(context.get(), transformation_context));
  199. instructionDescriptor = MakeInstructionDescriptor(66, spv::Op::OpFMul, 0);
  200. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  201. ASSERT_FALSE(
  202. transformation.IsApplicable(context.get(), transformation_context));
  203. // Tests there being an instruction with the desired opcode after the base
  204. // instruction id, but the skip count associated with the instruction
  205. // descriptor being so high.
  206. instructionDescriptor = MakeInstructionDescriptor(11, spv::Op::OpIAdd, 100);
  207. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  208. ASSERT_FALSE(
  209. transformation.IsApplicable(context.get(), transformation_context));
  210. instructionDescriptor = MakeInstructionDescriptor(16, spv::Op::OpIMul, 100);
  211. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  212. ASSERT_FALSE(
  213. transformation.IsApplicable(context.get(), transformation_context));
  214. instructionDescriptor = MakeInstructionDescriptor(23, spv::Op::OpFAdd, 100);
  215. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  216. ASSERT_FALSE(
  217. transformation.IsApplicable(context.get(), transformation_context));
  218. instructionDescriptor = MakeInstructionDescriptor(32, spv::Op::OpFMul, 100);
  219. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  220. ASSERT_FALSE(
  221. transformation.IsApplicable(context.get(), transformation_context));
  222. instructionDescriptor = MakeInstructionDescriptor(37, spv::Op::OpDot, 100);
  223. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  224. ASSERT_FALSE(
  225. transformation.IsApplicable(context.get(), transformation_context));
  226. }
  227. TEST(TransformationSwapCommutableOperandsTest, ApplyTest) {
  228. std::string shader = R"(
  229. OpCapability Shader
  230. %1 = OpExtInstImport "GLSL.std.450"
  231. OpMemoryModel Logical GLSL450
  232. OpEntryPoint Fragment %4 "main"
  233. OpExecutionMode %4 OriginUpperLeft
  234. OpSource ESSL 310
  235. OpName %4 "main"
  236. %2 = OpTypeVoid
  237. %3 = OpTypeFunction %2
  238. %6 = OpTypeInt 32 1
  239. %7 = OpTypeInt 32 0
  240. %8 = OpConstant %7 2
  241. %9 = OpTypeArray %6 %8
  242. %10 = OpTypePointer Function %9
  243. %12 = OpConstant %6 1
  244. %13 = OpConstant %6 2
  245. %14 = OpConstantComposite %9 %12 %13
  246. %15 = OpTypePointer Function %6
  247. %17 = OpConstant %6 0
  248. %29 = OpTypeFloat 32
  249. %30 = OpTypeArray %29 %8
  250. %31 = OpTypePointer Function %30
  251. %33 = OpConstant %29 1
  252. %34 = OpConstant %29 2
  253. %35 = OpConstantComposite %30 %33 %34
  254. %36 = OpTypePointer Function %29
  255. %49 = OpTypeVector %29 3
  256. %50 = OpTypeArray %49 %8
  257. %51 = OpTypePointer Function %50
  258. %53 = OpConstant %29 3
  259. %54 = OpConstantComposite %49 %33 %34 %53
  260. %55 = OpConstant %29 4
  261. %56 = OpConstant %29 5
  262. %57 = OpConstant %29 6
  263. %58 = OpConstantComposite %49 %55 %56 %57
  264. %59 = OpConstantComposite %50 %54 %58
  265. %61 = OpTypePointer Function %49
  266. %4 = OpFunction %2 None %3
  267. %5 = OpLabel
  268. %11 = OpVariable %10 Function
  269. %16 = OpVariable %15 Function
  270. %23 = OpVariable %15 Function
  271. %32 = OpVariable %31 Function
  272. %37 = OpVariable %36 Function
  273. %43 = OpVariable %36 Function
  274. %52 = OpVariable %51 Function
  275. %60 = OpVariable %36 Function
  276. OpStore %11 %14
  277. %18 = OpAccessChain %15 %11 %17
  278. %19 = OpLoad %6 %18
  279. %20 = OpAccessChain %15 %11 %12
  280. %21 = OpLoad %6 %20
  281. %22 = OpIAdd %6 %19 %21
  282. OpStore %16 %22
  283. %24 = OpAccessChain %15 %11 %17
  284. %25 = OpLoad %6 %24
  285. %26 = OpAccessChain %15 %11 %12
  286. %27 = OpLoad %6 %26
  287. %28 = OpIMul %6 %25 %27
  288. OpStore %23 %28
  289. OpStore %32 %35
  290. %38 = OpAccessChain %36 %32 %17
  291. %39 = OpLoad %29 %38
  292. %40 = OpAccessChain %36 %32 %12
  293. %41 = OpLoad %29 %40
  294. %42 = OpFAdd %29 %39 %41
  295. OpStore %37 %42
  296. %44 = OpAccessChain %36 %32 %17
  297. %45 = OpLoad %29 %44
  298. %46 = OpAccessChain %36 %32 %12
  299. %47 = OpLoad %29 %46
  300. %48 = OpFMul %29 %45 %47
  301. OpStore %43 %48
  302. OpStore %52 %59
  303. %62 = OpAccessChain %61 %52 %17
  304. %63 = OpLoad %49 %62
  305. %64 = OpAccessChain %61 %52 %12
  306. %65 = OpLoad %49 %64
  307. %66 = OpDot %29 %63 %65
  308. OpStore %60 %66
  309. OpReturn
  310. OpFunctionEnd
  311. )";
  312. const auto env = SPV_ENV_UNIVERSAL_1_5;
  313. const auto consumer = nullptr;
  314. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  315. spvtools::ValidatorOptions validator_options;
  316. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  317. kConsoleMessageConsumer));
  318. TransformationContext transformation_context(
  319. MakeUnique<FactManager>(context.get()), validator_options);
  320. auto instructionDescriptor =
  321. MakeInstructionDescriptor(22, spv::Op::OpIAdd, 0);
  322. auto transformation =
  323. TransformationSwapCommutableOperands(instructionDescriptor);
  324. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  325. instructionDescriptor = MakeInstructionDescriptor(28, spv::Op::OpIMul, 0);
  326. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  327. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  328. instructionDescriptor = MakeInstructionDescriptor(42, spv::Op::OpFAdd, 0);
  329. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  330. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  331. instructionDescriptor = MakeInstructionDescriptor(48, spv::Op::OpFMul, 0);
  332. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  333. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  334. instructionDescriptor = MakeInstructionDescriptor(66, spv::Op::OpDot, 0);
  335. transformation = TransformationSwapCommutableOperands(instructionDescriptor);
  336. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  337. std::string variantShader = R"(
  338. OpCapability Shader
  339. %1 = OpExtInstImport "GLSL.std.450"
  340. OpMemoryModel Logical GLSL450
  341. OpEntryPoint Fragment %4 "main"
  342. OpExecutionMode %4 OriginUpperLeft
  343. OpSource ESSL 310
  344. OpName %4 "main"
  345. %2 = OpTypeVoid
  346. %3 = OpTypeFunction %2
  347. %6 = OpTypeInt 32 1
  348. %7 = OpTypeInt 32 0
  349. %8 = OpConstant %7 2
  350. %9 = OpTypeArray %6 %8
  351. %10 = OpTypePointer Function %9
  352. %12 = OpConstant %6 1
  353. %13 = OpConstant %6 2
  354. %14 = OpConstantComposite %9 %12 %13
  355. %15 = OpTypePointer Function %6
  356. %17 = OpConstant %6 0
  357. %29 = OpTypeFloat 32
  358. %30 = OpTypeArray %29 %8
  359. %31 = OpTypePointer Function %30
  360. %33 = OpConstant %29 1
  361. %34 = OpConstant %29 2
  362. %35 = OpConstantComposite %30 %33 %34
  363. %36 = OpTypePointer Function %29
  364. %49 = OpTypeVector %29 3
  365. %50 = OpTypeArray %49 %8
  366. %51 = OpTypePointer Function %50
  367. %53 = OpConstant %29 3
  368. %54 = OpConstantComposite %49 %33 %34 %53
  369. %55 = OpConstant %29 4
  370. %56 = OpConstant %29 5
  371. %57 = OpConstant %29 6
  372. %58 = OpConstantComposite %49 %55 %56 %57
  373. %59 = OpConstantComposite %50 %54 %58
  374. %61 = OpTypePointer Function %49
  375. %4 = OpFunction %2 None %3
  376. %5 = OpLabel
  377. %11 = OpVariable %10 Function
  378. %16 = OpVariable %15 Function
  379. %23 = OpVariable %15 Function
  380. %32 = OpVariable %31 Function
  381. %37 = OpVariable %36 Function
  382. %43 = OpVariable %36 Function
  383. %52 = OpVariable %51 Function
  384. %60 = OpVariable %36 Function
  385. OpStore %11 %14
  386. %18 = OpAccessChain %15 %11 %17
  387. %19 = OpLoad %6 %18
  388. %20 = OpAccessChain %15 %11 %12
  389. %21 = OpLoad %6 %20
  390. %22 = OpIAdd %6 %21 %19
  391. OpStore %16 %22
  392. %24 = OpAccessChain %15 %11 %17
  393. %25 = OpLoad %6 %24
  394. %26 = OpAccessChain %15 %11 %12
  395. %27 = OpLoad %6 %26
  396. %28 = OpIMul %6 %27 %25
  397. OpStore %23 %28
  398. OpStore %32 %35
  399. %38 = OpAccessChain %36 %32 %17
  400. %39 = OpLoad %29 %38
  401. %40 = OpAccessChain %36 %32 %12
  402. %41 = OpLoad %29 %40
  403. %42 = OpFAdd %29 %41 %39
  404. OpStore %37 %42
  405. %44 = OpAccessChain %36 %32 %17
  406. %45 = OpLoad %29 %44
  407. %46 = OpAccessChain %36 %32 %12
  408. %47 = OpLoad %29 %46
  409. %48 = OpFMul %29 %47 %45
  410. OpStore %43 %48
  411. OpStore %52 %59
  412. %62 = OpAccessChain %61 %52 %17
  413. %63 = OpLoad %49 %62
  414. %64 = OpAccessChain %61 %52 %12
  415. %65 = OpLoad %49 %64
  416. %66 = OpDot %29 %65 %63
  417. OpStore %60 %66
  418. OpReturn
  419. OpFunctionEnd
  420. )";
  421. ASSERT_TRUE(IsEqual(env, variantShader, context.get()));
  422. }
  423. } // namespace
  424. } // namespace fuzz
  425. } // namespace spvtools