fuzzer_shrinker_test.cpp 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109
  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 <functional>
  15. #include <vector>
  16. #include "source/fuzz/fuzzer.h"
  17. #include "source/fuzz/pseudo_random_generator.h"
  18. #include "source/fuzz/shrinker.h"
  19. #include "source/fuzz/uniform_buffer_element_descriptor.h"
  20. #include "test/fuzz/fuzz_test_util.h"
  21. namespace spvtools {
  22. namespace fuzz {
  23. namespace {
  24. // Abstract class exposing an interestingness function as a virtual method.
  25. class InterestingnessTest {
  26. public:
  27. virtual ~InterestingnessTest() = default;
  28. // Abstract method that subclasses should implement for specific notions of
  29. // interestingness. Its signature matches Shrinker::InterestingnessFunction.
  30. // Argument |binary| is the SPIR-V binary to be checked; |counter| is used for
  31. // debugging purposes.
  32. virtual bool Interesting(const std::vector<uint32_t>& binary,
  33. uint32_t counter) = 0;
  34. // Yields the Interesting instance method wrapped in a function object.
  35. Shrinker::InterestingnessFunction AsFunction() {
  36. return std::bind(&InterestingnessTest::Interesting, this,
  37. std::placeholders::_1, std::placeholders::_2);
  38. }
  39. };
  40. // A test that says all binaries are interesting.
  41. class AlwaysInteresting : public InterestingnessTest {
  42. public:
  43. bool Interesting(const std::vector<uint32_t>&, uint32_t) override {
  44. return true;
  45. }
  46. };
  47. // A test that says a binary is interesting first time round, and uninteresting
  48. // thereafter.
  49. class OnlyInterestingFirstTime : public InterestingnessTest {
  50. public:
  51. explicit OnlyInterestingFirstTime() : first_time_(true) {}
  52. bool Interesting(const std::vector<uint32_t>&, uint32_t) override {
  53. if (first_time_) {
  54. first_time_ = false;
  55. return true;
  56. }
  57. return false;
  58. }
  59. private:
  60. bool first_time_;
  61. };
  62. // A test that says a binary is interesting first time round, after which
  63. // interestingness ping pongs between false and true.
  64. class PingPong : public InterestingnessTest {
  65. public:
  66. explicit PingPong() : interesting_(false) {}
  67. bool Interesting(const std::vector<uint32_t>&, uint32_t) override {
  68. interesting_ = !interesting_;
  69. return interesting_;
  70. }
  71. private:
  72. bool interesting_;
  73. };
  74. // A test that says a binary is interesting first time round, thereafter
  75. // decides at random whether it is interesting. This allows the logic of the
  76. // shrinker to be exercised quite a bit.
  77. class InterestingThenRandom : public InterestingnessTest {
  78. public:
  79. InterestingThenRandom(const PseudoRandomGenerator& random_generator)
  80. : first_time_(true), random_generator_(random_generator) {}
  81. bool Interesting(const std::vector<uint32_t>&, uint32_t) override {
  82. if (first_time_) {
  83. first_time_ = false;
  84. return true;
  85. }
  86. return random_generator_.RandomBool();
  87. }
  88. private:
  89. bool first_time_;
  90. PseudoRandomGenerator random_generator_;
  91. };
  92. // |binary_in| and |initial_facts| are a SPIR-V binary and sequence of facts to
  93. // which |transformation_sequence_in| can be applied. Shrinking of
  94. // |transformation_sequence_in| gets performed with respect to
  95. // |interestingness_function|. If |expected_binary_out| is non-empty, it must
  96. // match the binary obtained by applying the final shrunk set of
  97. // transformations, in which case the number of such transformations should
  98. // equal |expected_transformations_out_size|.
  99. //
  100. // The |step_limit| parameter restricts the number of steps that the shrinker
  101. // will try; it can be set to something small for a faster (but less thorough)
  102. // test.
  103. void RunAndCheckShrinker(
  104. const spv_target_env& target_env, const std::vector<uint32_t>& binary_in,
  105. const protobufs::FactSequence& initial_facts,
  106. const protobufs::TransformationSequence& transformation_sequence_in,
  107. const Shrinker::InterestingnessFunction& interestingness_function,
  108. const std::vector<uint32_t>& expected_binary_out,
  109. uint32_t expected_transformations_out_size, uint32_t step_limit) {
  110. // Run the shrinker.
  111. Shrinker shrinker(target_env, step_limit, false);
  112. shrinker.SetMessageConsumer(kSilentConsumer);
  113. std::vector<uint32_t> binary_out;
  114. protobufs::TransformationSequence transformations_out;
  115. Shrinker::ShrinkerResultStatus shrinker_result_status =
  116. shrinker.Run(binary_in, initial_facts, transformation_sequence_in,
  117. interestingness_function, &binary_out, &transformations_out);
  118. ASSERT_TRUE(Shrinker::ShrinkerResultStatus::kComplete ==
  119. shrinker_result_status ||
  120. Shrinker::ShrinkerResultStatus::kStepLimitReached ==
  121. shrinker_result_status);
  122. // If a non-empty expected binary was provided, check that it matches the
  123. // result of shrinking and that the expected number of transformations remain.
  124. if (!expected_binary_out.empty()) {
  125. ASSERT_EQ(expected_binary_out, binary_out);
  126. ASSERT_EQ(expected_transformations_out_size,
  127. static_cast<uint32_t>(transformations_out.transformation_size()));
  128. }
  129. }
  130. // Assembles the given |shader| text, and then:
  131. // - Runs the fuzzer with |seed| to yield a set of transformations
  132. // - Shrinks the transformation with various interestingness functions,
  133. // asserting some properties about the result each time
  134. void RunFuzzerAndShrinker(const std::string& shader,
  135. const protobufs::FactSequence& initial_facts,
  136. uint32_t seed) {
  137. const auto env = SPV_ENV_UNIVERSAL_1_5;
  138. std::vector<uint32_t> binary_in;
  139. SpirvTools t(env);
  140. t.SetMessageConsumer(kConsoleMessageConsumer);
  141. ASSERT_TRUE(t.Assemble(shader, &binary_in, kFuzzAssembleOption));
  142. ASSERT_TRUE(t.Validate(binary_in));
  143. // Run the fuzzer and check that it successfully yields a valid binary.
  144. std::vector<uint32_t> fuzzer_binary_out;
  145. protobufs::TransformationSequence fuzzer_transformation_sequence_out;
  146. spvtools::FuzzerOptions fuzzer_options;
  147. spvFuzzerOptionsSetRandomSeed(fuzzer_options, seed);
  148. Fuzzer fuzzer(env);
  149. fuzzer.SetMessageConsumer(kSilentConsumer);
  150. auto fuzzer_result_status =
  151. fuzzer.Run(binary_in, initial_facts, fuzzer_options, &fuzzer_binary_out,
  152. &fuzzer_transformation_sequence_out);
  153. ASSERT_EQ(Fuzzer::FuzzerResultStatus::kComplete, fuzzer_result_status);
  154. ASSERT_TRUE(t.Validate(fuzzer_binary_out));
  155. const uint32_t kReasonableStepLimit = 50;
  156. const uint32_t kSmallStepLimit = 20;
  157. // With the AlwaysInteresting test, we should quickly shrink to the original
  158. // binary with no transformations remaining.
  159. RunAndCheckShrinker(
  160. env, binary_in, initial_facts, fuzzer_transformation_sequence_out,
  161. AlwaysInteresting().AsFunction(), binary_in, 0, kReasonableStepLimit);
  162. // With the OnlyInterestingFirstTime test, no shrinking should be achieved.
  163. RunAndCheckShrinker(
  164. env, binary_in, initial_facts, fuzzer_transformation_sequence_out,
  165. OnlyInterestingFirstTime().AsFunction(), fuzzer_binary_out,
  166. static_cast<uint32_t>(
  167. fuzzer_transformation_sequence_out.transformation_size()),
  168. kReasonableStepLimit);
  169. // The PingPong test is unpredictable; passing an empty expected binary
  170. // means that we don't check anything beyond that shrinking completes
  171. // successfully.
  172. RunAndCheckShrinker(env, binary_in, initial_facts,
  173. fuzzer_transformation_sequence_out,
  174. PingPong().AsFunction(), {}, 0, kSmallStepLimit);
  175. // The InterestingThenRandom test is unpredictable; passing an empty
  176. // expected binary means that we do not check anything about shrinking
  177. // results.
  178. RunAndCheckShrinker(
  179. env, binary_in, initial_facts, fuzzer_transformation_sequence_out,
  180. InterestingThenRandom(PseudoRandomGenerator(seed)).AsFunction(), {}, 0,
  181. kSmallStepLimit);
  182. }
  183. TEST(FuzzerShrinkerTest, Miscellaneous1) {
  184. // The following SPIR-V came from this GLSL:
  185. //
  186. // #version 310 es
  187. //
  188. // void foo() {
  189. // int x;
  190. // x = 2;
  191. // for (int i = 0; i < 100; i++) {
  192. // x += i;
  193. // x = x * 2;
  194. // }
  195. // return;
  196. // }
  197. //
  198. // void main() {
  199. // foo();
  200. // for (int i = 0; i < 10; i++) {
  201. // int j = 20;
  202. // while(j > 0) {
  203. // foo();
  204. // j--;
  205. // }
  206. // do {
  207. // i++;
  208. // } while(i < 4);
  209. // }
  210. // }
  211. const std::string shader = R"(
  212. OpCapability Shader
  213. %1 = OpExtInstImport "GLSL.std.450"
  214. OpMemoryModel Logical GLSL450
  215. OpEntryPoint Fragment %4 "main"
  216. OpExecutionMode %4 OriginUpperLeft
  217. OpSource ESSL 310
  218. OpName %4 "main"
  219. OpName %6 "foo("
  220. OpName %10 "x"
  221. OpName %12 "i"
  222. OpName %33 "i"
  223. OpName %42 "j"
  224. OpDecorate %10 RelaxedPrecision
  225. OpDecorate %12 RelaxedPrecision
  226. OpDecorate %19 RelaxedPrecision
  227. OpDecorate %23 RelaxedPrecision
  228. OpDecorate %24 RelaxedPrecision
  229. OpDecorate %25 RelaxedPrecision
  230. OpDecorate %26 RelaxedPrecision
  231. OpDecorate %27 RelaxedPrecision
  232. OpDecorate %28 RelaxedPrecision
  233. OpDecorate %30 RelaxedPrecision
  234. OpDecorate %33 RelaxedPrecision
  235. OpDecorate %39 RelaxedPrecision
  236. OpDecorate %42 RelaxedPrecision
  237. OpDecorate %49 RelaxedPrecision
  238. OpDecorate %52 RelaxedPrecision
  239. OpDecorate %53 RelaxedPrecision
  240. OpDecorate %58 RelaxedPrecision
  241. OpDecorate %59 RelaxedPrecision
  242. OpDecorate %60 RelaxedPrecision
  243. OpDecorate %63 RelaxedPrecision
  244. OpDecorate %64 RelaxedPrecision
  245. %2 = OpTypeVoid
  246. %3 = OpTypeFunction %2
  247. %8 = OpTypeInt 32 1
  248. %9 = OpTypePointer Function %8
  249. %11 = OpConstant %8 2
  250. %13 = OpConstant %8 0
  251. %20 = OpConstant %8 100
  252. %21 = OpTypeBool
  253. %29 = OpConstant %8 1
  254. %40 = OpConstant %8 10
  255. %43 = OpConstant %8 20
  256. %61 = OpConstant %8 4
  257. %4 = OpFunction %2 None %3
  258. %5 = OpLabel
  259. %33 = OpVariable %9 Function
  260. %42 = OpVariable %9 Function
  261. %32 = OpFunctionCall %2 %6
  262. OpStore %33 %13
  263. OpBranch %34
  264. %34 = OpLabel
  265. OpLoopMerge %36 %37 None
  266. OpBranch %38
  267. %38 = OpLabel
  268. %39 = OpLoad %8 %33
  269. %41 = OpSLessThan %21 %39 %40
  270. OpBranchConditional %41 %35 %36
  271. %35 = OpLabel
  272. OpStore %42 %43
  273. OpBranch %44
  274. %44 = OpLabel
  275. OpLoopMerge %46 %47 None
  276. OpBranch %48
  277. %48 = OpLabel
  278. %49 = OpLoad %8 %42
  279. %50 = OpSGreaterThan %21 %49 %13
  280. OpBranchConditional %50 %45 %46
  281. %45 = OpLabel
  282. %51 = OpFunctionCall %2 %6
  283. %52 = OpLoad %8 %42
  284. %53 = OpISub %8 %52 %29
  285. OpStore %42 %53
  286. OpBranch %47
  287. %47 = OpLabel
  288. OpBranch %44
  289. %46 = OpLabel
  290. OpBranch %54
  291. %54 = OpLabel
  292. OpLoopMerge %56 %57 None
  293. OpBranch %55
  294. %55 = OpLabel
  295. %58 = OpLoad %8 %33
  296. %59 = OpIAdd %8 %58 %29
  297. OpStore %33 %59
  298. OpBranch %57
  299. %57 = OpLabel
  300. %60 = OpLoad %8 %33
  301. %62 = OpSLessThan %21 %60 %61
  302. OpBranchConditional %62 %54 %56
  303. %56 = OpLabel
  304. OpBranch %37
  305. %37 = OpLabel
  306. %63 = OpLoad %8 %33
  307. %64 = OpIAdd %8 %63 %29
  308. OpStore %33 %64
  309. OpBranch %34
  310. %36 = OpLabel
  311. OpReturn
  312. OpFunctionEnd
  313. %6 = OpFunction %2 None %3
  314. %7 = OpLabel
  315. %10 = OpVariable %9 Function
  316. %12 = OpVariable %9 Function
  317. OpStore %10 %11
  318. OpStore %12 %13
  319. OpBranch %14
  320. %14 = OpLabel
  321. OpLoopMerge %16 %17 None
  322. OpBranch %18
  323. %18 = OpLabel
  324. %19 = OpLoad %8 %12
  325. %22 = OpSLessThan %21 %19 %20
  326. OpBranchConditional %22 %15 %16
  327. %15 = OpLabel
  328. %23 = OpLoad %8 %12
  329. %24 = OpLoad %8 %10
  330. %25 = OpIAdd %8 %24 %23
  331. OpStore %10 %25
  332. %26 = OpLoad %8 %10
  333. %27 = OpIMul %8 %26 %11
  334. OpStore %10 %27
  335. OpBranch %17
  336. %17 = OpLabel
  337. %28 = OpLoad %8 %12
  338. %30 = OpIAdd %8 %28 %29
  339. OpStore %12 %30
  340. OpBranch %14
  341. %16 = OpLabel
  342. OpReturn
  343. OpFunctionEnd
  344. )";
  345. RunFuzzerAndShrinker(shader, protobufs::FactSequence(), 2);
  346. }
  347. TEST(FuzzerShrinkerTest, Miscellaneous2) {
  348. // The following SPIR-V came from this GLSL, which was then optimized using
  349. // spirv-opt with the -O argument:
  350. //
  351. // #version 310 es
  352. //
  353. // precision highp float;
  354. //
  355. // layout(location = 0) out vec4 _GLF_color;
  356. //
  357. // layout(set = 0, binding = 0) uniform buf0 {
  358. // vec2 injectionSwitch;
  359. // };
  360. // layout(set = 0, binding = 1) uniform buf1 {
  361. // vec2 resolution;
  362. // };
  363. // bool checkSwap(float a, float b)
  364. // {
  365. // return gl_FragCoord.y < resolution.y / 2.0 ? a > b : a < b;
  366. // }
  367. // void main()
  368. // {
  369. // float data[10];
  370. // for(int i = 0; i < 10; i++)
  371. // {
  372. // data[i] = float(10 - i) * injectionSwitch.y;
  373. // }
  374. // for(int i = 0; i < 9; i++)
  375. // {
  376. // for(int j = 0; j < 10; j++)
  377. // {
  378. // if(j < i + 1)
  379. // {
  380. // continue;
  381. // }
  382. // bool doSwap = checkSwap(data[i], data[j]);
  383. // if(doSwap)
  384. // {
  385. // float temp = data[i];
  386. // data[i] = data[j];
  387. // data[j] = temp;
  388. // }
  389. // }
  390. // }
  391. // if(gl_FragCoord.x < resolution.x / 2.0)
  392. // {
  393. // _GLF_color = vec4(data[0] / 10.0, data[5] / 10.0, data[9] / 10.0, 1.0);
  394. // }
  395. // else
  396. // {
  397. // _GLF_color = vec4(data[5] / 10.0, data[9] / 10.0, data[0] / 10.0, 1.0);
  398. // }
  399. // }
  400. const std::string shader = R"(
  401. OpCapability Shader
  402. %1 = OpExtInstImport "GLSL.std.450"
  403. OpMemoryModel Logical GLSL450
  404. OpEntryPoint Fragment %4 "main" %16 %139 %25 %68
  405. OpExecutionMode %4 OriginUpperLeft
  406. OpSource ESSL 310
  407. OpName %4 "main"
  408. OpName %16 "gl_FragCoord"
  409. OpName %23 "buf1"
  410. OpMemberName %23 0 "resolution"
  411. OpName %25 ""
  412. OpName %61 "data"
  413. OpName %66 "buf0"
  414. OpMemberName %66 0 "injectionSwitch"
  415. OpName %68 ""
  416. OpName %139 "_GLF_color"
  417. OpDecorate %16 BuiltIn FragCoord
  418. OpMemberDecorate %23 0 Offset 0
  419. OpDecorate %23 Block
  420. OpDecorate %25 DescriptorSet 0
  421. OpDecorate %25 Binding 1
  422. OpDecorate %64 RelaxedPrecision
  423. OpMemberDecorate %66 0 Offset 0
  424. OpDecorate %66 Block
  425. OpDecorate %68 DescriptorSet 0
  426. OpDecorate %68 Binding 0
  427. OpDecorate %75 RelaxedPrecision
  428. OpDecorate %95 RelaxedPrecision
  429. OpDecorate %126 RelaxedPrecision
  430. OpDecorate %128 RelaxedPrecision
  431. OpDecorate %139 Location 0
  432. OpDecorate %182 RelaxedPrecision
  433. OpDecorate %183 RelaxedPrecision
  434. OpDecorate %184 RelaxedPrecision
  435. %2 = OpTypeVoid
  436. %3 = OpTypeFunction %2
  437. %6 = OpTypeFloat 32
  438. %7 = OpTypePointer Function %6
  439. %8 = OpTypeBool
  440. %14 = OpTypeVector %6 4
  441. %15 = OpTypePointer Input %14
  442. %16 = OpVariable %15 Input
  443. %17 = OpTypeInt 32 0
  444. %18 = OpConstant %17 1
  445. %19 = OpTypePointer Input %6
  446. %22 = OpTypeVector %6 2
  447. %23 = OpTypeStruct %22
  448. %24 = OpTypePointer Uniform %23
  449. %25 = OpVariable %24 Uniform
  450. %26 = OpTypeInt 32 1
  451. %27 = OpConstant %26 0
  452. %28 = OpTypePointer Uniform %6
  453. %56 = OpConstant %26 10
  454. %58 = OpConstant %17 10
  455. %59 = OpTypeArray %6 %58
  456. %60 = OpTypePointer Function %59
  457. %66 = OpTypeStruct %22
  458. %67 = OpTypePointer Uniform %66
  459. %68 = OpVariable %67 Uniform
  460. %74 = OpConstant %26 1
  461. %83 = OpConstant %26 9
  462. %129 = OpConstant %17 0
  463. %138 = OpTypePointer Output %14
  464. %139 = OpVariable %138 Output
  465. %144 = OpConstant %26 5
  466. %151 = OpConstant %6 1
  467. %194 = OpConstant %6 0.5
  468. %195 = OpConstant %6 0.100000001
  469. %4 = OpFunction %2 None %3
  470. %5 = OpLabel
  471. %61 = OpVariable %60 Function
  472. OpBranch %50
  473. %50 = OpLabel
  474. %182 = OpPhi %26 %27 %5 %75 %51
  475. %57 = OpSLessThan %8 %182 %56
  476. OpLoopMerge %52 %51 None
  477. OpBranchConditional %57 %51 %52
  478. %51 = OpLabel
  479. %64 = OpISub %26 %56 %182
  480. %65 = OpConvertSToF %6 %64
  481. %69 = OpAccessChain %28 %68 %27 %18
  482. %70 = OpLoad %6 %69
  483. %71 = OpFMul %6 %65 %70
  484. %72 = OpAccessChain %7 %61 %182
  485. OpStore %72 %71
  486. %75 = OpIAdd %26 %182 %74
  487. OpBranch %50
  488. %52 = OpLabel
  489. OpBranch %77
  490. %77 = OpLabel
  491. %183 = OpPhi %26 %27 %52 %128 %88
  492. %84 = OpSLessThan %8 %183 %83
  493. OpLoopMerge %79 %88 None
  494. OpBranchConditional %84 %78 %79
  495. %78 = OpLabel
  496. OpBranch %86
  497. %86 = OpLabel
  498. %184 = OpPhi %26 %27 %78 %126 %89
  499. %92 = OpSLessThan %8 %184 %56
  500. OpLoopMerge %88 %89 None
  501. OpBranchConditional %92 %87 %88
  502. %87 = OpLabel
  503. %95 = OpIAdd %26 %183 %74
  504. %96 = OpSLessThan %8 %184 %95
  505. OpSelectionMerge %98 None
  506. OpBranchConditional %96 %97 %98
  507. %97 = OpLabel
  508. OpBranch %89
  509. %98 = OpLabel
  510. %104 = OpAccessChain %7 %61 %183
  511. %105 = OpLoad %6 %104
  512. %107 = OpAccessChain %7 %61 %184
  513. %108 = OpLoad %6 %107
  514. %166 = OpAccessChain %19 %16 %18
  515. %167 = OpLoad %6 %166
  516. %168 = OpAccessChain %28 %25 %27 %18
  517. %169 = OpLoad %6 %168
  518. %170 = OpFMul %6 %169 %194
  519. %171 = OpFOrdLessThan %8 %167 %170
  520. OpSelectionMerge %172 None
  521. OpBranchConditional %171 %173 %174
  522. %173 = OpLabel
  523. %177 = OpFOrdGreaterThan %8 %105 %108
  524. OpBranch %172
  525. %174 = OpLabel
  526. %180 = OpFOrdLessThan %8 %105 %108
  527. OpBranch %172
  528. %172 = OpLabel
  529. %186 = OpPhi %8 %177 %173 %180 %174
  530. OpSelectionMerge %112 None
  531. OpBranchConditional %186 %111 %112
  532. %111 = OpLabel
  533. %116 = OpLoad %6 %104
  534. %120 = OpLoad %6 %107
  535. OpStore %104 %120
  536. OpStore %107 %116
  537. OpBranch %112
  538. %112 = OpLabel
  539. OpBranch %89
  540. %89 = OpLabel
  541. %126 = OpIAdd %26 %184 %74
  542. OpBranch %86
  543. %88 = OpLabel
  544. %128 = OpIAdd %26 %183 %74
  545. OpBranch %77
  546. %79 = OpLabel
  547. %130 = OpAccessChain %19 %16 %129
  548. %131 = OpLoad %6 %130
  549. %132 = OpAccessChain %28 %25 %27 %129
  550. %133 = OpLoad %6 %132
  551. %134 = OpFMul %6 %133 %194
  552. %135 = OpFOrdLessThan %8 %131 %134
  553. OpSelectionMerge %137 None
  554. OpBranchConditional %135 %136 %153
  555. %136 = OpLabel
  556. %140 = OpAccessChain %7 %61 %27
  557. %141 = OpLoad %6 %140
  558. %143 = OpFMul %6 %141 %195
  559. %145 = OpAccessChain %7 %61 %144
  560. %146 = OpLoad %6 %145
  561. %147 = OpFMul %6 %146 %195
  562. %148 = OpAccessChain %7 %61 %83
  563. %149 = OpLoad %6 %148
  564. %150 = OpFMul %6 %149 %195
  565. %152 = OpCompositeConstruct %14 %143 %147 %150 %151
  566. OpStore %139 %152
  567. OpBranch %137
  568. %153 = OpLabel
  569. %154 = OpAccessChain %7 %61 %144
  570. %155 = OpLoad %6 %154
  571. %156 = OpFMul %6 %155 %195
  572. %157 = OpAccessChain %7 %61 %83
  573. %158 = OpLoad %6 %157
  574. %159 = OpFMul %6 %158 %195
  575. %160 = OpAccessChain %7 %61 %27
  576. %161 = OpLoad %6 %160
  577. %162 = OpFMul %6 %161 %195
  578. %163 = OpCompositeConstruct %14 %156 %159 %162 %151
  579. OpStore %139 %163
  580. OpBranch %137
  581. %137 = OpLabel
  582. OpReturn
  583. OpFunctionEnd
  584. )";
  585. RunFuzzerAndShrinker(shader, protobufs::FactSequence(), 19);
  586. }
  587. TEST(FuzzerShrinkerTest, Miscellaneous3) {
  588. // The following SPIR-V came from this GLSL, which was then optimized using
  589. // spirv-opt with the -O argument:
  590. //
  591. // #version 310 es
  592. //
  593. // precision highp float;
  594. //
  595. // layout(location = 0) out vec4 _GLF_color;
  596. //
  597. // layout(set = 0, binding = 0) uniform buf0 {
  598. // vec2 resolution;
  599. // };
  600. // void main(void)
  601. // {
  602. // float A[50];
  603. // for(
  604. // int i = 0;
  605. // i < 200;
  606. // i ++
  607. // )
  608. // {
  609. // if(i >= int(resolution.x))
  610. // {
  611. // break;
  612. // }
  613. // if((4 * (i / 4)) == i)
  614. // {
  615. // A[i / 4] = float(i);
  616. // }
  617. // }
  618. // for(
  619. // int i = 0;
  620. // i < 50;
  621. // i ++
  622. // )
  623. // {
  624. // if(i < int(gl_FragCoord.x))
  625. // {
  626. // break;
  627. // }
  628. // if(i > 0)
  629. // {
  630. // A[i] += A[i - 1];
  631. // }
  632. // }
  633. // if(int(gl_FragCoord.x) < 20)
  634. // {
  635. // _GLF_color = vec4(A[0] / resolution.x, A[4] / resolution.y, 1.0, 1.0);
  636. // }
  637. // else
  638. // if(int(gl_FragCoord.x) < 40)
  639. // {
  640. // _GLF_color = vec4(A[5] / resolution.x, A[9] / resolution.y, 1.0, 1.0);
  641. // }
  642. // else
  643. // if(int(gl_FragCoord.x) < 60)
  644. // {
  645. // _GLF_color = vec4(A[10] / resolution.x, A[14] / resolution.y,
  646. // 1.0, 1.0);
  647. // }
  648. // else
  649. // if(int(gl_FragCoord.x) < 80)
  650. // {
  651. // _GLF_color = vec4(A[15] / resolution.x, A[19] / resolution.y,
  652. // 1.0, 1.0);
  653. // }
  654. // else
  655. // if(int(gl_FragCoord.x) < 100)
  656. // {
  657. // _GLF_color = vec4(A[20] / resolution.x, A[24] / resolution.y,
  658. // 1.0, 1.0);
  659. // }
  660. // else
  661. // if(int(gl_FragCoord.x) < 120)
  662. // {
  663. // _GLF_color = vec4(A[25] / resolution.x, A[29] / resolution.y,
  664. // 1.0, 1.0);
  665. // }
  666. // else
  667. // if(int(gl_FragCoord.x) < 140)
  668. // {
  669. // _GLF_color = vec4(A[30] / resolution.x, A[34] / resolution.y,
  670. // 1.0, 1.0);
  671. // }
  672. // else
  673. // if(int(gl_FragCoord.x) < 160)
  674. // {
  675. // _GLF_color = vec4(A[35] / resolution.x, A[39] /
  676. // resolution.y, 1.0, 1.0);
  677. // }
  678. // else
  679. // if(int(gl_FragCoord.x) < 180)
  680. // {
  681. // _GLF_color = vec4(A[40] / resolution.x, A[44] /
  682. // resolution.y, 1.0, 1.0);
  683. // }
  684. // else
  685. // if(int(gl_FragCoord.x) < 180)
  686. // {
  687. // _GLF_color = vec4(A[45] / resolution.x, A[49] /
  688. // resolution.y, 1.0, 1.0);
  689. // }
  690. // else
  691. // {
  692. // discard;
  693. // }
  694. // }
  695. const std::string shader = R"(
  696. OpCapability Shader
  697. %1 = OpExtInstImport "GLSL.std.450"
  698. OpMemoryModel Logical GLSL450
  699. OpEntryPoint Fragment %4 "main" %68 %100 %24
  700. OpExecutionMode %4 OriginUpperLeft
  701. OpSource ESSL 310
  702. OpName %4 "main"
  703. OpName %22 "buf0"
  704. OpMemberName %22 0 "resolution"
  705. OpName %24 ""
  706. OpName %46 "A"
  707. OpName %68 "gl_FragCoord"
  708. OpName %100 "_GLF_color"
  709. OpMemberDecorate %22 0 Offset 0
  710. OpDecorate %22 Block
  711. OpDecorate %24 DescriptorSet 0
  712. OpDecorate %24 Binding 0
  713. OpDecorate %37 RelaxedPrecision
  714. OpDecorate %38 RelaxedPrecision
  715. OpDecorate %55 RelaxedPrecision
  716. OpDecorate %68 BuiltIn FragCoord
  717. OpDecorate %83 RelaxedPrecision
  718. OpDecorate %91 RelaxedPrecision
  719. OpDecorate %100 Location 0
  720. OpDecorate %302 RelaxedPrecision
  721. OpDecorate %304 RelaxedPrecision
  722. %2 = OpTypeVoid
  723. %3 = OpTypeFunction %2
  724. %6 = OpTypeInt 32 1
  725. %9 = OpConstant %6 0
  726. %16 = OpConstant %6 200
  727. %17 = OpTypeBool
  728. %20 = OpTypeFloat 32
  729. %21 = OpTypeVector %20 2
  730. %22 = OpTypeStruct %21
  731. %23 = OpTypePointer Uniform %22
  732. %24 = OpVariable %23 Uniform
  733. %25 = OpTypeInt 32 0
  734. %26 = OpConstant %25 0
  735. %27 = OpTypePointer Uniform %20
  736. %35 = OpConstant %6 4
  737. %43 = OpConstant %25 50
  738. %44 = OpTypeArray %20 %43
  739. %45 = OpTypePointer Function %44
  740. %51 = OpTypePointer Function %20
  741. %54 = OpConstant %6 1
  742. %63 = OpConstant %6 50
  743. %66 = OpTypeVector %20 4
  744. %67 = OpTypePointer Input %66
  745. %68 = OpVariable %67 Input
  746. %69 = OpTypePointer Input %20
  747. %95 = OpConstant %6 20
  748. %99 = OpTypePointer Output %66
  749. %100 = OpVariable %99 Output
  750. %108 = OpConstant %25 1
  751. %112 = OpConstant %20 1
  752. %118 = OpConstant %6 40
  753. %122 = OpConstant %6 5
  754. %128 = OpConstant %6 9
  755. %139 = OpConstant %6 60
  756. %143 = OpConstant %6 10
  757. %149 = OpConstant %6 14
  758. %160 = OpConstant %6 80
  759. %164 = OpConstant %6 15
  760. %170 = OpConstant %6 19
  761. %181 = OpConstant %6 100
  762. %190 = OpConstant %6 24
  763. %201 = OpConstant %6 120
  764. %205 = OpConstant %6 25
  765. %211 = OpConstant %6 29
  766. %222 = OpConstant %6 140
  767. %226 = OpConstant %6 30
  768. %232 = OpConstant %6 34
  769. %243 = OpConstant %6 160
  770. %247 = OpConstant %6 35
  771. %253 = OpConstant %6 39
  772. %264 = OpConstant %6 180
  773. %273 = OpConstant %6 44
  774. %287 = OpConstant %6 45
  775. %293 = OpConstant %6 49
  776. %4 = OpFunction %2 None %3
  777. %5 = OpLabel
  778. %46 = OpVariable %45 Function
  779. OpBranch %10
  780. %10 = OpLabel
  781. %302 = OpPhi %6 %9 %5 %55 %42
  782. %18 = OpSLessThan %17 %302 %16
  783. OpLoopMerge %12 %42 None
  784. OpBranchConditional %18 %11 %12
  785. %11 = OpLabel
  786. %28 = OpAccessChain %27 %24 %9 %26
  787. %29 = OpLoad %20 %28
  788. %30 = OpConvertFToS %6 %29
  789. %31 = OpSGreaterThanEqual %17 %302 %30
  790. OpSelectionMerge %33 None
  791. OpBranchConditional %31 %32 %33
  792. %32 = OpLabel
  793. OpBranch %12
  794. %33 = OpLabel
  795. %37 = OpSDiv %6 %302 %35
  796. %38 = OpIMul %6 %35 %37
  797. %40 = OpIEqual %17 %38 %302
  798. OpSelectionMerge %42 None
  799. OpBranchConditional %40 %41 %42
  800. %41 = OpLabel
  801. %50 = OpConvertSToF %20 %302
  802. %52 = OpAccessChain %51 %46 %37
  803. OpStore %52 %50
  804. OpBranch %42
  805. %42 = OpLabel
  806. %55 = OpIAdd %6 %302 %54
  807. OpBranch %10
  808. %12 = OpLabel
  809. OpBranch %57
  810. %57 = OpLabel
  811. %304 = OpPhi %6 %9 %12 %91 %80
  812. %64 = OpSLessThan %17 %304 %63
  813. OpLoopMerge %59 %80 None
  814. OpBranchConditional %64 %58 %59
  815. %58 = OpLabel
  816. %70 = OpAccessChain %69 %68 %26
  817. %71 = OpLoad %20 %70
  818. %72 = OpConvertFToS %6 %71
  819. %73 = OpSLessThan %17 %304 %72
  820. OpSelectionMerge %75 None
  821. OpBranchConditional %73 %74 %75
  822. %74 = OpLabel
  823. OpBranch %59
  824. %75 = OpLabel
  825. %78 = OpSGreaterThan %17 %304 %9
  826. OpSelectionMerge %80 None
  827. OpBranchConditional %78 %79 %80
  828. %79 = OpLabel
  829. %83 = OpISub %6 %304 %54
  830. %84 = OpAccessChain %51 %46 %83
  831. %85 = OpLoad %20 %84
  832. %86 = OpAccessChain %51 %46 %304
  833. %87 = OpLoad %20 %86
  834. %88 = OpFAdd %20 %87 %85
  835. OpStore %86 %88
  836. OpBranch %80
  837. %80 = OpLabel
  838. %91 = OpIAdd %6 %304 %54
  839. OpBranch %57
  840. %59 = OpLabel
  841. %92 = OpAccessChain %69 %68 %26
  842. %93 = OpLoad %20 %92
  843. %94 = OpConvertFToS %6 %93
  844. %96 = OpSLessThan %17 %94 %95
  845. OpSelectionMerge %98 None
  846. OpBranchConditional %96 %97 %114
  847. %97 = OpLabel
  848. %101 = OpAccessChain %51 %46 %9
  849. %102 = OpLoad %20 %101
  850. %103 = OpAccessChain %27 %24 %9 %26
  851. %104 = OpLoad %20 %103
  852. %105 = OpFDiv %20 %102 %104
  853. %106 = OpAccessChain %51 %46 %35
  854. %107 = OpLoad %20 %106
  855. %109 = OpAccessChain %27 %24 %9 %108
  856. %110 = OpLoad %20 %109
  857. %111 = OpFDiv %20 %107 %110
  858. %113 = OpCompositeConstruct %66 %105 %111 %112 %112
  859. OpStore %100 %113
  860. OpBranch %98
  861. %114 = OpLabel
  862. %119 = OpSLessThan %17 %94 %118
  863. OpSelectionMerge %121 None
  864. OpBranchConditional %119 %120 %135
  865. %120 = OpLabel
  866. %123 = OpAccessChain %51 %46 %122
  867. %124 = OpLoad %20 %123
  868. %125 = OpAccessChain %27 %24 %9 %26
  869. %126 = OpLoad %20 %125
  870. %127 = OpFDiv %20 %124 %126
  871. %129 = OpAccessChain %51 %46 %128
  872. %130 = OpLoad %20 %129
  873. %131 = OpAccessChain %27 %24 %9 %108
  874. %132 = OpLoad %20 %131
  875. %133 = OpFDiv %20 %130 %132
  876. %134 = OpCompositeConstruct %66 %127 %133 %112 %112
  877. OpStore %100 %134
  878. OpBranch %121
  879. %135 = OpLabel
  880. %140 = OpSLessThan %17 %94 %139
  881. OpSelectionMerge %142 None
  882. OpBranchConditional %140 %141 %156
  883. %141 = OpLabel
  884. %144 = OpAccessChain %51 %46 %143
  885. %145 = OpLoad %20 %144
  886. %146 = OpAccessChain %27 %24 %9 %26
  887. %147 = OpLoad %20 %146
  888. %148 = OpFDiv %20 %145 %147
  889. %150 = OpAccessChain %51 %46 %149
  890. %151 = OpLoad %20 %150
  891. %152 = OpAccessChain %27 %24 %9 %108
  892. %153 = OpLoad %20 %152
  893. %154 = OpFDiv %20 %151 %153
  894. %155 = OpCompositeConstruct %66 %148 %154 %112 %112
  895. OpStore %100 %155
  896. OpBranch %142
  897. %156 = OpLabel
  898. %161 = OpSLessThan %17 %94 %160
  899. OpSelectionMerge %163 None
  900. OpBranchConditional %161 %162 %177
  901. %162 = OpLabel
  902. %165 = OpAccessChain %51 %46 %164
  903. %166 = OpLoad %20 %165
  904. %167 = OpAccessChain %27 %24 %9 %26
  905. %168 = OpLoad %20 %167
  906. %169 = OpFDiv %20 %166 %168
  907. %171 = OpAccessChain %51 %46 %170
  908. %172 = OpLoad %20 %171
  909. %173 = OpAccessChain %27 %24 %9 %108
  910. %174 = OpLoad %20 %173
  911. %175 = OpFDiv %20 %172 %174
  912. %176 = OpCompositeConstruct %66 %169 %175 %112 %112
  913. OpStore %100 %176
  914. OpBranch %163
  915. %177 = OpLabel
  916. %182 = OpSLessThan %17 %94 %181
  917. OpSelectionMerge %184 None
  918. OpBranchConditional %182 %183 %197
  919. %183 = OpLabel
  920. %185 = OpAccessChain %51 %46 %95
  921. %186 = OpLoad %20 %185
  922. %187 = OpAccessChain %27 %24 %9 %26
  923. %188 = OpLoad %20 %187
  924. %189 = OpFDiv %20 %186 %188
  925. %191 = OpAccessChain %51 %46 %190
  926. %192 = OpLoad %20 %191
  927. %193 = OpAccessChain %27 %24 %9 %108
  928. %194 = OpLoad %20 %193
  929. %195 = OpFDiv %20 %192 %194
  930. %196 = OpCompositeConstruct %66 %189 %195 %112 %112
  931. OpStore %100 %196
  932. OpBranch %184
  933. %197 = OpLabel
  934. %202 = OpSLessThan %17 %94 %201
  935. OpSelectionMerge %204 None
  936. OpBranchConditional %202 %203 %218
  937. %203 = OpLabel
  938. %206 = OpAccessChain %51 %46 %205
  939. %207 = OpLoad %20 %206
  940. %208 = OpAccessChain %27 %24 %9 %26
  941. %209 = OpLoad %20 %208
  942. %210 = OpFDiv %20 %207 %209
  943. %212 = OpAccessChain %51 %46 %211
  944. %213 = OpLoad %20 %212
  945. %214 = OpAccessChain %27 %24 %9 %108
  946. %215 = OpLoad %20 %214
  947. %216 = OpFDiv %20 %213 %215
  948. %217 = OpCompositeConstruct %66 %210 %216 %112 %112
  949. OpStore %100 %217
  950. OpBranch %204
  951. %218 = OpLabel
  952. %223 = OpSLessThan %17 %94 %222
  953. OpSelectionMerge %225 None
  954. OpBranchConditional %223 %224 %239
  955. %224 = OpLabel
  956. %227 = OpAccessChain %51 %46 %226
  957. %228 = OpLoad %20 %227
  958. %229 = OpAccessChain %27 %24 %9 %26
  959. %230 = OpLoad %20 %229
  960. %231 = OpFDiv %20 %228 %230
  961. %233 = OpAccessChain %51 %46 %232
  962. %234 = OpLoad %20 %233
  963. %235 = OpAccessChain %27 %24 %9 %108
  964. %236 = OpLoad %20 %235
  965. %237 = OpFDiv %20 %234 %236
  966. %238 = OpCompositeConstruct %66 %231 %237 %112 %112
  967. OpStore %100 %238
  968. OpBranch %225
  969. %239 = OpLabel
  970. %244 = OpSLessThan %17 %94 %243
  971. OpSelectionMerge %246 None
  972. OpBranchConditional %244 %245 %260
  973. %245 = OpLabel
  974. %248 = OpAccessChain %51 %46 %247
  975. %249 = OpLoad %20 %248
  976. %250 = OpAccessChain %27 %24 %9 %26
  977. %251 = OpLoad %20 %250
  978. %252 = OpFDiv %20 %249 %251
  979. %254 = OpAccessChain %51 %46 %253
  980. %255 = OpLoad %20 %254
  981. %256 = OpAccessChain %27 %24 %9 %108
  982. %257 = OpLoad %20 %256
  983. %258 = OpFDiv %20 %255 %257
  984. %259 = OpCompositeConstruct %66 %252 %258 %112 %112
  985. OpStore %100 %259
  986. OpBranch %246
  987. %260 = OpLabel
  988. %265 = OpSLessThan %17 %94 %264
  989. OpSelectionMerge %267 None
  990. OpBranchConditional %265 %266 %280
  991. %266 = OpLabel
  992. %268 = OpAccessChain %51 %46 %118
  993. %269 = OpLoad %20 %268
  994. %270 = OpAccessChain %27 %24 %9 %26
  995. %271 = OpLoad %20 %270
  996. %272 = OpFDiv %20 %269 %271
  997. %274 = OpAccessChain %51 %46 %273
  998. %275 = OpLoad %20 %274
  999. %276 = OpAccessChain %27 %24 %9 %108
  1000. %277 = OpLoad %20 %276
  1001. %278 = OpFDiv %20 %275 %277
  1002. %279 = OpCompositeConstruct %66 %272 %278 %112 %112
  1003. OpStore %100 %279
  1004. OpBranch %267
  1005. %280 = OpLabel
  1006. OpSelectionMerge %285 None
  1007. OpBranchConditional %265 %285 %300
  1008. %285 = OpLabel
  1009. %288 = OpAccessChain %51 %46 %287
  1010. %289 = OpLoad %20 %288
  1011. %290 = OpAccessChain %27 %24 %9 %26
  1012. %291 = OpLoad %20 %290
  1013. %292 = OpFDiv %20 %289 %291
  1014. %294 = OpAccessChain %51 %46 %293
  1015. %295 = OpLoad %20 %294
  1016. %296 = OpAccessChain %27 %24 %9 %108
  1017. %297 = OpLoad %20 %296
  1018. %298 = OpFDiv %20 %295 %297
  1019. %299 = OpCompositeConstruct %66 %292 %298 %112 %112
  1020. OpStore %100 %299
  1021. OpBranch %267
  1022. %300 = OpLabel
  1023. OpKill
  1024. %267 = OpLabel
  1025. OpBranch %246
  1026. %246 = OpLabel
  1027. OpBranch %225
  1028. %225 = OpLabel
  1029. OpBranch %204
  1030. %204 = OpLabel
  1031. OpBranch %184
  1032. %184 = OpLabel
  1033. OpBranch %163
  1034. %163 = OpLabel
  1035. OpBranch %142
  1036. %142 = OpLabel
  1037. OpBranch %121
  1038. %121 = OpLabel
  1039. OpBranch %98
  1040. %98 = OpLabel
  1041. OpReturn
  1042. OpFunctionEnd
  1043. )";
  1044. // Add the facts "resolution.x == 250" and "resolution.y == 100".
  1045. protobufs::FactSequence facts;
  1046. {
  1047. protobufs::FactConstantUniform resolution_x_eq_250;
  1048. *resolution_x_eq_250.mutable_uniform_buffer_element_descriptor() =
  1049. MakeUniformBufferElementDescriptor(0, 0, {0, 0});
  1050. *resolution_x_eq_250.mutable_constant_word()->Add() = 250;
  1051. protobufs::Fact temp;
  1052. *temp.mutable_constant_uniform_fact() = resolution_x_eq_250;
  1053. *facts.mutable_fact()->Add() = temp;
  1054. }
  1055. {
  1056. protobufs::FactConstantUniform resolution_y_eq_100;
  1057. *resolution_y_eq_100.mutable_uniform_buffer_element_descriptor() =
  1058. MakeUniformBufferElementDescriptor(0, 0, {0, 1});
  1059. *resolution_y_eq_100.mutable_constant_word()->Add() = 100;
  1060. protobufs::Fact temp;
  1061. *temp.mutable_constant_uniform_fact() = resolution_y_eq_100;
  1062. *facts.mutable_fact()->Add() = temp;
  1063. }
  1064. // Do 2 fuzzer runs, starting from an initial seed of 194 (seed value chosen
  1065. // arbitrarily).
  1066. RunFuzzerAndShrinker(shader, facts, 194);
  1067. }
  1068. } // namespace
  1069. } // namespace fuzz
  1070. } // namespace spvtools