available_instructions_test.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. // Copyright (c) 2021 Alastair F. Donaldson
  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/available_instructions.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(AvailableInstructionsTest, 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 320
  29. %2 = OpTypeVoid
  30. %3 = OpTypeFunction %2
  31. %6 = OpTypeInt 32 1
  32. %7 = OpTypePointer Function %6
  33. %8 = OpTypeFloat 32
  34. %9 = OpTypePointer Function %8
  35. %10 = OpTypeFunction %6 %7 %9
  36. %15 = OpTypeVector %8 2
  37. %16 = OpTypePointer Private %15
  38. %17 = OpVariable %16 Private
  39. %18 = OpConstant %8 1
  40. %19 = OpConstant %8 2
  41. %20 = OpConstantComposite %15 %18 %19
  42. %21 = OpTypeVector %8 4
  43. %22 = OpTypePointer Private %21
  44. %23 = OpVariable %22 Private
  45. %24 = OpConstant %8 10
  46. %25 = OpConstant %8 20
  47. %26 = OpConstant %8 30
  48. %27 = OpConstant %8 40
  49. %28 = OpConstantComposite %21 %24 %25 %26 %27
  50. %31 = OpTypeInt 32 0
  51. %32 = OpConstant %31 0
  52. %33 = OpTypePointer Private %8
  53. %41 = OpTypeBool
  54. %46 = OpConstant %6 1
  55. %54 = OpConstant %6 10
  56. %57 = OpConstant %31 3
  57. %61 = OpConstant %6 0
  58. %66 = OpConstant %6 3
  59. %4 = OpFunction %2 None %3
  60. %5 = OpLabel
  61. %55 = OpVariable %7 Function
  62. %56 = OpVariable %9 Function
  63. %65 = OpVariable %7 Function
  64. %68 = OpVariable %7 Function
  65. OpStore %17 %20
  66. OpStore %23 %28
  67. OpStore %55 %54
  68. %58 = OpAccessChain %33 %23 %57
  69. %59 = OpLoad %8 %58
  70. OpStore %56 %59
  71. %60 = OpFunctionCall %6 %13 %55 %56
  72. %100 = OpCopyObject %21 %28
  73. %62 = OpSGreaterThan %41 %60 %61
  74. OpSelectionMerge %64 None
  75. OpBranchConditional %62 %63 %67
  76. %63 = OpLabel
  77. OpStore %65 %66
  78. %101 = OpCopyObject %21 %28
  79. OpBranch %64
  80. %67 = OpLabel
  81. OpStore %68 %61
  82. OpBranch %69
  83. %69 = OpLabel
  84. OpLoopMerge %71 %72 None
  85. OpBranch %73
  86. %73 = OpLabel
  87. %74 = OpLoad %6 %68
  88. %75 = OpSLessThan %41 %74 %54
  89. OpBranchConditional %75 %70 %71
  90. %70 = OpLabel
  91. %76 = OpLoad %6 %65
  92. %77 = OpIAdd %6 %76 %46
  93. OpStore %65 %77
  94. OpBranch %72
  95. %72 = OpLabel
  96. %78 = OpLoad %6 %68
  97. %79 = OpIAdd %6 %78 %46
  98. OpStore %68 %79
  99. OpBranch %69
  100. %71 = OpLabel
  101. %102 = OpCopyObject %21 %28
  102. OpBranch %64
  103. %64 = OpLabel
  104. OpReturn
  105. OpFunctionEnd
  106. %13 = OpFunction %6 None %10
  107. %11 = OpFunctionParameter %7
  108. %12 = OpFunctionParameter %9
  109. %14 = OpLabel
  110. %29 = OpVariable %7 Function
  111. %30 = OpLoad %6 %11
  112. %34 = OpAccessChain %33 %17 %32
  113. %35 = OpLoad %8 %34
  114. %36 = OpConvertFToS %6 %35
  115. %37 = OpIAdd %6 %30 %36
  116. OpStore %29 %37
  117. %38 = OpLoad %6 %11
  118. %39 = OpLoad %8 %12
  119. %40 = OpConvertFToS %6 %39
  120. %42 = OpSLessThan %41 %38 %40
  121. %103 = OpCopyObject %21 %28
  122. OpSelectionMerge %44 None
  123. OpBranchConditional %42 %43 %48
  124. %43 = OpLabel
  125. %45 = OpLoad %6 %29
  126. %47 = OpIAdd %6 %45 %46
  127. OpStore %29 %47
  128. OpBranch %44
  129. %48 = OpLabel
  130. %49 = OpLoad %6 %29
  131. %50 = OpISub %6 %49 %46
  132. OpStore %29 %50
  133. OpBranch %44
  134. %44 = OpLabel
  135. %51 = OpLoad %6 %29
  136. OpReturnValue %51
  137. OpFunctionEnd
  138. )";
  139. const auto env = SPV_ENV_UNIVERSAL_1_3;
  140. const auto consumer = nullptr;
  141. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  142. spvtools::ValidatorOptions validator_options;
  143. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  144. kConsoleMessageConsumer));
  145. opt::Instruction* i1 = context->get_def_use_mgr()->GetDef(55);
  146. opt::Instruction* i2 = context->get_def_use_mgr()->GetDef(101);
  147. opt::Instruction* i3 = &*context->cfg()->block(67)->begin();
  148. opt::Instruction* i4 = context->get_def_use_mgr()->GetDef(74);
  149. opt::Instruction* i5 = context->get_def_use_mgr()->GetDef(102);
  150. opt::Instruction* i6 = context->get_def_use_mgr()->GetDef(30);
  151. opt::Instruction* i7 = context->get_def_use_mgr()->GetDef(47);
  152. opt::Instruction* i8 = context->get_def_use_mgr()->GetDef(50);
  153. opt::Instruction* i9 = context->get_def_use_mgr()->GetDef(51);
  154. {
  155. AvailableInstructions no_instructions(
  156. context.get(),
  157. [](opt::IRContext*, opt::Instruction*) -> bool { return false; });
  158. for (auto i : {i1, i2, i3, i4, i5, i6, i7, i8, i9}) {
  159. auto available = no_instructions.GetAvailableBeforeInstruction(i);
  160. ASSERT_EQ(0, available.size());
  161. ASSERT_TRUE(available.empty());
  162. }
  163. }
  164. {
  165. AvailableInstructions all_instructions(
  166. context.get(),
  167. [](opt::IRContext*, opt::Instruction*) -> bool { return true; });
  168. {
  169. auto available = all_instructions.GetAvailableBeforeInstruction(i1);
  170. ASSERT_FALSE(available.empty());
  171. ASSERT_EQ(30, available.size());
  172. ASSERT_EQ(spv::Op::OpTypeVoid, available[0]->opcode());
  173. ASSERT_EQ(spv::Op::OpVariable, available[15]->opcode());
  174. }
  175. {
  176. auto available = all_instructions.GetAvailableBeforeInstruction(i2);
  177. ASSERT_FALSE(available.empty());
  178. ASSERT_EQ(46, available.size());
  179. ASSERT_EQ(spv::Op::OpTypeVoid, available[0]->opcode());
  180. ASSERT_EQ(spv::Op::OpTypePointer, available[3]->opcode());
  181. ASSERT_EQ(spv::Op::OpVariable, available[15]->opcode());
  182. ASSERT_EQ(spv::Op::OpFunctionCall, available[40]->opcode());
  183. ASSERT_EQ(spv::Op::OpStore, available[45]->opcode());
  184. }
  185. {
  186. auto available = all_instructions.GetAvailableBeforeInstruction(i3);
  187. ASSERT_FALSE(available.empty());
  188. ASSERT_EQ(45, available.size());
  189. ASSERT_EQ(spv::Op::OpTypeVoid, available[0]->opcode());
  190. ASSERT_EQ(spv::Op::OpTypePointer, available[3]->opcode());
  191. ASSERT_EQ(spv::Op::OpVariable, available[15]->opcode());
  192. ASSERT_EQ(spv::Op::OpFunctionCall, available[40]->opcode());
  193. ASSERT_EQ(spv::Op::OpBranchConditional, available[44]->opcode());
  194. }
  195. {
  196. auto available = all_instructions.GetAvailableBeforeInstruction(i6);
  197. ASSERT_FALSE(available.empty());
  198. ASSERT_EQ(33, available.size());
  199. ASSERT_EQ(spv::Op::OpTypeVoid, available[0]->opcode());
  200. ASSERT_EQ(spv::Op::OpTypeFloat, available[4]->opcode());
  201. ASSERT_EQ(spv::Op::OpTypePointer, available[8]->opcode());
  202. ASSERT_EQ(spv::Op::OpConstantComposite, available[12]->opcode());
  203. ASSERT_EQ(spv::Op::OpConstant, available[16]->opcode());
  204. ASSERT_EQ(spv::Op::OpFunctionParameter, available[30]->opcode());
  205. ASSERT_EQ(spv::Op::OpFunctionParameter, available[31]->opcode());
  206. ASSERT_EQ(spv::Op::OpVariable, available[32]->opcode());
  207. }
  208. }
  209. {
  210. AvailableInstructions vector_instructions(
  211. context.get(),
  212. [](opt::IRContext* ir_context, opt::Instruction* inst) -> bool {
  213. return inst->type_id() != 0 && ir_context->get_type_mgr()
  214. ->GetType(inst->type_id())
  215. ->AsVector() != nullptr;
  216. });
  217. {
  218. auto available = vector_instructions.GetAvailableBeforeInstruction(i4);
  219. ASSERT_FALSE(available.empty());
  220. ASSERT_EQ(3, available.size());
  221. ASSERT_EQ(spv::Op::OpConstantComposite, available[0]->opcode());
  222. ASSERT_EQ(spv::Op::OpConstantComposite, available[1]->opcode());
  223. ASSERT_EQ(spv::Op::OpCopyObject, available[2]->opcode());
  224. }
  225. {
  226. auto available = vector_instructions.GetAvailableBeforeInstruction(i5);
  227. ASSERT_FALSE(available.empty());
  228. ASSERT_EQ(3, available.size());
  229. ASSERT_EQ(spv::Op::OpConstantComposite, available[0]->opcode());
  230. ASSERT_EQ(spv::Op::OpConstantComposite, available[1]->opcode());
  231. ASSERT_EQ(spv::Op::OpCopyObject, available[2]->opcode());
  232. }
  233. {
  234. auto available = vector_instructions.GetAvailableBeforeInstruction(i6);
  235. ASSERT_FALSE(available.empty());
  236. ASSERT_EQ(2, available.size());
  237. ASSERT_EQ(spv::Op::OpConstantComposite, available[0]->opcode());
  238. ASSERT_EQ(spv::Op::OpConstantComposite, available[1]->opcode());
  239. }
  240. }
  241. {
  242. AvailableInstructions integer_add_instructions(
  243. context.get(), [](opt::IRContext*, opt::Instruction* inst) -> bool {
  244. return inst->opcode() == spv::Op::OpIAdd;
  245. });
  246. {
  247. auto available =
  248. integer_add_instructions.GetAvailableBeforeInstruction(i7);
  249. ASSERT_FALSE(available.empty());
  250. ASSERT_EQ(1, available.size());
  251. ASSERT_EQ(spv::Op::OpIAdd, available[0]->opcode());
  252. }
  253. {
  254. auto available =
  255. integer_add_instructions.GetAvailableBeforeInstruction(i8);
  256. ASSERT_FALSE(available.empty());
  257. ASSERT_EQ(1, available.size());
  258. ASSERT_EQ(spv::Op::OpIAdd, available[0]->opcode());
  259. }
  260. {
  261. auto available =
  262. integer_add_instructions.GetAvailableBeforeInstruction(i9);
  263. ASSERT_FALSE(available.empty());
  264. ASSERT_EQ(1, available.size());
  265. ASSERT_EQ(spv::Op::OpIAdd, available[0]->opcode());
  266. }
  267. }
  268. }
  269. TEST(AvailableInstructionsTest, UnreachableBlock) {
  270. std::string shader = R"(
  271. OpCapability Shader
  272. %1 = OpExtInstImport "GLSL.std.450"
  273. OpMemoryModel Logical GLSL450
  274. OpEntryPoint Fragment %4 "main"
  275. OpExecutionMode %4 OriginUpperLeft
  276. OpSource ESSL 320
  277. OpName %4 "main"
  278. OpName %8 "x"
  279. %2 = OpTypeVoid
  280. %3 = OpTypeFunction %2
  281. %6 = OpTypeInt 32 1
  282. %7 = OpTypePointer Function %6
  283. %9 = OpConstant %6 2
  284. %4 = OpFunction %2 None %3
  285. %5 = OpLabel
  286. %8 = OpVariable %7 Function
  287. OpStore %8 %9
  288. %12 = OpLoad %6 %8
  289. OpReturn
  290. %10 = OpLabel
  291. %11 = OpLoad %6 %8
  292. OpReturn
  293. OpFunctionEnd
  294. )";
  295. const auto env = SPV_ENV_UNIVERSAL_1_3;
  296. const auto consumer = nullptr;
  297. const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
  298. spvtools::ValidatorOptions validator_options;
  299. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
  300. kConsoleMessageConsumer));
  301. AvailableInstructions all_instructions(
  302. context.get(),
  303. [](opt::IRContext*, opt::Instruction*) -> bool { return true; });
  304. ASSERT_EQ(7, all_instructions
  305. .GetAvailableBeforeInstruction(
  306. context->get_def_use_mgr()->GetDef(12))
  307. .size());
  308. #ifndef NDEBUG
  309. ASSERT_DEATH(all_instructions.GetAvailableBeforeInstruction(
  310. context->get_def_use_mgr()->GetDef(11)),
  311. "Availability can only be queried for reachable instructions.");
  312. #endif
  313. }
  314. } // namespace
  315. } // namespace fuzz
  316. } // namespace spvtools