transformation_access_chain_test.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. // Copyright (c) 2020 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "source/fuzz/transformation_access_chain.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(TransformationAccessChainTest, BasicTest) {
  23. std::string shader = R"(
  24. OpCapability Shader
  25. OpCapability VariablePointers
  26. %1 = OpExtInstImport "GLSL.std.450"
  27. OpMemoryModel Logical GLSL450
  28. OpEntryPoint Fragment %4 "main" %48 %54
  29. OpExecutionMode %4 OriginUpperLeft
  30. OpSource ESSL 310
  31. %2 = OpTypeVoid
  32. %3 = OpTypeFunction %2
  33. %6 = OpTypeFloat 32
  34. %7 = OpTypeVector %6 2
  35. %50 = OpTypeMatrix %7 2
  36. %70 = OpTypePointer Function %7
  37. %71 = OpTypePointer Function %50
  38. %8 = OpTypeStruct %7 %6
  39. %9 = OpTypePointer Function %8
  40. %10 = OpTypeInt 32 1
  41. %11 = OpTypePointer Function %10
  42. %12 = OpTypeFunction %10 %9 %11
  43. %17 = OpConstant %10 0
  44. %18 = OpTypeInt 32 0
  45. %19 = OpConstant %18 0
  46. %20 = OpTypePointer Function %6
  47. %99 = OpTypePointer Private %6
  48. %29 = OpConstant %6 0
  49. %30 = OpConstant %6 1
  50. %31 = OpConstantComposite %7 %29 %30
  51. %32 = OpConstant %6 2
  52. %33 = OpConstantComposite %8 %31 %32
  53. %35 = OpConstant %10 10
  54. %51 = OpConstant %18 10
  55. %80 = OpConstant %18 0
  56. %81 = OpConstant %10 1
  57. %82 = OpConstant %18 2
  58. %83 = OpConstant %10 3
  59. %84 = OpConstant %18 4
  60. %85 = OpConstant %10 5
  61. %52 = OpTypeArray %50 %51
  62. %53 = OpTypePointer Private %52
  63. %46 = OpConstantNull %9
  64. %47 = OpTypePointer Private %8
  65. %48 = OpVariable %47 Private
  66. %54 = OpVariable %53 Private
  67. %4 = OpFunction %2 None %3
  68. %5 = OpLabel
  69. %28 = OpVariable %9 Function
  70. %34 = OpVariable %11 Function
  71. %36 = OpVariable %9 Function
  72. %38 = OpVariable %11 Function
  73. %44 = OpCopyObject %9 %36
  74. OpStore %28 %33
  75. OpStore %34 %35
  76. %37 = OpLoad %8 %28
  77. OpStore %36 %37
  78. %39 = OpLoad %10 %34
  79. OpStore %38 %39
  80. %40 = OpFunctionCall %10 %15 %36 %38
  81. %41 = OpLoad %10 %34
  82. %42 = OpIAdd %10 %41 %40
  83. OpStore %34 %42
  84. OpReturn
  85. OpFunctionEnd
  86. %15 = OpFunction %10 None %12
  87. %13 = OpFunctionParameter %9
  88. %14 = OpFunctionParameter %11
  89. %16 = OpLabel
  90. %21 = OpAccessChain %20 %13 %17 %19
  91. %43 = OpCopyObject %9 %13
  92. %22 = OpLoad %6 %21
  93. %23 = OpConvertFToS %10 %22
  94. %24 = OpLoad %10 %14
  95. %25 = OpIAdd %10 %23 %24
  96. OpReturnValue %25
  97. OpFunctionEnd
  98. )";
  99. const auto env = SPV_ENV_UNIVERSAL_1_4;
  100. const auto consumer = nullptr;
  101. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  102. spvtools::ValidatorOptions validator_options;
  103. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  104. kConsoleMessageConsumer));
  105. // Types:
  106. // Ptr | Pointee | Storage class | GLSL for pointee | Ids of this type
  107. // ----+---------+---------------+---------------------+------------------
  108. // 9 | 8 | Function | struct(vec2, float) | 28, 36, 44, 13, 43
  109. // 11 | 10 | Function | int | 34, 38, 14
  110. // 20 | 6 | Function | float | -
  111. // 99 | 6 | Private | float | -
  112. // 53 | 52 | Private | mat2x2[10] | 54
  113. // 47 | 8 | Private | struct(vec2, float) | 48
  114. // 70 | 7 | Function | vec2 | -
  115. // 71 | 59 | Function | mat2x2 | -
  116. // Indices 0-5 are in ids 80-85
  117. TransformationContext transformation_context(
  118. MakeUnique<FactManager>(context.get()), validator_options);
  119. transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
  120. 54);
  121. // Check the case where the index type is not a 32-bit integer.
  122. TransformationAccessChain invalid_index_example1(
  123. 101, 28, {29}, MakeInstructionDescriptor(42, spv::Op::OpReturn, 0));
  124. // Since the index is not a 32-bit integer type but a 32-bit float type,
  125. // ValidIndexComposite should return false and thus the transformation is not
  126. // applicable.
  127. ASSERT_FALSE(invalid_index_example1.IsApplicable(context.get(),
  128. transformation_context));
  129. // Bad: id is not fresh
  130. ASSERT_FALSE(
  131. TransformationAccessChain(
  132. 43, 43, {80}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
  133. .IsApplicable(context.get(), transformation_context));
  134. // Bad: pointer id does not exist
  135. ASSERT_FALSE(
  136. TransformationAccessChain(
  137. 100, 1000, {80}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
  138. .IsApplicable(context.get(), transformation_context));
  139. // Bad: pointer id is not a type
  140. ASSERT_FALSE(
  141. TransformationAccessChain(
  142. 100, 5, {80}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
  143. .IsApplicable(context.get(), transformation_context));
  144. // Bad: pointer id is not a pointer
  145. ASSERT_FALSE(
  146. TransformationAccessChain(
  147. 100, 23, {80}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
  148. .IsApplicable(context.get(), transformation_context));
  149. // Bad: index id does not exist
  150. ASSERT_FALSE(
  151. TransformationAccessChain(
  152. 100, 43, {1000}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
  153. .IsApplicable(context.get(), transformation_context));
  154. // Bad: index id is not a constant and the pointer refers to a struct
  155. ASSERT_FALSE(
  156. TransformationAccessChain(
  157. 100, 43, {24}, MakeInstructionDescriptor(25, spv::Op::OpIAdd, 0))
  158. .IsApplicable(context.get(), transformation_context));
  159. // Bad: too many indices
  160. ASSERT_FALSE(TransformationAccessChain(
  161. 100, 43, {80, 80, 80},
  162. MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
  163. .IsApplicable(context.get(), transformation_context));
  164. // Bad: index id is out of bounds when accessing a struct
  165. ASSERT_FALSE(
  166. TransformationAccessChain(
  167. 100, 43, {83, 80}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
  168. .IsApplicable(context.get(), transformation_context));
  169. // Bad: attempt to insert before variable
  170. ASSERT_FALSE(
  171. TransformationAccessChain(
  172. 100, 34, {}, MakeInstructionDescriptor(36, spv::Op::OpVariable, 0))
  173. .IsApplicable(context.get(), transformation_context));
  174. // Bad: OpTypeBool must be present in the module to clamp an index
  175. ASSERT_FALSE(
  176. TransformationAccessChain(
  177. 100, 36, {80, 81}, MakeInstructionDescriptor(37, spv::Op::OpStore, 0))
  178. .IsApplicable(context.get(), transformation_context));
  179. // Bad: pointer not available
  180. ASSERT_FALSE(TransformationAccessChain(
  181. 100, 43, {80},
  182. MakeInstructionDescriptor(21, spv::Op::OpAccessChain, 0))
  183. .IsApplicable(context.get(), transformation_context));
  184. // Bad: instruction descriptor does not identify anything
  185. ASSERT_FALSE(
  186. TransformationAccessChain(
  187. 100, 43, {80}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 100))
  188. .IsApplicable(context.get(), transformation_context));
  189. #ifndef NDEBUG
  190. // Bad: pointer is null
  191. ASSERT_DEATH(
  192. TransformationAccessChain(
  193. 100, 46, {80}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
  194. .IsApplicable(context.get(), transformation_context),
  195. "Access chains should not be created from null/undefined pointers");
  196. #endif
  197. // Bad: pointer to result type does not exist
  198. ASSERT_FALSE(
  199. TransformationAccessChain(
  200. 100, 52, {0}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
  201. .IsApplicable(context.get(), transformation_context));
  202. {
  203. TransformationAccessChain transformation(
  204. 100, 43, {80}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0));
  205. ASSERT_TRUE(
  206. transformation.IsApplicable(context.get(), transformation_context));
  207. ApplyAndCheckFreshIds(transformation, context.get(),
  208. &transformation_context);
  209. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  210. context.get(), validator_options, kConsoleMessageConsumer));
  211. ASSERT_FALSE(
  212. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(100));
  213. }
  214. {
  215. TransformationAccessChain transformation(
  216. 101, 28, {81}, MakeInstructionDescriptor(42, spv::Op::OpReturn, 0));
  217. ASSERT_TRUE(
  218. transformation.IsApplicable(context.get(), transformation_context));
  219. ApplyAndCheckFreshIds(transformation, context.get(),
  220. &transformation_context);
  221. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  222. context.get(), validator_options, kConsoleMessageConsumer));
  223. ASSERT_FALSE(
  224. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(101));
  225. }
  226. {
  227. TransformationAccessChain transformation(
  228. 102, 44, {}, MakeInstructionDescriptor(44, spv::Op::OpStore, 0));
  229. ASSERT_TRUE(
  230. transformation.IsApplicable(context.get(), transformation_context));
  231. ApplyAndCheckFreshIds(transformation, context.get(),
  232. &transformation_context);
  233. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  234. context.get(), validator_options, kConsoleMessageConsumer));
  235. ASSERT_FALSE(
  236. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(103));
  237. }
  238. {
  239. TransformationAccessChain transformation(
  240. 103, 13, {80},
  241. MakeInstructionDescriptor(21, spv::Op::OpAccessChain, 0));
  242. ASSERT_TRUE(
  243. transformation.IsApplicable(context.get(), transformation_context));
  244. ApplyAndCheckFreshIds(transformation, context.get(),
  245. &transformation_context);
  246. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  247. context.get(), validator_options, kConsoleMessageConsumer));
  248. ASSERT_FALSE(
  249. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(104));
  250. }
  251. {
  252. TransformationAccessChain transformation(
  253. 104, 34, {}, MakeInstructionDescriptor(44, spv::Op::OpStore, 1));
  254. ASSERT_TRUE(
  255. transformation.IsApplicable(context.get(), transformation_context));
  256. ApplyAndCheckFreshIds(transformation, context.get(),
  257. &transformation_context);
  258. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  259. context.get(), validator_options, kConsoleMessageConsumer));
  260. ASSERT_FALSE(
  261. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(105));
  262. }
  263. {
  264. TransformationAccessChain transformation(
  265. 105, 38, {}, MakeInstructionDescriptor(40, spv::Op::OpFunctionCall, 0));
  266. ASSERT_TRUE(
  267. transformation.IsApplicable(context.get(), transformation_context));
  268. ApplyAndCheckFreshIds(transformation, context.get(),
  269. &transformation_context);
  270. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  271. context.get(), validator_options, kConsoleMessageConsumer));
  272. ASSERT_FALSE(
  273. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(106));
  274. }
  275. {
  276. TransformationAccessChain transformation(
  277. 106, 14, {}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0));
  278. ASSERT_TRUE(
  279. transformation.IsApplicable(context.get(), transformation_context));
  280. ApplyAndCheckFreshIds(transformation, context.get(),
  281. &transformation_context);
  282. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  283. context.get(), validator_options, kConsoleMessageConsumer));
  284. ASSERT_FALSE(
  285. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(107));
  286. }
  287. {
  288. // Check the case where the access chain's base pointer has the irrelevant
  289. // pointee fact; the resulting access chain should inherit this fact.
  290. TransformationAccessChain transformation(
  291. 107, 54, {}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0));
  292. ASSERT_TRUE(
  293. transformation.IsApplicable(context.get(), transformation_context));
  294. ApplyAndCheckFreshIds(transformation, context.get(),
  295. &transformation_context);
  296. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  297. context.get(), validator_options, kConsoleMessageConsumer));
  298. ASSERT_TRUE(
  299. transformation_context.GetFactManager()->PointeeValueIsIrrelevant(54));
  300. }
  301. std::string after_transformation = R"(
  302. OpCapability Shader
  303. OpCapability VariablePointers
  304. %1 = OpExtInstImport "GLSL.std.450"
  305. OpMemoryModel Logical GLSL450
  306. OpEntryPoint Fragment %4 "main" %48 %54
  307. OpExecutionMode %4 OriginUpperLeft
  308. OpSource ESSL 310
  309. %2 = OpTypeVoid
  310. %3 = OpTypeFunction %2
  311. %6 = OpTypeFloat 32
  312. %7 = OpTypeVector %6 2
  313. %50 = OpTypeMatrix %7 2
  314. %70 = OpTypePointer Function %7
  315. %71 = OpTypePointer Function %50
  316. %8 = OpTypeStruct %7 %6
  317. %9 = OpTypePointer Function %8
  318. %10 = OpTypeInt 32 1
  319. %11 = OpTypePointer Function %10
  320. %12 = OpTypeFunction %10 %9 %11
  321. %17 = OpConstant %10 0
  322. %18 = OpTypeInt 32 0
  323. %19 = OpConstant %18 0
  324. %20 = OpTypePointer Function %6
  325. %99 = OpTypePointer Private %6
  326. %29 = OpConstant %6 0
  327. %30 = OpConstant %6 1
  328. %31 = OpConstantComposite %7 %29 %30
  329. %32 = OpConstant %6 2
  330. %33 = OpConstantComposite %8 %31 %32
  331. %35 = OpConstant %10 10
  332. %51 = OpConstant %18 10
  333. %80 = OpConstant %18 0
  334. %81 = OpConstant %10 1
  335. %82 = OpConstant %18 2
  336. %83 = OpConstant %10 3
  337. %84 = OpConstant %18 4
  338. %85 = OpConstant %10 5
  339. %52 = OpTypeArray %50 %51
  340. %53 = OpTypePointer Private %52
  341. %46 = OpConstantNull %9
  342. %47 = OpTypePointer Private %8
  343. %48 = OpVariable %47 Private
  344. %54 = OpVariable %53 Private
  345. %4 = OpFunction %2 None %3
  346. %5 = OpLabel
  347. %28 = OpVariable %9 Function
  348. %34 = OpVariable %11 Function
  349. %36 = OpVariable %9 Function
  350. %38 = OpVariable %11 Function
  351. %44 = OpCopyObject %9 %36
  352. %102 = OpAccessChain %9 %44
  353. OpStore %28 %33
  354. %104 = OpAccessChain %11 %34
  355. OpStore %34 %35
  356. %37 = OpLoad %8 %28
  357. OpStore %36 %37
  358. %39 = OpLoad %10 %34
  359. OpStore %38 %39
  360. %105 = OpAccessChain %11 %38
  361. %40 = OpFunctionCall %10 %15 %36 %38
  362. %41 = OpLoad %10 %34
  363. %42 = OpIAdd %10 %41 %40
  364. OpStore %34 %42
  365. %101 = OpAccessChain %20 %28 %81
  366. OpReturn
  367. OpFunctionEnd
  368. %15 = OpFunction %10 None %12
  369. %13 = OpFunctionParameter %9
  370. %14 = OpFunctionParameter %11
  371. %16 = OpLabel
  372. %103 = OpAccessChain %70 %13 %80
  373. %21 = OpAccessChain %20 %13 %17 %19
  374. %43 = OpCopyObject %9 %13
  375. %22 = OpLoad %6 %21
  376. %23 = OpConvertFToS %10 %22
  377. %100 = OpAccessChain %70 %43 %80
  378. %106 = OpAccessChain %11 %14
  379. %107 = OpAccessChain %53 %54
  380. %24 = OpLoad %10 %14
  381. %25 = OpIAdd %10 %23 %24
  382. OpReturnValue %25
  383. OpFunctionEnd
  384. )";
  385. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  386. }
  387. TEST(TransformationAccessChainTest, StructIndexMustBeConstant) {
  388. std::string shader = R"(
  389. OpCapability Shader
  390. %1 = OpExtInstImport "GLSL.std.450"
  391. OpMemoryModel Logical GLSL450
  392. OpEntryPoint Fragment %4 "main"
  393. OpExecutionMode %4 OriginUpperLeft
  394. OpSource ESSL 320
  395. %2 = OpTypeVoid
  396. %3 = OpTypeFunction %2
  397. %6 = OpTypeInt 32 1
  398. %20 = OpUndef %6
  399. %7 = OpTypeStruct %6 %6
  400. %8 = OpTypePointer Function %7
  401. %10 = OpConstant %6 0
  402. %11 = OpConstant %6 2
  403. %12 = OpTypePointer Function %6
  404. %4 = OpFunction %2 None %3
  405. %5 = OpLabel
  406. %9 = OpVariable %8 Function
  407. OpReturn
  408. OpFunctionEnd
  409. )";
  410. const auto env = SPV_ENV_UNIVERSAL_1_4;
  411. const auto consumer = nullptr;
  412. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  413. spvtools::ValidatorOptions validator_options;
  414. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  415. kConsoleMessageConsumer));
  416. TransformationContext transformation_context(
  417. MakeUnique<FactManager>(context.get()), validator_options);
  418. // Bad: %9 is a pointer to a struct, but %20 is not a constant.
  419. ASSERT_FALSE(
  420. TransformationAccessChain(
  421. 100, 9, {20}, MakeInstructionDescriptor(9, spv::Op::OpReturn, 0))
  422. .IsApplicable(context.get(), transformation_context));
  423. }
  424. TEST(TransformationAccessChainTest, IsomorphicStructs) {
  425. std::string shader = R"(
  426. OpCapability Shader
  427. %1 = OpExtInstImport "GLSL.std.450"
  428. OpMemoryModel Logical GLSL450
  429. OpEntryPoint Fragment %4 "main" %11 %12
  430. OpExecutionMode %4 OriginUpperLeft
  431. OpSource ESSL 310
  432. %2 = OpTypeVoid
  433. %3 = OpTypeFunction %2
  434. %6 = OpTypeFloat 32
  435. %7 = OpTypeStruct %6
  436. %8 = OpTypePointer Private %7
  437. %9 = OpTypeStruct %6
  438. %10 = OpTypePointer Private %9
  439. %11 = OpVariable %8 Private
  440. %12 = OpVariable %10 Private
  441. %4 = OpFunction %2 None %3
  442. %5 = OpLabel
  443. OpReturn
  444. OpFunctionEnd
  445. )";
  446. const auto env = SPV_ENV_UNIVERSAL_1_4;
  447. const auto consumer = nullptr;
  448. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  449. spvtools::ValidatorOptions validator_options;
  450. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  451. kConsoleMessageConsumer));
  452. TransformationContext transformation_context(
  453. MakeUnique<FactManager>(context.get()), validator_options);
  454. {
  455. TransformationAccessChain transformation(
  456. 100, 11, {}, MakeInstructionDescriptor(5, spv::Op::OpReturn, 0));
  457. ASSERT_TRUE(
  458. transformation.IsApplicable(context.get(), transformation_context));
  459. ApplyAndCheckFreshIds(transformation, context.get(),
  460. &transformation_context);
  461. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  462. context.get(), validator_options, kConsoleMessageConsumer));
  463. }
  464. {
  465. TransformationAccessChain transformation(
  466. 101, 12, {}, MakeInstructionDescriptor(5, spv::Op::OpReturn, 0));
  467. ASSERT_TRUE(
  468. transformation.IsApplicable(context.get(), transformation_context));
  469. ApplyAndCheckFreshIds(transformation, context.get(),
  470. &transformation_context);
  471. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  472. context.get(), validator_options, kConsoleMessageConsumer));
  473. }
  474. std::string after_transformation = R"(
  475. OpCapability Shader
  476. %1 = OpExtInstImport "GLSL.std.450"
  477. OpMemoryModel Logical GLSL450
  478. OpEntryPoint Fragment %4 "main" %11 %12
  479. OpExecutionMode %4 OriginUpperLeft
  480. OpSource ESSL 310
  481. %2 = OpTypeVoid
  482. %3 = OpTypeFunction %2
  483. %6 = OpTypeFloat 32
  484. %7 = OpTypeStruct %6
  485. %8 = OpTypePointer Private %7
  486. %9 = OpTypeStruct %6
  487. %10 = OpTypePointer Private %9
  488. %11 = OpVariable %8 Private
  489. %12 = OpVariable %10 Private
  490. %4 = OpFunction %2 None %3
  491. %5 = OpLabel
  492. %100 = OpAccessChain %8 %11
  493. %101 = OpAccessChain %10 %12
  494. OpReturn
  495. OpFunctionEnd
  496. )";
  497. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  498. }
  499. TEST(TransformationAccessChainTest, ClampingVariables) {
  500. std::string shader = R"(
  501. OpCapability Shader
  502. %1 = OpExtInstImport "GLSL.std.450"
  503. OpMemoryModel Logical GLSL450
  504. OpEntryPoint Fragment %2 "main" %3
  505. OpExecutionMode %2 OriginUpperLeft
  506. OpSource ESSL 310
  507. %4 = OpTypeVoid
  508. %5 = OpTypeBool
  509. %6 = OpTypeFunction %4
  510. %7 = OpTypeInt 32 1
  511. %8 = OpTypeVector %7 4
  512. %9 = OpTypePointer Function %8
  513. %10 = OpConstant %7 0
  514. %11 = OpConstant %7 1
  515. %12 = OpConstant %7 3
  516. %13 = OpConstant %7 2
  517. %14 = OpConstantComposite %8 %10 %11 %12 %13
  518. %15 = OpTypePointer Function %7
  519. %16 = OpTypeInt 32 0
  520. %17 = OpConstant %16 1
  521. %18 = OpConstant %16 3
  522. %19 = OpTypeStruct %8
  523. %20 = OpTypePointer Function %19
  524. %21 = OpConstant %7 9
  525. %22 = OpConstant %16 10
  526. %23 = OpTypeArray %19 %22
  527. %24 = OpTypePointer Function %23
  528. %25 = OpTypeFloat 32
  529. %26 = OpTypeVector %25 4
  530. %27 = OpTypePointer Output %26
  531. %3 = OpVariable %27 Output
  532. %2 = OpFunction %4 None %6
  533. %28 = OpLabel
  534. %29 = OpVariable %9 Function
  535. %30 = OpVariable %15 Function
  536. %31 = OpVariable %15 Function
  537. %32 = OpVariable %20 Function
  538. %33 = OpVariable %15 Function
  539. %34 = OpVariable %24 Function
  540. OpStore %29 %14
  541. OpStore %30 %10
  542. %36 = OpLoad %7 %30
  543. %38 = OpLoad %8 %29
  544. %39 = OpCompositeConstruct %19 %38
  545. %40 = OpLoad %7 %30
  546. %42 = OpLoad %8 %29
  547. %43 = OpCompositeConstruct %19 %42
  548. %45 = OpLoad %7 %30
  549. %46 = OpLoad %7 %33
  550. OpReturn
  551. OpFunctionEnd
  552. )";
  553. const auto env = SPV_ENV_UNIVERSAL_1_4;
  554. const auto consumer = nullptr;
  555. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  556. spvtools::ValidatorOptions validator_options;
  557. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  558. kConsoleMessageConsumer));
  559. TransformationContext transformation_context(
  560. MakeUnique<FactManager>(context.get()), validator_options);
  561. // Bad: no ids given for clamping
  562. ASSERT_FALSE(
  563. TransformationAccessChain(
  564. 100, 29, {17}, MakeInstructionDescriptor(36, spv::Op::OpLoad, 0))
  565. .IsApplicable(context.get(), transformation_context));
  566. // Bad: an id given for clamping is not fresh
  567. ASSERT_FALSE(TransformationAccessChain(
  568. 100, 29, {17},
  569. MakeInstructionDescriptor(36, spv::Op::OpLoad, 0),
  570. {{46, 201}})
  571. .IsApplicable(context.get(), transformation_context));
  572. // Bad: an id given for clamping is not fresh
  573. ASSERT_FALSE(TransformationAccessChain(
  574. 100, 29, {17},
  575. MakeInstructionDescriptor(36, spv::Op::OpLoad, 0),
  576. {{200, 46}})
  577. .IsApplicable(context.get(), transformation_context));
  578. // Bad: an id given for clamping is the same as the id for the access chain
  579. ASSERT_FALSE(TransformationAccessChain(
  580. 100, 29, {17},
  581. MakeInstructionDescriptor(36, spv::Op::OpLoad, 0),
  582. {{100, 201}})
  583. .IsApplicable(context.get(), transformation_context));
  584. // Bad: the fresh ids given are not distinct
  585. ASSERT_FALSE(TransformationAccessChain(
  586. 100, 29, {17},
  587. MakeInstructionDescriptor(36, spv::Op::OpLoad, 0),
  588. {{200, 200}})
  589. .IsApplicable(context.get(), transformation_context));
  590. // Bad: not enough ids given for clamping (2 pairs needed)
  591. ASSERT_FALSE(TransformationAccessChain(
  592. 104, 34, {45, 10, 46},
  593. MakeInstructionDescriptor(46, spv::Op::OpReturn, 0),
  594. {{208, 209}, {209, 211}})
  595. .IsApplicable(context.get(), transformation_context));
  596. // Bad: the fresh ids given are not distinct
  597. ASSERT_FALSE(TransformationAccessChain(
  598. 104, 34, {45, 10, 46},
  599. MakeInstructionDescriptor(46, spv::Op::OpReturn, 0),
  600. {{208, 209}, {209, 211}})
  601. .IsApplicable(context.get(), transformation_context));
  602. {
  603. TransformationAccessChain transformation(
  604. 100, 29, {17}, MakeInstructionDescriptor(36, spv::Op::OpLoad, 0),
  605. {{200, 201}});
  606. ASSERT_TRUE(
  607. transformation.IsApplicable(context.get(), transformation_context));
  608. ApplyAndCheckFreshIds(transformation, context.get(),
  609. &transformation_context);
  610. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  611. context.get(), validator_options, kConsoleMessageConsumer));
  612. }
  613. {
  614. TransformationAccessChain transformation(
  615. 101, 29, {36}, MakeInstructionDescriptor(38, spv::Op::OpLoad, 0),
  616. {{202, 203}});
  617. ASSERT_TRUE(
  618. transformation.IsApplicable(context.get(), transformation_context));
  619. ApplyAndCheckFreshIds(transformation, context.get(),
  620. &transformation_context);
  621. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  622. context.get(), validator_options, kConsoleMessageConsumer));
  623. }
  624. {
  625. TransformationAccessChain transformation(
  626. 102, 32, {10, 40}, MakeInstructionDescriptor(42, spv::Op::OpLoad, 0),
  627. {{204, 205}});
  628. ASSERT_TRUE(
  629. transformation.IsApplicable(context.get(), transformation_context));
  630. ApplyAndCheckFreshIds(transformation, context.get(),
  631. &transformation_context);
  632. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  633. context.get(), validator_options, kConsoleMessageConsumer));
  634. }
  635. {
  636. TransformationAccessChain transformation(
  637. 103, 34, {11}, MakeInstructionDescriptor(45, spv::Op::OpLoad, 0),
  638. {{206, 207}});
  639. ASSERT_TRUE(
  640. transformation.IsApplicable(context.get(), transformation_context));
  641. ApplyAndCheckFreshIds(transformation, context.get(),
  642. &transformation_context);
  643. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  644. context.get(), validator_options, kConsoleMessageConsumer));
  645. }
  646. {
  647. TransformationAccessChain transformation(
  648. 104, 34, {45, 10, 46},
  649. MakeInstructionDescriptor(46, spv::Op::OpReturn, 0),
  650. {{208, 209}, {210, 211}});
  651. ASSERT_TRUE(
  652. transformation.IsApplicable(context.get(), transformation_context));
  653. ApplyAndCheckFreshIds(transformation, context.get(),
  654. &transformation_context);
  655. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
  656. context.get(), validator_options, kConsoleMessageConsumer));
  657. }
  658. std::string after_transformation = R"(
  659. OpCapability Shader
  660. %1 = OpExtInstImport "GLSL.std.450"
  661. OpMemoryModel Logical GLSL450
  662. OpEntryPoint Fragment %2 "main" %3
  663. OpExecutionMode %2 OriginUpperLeft
  664. OpSource ESSL 310
  665. %4 = OpTypeVoid
  666. %5 = OpTypeBool
  667. %6 = OpTypeFunction %4
  668. %7 = OpTypeInt 32 1
  669. %8 = OpTypeVector %7 4
  670. %9 = OpTypePointer Function %8
  671. %10 = OpConstant %7 0
  672. %11 = OpConstant %7 1
  673. %12 = OpConstant %7 3
  674. %13 = OpConstant %7 2
  675. %14 = OpConstantComposite %8 %10 %11 %12 %13
  676. %15 = OpTypePointer Function %7
  677. %16 = OpTypeInt 32 0
  678. %17 = OpConstant %16 1
  679. %18 = OpConstant %16 3
  680. %19 = OpTypeStruct %8
  681. %20 = OpTypePointer Function %19
  682. %21 = OpConstant %7 9
  683. %22 = OpConstant %16 10
  684. %23 = OpTypeArray %19 %22
  685. %24 = OpTypePointer Function %23
  686. %25 = OpTypeFloat 32
  687. %26 = OpTypeVector %25 4
  688. %27 = OpTypePointer Output %26
  689. %3 = OpVariable %27 Output
  690. %2 = OpFunction %4 None %6
  691. %28 = OpLabel
  692. %29 = OpVariable %9 Function
  693. %30 = OpVariable %15 Function
  694. %31 = OpVariable %15 Function
  695. %32 = OpVariable %20 Function
  696. %33 = OpVariable %15 Function
  697. %34 = OpVariable %24 Function
  698. OpStore %29 %14
  699. OpStore %30 %10
  700. %200 = OpULessThanEqual %5 %17 %18
  701. %201 = OpSelect %16 %200 %17 %18
  702. %100 = OpAccessChain %15 %29 %201
  703. %36 = OpLoad %7 %30
  704. %202 = OpULessThanEqual %5 %36 %12
  705. %203 = OpSelect %7 %202 %36 %12
  706. %101 = OpAccessChain %15 %29 %203
  707. %38 = OpLoad %8 %29
  708. %39 = OpCompositeConstruct %19 %38
  709. %40 = OpLoad %7 %30
  710. %204 = OpULessThanEqual %5 %40 %12
  711. %205 = OpSelect %7 %204 %40 %12
  712. %102 = OpAccessChain %15 %32 %10 %205
  713. %42 = OpLoad %8 %29
  714. %43 = OpCompositeConstruct %19 %42
  715. %206 = OpULessThanEqual %5 %11 %21
  716. %207 = OpSelect %7 %206 %11 %21
  717. %103 = OpAccessChain %20 %34 %207
  718. %45 = OpLoad %7 %30
  719. %46 = OpLoad %7 %33
  720. %208 = OpULessThanEqual %5 %45 %21
  721. %209 = OpSelect %7 %208 %45 %21
  722. %210 = OpULessThanEqual %5 %46 %12
  723. %211 = OpSelect %7 %210 %46 %12
  724. %104 = OpAccessChain %15 %34 %209 %10 %211
  725. OpReturn
  726. OpFunctionEnd
  727. )";
  728. ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
  729. }
  730. } // namespace
  731. } // namespace fuzz
  732. } // namespace spvtools