transformation_add_global_variable_test.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. // Copyright (c) 2019 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "source/fuzz/transformation_add_global_variable.h"
  15. #include "gtest/gtest.h"
  16. #include "source/fuzz/fuzzer_util.h"
  17. #include "test/fuzz/fuzz_test_util.h"
  18. namespace spvtools {
  19. namespace fuzz {
  20. namespace {
  21. TEST(TransformationAddGlobalVariableTest, BasicTest) {
  22. std::string shader = R"(
  23. OpCapability Shader
  24. %1 = OpExtInstImport "GLSL.std.450"
  25. OpMemoryModel Logical GLSL450
  26. OpEntryPoint Fragment %4 "main"
  27. OpExecutionMode %4 OriginUpperLeft
  28. OpSource ESSL 310
  29. %2 = OpTypeVoid
  30. %3 = OpTypeFunction %2
  31. %6 = OpTypeFloat 32
  32. %40 = OpConstant %6 0
  33. %7 = OpTypeInt 32 1
  34. %8 = OpTypeVector %6 2
  35. %41 = OpConstantComposite %8 %40 %40
  36. %9 = OpTypePointer Function %6
  37. %10 = OpTypePointer Private %6
  38. %20 = OpTypePointer Uniform %6
  39. %11 = OpTypePointer Function %7
  40. %12 = OpTypePointer Private %7
  41. %13 = OpTypePointer Private %8
  42. %14 = OpVariable %10 Private
  43. %15 = OpVariable %20 Uniform
  44. %16 = OpConstant %7 1
  45. %17 = OpTypePointer Private %10
  46. %18 = OpTypeBool
  47. %19 = OpTypePointer Private %18
  48. %21 = OpConstantTrue %18
  49. %22 = OpConstantFalse %18
  50. %4 = OpFunction %2 None %3
  51. %5 = OpLabel
  52. OpReturn
  53. OpFunctionEnd
  54. )";
  55. const auto env = SPV_ENV_UNIVERSAL_1_3;
  56. const auto consumer = nullptr;
  57. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  58. spvtools::ValidatorOptions validator_options;
  59. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  60. kConsoleMessageConsumer));
  61. TransformationContext transformation_context(
  62. MakeUnique<FactManager>(context.get()), validator_options);
  63. // Id already in use
  64. ASSERT_FALSE(TransformationAddGlobalVariable(
  65. 4, 10, spv::StorageClass::Private, 0, true)
  66. .IsApplicable(context.get(), transformation_context));
  67. // %1 is not a type
  68. ASSERT_FALSE(TransformationAddGlobalVariable(
  69. 100, 1, spv::StorageClass::Private, 0, false)
  70. .IsApplicable(context.get(), transformation_context));
  71. // %7 is not a pointer type
  72. ASSERT_FALSE(TransformationAddGlobalVariable(
  73. 100, 7, spv::StorageClass::Private, 0, true)
  74. .IsApplicable(context.get(), transformation_context));
  75. // %9 does not have Private storage class
  76. ASSERT_FALSE(TransformationAddGlobalVariable(
  77. 100, 9, spv::StorageClass::Private, 0, false)
  78. .IsApplicable(context.get(), transformation_context));
  79. // %15 does not have Private storage class
  80. ASSERT_FALSE(TransformationAddGlobalVariable(
  81. 100, 15, spv::StorageClass::Private, 0, true)
  82. .IsApplicable(context.get(), transformation_context));
  83. // %10 is a pointer to float, while %16 is an int constant
  84. ASSERT_FALSE(TransformationAddGlobalVariable(
  85. 100, 10, spv::StorageClass::Private, 16, false)
  86. .IsApplicable(context.get(), transformation_context));
  87. // %10 is a Private pointer to float, while %15 is a variable with type
  88. // Uniform float pointer
  89. ASSERT_FALSE(TransformationAddGlobalVariable(
  90. 100, 10, spv::StorageClass::Private, 15, true)
  91. .IsApplicable(context.get(), transformation_context));
  92. // %12 is a Private pointer to int, while %10 is a variable with type
  93. // Private float pointer
  94. ASSERT_FALSE(TransformationAddGlobalVariable(
  95. 100, 12, spv::StorageClass::Private, 10, false)
  96. .IsApplicable(context.get(), transformation_context));
  97. // %10 is pointer-to-float, and %14 has type pointer-to-float; that's not OK
  98. // since the initializer's type should be the *pointee* type.
  99. ASSERT_FALSE(TransformationAddGlobalVariable(
  100. 104, 10, spv::StorageClass::Private, 14, true)
  101. .IsApplicable(context.get(), transformation_context));
  102. // This would work in principle, but logical addressing does not allow
  103. // a pointer to a pointer.
  104. ASSERT_FALSE(TransformationAddGlobalVariable(
  105. 104, 17, spv::StorageClass::Private, 14, false)
  106. .IsApplicable(context.get(), transformation_context));
  107. {
  108. // %100 = OpVariable %12 Private
  109. ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(100));
  110. TransformationAddGlobalVariable transformation(
  111. 100, 12, spv::StorageClass::Private, 16, true);
  112. ASSERT_TRUE(
  113. transformation.IsApplicable(context.get(), transformation_context));
  114. ApplyAndCheckFreshIds(transformation, context.get(),
  115. &transformation_context);
  116. ASSERT_EQ(spv::Op::OpVariable,
  117. context->get_def_use_mgr()->GetDef(100)->opcode());
  118. ASSERT_EQ(
  119. spv::StorageClass::Private,
  120. static_cast<spv::StorageClass>(
  121. context->get_def_use_mgr()->GetDef(100)->GetSingleWordInOperand(
  122. 0)));
  123. }
  124. TransformationAddGlobalVariable transformations[] = {
  125. // %101 = OpVariable %10 Private
  126. TransformationAddGlobalVariable(101, 10, spv::StorageClass::Private, 40,
  127. false),
  128. // %102 = OpVariable %13 Private
  129. TransformationAddGlobalVariable(102, 13, spv::StorageClass::Private, 41,
  130. true),
  131. // %103 = OpVariable %12 Private %16
  132. TransformationAddGlobalVariable(103, 12, spv::StorageClass::Private, 16,
  133. false),
  134. // %104 = OpVariable %19 Private %21
  135. TransformationAddGlobalVariable(104, 19, spv::StorageClass::Private, 21,
  136. true),
  137. // %105 = OpVariable %19 Private %22
  138. TransformationAddGlobalVariable(105, 19, spv::StorageClass::Private, 22,
  139. false)};
  140. for (auto& transformation : transformations) {
  141. ASSERT_TRUE(
  142. transformation.IsApplicable(context.get(), transformation_context));
  143. ApplyAndCheckFreshIds(transformation, context.get(),
  144. &transformation_context);
  145. }
  146. ASSERT_TRUE(
  147. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(100));
  148. ASSERT_TRUE(
  149. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(102));
  150. ASSERT_TRUE(
  151. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(104));
  152. ASSERT_FALSE(
  153. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(101));
  154. ASSERT_FALSE(
  155. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(103));
  156. ASSERT_FALSE(
  157. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(105));
  158. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  159. kConsoleMessageConsumer));
  160. std::string after_transformation = 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. %2 = OpTypeVoid
  168. %3 = OpTypeFunction %2
  169. %6 = OpTypeFloat 32
  170. %40 = OpConstant %6 0
  171. %7 = OpTypeInt 32 1
  172. %8 = OpTypeVector %6 2
  173. %41 = OpConstantComposite %8 %40 %40
  174. %9 = OpTypePointer Function %6
  175. %10 = OpTypePointer Private %6
  176. %20 = OpTypePointer Uniform %6
  177. %11 = OpTypePointer Function %7
  178. %12 = OpTypePointer Private %7
  179. %13 = OpTypePointer Private %8
  180. %14 = OpVariable %10 Private
  181. %15 = OpVariable %20 Uniform
  182. %16 = OpConstant %7 1
  183. %17 = OpTypePointer Private %10
  184. %18 = OpTypeBool
  185. %19 = OpTypePointer Private %18
  186. %21 = OpConstantTrue %18
  187. %22 = OpConstantFalse %18
  188. %100 = OpVariable %12 Private %16
  189. %101 = OpVariable %10 Private %40
  190. %102 = OpVariable %13 Private %41
  191. %103 = OpVariable %12 Private %16
  192. %104 = OpVariable %19 Private %21
  193. %105 = OpVariable %19 Private %22
  194. %4 = OpFunction %2 None %3
  195. %5 = OpLabel
  196. OpReturn
  197. OpFunctionEnd
  198. )";
  199. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  200. }
  201. TEST(TransformationAddGlobalVariableTest, TestEntryPointInterfaceEnlargement) {
  202. // This checks that when global variables are added to a SPIR-V 1.4+ module,
  203. // they are also added to entry points of that module.
  204. std::string shader = R"(
  205. OpCapability Shader
  206. %1 = OpExtInstImport "GLSL.std.450"
  207. OpMemoryModel Logical GLSL450
  208. OpEntryPoint Fragment %4 "m1"
  209. OpEntryPoint Vertex %5 "m2"
  210. OpExecutionMode %4 OriginUpperLeft
  211. OpSource ESSL 310
  212. %2 = OpTypeVoid
  213. %3 = OpTypeFunction %2
  214. %6 = OpTypeFloat 32
  215. %7 = OpTypeInt 32 1
  216. %8 = OpTypeVector %6 2
  217. %9 = OpTypePointer Function %6
  218. %10 = OpTypePointer Private %6
  219. %11 = OpTypePointer Function %7
  220. %12 = OpTypePointer Private %7
  221. %13 = OpTypePointer Private %8
  222. %14 = OpVariable %10 Private
  223. %16 = OpConstant %7 1
  224. %17 = OpTypePointer Private %10
  225. %18 = OpTypeBool
  226. %19 = OpTypePointer Private %18
  227. %21 = OpConstantTrue %18
  228. %4 = OpFunction %2 None %3
  229. %30 = OpLabel
  230. OpReturn
  231. OpFunctionEnd
  232. %5 = OpFunction %2 None %3
  233. %31 = OpLabel
  234. OpReturn
  235. OpFunctionEnd
  236. )";
  237. for (auto env : {SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5,
  238. SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_VULKAN_1_2}) {
  239. const auto consumer = nullptr;
  240. const auto context =
  241. BuildModule(env, consumer, shader, kFuzzAssembleOption);
  242. spvtools::ValidatorOptions validator_options;
  243. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  244. context.get(), validator_options, kConsoleMessageConsumer));
  245. TransformationContext transformation_context(
  246. MakeUnique<FactManager>(context.get()), validator_options);
  247. TransformationAddGlobalVariable transformations[] = {
  248. // %100 = OpVariable %12 Private
  249. TransformationAddGlobalVariable(100, 12, spv::StorageClass::Private, 16,
  250. true),
  251. // %101 = OpVariable %12 Private %16
  252. TransformationAddGlobalVariable(101, 12, spv::StorageClass::Private, 16,
  253. false),
  254. // %102 = OpVariable %19 Private %21
  255. TransformationAddGlobalVariable(102, 19, spv::StorageClass::Private, 21,
  256. true)};
  257. for (auto& transformation : transformations) {
  258. ASSERT_TRUE(
  259. transformation.IsApplicable(context.get(), transformation_context));
  260. ApplyAndCheckFreshIds(transformation, context.get(),
  261. &transformation_context);
  262. }
  263. ASSERT_TRUE(
  264. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(100));
  265. ASSERT_TRUE(
  266. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(102));
  267. ASSERT_FALSE(
  268. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(101));
  269. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  270. context.get(), validator_options, kConsoleMessageConsumer));
  271. std::string after_transformation_enlarged_interface = R"(
  272. OpCapability Shader
  273. %1 = OpExtInstImport "GLSL.std.450"
  274. OpMemoryModel Logical GLSL450
  275. OpEntryPoint Fragment %4 "m1" %100 %101 %102
  276. OpEntryPoint Vertex %5 "m2" %100 %101 %102
  277. OpExecutionMode %4 OriginUpperLeft
  278. OpSource ESSL 310
  279. %2 = OpTypeVoid
  280. %3 = OpTypeFunction %2
  281. %6 = OpTypeFloat 32
  282. %7 = OpTypeInt 32 1
  283. %8 = OpTypeVector %6 2
  284. %9 = OpTypePointer Function %6
  285. %10 = OpTypePointer Private %6
  286. %11 = OpTypePointer Function %7
  287. %12 = OpTypePointer Private %7
  288. %13 = OpTypePointer Private %8
  289. %14 = OpVariable %10 Private
  290. %16 = OpConstant %7 1
  291. %17 = OpTypePointer Private %10
  292. %18 = OpTypeBool
  293. %19 = OpTypePointer Private %18
  294. %21 = OpConstantTrue %18
  295. %100 = OpVariable %12 Private %16
  296. %101 = OpVariable %12 Private %16
  297. %102 = OpVariable %19 Private %21
  298. %4 = OpFunction %2 None %3
  299. %30 = OpLabel
  300. OpReturn
  301. OpFunctionEnd
  302. %5 = OpFunction %2 None %3
  303. %31 = OpLabel
  304. OpReturn
  305. OpFunctionEnd
  306. )";
  307. ASSERT_TRUE(
  308. IsEqual(env, after_transformation_enlarged_interface, context.get()));
  309. }
  310. }
  311. TEST(TransformationAddGlobalVariableTest,
  312. TestEntryPointInterfaceNoEnlargement) {
  313. // This checks that when global variables are added to a SPIR-V 1.3- module,
  314. // they are not added to entry points of that module.
  315. std::string shader = R"(
  316. OpCapability Shader
  317. %1 = OpExtInstImport "GLSL.std.450"
  318. OpMemoryModel Logical GLSL450
  319. OpEntryPoint Fragment %4 "m1"
  320. OpEntryPoint Vertex %5 "m2"
  321. OpExecutionMode %4 OriginUpperLeft
  322. OpSource ESSL 310
  323. %2 = OpTypeVoid
  324. %3 = OpTypeFunction %2
  325. %6 = OpTypeFloat 32
  326. %7 = OpTypeInt 32 1
  327. %8 = OpTypeVector %6 2
  328. %9 = OpTypePointer Function %6
  329. %10 = OpTypePointer Private %6
  330. %11 = OpTypePointer Function %7
  331. %12 = OpTypePointer Private %7
  332. %13 = OpTypePointer Private %8
  333. %14 = OpVariable %10 Private
  334. %16 = OpConstant %7 1
  335. %17 = OpTypePointer Private %10
  336. %18 = OpTypeBool
  337. %19 = OpTypePointer Private %18
  338. %21 = OpConstantTrue %18
  339. %4 = OpFunction %2 None %3
  340. %30 = OpLabel
  341. OpReturn
  342. OpFunctionEnd
  343. %5 = OpFunction %2 None %3
  344. %31 = OpLabel
  345. OpReturn
  346. OpFunctionEnd
  347. )";
  348. for (auto env :
  349. {SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2,
  350. SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1}) {
  351. const auto consumer = nullptr;
  352. const auto context =
  353. BuildModule(env, consumer, shader, kFuzzAssembleOption);
  354. spvtools::ValidatorOptions validator_options;
  355. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  356. context.get(), validator_options, kConsoleMessageConsumer));
  357. TransformationContext transformation_context(
  358. MakeUnique<FactManager>(context.get()), validator_options);
  359. TransformationAddGlobalVariable transformations[] = {
  360. // %100 = OpVariable %12 Private
  361. TransformationAddGlobalVariable(100, 12, spv::StorageClass::Private, 16,
  362. true),
  363. // %101 = OpVariable %12 Private %16
  364. TransformationAddGlobalVariable(101, 12, spv::StorageClass::Private, 16,
  365. false),
  366. // %102 = OpVariable %19 Private %21
  367. TransformationAddGlobalVariable(102, 19, spv::StorageClass::Private, 21,
  368. true)};
  369. for (auto& transformation : transformations) {
  370. ASSERT_TRUE(
  371. transformation.IsApplicable(context.get(), transformation_context));
  372. ApplyAndCheckFreshIds(transformation, context.get(),
  373. &transformation_context);
  374. }
  375. ASSERT_TRUE(
  376. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(100));
  377. ASSERT_TRUE(
  378. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(102));
  379. ASSERT_FALSE(
  380. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(101));
  381. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  382. context.get(), validator_options, kConsoleMessageConsumer));
  383. std::string after_transformation_fixed_interface = R"(
  384. OpCapability Shader
  385. %1 = OpExtInstImport "GLSL.std.450"
  386. OpMemoryModel Logical GLSL450
  387. OpEntryPoint Fragment %4 "m1"
  388. OpEntryPoint Vertex %5 "m2"
  389. OpExecutionMode %4 OriginUpperLeft
  390. OpSource ESSL 310
  391. %2 = OpTypeVoid
  392. %3 = OpTypeFunction %2
  393. %6 = OpTypeFloat 32
  394. %7 = OpTypeInt 32 1
  395. %8 = OpTypeVector %6 2
  396. %9 = OpTypePointer Function %6
  397. %10 = OpTypePointer Private %6
  398. %11 = OpTypePointer Function %7
  399. %12 = OpTypePointer Private %7
  400. %13 = OpTypePointer Private %8
  401. %14 = OpVariable %10 Private
  402. %16 = OpConstant %7 1
  403. %17 = OpTypePointer Private %10
  404. %18 = OpTypeBool
  405. %19 = OpTypePointer Private %18
  406. %21 = OpConstantTrue %18
  407. %100 = OpVariable %12 Private %16
  408. %101 = OpVariable %12 Private %16
  409. %102 = OpVariable %19 Private %21
  410. %4 = OpFunction %2 None %3
  411. %30 = OpLabel
  412. OpReturn
  413. OpFunctionEnd
  414. %5 = OpFunction %2 None %3
  415. %31 = OpLabel
  416. OpReturn
  417. OpFunctionEnd
  418. )";
  419. ASSERT_TRUE(
  420. IsEqual(env, after_transformation_fixed_interface, context.get()));
  421. }
  422. }
  423. TEST(TransformationAddGlobalVariableTest, TestAddingWorkgroupGlobals) {
  424. // This checks that workgroup globals can be added to a compute shader.
  425. std::string shader = R"(
  426. OpCapability Shader
  427. %1 = OpExtInstImport "GLSL.std.450"
  428. OpMemoryModel Logical GLSL450
  429. OpEntryPoint GLCompute %4 "main"
  430. OpExecutionMode %4 LocalSize 1 1 1
  431. OpSource ESSL 310
  432. %2 = OpTypeVoid
  433. %3 = OpTypeFunction %2
  434. %6 = OpTypeInt 32 1
  435. %7 = OpTypePointer Workgroup %6
  436. %50 = OpConstant %6 2
  437. %4 = OpFunction %2 None %3
  438. %5 = 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. #ifndef NDEBUG
  451. ASSERT_DEATH(
  452. TransformationAddGlobalVariable(8, 7, spv::StorageClass::Workgroup, 50,
  453. true)
  454. .IsApplicable(context.get(), transformation_context),
  455. "By construction this transformation should not have an.*initializer "
  456. "when Workgroup storage class is used");
  457. #endif
  458. TransformationAddGlobalVariable transformations[] = {
  459. // %8 = OpVariable %7 Workgroup
  460. TransformationAddGlobalVariable(8, 7, spv::StorageClass::Workgroup, 0,
  461. true),
  462. // %10 = OpVariable %7 Workgroup
  463. TransformationAddGlobalVariable(10, 7, spv::StorageClass::Workgroup, 0,
  464. false)};
  465. for (auto& transformation : transformations) {
  466. ASSERT_TRUE(
  467. transformation.IsApplicable(context.get(), transformation_context));
  468. ApplyAndCheckFreshIds(transformation, context.get(),
  469. &transformation_context);
  470. }
  471. ASSERT_TRUE(
  472. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(8));
  473. ASSERT_FALSE(
  474. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(10));
  475. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  476. kConsoleMessageConsumer));
  477. std::string after_transformation = R"(
  478. OpCapability Shader
  479. %1 = OpExtInstImport "GLSL.std.450"
  480. OpMemoryModel Logical GLSL450
  481. OpEntryPoint GLCompute %4 "main" %8 %10
  482. OpExecutionMode %4 LocalSize 1 1 1
  483. OpSource ESSL 310
  484. %2 = OpTypeVoid
  485. %3 = OpTypeFunction %2
  486. %6 = OpTypeInt 32 1
  487. %7 = OpTypePointer Workgroup %6
  488. %50 = OpConstant %6 2
  489. %8 = OpVariable %7 Workgroup
  490. %10 = OpVariable %7 Workgroup
  491. %4 = OpFunction %2 None %3
  492. %5 = OpLabel
  493. OpReturn
  494. OpFunctionEnd
  495. )";
  496. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  497. }
  498. } // namespace
  499. } // namespace fuzz
  500. } // namespace spvtools