transformation_inline_function_test.cpp 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116
  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_inline_function.h"
  15. #include "gtest/gtest.h"
  16. #include "source/fuzz/counter_overflow_id_source.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(TransformationInlineFunctionTest, IsApplicable) {
  24. std::string shader = R"(
  25. OpCapability Shader
  26. %1 = OpExtInstImport "GLSL.std.450"
  27. OpMemoryModel Logical GLSL450
  28. OpEntryPoint Fragment %52 "main"
  29. OpExecutionMode %52 OriginUpperLeft
  30. OpName %56 "function_with_void_return"
  31. ; Types
  32. %2 = OpTypeBool
  33. %3 = OpTypeFloat 32
  34. %4 = OpTypeVector %3 4
  35. %5 = OpTypePointer Function %4
  36. %6 = OpTypeVoid
  37. %7 = OpTypeFunction %6
  38. %8 = OpTypeFunction %3 %5 %5
  39. ; Constant scalars
  40. %9 = OpConstant %3 1
  41. %10 = OpConstant %3 2
  42. %11 = OpConstant %3 3
  43. %12 = OpConstant %3 4
  44. %13 = OpConstant %3 5
  45. %14 = OpConstant %3 6
  46. %15 = OpConstant %3 7
  47. %16 = OpConstant %3 8
  48. %17 = OpConstantTrue %2
  49. ; Constant vectors
  50. %18 = OpConstantComposite %4 %9 %10 %11 %12
  51. %19 = OpConstantComposite %4 %13 %14 %15 %16
  52. ; function with void return
  53. %20 = OpFunction %6 None %7
  54. %21 = OpLabel
  55. OpReturn
  56. OpFunctionEnd
  57. ; function with early return
  58. %22 = OpFunction %6 None %7
  59. %23 = OpLabel
  60. OpSelectionMerge %26 None
  61. OpBranchConditional %17 %24 %25
  62. %24 = OpLabel
  63. OpReturn
  64. %25 = OpLabel
  65. OpBranch %26
  66. %26 = OpLabel
  67. OpReturn
  68. OpFunctionEnd
  69. ; function containing an OpKill instruction
  70. %27 = OpFunction %6 None %7
  71. %28 = OpLabel
  72. OpKill
  73. OpFunctionEnd
  74. ; function containing an OpUnreachable instruction
  75. %29 = OpFunction %6 None %7
  76. %30 = OpLabel
  77. OpUnreachable
  78. OpFunctionEnd
  79. ; dot product function
  80. %31 = OpFunction %3 None %8
  81. %32 = OpFunctionParameter %5
  82. %33 = OpFunctionParameter %5
  83. %34 = OpLabel
  84. %35 = OpLoad %4 %32
  85. %36 = OpLoad %4 %33
  86. %37 = OpCompositeExtract %3 %35 0
  87. %38 = OpCompositeExtract %3 %36 0
  88. %39 = OpFMul %3 %37 %38
  89. %40 = OpCompositeExtract %3 %35 1
  90. %41 = OpCompositeExtract %3 %36 1
  91. %42 = OpFMul %3 %40 %41
  92. %43 = OpCompositeExtract %3 %35 2
  93. %44 = OpCompositeExtract %3 %36 2
  94. %45 = OpFMul %3 %43 %44
  95. %46 = OpCompositeExtract %3 %35 3
  96. %47 = OpCompositeExtract %3 %36 3
  97. %48 = OpFMul %3 %46 %47
  98. %49 = OpFAdd %3 %39 %42
  99. %50 = OpFAdd %3 %45 %49
  100. %51 = OpFAdd %3 %48 %50
  101. OpReturnValue %51
  102. OpFunctionEnd
  103. ; main function
  104. %52 = OpFunction %6 None %7
  105. %53 = OpLabel
  106. %54 = OpVariable %5 Function
  107. %55 = OpVariable %5 Function
  108. %56 = OpFunctionCall %6 %20 ; function with void return
  109. OpBranch %57
  110. %57 = OpLabel
  111. %59 = OpFunctionCall %6 %22 ; function with early return
  112. OpBranch %60
  113. %60 = OpLabel
  114. %61 = OpFunctionCall %6 %27 ; function containing OpKill
  115. OpBranch %62
  116. %62 = OpLabel
  117. %63 = OpFunctionCall %6 %29 ; function containing OpUnreachable
  118. OpBranch %64
  119. %64 = OpLabel
  120. OpStore %54 %18
  121. OpStore %55 %19
  122. %65 = OpFunctionCall %3 %31 %54 %55 ; dot product function
  123. OpBranch %66
  124. %66 = OpLabel
  125. OpReturn
  126. OpFunctionEnd
  127. )";
  128. const auto env = SPV_ENV_UNIVERSAL_1_5;
  129. const auto consumer = nullptr;
  130. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  131. spvtools::ValidatorOptions validator_options;
  132. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  133. kConsoleMessageConsumer));
  134. TransformationContext transformation_context(
  135. MakeUnique<FactManager>(context.get()), validator_options);
  136. // Tests undefined OpFunctionCall instruction.
  137. auto transformation = TransformationInlineFunction(67, {});
  138. ASSERT_FALSE(
  139. transformation.IsApplicable(context.get(), transformation_context));
  140. // Tests false OpFunctionCall instruction.
  141. transformation = TransformationInlineFunction(42, {});
  142. ASSERT_FALSE(
  143. transformation.IsApplicable(context.get(), transformation_context));
  144. // Tests use of called function with void return.
  145. transformation = TransformationInlineFunction(56, {});
  146. ASSERT_FALSE(
  147. transformation.IsApplicable(context.get(), transformation_context));
  148. // Tests called function having an early return.
  149. transformation =
  150. TransformationInlineFunction(59, {{24, 67}, {25, 68}, {26, 69}});
  151. ASSERT_FALSE(
  152. transformation.IsApplicable(context.get(), transformation_context));
  153. // Tests called function containing an OpKill instruction.
  154. transformation = TransformationInlineFunction(61, {});
  155. ASSERT_FALSE(
  156. transformation.IsApplicable(context.get(), transformation_context));
  157. // Tests called function containing an OpUnreachable instruction.
  158. transformation = TransformationInlineFunction(63, {});
  159. ASSERT_FALSE(
  160. transformation.IsApplicable(context.get(), transformation_context));
  161. // Tests applicable transformation.
  162. transformation = TransformationInlineFunction(65, {{35, 67},
  163. {36, 68},
  164. {37, 69},
  165. {38, 70},
  166. {39, 71},
  167. {40, 72},
  168. {41, 73},
  169. {42, 74},
  170. {43, 75},
  171. {44, 76},
  172. {45, 77},
  173. {46, 78},
  174. {47, 79},
  175. {48, 80},
  176. {49, 81},
  177. {50, 82},
  178. {51, 83}});
  179. ASSERT_TRUE(
  180. transformation.IsApplicable(context.get(), transformation_context));
  181. }
  182. TEST(TransformationInlineFunctionTest, Apply) {
  183. std::string reference_shader = R"(
  184. OpCapability Shader
  185. %1 = OpExtInstImport "GLSL.std.450"
  186. OpMemoryModel Logical GLSL450
  187. OpEntryPoint Vertex %39 "main"
  188. ; Types
  189. %2 = OpTypeFloat 32
  190. %3 = OpTypeVector %2 4
  191. %4 = OpTypePointer Function %3
  192. %5 = OpTypeVoid
  193. %6 = OpTypeFunction %5
  194. %7 = OpTypeFunction %2 %4 %4
  195. ; Constant scalars
  196. %8 = OpConstant %2 1
  197. %9 = OpConstant %2 2
  198. %10 = OpConstant %2 3
  199. %11 = OpConstant %2 4
  200. %12 = OpConstant %2 5
  201. %13 = OpConstant %2 6
  202. %14 = OpConstant %2 7
  203. %15 = OpConstant %2 8
  204. ; Constant vectors
  205. %16 = OpConstantComposite %3 %8 %9 %10 %11
  206. %17 = OpConstantComposite %3 %12 %13 %14 %15
  207. ; dot product function
  208. %18 = OpFunction %2 None %7
  209. %19 = OpFunctionParameter %4
  210. %20 = OpFunctionParameter %4
  211. %21 = OpLabel
  212. %22 = OpLoad %3 %19
  213. %23 = OpLoad %3 %20
  214. %24 = OpCompositeExtract %2 %22 0
  215. %25 = OpCompositeExtract %2 %23 0
  216. %26 = OpFMul %2 %24 %25
  217. %27 = OpCompositeExtract %2 %22 1
  218. %28 = OpCompositeExtract %2 %23 1
  219. %29 = OpFMul %2 %27 %28
  220. %30 = OpCompositeExtract %2 %22 2
  221. %31 = OpCompositeExtract %2 %23 2
  222. %32 = OpFMul %2 %30 %31
  223. %33 = OpCompositeExtract %2 %22 3
  224. %34 = OpCompositeExtract %2 %23 3
  225. %35 = OpFMul %2 %33 %34
  226. %36 = OpFAdd %2 %26 %29
  227. %37 = OpFAdd %2 %32 %36
  228. %38 = OpFAdd %2 %35 %37
  229. OpReturnValue %38
  230. OpFunctionEnd
  231. ; main function
  232. %39 = OpFunction %5 None %6
  233. %40 = OpLabel
  234. %41 = OpVariable %4 Function
  235. %42 = OpVariable %4 Function
  236. OpStore %41 %16
  237. OpStore %42 %17
  238. %43 = OpFunctionCall %2 %18 %41 %42 ; dot product function call
  239. OpBranch %44
  240. %44 = OpLabel
  241. OpReturn
  242. OpFunctionEnd
  243. )";
  244. const auto env = SPV_ENV_UNIVERSAL_1_5;
  245. const auto consumer = nullptr;
  246. const auto context =
  247. BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
  248. spvtools::ValidatorOptions validator_options;
  249. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  250. kConsoleMessageConsumer));
  251. TransformationContext transformation_context(
  252. MakeUnique<FactManager>(context.get()), validator_options);
  253. auto transformation = TransformationInlineFunction(43, {{22, 45},
  254. {23, 46},
  255. {24, 47},
  256. {25, 48},
  257. {26, 49},
  258. {27, 50},
  259. {28, 51},
  260. {29, 52},
  261. {30, 53},
  262. {31, 54},
  263. {32, 55},
  264. {33, 56},
  265. {34, 57},
  266. {35, 58},
  267. {36, 59},
  268. {37, 60},
  269. {38, 61}});
  270. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  271. std::string variant_shader = R"(
  272. OpCapability Shader
  273. %1 = OpExtInstImport "GLSL.std.450"
  274. OpMemoryModel Logical GLSL450
  275. OpEntryPoint Vertex %39 "main"
  276. ; Types
  277. %2 = OpTypeFloat 32
  278. %3 = OpTypeVector %2 4
  279. %4 = OpTypePointer Function %3
  280. %5 = OpTypeVoid
  281. %6 = OpTypeFunction %5
  282. %7 = OpTypeFunction %2 %4 %4
  283. ; Constant scalars
  284. %8 = OpConstant %2 1
  285. %9 = OpConstant %2 2
  286. %10 = OpConstant %2 3
  287. %11 = OpConstant %2 4
  288. %12 = OpConstant %2 5
  289. %13 = OpConstant %2 6
  290. %14 = OpConstant %2 7
  291. %15 = OpConstant %2 8
  292. ; Constant vectors
  293. %16 = OpConstantComposite %3 %8 %9 %10 %11
  294. %17 = OpConstantComposite %3 %12 %13 %14 %15
  295. ; dot product function
  296. %18 = OpFunction %2 None %7
  297. %19 = OpFunctionParameter %4
  298. %20 = OpFunctionParameter %4
  299. %21 = OpLabel
  300. %22 = OpLoad %3 %19
  301. %23 = OpLoad %3 %20
  302. %24 = OpCompositeExtract %2 %22 0
  303. %25 = OpCompositeExtract %2 %23 0
  304. %26 = OpFMul %2 %24 %25
  305. %27 = OpCompositeExtract %2 %22 1
  306. %28 = OpCompositeExtract %2 %23 1
  307. %29 = OpFMul %2 %27 %28
  308. %30 = OpCompositeExtract %2 %22 2
  309. %31 = OpCompositeExtract %2 %23 2
  310. %32 = OpFMul %2 %30 %31
  311. %33 = OpCompositeExtract %2 %22 3
  312. %34 = OpCompositeExtract %2 %23 3
  313. %35 = OpFMul %2 %33 %34
  314. %36 = OpFAdd %2 %26 %29
  315. %37 = OpFAdd %2 %32 %36
  316. %38 = OpFAdd %2 %35 %37
  317. OpReturnValue %38
  318. OpFunctionEnd
  319. ; main function
  320. %39 = OpFunction %5 None %6
  321. %40 = OpLabel
  322. %41 = OpVariable %4 Function
  323. %42 = OpVariable %4 Function
  324. OpStore %41 %16
  325. OpStore %42 %17
  326. %45 = OpLoad %3 %41
  327. %46 = OpLoad %3 %42
  328. %47 = OpCompositeExtract %2 %45 0
  329. %48 = OpCompositeExtract %2 %46 0
  330. %49 = OpFMul %2 %47 %48
  331. %50 = OpCompositeExtract %2 %45 1
  332. %51 = OpCompositeExtract %2 %46 1
  333. %52 = OpFMul %2 %50 %51
  334. %53 = OpCompositeExtract %2 %45 2
  335. %54 = OpCompositeExtract %2 %46 2
  336. %55 = OpFMul %2 %53 %54
  337. %56 = OpCompositeExtract %2 %45 3
  338. %57 = OpCompositeExtract %2 %46 3
  339. %58 = OpFMul %2 %56 %57
  340. %59 = OpFAdd %2 %49 %52
  341. %60 = OpFAdd %2 %55 %59
  342. %61 = OpFAdd %2 %58 %60
  343. %43 = OpCopyObject %2 %61
  344. OpBranch %44
  345. %44 = OpLabel
  346. OpReturn
  347. OpFunctionEnd
  348. )";
  349. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  350. kConsoleMessageConsumer));
  351. ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
  352. }
  353. TEST(TransformationInlineFunctionTest, ApplyToMultipleFunctions) {
  354. std::string reference_shader = R"(
  355. OpCapability Shader
  356. %1 = OpExtInstImport "GLSL.std.450"
  357. OpMemoryModel Logical GLSL450
  358. OpEntryPoint Vertex %15 "main"
  359. ; Types
  360. %2 = OpTypeInt 32 1
  361. %3 = OpTypeBool
  362. %4 = OpTypePointer Private %2
  363. %5 = OpTypePointer Function %2
  364. %6 = OpTypeVoid
  365. %7 = OpTypeFunction %6
  366. %8 = OpTypeFunction %2 %5
  367. %9 = OpTypeFunction %2 %2
  368. ; Constants
  369. %10 = OpConstant %2 0
  370. %11 = OpConstant %2 1
  371. %12 = OpConstant %2 2
  372. %13 = OpConstant %2 3
  373. ; Global variable
  374. %14 = OpVariable %4 Private
  375. ; main function
  376. %15 = OpFunction %6 None %7
  377. %16 = OpLabel
  378. %17 = OpVariable %5 Function
  379. %18 = OpVariable %5 Function
  380. %19 = OpVariable %5 Function
  381. OpStore %17 %13
  382. %20 = OpLoad %2 %17
  383. OpStore %18 %20
  384. %21 = OpFunctionCall %2 %36 %18
  385. OpBranch %22
  386. %22 = OpLabel
  387. %23 = OpFunctionCall %2 %36 %18
  388. OpStore %17 %21
  389. %24 = OpLoad %2 %17
  390. %25 = OpFunctionCall %2 %54 %24
  391. OpBranch %26
  392. %26 = OpLabel
  393. %27 = OpFunctionCall %2 %54 %24
  394. %28 = OpLoad %2 %17
  395. %29 = OpIAdd %2 %28 %25
  396. OpStore %17 %29
  397. %30 = OpFunctionCall %6 %67
  398. OpBranch %31
  399. %31 = OpLabel
  400. %32 = OpFunctionCall %6 %67
  401. %33 = OpLoad %2 %14
  402. %34 = OpLoad %2 %17
  403. %35 = OpIAdd %2 %34 %33
  404. OpStore %17 %35
  405. OpReturn
  406. OpFunctionEnd
  407. ; Function %36
  408. %36 = OpFunction %2 None %8
  409. %37 = OpFunctionParameter %5
  410. %38 = OpLabel
  411. %39 = OpVariable %5 Function
  412. %40 = OpVariable %5 Function
  413. OpStore %39 %10
  414. OpBranch %41
  415. %41 = OpLabel
  416. OpLoopMerge %52 %49 None
  417. OpBranch %42
  418. %42 = OpLabel
  419. %43 = OpLoad %2 %39
  420. %44 = OpLoad %2 %37
  421. %45 = OpSLessThan %3 %43 %44
  422. OpBranchConditional %45 %46 %52
  423. %46 = OpLabel
  424. %47 = OpLoad %2 %40
  425. %48 = OpIAdd %2 %47 %11
  426. OpStore %40 %48
  427. OpBranch %49
  428. %49 = OpLabel
  429. %50 = OpLoad %2 %39
  430. %51 = OpIAdd %2 %50 %12
  431. OpStore %39 %51
  432. OpBranch %41
  433. %52 = OpLabel
  434. %53 = OpLoad %2 %40
  435. OpReturnValue %53
  436. OpFunctionEnd
  437. ; Function %54
  438. %54 = OpFunction %2 None %9
  439. %55 = OpFunctionParameter %2
  440. %56 = OpLabel
  441. %57 = OpVariable %5 Function
  442. OpStore %57 %10
  443. %58 = OpSGreaterThan %3 %55 %10
  444. OpSelectionMerge %62 None
  445. OpBranchConditional %58 %64 %59
  446. %59 = OpLabel
  447. %60 = OpLoad %2 %57
  448. %61 = OpISub %2 %60 %12
  449. OpStore %57 %61
  450. OpBranch %62
  451. %62 = OpLabel
  452. %63 = OpLoad %2 %57
  453. OpReturnValue %63
  454. %64 = OpLabel
  455. %65 = OpLoad %2 %57
  456. %66 = OpIAdd %2 %65 %11
  457. OpStore %57 %66
  458. OpBranch %62
  459. OpFunctionEnd
  460. ; Function %67
  461. %67 = OpFunction %6 None %7
  462. %68 = OpLabel
  463. OpStore %14 %12
  464. OpReturn
  465. OpFunctionEnd
  466. )";
  467. const auto env = SPV_ENV_UNIVERSAL_1_3;
  468. const auto consumer = nullptr;
  469. const auto context =
  470. BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
  471. spvtools::ValidatorOptions validator_options;
  472. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  473. kConsoleMessageConsumer));
  474. TransformationContext transformation_context(
  475. MakeUnique<FactManager>(context.get()), validator_options);
  476. auto transformation = TransformationInlineFunction(30, {});
  477. ASSERT_TRUE(
  478. transformation.IsApplicable(context.get(), transformation_context));
  479. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  480. // Tests a parameter included in the id map.
  481. transformation = TransformationInlineFunction(25, {{55, 69},
  482. {56, 70},
  483. {57, 71},
  484. {58, 72},
  485. {59, 73},
  486. {60, 74},
  487. {61, 75},
  488. {62, 76},
  489. {63, 77},
  490. {64, 78},
  491. {65, 79},
  492. {66, 80}});
  493. ASSERT_FALSE(
  494. transformation.IsApplicable(context.get(), transformation_context));
  495. #ifndef NDEBUG
  496. // Tests the id of the returned value not included in the id map.
  497. transformation = TransformationInlineFunction(25, {{56, 69},
  498. {57, 70},
  499. {58, 71},
  500. {59, 72},
  501. {60, 73},
  502. {61, 74},
  503. {62, 75},
  504. {64, 76},
  505. {65, 77},
  506. {66, 78}});
  507. ASSERT_DEATH(
  508. transformation.IsApplicable(context.get(), transformation_context),
  509. "Bad attempt to query whether overflow ids are available.");
  510. #endif
  511. transformation = TransformationInlineFunction(25, {{57, 69},
  512. {58, 70},
  513. {59, 71},
  514. {60, 72},
  515. {61, 73},
  516. {62, 74},
  517. {63, 75},
  518. {64, 76},
  519. {65, 77},
  520. {66, 78}});
  521. ASSERT_TRUE(
  522. transformation.IsApplicable(context.get(), transformation_context));
  523. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  524. transformation = TransformationInlineFunction(21, {{39, 79},
  525. {40, 80},
  526. {41, 81},
  527. {42, 82},
  528. {43, 83},
  529. {44, 84},
  530. {45, 85},
  531. {46, 86},
  532. {47, 87},
  533. {48, 88},
  534. {49, 89},
  535. {50, 90},
  536. {51, 91},
  537. {52, 92},
  538. {53, 93}});
  539. ASSERT_TRUE(
  540. transformation.IsApplicable(context.get(), transformation_context));
  541. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  542. std::string variant_shader = R"(
  543. OpCapability Shader
  544. %1 = OpExtInstImport "GLSL.std.450"
  545. OpMemoryModel Logical GLSL450
  546. OpEntryPoint Vertex %15 "main"
  547. ; Types
  548. %2 = OpTypeInt 32 1
  549. %3 = OpTypeBool
  550. %4 = OpTypePointer Private %2
  551. %5 = OpTypePointer Function %2
  552. %6 = OpTypeVoid
  553. %7 = OpTypeFunction %6
  554. %8 = OpTypeFunction %2 %5
  555. %9 = OpTypeFunction %2 %2
  556. ; Constants
  557. %10 = OpConstant %2 0
  558. %11 = OpConstant %2 1
  559. %12 = OpConstant %2 2
  560. %13 = OpConstant %2 3
  561. ; Global variable
  562. %14 = OpVariable %4 Private
  563. ; main function
  564. %15 = OpFunction %6 None %7
  565. %16 = OpLabel
  566. %80 = OpVariable %5 Function
  567. %79 = OpVariable %5 Function
  568. %69 = OpVariable %5 Function
  569. %17 = OpVariable %5 Function
  570. %18 = OpVariable %5 Function
  571. %19 = OpVariable %5 Function
  572. OpStore %17 %13
  573. %20 = OpLoad %2 %17
  574. OpStore %18 %20
  575. OpStore %79 %10
  576. OpBranch %81
  577. %81 = OpLabel
  578. OpLoopMerge %92 %89 None
  579. OpBranch %82
  580. %82 = OpLabel
  581. %83 = OpLoad %2 %79
  582. %84 = OpLoad %2 %18
  583. %85 = OpSLessThan %3 %83 %84
  584. OpBranchConditional %85 %86 %92
  585. %86 = OpLabel
  586. %87 = OpLoad %2 %80
  587. %88 = OpIAdd %2 %87 %11
  588. OpStore %80 %88
  589. OpBranch %89
  590. %89 = OpLabel
  591. %90 = OpLoad %2 %79
  592. %91 = OpIAdd %2 %90 %12
  593. OpStore %79 %91
  594. OpBranch %81
  595. %92 = OpLabel
  596. %93 = OpLoad %2 %80
  597. %21 = OpCopyObject %2 %93
  598. OpBranch %22
  599. %22 = OpLabel
  600. %23 = OpFunctionCall %2 %36 %18
  601. OpStore %17 %21
  602. %24 = OpLoad %2 %17
  603. OpStore %69 %10
  604. %70 = OpSGreaterThan %3 %24 %10
  605. OpSelectionMerge %74 None
  606. OpBranchConditional %70 %76 %71
  607. %71 = OpLabel
  608. %72 = OpLoad %2 %69
  609. %73 = OpISub %2 %72 %12
  610. OpStore %69 %73
  611. OpBranch %74
  612. %74 = OpLabel
  613. %75 = OpLoad %2 %69
  614. %25 = OpCopyObject %2 %75
  615. OpBranch %26
  616. %76 = OpLabel
  617. %77 = OpLoad %2 %69
  618. %78 = OpIAdd %2 %77 %11
  619. OpStore %69 %78
  620. OpBranch %74
  621. %26 = OpLabel
  622. %27 = OpFunctionCall %2 %54 %24
  623. %28 = OpLoad %2 %17
  624. %29 = OpIAdd %2 %28 %25
  625. OpStore %17 %29
  626. OpStore %14 %12
  627. OpBranch %31
  628. %31 = OpLabel
  629. %32 = OpFunctionCall %6 %67
  630. %33 = OpLoad %2 %14
  631. %34 = OpLoad %2 %17
  632. %35 = OpIAdd %2 %34 %33
  633. OpStore %17 %35
  634. OpReturn
  635. OpFunctionEnd
  636. ; Function %36
  637. %36 = OpFunction %2 None %8
  638. %37 = OpFunctionParameter %5
  639. %38 = OpLabel
  640. %39 = OpVariable %5 Function
  641. %40 = OpVariable %5 Function
  642. OpStore %39 %10
  643. OpBranch %41
  644. %41 = OpLabel
  645. OpLoopMerge %52 %49 None
  646. OpBranch %42
  647. %42 = OpLabel
  648. %43 = OpLoad %2 %39
  649. %44 = OpLoad %2 %37
  650. %45 = OpSLessThan %3 %43 %44
  651. OpBranchConditional %45 %46 %52
  652. %46 = OpLabel
  653. %47 = OpLoad %2 %40
  654. %48 = OpIAdd %2 %47 %11
  655. OpStore %40 %48
  656. OpBranch %49
  657. %49 = OpLabel
  658. %50 = OpLoad %2 %39
  659. %51 = OpIAdd %2 %50 %12
  660. OpStore %39 %51
  661. OpBranch %41
  662. %52 = OpLabel
  663. %53 = OpLoad %2 %40
  664. OpReturnValue %53
  665. OpFunctionEnd
  666. ; Function %54
  667. %54 = OpFunction %2 None %9
  668. %55 = OpFunctionParameter %2
  669. %56 = OpLabel
  670. %57 = OpVariable %5 Function
  671. OpStore %57 %10
  672. %58 = OpSGreaterThan %3 %55 %10
  673. OpSelectionMerge %62 None
  674. OpBranchConditional %58 %64 %59
  675. %59 = OpLabel
  676. %60 = OpLoad %2 %57
  677. %61 = OpISub %2 %60 %12
  678. OpStore %57 %61
  679. OpBranch %62
  680. %62 = OpLabel
  681. %63 = OpLoad %2 %57
  682. OpReturnValue %63
  683. %64 = OpLabel
  684. %65 = OpLoad %2 %57
  685. %66 = OpIAdd %2 %65 %11
  686. OpStore %57 %66
  687. OpBranch %62
  688. OpFunctionEnd
  689. ; Function %67
  690. %67 = OpFunction %6 None %7
  691. %68 = OpLabel
  692. OpStore %14 %12
  693. OpReturn
  694. OpFunctionEnd
  695. )";
  696. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  697. kConsoleMessageConsumer));
  698. ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
  699. }
  700. TEST(TransformationInlineFunctionTest, HandlesOpPhisInTheSecondBlock) {
  701. std::string shader = R"(
  702. OpCapability Shader
  703. %1 = OpExtInstImport "GLSL.std.450"
  704. OpMemoryModel Logical GLSL450
  705. OpEntryPoint Fragment %4 "main"
  706. OpExecutionMode %4 OriginUpperLeft
  707. %2 = OpTypeVoid
  708. %3 = OpTypeFunction %2
  709. %10 = OpTypeInt 32 0
  710. %11 = OpUndef %10
  711. %4 = OpFunction %2 None %3
  712. %5 = OpLabel
  713. %6 = OpFunctionCall %2 %7
  714. OpBranch %14
  715. %14 = OpLabel
  716. OpReturn
  717. OpFunctionEnd
  718. %7 = OpFunction %2 None %3
  719. %8 = OpLabel
  720. OpBranch %13
  721. %13 = OpLabel
  722. %12 = OpPhi %10 %11 %8
  723. OpReturn
  724. OpFunctionEnd
  725. )";
  726. const auto env = SPV_ENV_UNIVERSAL_1_3;
  727. const auto consumer = nullptr;
  728. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  729. spvtools::ValidatorOptions validator_options;
  730. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  731. kConsoleMessageConsumer));
  732. TransformationContext transformation_context(
  733. MakeUnique<FactManager>(context.get()), validator_options);
  734. TransformationInlineFunction transformation(6,
  735. {{{8, 20}, {13, 21}, {12, 22}}});
  736. ASSERT_TRUE(
  737. transformation.IsApplicable(context.get(), transformation_context));
  738. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  739. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  740. kConsoleMessageConsumer));
  741. std::string after_transformation = R"(
  742. OpCapability Shader
  743. %1 = OpExtInstImport "GLSL.std.450"
  744. OpMemoryModel Logical GLSL450
  745. OpEntryPoint Fragment %4 "main"
  746. OpExecutionMode %4 OriginUpperLeft
  747. %2 = OpTypeVoid
  748. %3 = OpTypeFunction %2
  749. %10 = OpTypeInt 32 0
  750. %11 = OpUndef %10
  751. %4 = OpFunction %2 None %3
  752. %5 = OpLabel
  753. OpBranch %21
  754. %21 = OpLabel
  755. %22 = OpPhi %10 %11 %5
  756. OpBranch %14
  757. %14 = OpLabel
  758. OpReturn
  759. OpFunctionEnd
  760. %7 = OpFunction %2 None %3
  761. %8 = OpLabel
  762. OpBranch %13
  763. %13 = OpLabel
  764. %12 = OpPhi %10 %11 %8
  765. OpReturn
  766. OpFunctionEnd
  767. )";
  768. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  769. }
  770. TEST(TransformationInlineFunctionTest, OverflowIds) {
  771. std::string reference_shader = R"(
  772. OpCapability Shader
  773. %1 = OpExtInstImport "GLSL.std.450"
  774. OpMemoryModel Logical GLSL450
  775. OpEntryPoint Vertex %39 "main"
  776. ; Types
  777. %2 = OpTypeFloat 32
  778. %3 = OpTypeVector %2 4
  779. %4 = OpTypePointer Function %3
  780. %5 = OpTypeVoid
  781. %6 = OpTypeFunction %5
  782. %7 = OpTypeFunction %2 %4 %4
  783. ; Constant scalars
  784. %8 = OpConstant %2 1
  785. %9 = OpConstant %2 2
  786. %10 = OpConstant %2 3
  787. %11 = OpConstant %2 4
  788. %12 = OpConstant %2 5
  789. %13 = OpConstant %2 6
  790. %14 = OpConstant %2 7
  791. %15 = OpConstant %2 8
  792. ; Constant vectors
  793. %16 = OpConstantComposite %3 %8 %9 %10 %11
  794. %17 = OpConstantComposite %3 %12 %13 %14 %15
  795. ; dot product function
  796. %18 = OpFunction %2 None %7
  797. %19 = OpFunctionParameter %4
  798. %20 = OpFunctionParameter %4
  799. %21 = OpLabel
  800. %22 = OpLoad %3 %19
  801. %23 = OpLoad %3 %20
  802. %24 = OpCompositeExtract %2 %22 0
  803. %25 = OpCompositeExtract %2 %23 0
  804. %26 = OpFMul %2 %24 %25
  805. %27 = OpCompositeExtract %2 %22 1
  806. %28 = OpCompositeExtract %2 %23 1
  807. %29 = OpFMul %2 %27 %28
  808. OpBranch %100
  809. %100 = OpLabel
  810. %30 = OpCompositeExtract %2 %22 2
  811. %31 = OpCompositeExtract %2 %23 2
  812. %32 = OpFMul %2 %30 %31
  813. %33 = OpCompositeExtract %2 %22 3
  814. %34 = OpCompositeExtract %2 %23 3
  815. %35 = OpFMul %2 %33 %34
  816. %36 = OpFAdd %2 %26 %29
  817. %37 = OpFAdd %2 %32 %36
  818. %38 = OpFAdd %2 %35 %37
  819. OpReturnValue %38
  820. OpFunctionEnd
  821. ; main function
  822. %39 = OpFunction %5 None %6
  823. %40 = OpLabel
  824. %41 = OpVariable %4 Function
  825. %42 = OpVariable %4 Function
  826. OpStore %41 %16
  827. OpStore %42 %17
  828. %43 = OpFunctionCall %2 %18 %41 %42 ; dot product function call
  829. OpBranch %44
  830. %44 = OpLabel
  831. OpReturn
  832. OpFunctionEnd
  833. )";
  834. const auto env = SPV_ENV_UNIVERSAL_1_5;
  835. const auto consumer = nullptr;
  836. const auto context =
  837. BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
  838. spvtools::ValidatorOptions validator_options;
  839. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  840. kConsoleMessageConsumer));
  841. auto overflow_ids_unique_ptr = MakeUnique<CounterOverflowIdSource>(1000);
  842. auto overflow_ids_ptr = overflow_ids_unique_ptr.get();
  843. TransformationContext transformation_context(
  844. MakeUnique<FactManager>(context.get()), validator_options,
  845. std::move(overflow_ids_unique_ptr));
  846. auto transformation = TransformationInlineFunction(43, {{22, 45},
  847. {23, 46},
  848. {24, 47},
  849. {25, 48},
  850. {26, 49},
  851. {27, 50},
  852. {28, 51},
  853. {29, 52}});
  854. // The following ids are left un-mapped; overflow ids will be required for
  855. // them: 30, 31, 32, 33, 34, 35, 36, 37, 38, 100
  856. ASSERT_TRUE(
  857. transformation.IsApplicable(context.get(), transformation_context));
  858. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context,
  859. overflow_ids_ptr->GetIssuedOverflowIds());
  860. std::string variant_shader = R"(
  861. OpCapability Shader
  862. %1 = OpExtInstImport "GLSL.std.450"
  863. OpMemoryModel Logical GLSL450
  864. OpEntryPoint Vertex %39 "main"
  865. ; Types
  866. %2 = OpTypeFloat 32
  867. %3 = OpTypeVector %2 4
  868. %4 = OpTypePointer Function %3
  869. %5 = OpTypeVoid
  870. %6 = OpTypeFunction %5
  871. %7 = OpTypeFunction %2 %4 %4
  872. ; Constant scalars
  873. %8 = OpConstant %2 1
  874. %9 = OpConstant %2 2
  875. %10 = OpConstant %2 3
  876. %11 = OpConstant %2 4
  877. %12 = OpConstant %2 5
  878. %13 = OpConstant %2 6
  879. %14 = OpConstant %2 7
  880. %15 = OpConstant %2 8
  881. ; Constant vectors
  882. %16 = OpConstantComposite %3 %8 %9 %10 %11
  883. %17 = OpConstantComposite %3 %12 %13 %14 %15
  884. ; dot product function
  885. %18 = OpFunction %2 None %7
  886. %19 = OpFunctionParameter %4
  887. %20 = OpFunctionParameter %4
  888. %21 = OpLabel
  889. %22 = OpLoad %3 %19
  890. %23 = OpLoad %3 %20
  891. %24 = OpCompositeExtract %2 %22 0
  892. %25 = OpCompositeExtract %2 %23 0
  893. %26 = OpFMul %2 %24 %25
  894. %27 = OpCompositeExtract %2 %22 1
  895. %28 = OpCompositeExtract %2 %23 1
  896. %29 = OpFMul %2 %27 %28
  897. OpBranch %100
  898. %100 = OpLabel
  899. %30 = OpCompositeExtract %2 %22 2
  900. %31 = OpCompositeExtract %2 %23 2
  901. %32 = OpFMul %2 %30 %31
  902. %33 = OpCompositeExtract %2 %22 3
  903. %34 = OpCompositeExtract %2 %23 3
  904. %35 = OpFMul %2 %33 %34
  905. %36 = OpFAdd %2 %26 %29
  906. %37 = OpFAdd %2 %32 %36
  907. %38 = OpFAdd %2 %35 %37
  908. OpReturnValue %38
  909. OpFunctionEnd
  910. ; main function
  911. %39 = OpFunction %5 None %6
  912. %40 = OpLabel
  913. %41 = OpVariable %4 Function
  914. %42 = OpVariable %4 Function
  915. OpStore %41 %16
  916. OpStore %42 %17
  917. %45 = OpLoad %3 %41
  918. %46 = OpLoad %3 %42
  919. %47 = OpCompositeExtract %2 %45 0
  920. %48 = OpCompositeExtract %2 %46 0
  921. %49 = OpFMul %2 %47 %48
  922. %50 = OpCompositeExtract %2 %45 1
  923. %51 = OpCompositeExtract %2 %46 1
  924. %52 = OpFMul %2 %50 %51
  925. OpBranch %1000
  926. %1000 = OpLabel
  927. %1001 = OpCompositeExtract %2 %45 2
  928. %1002 = OpCompositeExtract %2 %46 2
  929. %1003 = OpFMul %2 %1001 %1002
  930. %1004 = OpCompositeExtract %2 %45 3
  931. %1005 = OpCompositeExtract %2 %46 3
  932. %1006 = OpFMul %2 %1004 %1005
  933. %1007 = OpFAdd %2 %49 %52
  934. %1008 = OpFAdd %2 %1003 %1007
  935. %1009 = OpFAdd %2 %1006 %1008
  936. %43 = OpCopyObject %2 %1009
  937. OpBranch %44
  938. %44 = OpLabel
  939. OpReturn
  940. OpFunctionEnd
  941. )";
  942. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  943. kConsoleMessageConsumer));
  944. ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
  945. }
  946. TEST(TransformationInlineFunctionTest, OpPhiInBlockFollowingCall) {
  947. // This test checks that if the block after the inlined function call has an
  948. // OpPhi instruction and the called function contains multiple blocks then the
  949. // OpPhi instruction gets updated to refer to the return block of the inlined
  950. // function, since the block containing the call will no longer be a
  951. // predecessor.
  952. std::string reference_shader = R"(
  953. OpCapability Shader
  954. %1 = OpExtInstImport "GLSL.std.450"
  955. OpMemoryModel Logical GLSL450
  956. OpEntryPoint Fragment %4 "main"
  957. OpExecutionMode %4 OriginUpperLeft
  958. OpSource ESSL 320
  959. %2 = OpTypeVoid
  960. %3 = OpTypeFunction %2
  961. %13 = OpTypeBool
  962. %14 = OpConstantTrue %13
  963. %4 = OpFunction %2 None %3
  964. %5 = OpLabel
  965. OpBranch %10
  966. %10 = OpLabel
  967. %8 = OpFunctionCall %2 %6
  968. OpBranch %11
  969. %11 = OpLabel
  970. %12 = OpPhi %13 %14 %10
  971. OpReturn
  972. OpFunctionEnd
  973. %6 = OpFunction %2 None %3
  974. %7 = OpLabel
  975. OpBranch %20
  976. %20 = OpLabel
  977. OpReturn
  978. OpFunctionEnd
  979. )";
  980. const auto env = SPV_ENV_UNIVERSAL_1_5;
  981. const auto consumer = nullptr;
  982. const auto context =
  983. BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
  984. spvtools::ValidatorOptions validator_options;
  985. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  986. kConsoleMessageConsumer));
  987. TransformationContext transformation_context(
  988. MakeUnique<FactManager>(context.get()), validator_options);
  989. auto transformation = TransformationInlineFunction(8, {{7, 100}, {20, 101}});
  990. ASSERT_TRUE(
  991. transformation.IsApplicable(context.get(), transformation_context));
  992. ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
  993. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  994. kConsoleMessageConsumer));
  995. std::string variant_shader = R"(
  996. OpCapability Shader
  997. %1 = OpExtInstImport "GLSL.std.450"
  998. OpMemoryModel Logical GLSL450
  999. OpEntryPoint Fragment %4 "main"
  1000. OpExecutionMode %4 OriginUpperLeft
  1001. OpSource ESSL 320
  1002. %2 = OpTypeVoid
  1003. %3 = OpTypeFunction %2
  1004. %13 = OpTypeBool
  1005. %14 = OpConstantTrue %13
  1006. %4 = OpFunction %2 None %3
  1007. %5 = OpLabel
  1008. OpBranch %10
  1009. %10 = OpLabel
  1010. OpBranch %101
  1011. %101 = OpLabel
  1012. OpBranch %11
  1013. %11 = OpLabel
  1014. %12 = OpPhi %13 %14 %101
  1015. OpReturn
  1016. OpFunctionEnd
  1017. %6 = OpFunction %2 None %3
  1018. %7 = OpLabel
  1019. OpBranch %20
  1020. %20 = OpLabel
  1021. OpReturn
  1022. OpFunctionEnd
  1023. )";
  1024. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  1025. kConsoleMessageConsumer));
  1026. ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
  1027. }
  1028. } // namespace
  1029. } // namespace fuzz
  1030. } // namespace spvtools