resolve_binding_conflicts_pass_test.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. // Copyright (c) 2025 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 <iostream>
  15. #include <ostream>
  16. #include "spirv-tools/optimizer.hpp"
  17. #include "test/opt/pass_fixture.h"
  18. #include "test/opt/pass_utils.h"
  19. namespace spvtools {
  20. namespace opt {
  21. namespace {
  22. struct ResolveBindingConflictsTest : public PassTest<::testing::Test> {
  23. virtual void SetUp() override {
  24. SetTargetEnv(SPV_ENV_VULKAN_1_1); // allow storage buffer storage class
  25. // without extension.
  26. SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  27. SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES |
  28. SPV_BINARY_TO_TEXT_OPTION_INDENT |
  29. SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
  30. }
  31. };
  32. using StringList = std::vector<std::string>;
  33. std::string EntryPointDecls(const StringList& names) {
  34. std::ostringstream os;
  35. for (auto& name : names) {
  36. os << " OpEntryPoint GLCompute %" + name + " \"" + name +
  37. "\"\n";
  38. }
  39. for (auto& name : names) {
  40. os << " OpExecutionMode %" + name + " LocalSize 1 1 1\n";
  41. }
  42. for (auto& name : names) {
  43. os << " OpName %" + name + " \"" + name + "\"\n";
  44. }
  45. return os.str();
  46. }
  47. std::string Preamble(const StringList& names = {"main"}) {
  48. return R"( OpCapability Shader
  49. OpMemoryModel Logical GLSL450
  50. )" + EntryPointDecls(names) +
  51. R"( OpName %voidfn "voidfn"
  52. OpName %s_ty "s_ty"
  53. OpName %i_ty "i_ty"
  54. OpName %si_ty "si_ty"
  55. OpName %p_s_ty "p_s_ty"
  56. OpName %p_i_ty "p_i_ty"
  57. OpName %p_si_ty "p_si_ty"
  58. OpName %st_ty "st_ty"
  59. OpName %pu_st_ty "pu_st_ty"
  60. OpName %pb_st_ty "pb_st_ty"
  61. )";
  62. }
  63. std::string BasicTypes() {
  64. return R"( OpDecorate %st_ty Block
  65. OpMemberDecorate %st_ty 0 Offset 0
  66. %float = OpTypeFloat 32
  67. %uint = OpTypeInt 32 0
  68. %uint_0 = OpConstant %uint 0
  69. %uint_3 = OpConstant %uint 3
  70. %void = OpTypeVoid
  71. %voidfn = OpTypeFunction %void
  72. %s_ty = OpTypeSampler
  73. %i_ty = OpTypeImage %float 2D 0 0 0 1 Unknown
  74. %si_ty = OpTypeSampledImage %i_ty
  75. %p_i_ty = OpTypePointer UniformConstant %i_ty
  76. %p_s_ty = OpTypePointer UniformConstant %s_ty
  77. %p_si_ty = OpTypePointer UniformConstant %si_ty
  78. %st_ty = OpTypeStruct %uint
  79. %pu_st_ty = OpTypePointer Uniform %st_ty
  80. %pb_st_ty = OpTypePointer StorageBuffer %st_ty
  81. )";
  82. }
  83. std::string NoCheck() { return "; CHECK-NOT: nothing to see"; }
  84. TEST_F(ResolveBindingConflictsTest, NoBindings_NoChange) {
  85. const std::string kTest = Preamble() + BasicTypes() +
  86. R"( %main = OpFunction %void None %voidfn
  87. %100 = OpLabel
  88. OpReturn
  89. OpFunctionEnd
  90. )";
  91. auto [disasm, status] = SinglePassRunAndMatch<ResolveBindingConflictsPass>(
  92. kTest + NoCheck(), /* do_validation= */ true);
  93. EXPECT_EQ(status, Pass::Status::SuccessWithoutChange);
  94. EXPECT_EQ(kTest, disasm);
  95. }
  96. TEST_F(ResolveBindingConflictsTest, NoConflict_UnusedVars_NoChange) {
  97. const std::string kTest = Preamble() +
  98. R"(
  99. OpDecorate %100 DescriptorSet 0
  100. OpDecorate %100 Binding 0
  101. OpDecorate %101 DescriptorSet 0
  102. OpDecorate %101 Binding 0
  103. OpDecorate %102 DescriptorSet 0
  104. OpDecorate %102 Binding 0
  105. OpDecorate %103 DescriptorSet 0
  106. OpDecorate %103 Binding 0
  107. OpDecorate %104 DescriptorSet 0
  108. OpDecorate %104 Binding 0
  109. ; CHECK: OpDecorate %100 DescriptorSet 0
  110. ; CHECK: OpDecorate %100 Binding 0
  111. ; CHECK: OpDecorate %101 DescriptorSet 0
  112. ; CHECK: OpDecorate %101 Binding 0
  113. ; CHECK: OpDecorate %102 DescriptorSet 0
  114. ; CHECK: OpDecorate %102 Binding 0
  115. ; CHECK: OpDecorate %103 DescriptorSet 0
  116. ; CHECK: OpDecorate %103 Binding 0
  117. ; CHECK: OpDecorate %104 DescriptorSet 0
  118. ; CHECK: OpDecorate %104 Binding 0
  119. )" + BasicTypes() + R"(
  120. ; Unused variables
  121. %100 = OpVariable %p_i_ty UniformConstant ; image
  122. %101 = OpVariable %p_s_ty UniformConstant ; sampler
  123. %102 = OpVariable %pu_st_ty Uniform ; UBO
  124. %103 = OpVariable %pb_st_ty StorageBuffer ; SSBO
  125. %104 = OpVariable %p_si_ty UniformConstant ; combined sampled image
  126. %main = OpFunction %void None %voidfn
  127. %10 = OpLabel
  128. OpReturn
  129. OpFunctionEnd
  130. )";
  131. auto [disasm, status] = SinglePassRunAndMatch<ResolveBindingConflictsPass>(
  132. kTest, /* do_validation= */ true);
  133. EXPECT_EQ(status, Pass::Status::SuccessWithoutChange) << disasm;
  134. }
  135. TEST_F(ResolveBindingConflictsTest, NoConflict_UsedVars_NoChange) {
  136. const std::string kTest = Preamble() +
  137. R"(
  138. OpDecorate %100 DescriptorSet 0
  139. OpDecorate %100 Binding 0
  140. OpDecorate %101 DescriptorSet 0
  141. OpDecorate %101 Binding 1
  142. OpDecorate %102 DescriptorSet 0
  143. OpDecorate %102 Binding 2
  144. OpDecorate %103 DescriptorSet 0
  145. OpDecorate %103 Binding 3
  146. OpDecorate %110 DescriptorSet 1
  147. OpDecorate %110 Binding 0
  148. ; CHECK: OpDecorate %100 DescriptorSet 0
  149. ; CHECK: OpDecorate %100 Binding 0
  150. ; CHECK: OpDecorate %101 DescriptorSet 0
  151. ; CHECK: OpDecorate %101 Binding 1
  152. ; CHECK: OpDecorate %102 DescriptorSet 0
  153. ; CHECK: OpDecorate %102 Binding 2
  154. ; CHECK: OpDecorate %103 DescriptorSet 0
  155. ; CHECK: OpDecorate %103 Binding 3
  156. ; CHECK: OpDecorate %110 DescriptorSet 1
  157. ; CHECK: OpDecorate %110 Binding 0
  158. )" + BasicTypes() + R"(
  159. %100 = OpVariable %p_i_ty UniformConstant ; image
  160. %101 = OpVariable %p_s_ty UniformConstant ; sampler
  161. %102 = OpVariable %pu_st_ty Uniform ; UBO
  162. %103 = OpVariable %pb_st_ty StorageBuffer ; SSBO
  163. %110 = OpVariable %p_si_ty UniformConstant ; combined sampled image
  164. %main = OpFunction %void None %voidfn
  165. %10 = OpLabel
  166. %11 = OpCopyObject %p_i_ty %100
  167. %12 = OpCopyObject %p_s_ty %101
  168. %13 = OpCopyObject %pu_st_ty %102
  169. %14 = OpCopyObject %pb_st_ty %103
  170. %15 = OpCopyObject %p_si_ty %110
  171. OpReturn
  172. OpFunctionEnd
  173. )";
  174. auto [disasm, status] = SinglePassRunAndMatch<ResolveBindingConflictsPass>(
  175. kTest, /* do_validation= */ true);
  176. EXPECT_EQ(status, Pass::Status::SuccessWithoutChange) << disasm;
  177. }
  178. TEST_F(ResolveBindingConflictsTest,
  179. OneEntryPoint_SamplerFirstConflict_Resolves) {
  180. const std::string kTest = Preamble() +
  181. R"(
  182. OpDecorate %100 DescriptorSet 0
  183. OpDecorate %100 Binding 0
  184. OpDecorate %101 DescriptorSet 0
  185. OpDecorate %101 Binding 0
  186. ; The sampler's binding number is incremented, even when listed first.
  187. ; CHECK: OpDecorate %100 DescriptorSet 0
  188. ; CHECK: OpDecorate %100 Binding 1
  189. ; CHECK: OpDecorate %101 DescriptorSet 0
  190. ; CHECK: OpDecorate %101 Binding 0
  191. )" + BasicTypes() + R"(
  192. %100 = OpVariable %p_s_ty UniformConstant ; sampler listed first
  193. %101 = OpVariable %p_i_ty UniformConstant
  194. %main = OpFunction %void None %voidfn
  195. %10 = OpLabel
  196. %11 = OpCopyObject %p_s_ty %100
  197. %12 = OpCopyObject %p_i_ty %101
  198. OpReturn
  199. OpFunctionEnd
  200. )";
  201. auto [disasm, status] = SinglePassRunAndMatch<ResolveBindingConflictsPass>(
  202. kTest, /* do_validation= */ true);
  203. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  204. }
  205. TEST_F(ResolveBindingConflictsTest,
  206. OneEntryPoint_SamplerSecondConflict_Resolves) {
  207. const std::string kTest = Preamble() +
  208. R"(
  209. OpDecorate %100 DescriptorSet 0
  210. OpDecorate %100 Binding 0
  211. OpDecorate %101 DescriptorSet 0
  212. OpDecorate %101 Binding 0
  213. ; The sampler's binding number is incremented, even when listed second.
  214. ; CHECK: OpDecorate %100 DescriptorSet 0
  215. ; CHECK: OpDecorate %100 Binding 0
  216. ; CHECK: OpDecorate %101 DescriptorSet 0
  217. ; CHECK: OpDecorate %101 Binding 1
  218. )" + BasicTypes() + R"(
  219. %100 = OpVariable %p_i_ty UniformConstant
  220. %101 = OpVariable %p_s_ty UniformConstant ; sampler listed second
  221. %main = OpFunction %void None %voidfn
  222. %10 = OpLabel
  223. %11 = OpCopyObject %p_i_ty %100
  224. %12 = OpCopyObject %p_s_ty %101
  225. OpReturn
  226. OpFunctionEnd
  227. )";
  228. auto [disasm, status] = SinglePassRunAndMatch<ResolveBindingConflictsPass>(
  229. kTest, /* do_validation= */ true);
  230. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  231. }
  232. TEST_F(ResolveBindingConflictsTest, OneEntryPoint_Conflict_Ripples) {
  233. const std::string kTest = Preamble() +
  234. R"(
  235. OpDecorate %100 DescriptorSet 0
  236. OpDecorate %100 Binding 0
  237. OpDecorate %101 DescriptorSet 0
  238. OpDecorate %101 Binding 0
  239. OpDecorate %102 DescriptorSet 0
  240. OpDecorate %102 Binding 1
  241. OpDecorate %103 DescriptorSet 0
  242. OpDecorate %103 Binding 2
  243. OpDecorate %104 DescriptorSet 0
  244. OpDecorate %104 Binding 3
  245. ; The sampler's binding number is incremented, and later
  246. ; bindings move out of the way.
  247. ; CHECK: OpDecorate %100 DescriptorSet 0
  248. ; CHECK: OpDecorate %100 Binding 1
  249. ; CHECK: OpDecorate %101 DescriptorSet 0
  250. ; CHECK: OpDecorate %101 Binding 0
  251. ; CHECK: OpDecorate %102 DescriptorSet 0
  252. ; CHECK: OpDecorate %102 Binding 2
  253. ; CHECK: OpDecorate %103 DescriptorSet 0
  254. ; CHECK: OpDecorate %103 Binding 3
  255. ; CHECK: OpDecorate %104 DescriptorSet 0
  256. ; CHECK: OpDecorate %104 Binding 4
  257. )" + BasicTypes() + R"(
  258. %100 = OpVariable %p_s_ty UniformConstant ; sampler comes first
  259. %101 = OpVariable %p_i_ty UniformConstant
  260. %102 = OpVariable %pu_st_ty Uniform
  261. %103 = OpVariable %pb_st_ty StorageBuffer
  262. %104 = OpVariable %p_si_ty UniformConstant
  263. %main = OpFunction %void None %voidfn
  264. %10 = OpLabel
  265. %11 = OpCopyObject %p_s_ty %100
  266. %12 = OpCopyObject %p_i_ty %101
  267. %13 = OpCopyObject %pu_st_ty %102
  268. %14 = OpCopyObject %pb_st_ty %103
  269. %15 = OpCopyObject %p_si_ty %104
  270. OpReturn
  271. OpFunctionEnd
  272. )";
  273. auto [disasm, status] = SinglePassRunAndMatch<ResolveBindingConflictsPass>(
  274. kTest, /* do_validation= */ true);
  275. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  276. }
  277. TEST_F(ResolveBindingConflictsTest,
  278. OneEntryPoint_Conflict_RippleStopsAtFirstHole) {
  279. const std::string kTest = Preamble() +
  280. R"(
  281. OpDecorate %100 DescriptorSet 0
  282. OpDecorate %100 Binding 0
  283. OpDecorate %101 DescriptorSet 0
  284. OpDecorate %101 Binding 0
  285. OpDecorate %102 DescriptorSet 0
  286. OpDecorate %102 Binding 1
  287. ; Leave a hole at (0, 2)
  288. OpDecorate %103 DescriptorSet 0
  289. OpDecorate %103 Binding 3
  290. OpDecorate %104 DescriptorSet 0
  291. OpDecorate %104 Binding 4
  292. ; There was a hole at binding 2. The ripple stops there.
  293. ; CHECK: OpDecorate %100 DescriptorSet 0
  294. ; CHECK: OpDecorate %100 Binding 1
  295. ; CHECK: OpDecorate %101 DescriptorSet 0
  296. ; CHECK: OpDecorate %101 Binding 0
  297. ; CHECK: OpDecorate %102 DescriptorSet 0
  298. ; CHECK: OpDecorate %102 Binding 2
  299. ; CHECK: OpDecorate %103 DescriptorSet 0
  300. ; CHECK: OpDecorate %103 Binding 3
  301. ; CHECK: OpDecorate %104 DescriptorSet 0
  302. ; CHECK: OpDecorate %104 Binding 4
  303. )" + BasicTypes() + R"(
  304. %100 = OpVariable %p_s_ty UniformConstant ; sampler comes first
  305. %101 = OpVariable %p_i_ty UniformConstant
  306. %102 = OpVariable %pu_st_ty Uniform
  307. %103 = OpVariable %pb_st_ty StorageBuffer
  308. %104 = OpVariable %p_si_ty UniformConstant
  309. %main = OpFunction %void None %voidfn
  310. %10 = OpLabel
  311. %11 = OpCopyObject %p_s_ty %100
  312. %12 = OpCopyObject %p_i_ty %101
  313. %13 = OpCopyObject %pu_st_ty %102
  314. %14 = OpCopyObject %pb_st_ty %103
  315. %15 = OpCopyObject %p_si_ty %104
  316. OpReturn
  317. OpFunctionEnd
  318. )";
  319. auto [disasm, status] = SinglePassRunAndMatch<ResolveBindingConflictsPass>(
  320. kTest, /* do_validation= */ true);
  321. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  322. }
  323. TEST_F(ResolveBindingConflictsTest, OneEntryPoint_MultiConflict_Resolves) {
  324. const std::string kTest = Preamble() +
  325. R"(
  326. ; Two conflicts: at Bindings 0, and 1
  327. OpDecorate %100 DescriptorSet 0
  328. OpDecorate %100 Binding 0
  329. OpDecorate %101 DescriptorSet 0
  330. OpDecorate %101 Binding 0
  331. OpDecorate %102 DescriptorSet 0
  332. OpDecorate %102 Binding 1
  333. OpDecorate %103 DescriptorSet 0
  334. OpDecorate %103 Binding 1
  335. OpDecorate %104 DescriptorSet 0
  336. OpDecorate %104 Binding 2
  337. ; CHECK: OpDecorate %100 DescriptorSet 0
  338. ; CHECK: OpDecorate %100 Binding 1
  339. ; CHECK: OpDecorate %101 DescriptorSet 0
  340. ; CHECK: OpDecorate %101 Binding 0
  341. ; CHECK: OpDecorate %102 DescriptorSet 0
  342. ; CHECK: OpDecorate %102 Binding 2
  343. ; CHECK: OpDecorate %103 DescriptorSet 0
  344. ; CHECK: OpDecorate %103 Binding 3
  345. ; CHECK: OpDecorate %104 DescriptorSet 0
  346. ; CHECK: OpDecorate %104 Binding 4
  347. )" + BasicTypes() + R"(
  348. %100 = OpVariable %p_s_ty UniformConstant ; sampler first
  349. %101 = OpVariable %p_i_ty UniformConstant
  350. %102 = OpVariable %p_i_ty UniformConstant
  351. %103 = OpVariable %p_s_ty UniformConstant ; sampler second
  352. %104 = OpVariable %pu_st_ty Uniform
  353. %main = OpFunction %void None %voidfn
  354. %10 = OpLabel
  355. %11 = OpCopyObject %p_s_ty %100
  356. %12 = OpCopyObject %p_i_ty %101
  357. %13 = OpCopyObject %p_i_ty %102
  358. %14 = OpCopyObject %p_s_ty %103
  359. %15 = OpCopyObject %pu_st_ty %104
  360. OpReturn
  361. OpFunctionEnd
  362. )";
  363. auto [disasm, status] = SinglePassRunAndMatch<ResolveBindingConflictsPass>(
  364. kTest, /* do_validation= */ true);
  365. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  366. }
  367. TEST_F(ResolveBindingConflictsTest,
  368. OneEntryPoint_MultiConflict_ComplexCallGraph_Resolves) {
  369. // Check that uses are seen even when used at various points in a complex call
  370. // graph.
  371. const std::string kTest = Preamble() +
  372. R"(
  373. OpDecorate %100 DescriptorSet 0
  374. OpDecorate %100 Binding 0
  375. OpDecorate %101 DescriptorSet 0
  376. OpDecorate %101 Binding 0
  377. OpDecorate %102 DescriptorSet 0
  378. OpDecorate %102 Binding 1
  379. OpDecorate %103 DescriptorSet 0
  380. OpDecorate %103 Binding 1
  381. OpDecorate %104 DescriptorSet 0
  382. OpDecorate %104 Binding 2
  383. ; CHECK: OpDecorate %100 DescriptorSet 0
  384. ; CHECK: OpDecorate %100 Binding 1
  385. ; CHECK: OpDecorate %101 DescriptorSet 0
  386. ; CHECK: OpDecorate %101 Binding 0
  387. ; CHECK: OpDecorate %102 DescriptorSet 0
  388. ; CHECK: OpDecorate %102 Binding 2
  389. ; CHECK: OpDecorate %103 DescriptorSet 0
  390. ; CHECK: OpDecorate %103 Binding 3
  391. ; CHECK: OpDecorate %104 DescriptorSet 0
  392. ; CHECK: OpDecorate %104 Binding 4
  393. )" + BasicTypes() + R"(
  394. %100 = OpVariable %p_s_ty UniformConstant ; used in %200
  395. %101 = OpVariable %p_i_ty UniformConstant ; used in %300, %400
  396. %102 = OpVariable %p_i_ty UniformConstant ; used in %500
  397. %103 = OpVariable %p_s_ty UniformConstant ; used in %400 twice
  398. %104 = OpVariable %pu_st_ty Uniform ; used in %600
  399. %200 = OpFunction %void None %voidfn
  400. %201 = OpLabel
  401. %202 = OpCopyObject %p_s_ty %100
  402. OpReturn
  403. OpFunctionEnd
  404. %300 = OpFunction %void None %voidfn
  405. %301 = OpLabel
  406. %302 = OpCopyObject %p_i_ty %101
  407. OpReturn
  408. OpFunctionEnd
  409. %400 = OpFunction %void None %voidfn
  410. %401 = OpLabel
  411. %402 = OpFunctionCall %void %200
  412. %403 = OpCopyObject %p_s_ty %103
  413. %404 = OpCopyObject %p_i_ty %101
  414. %405 = OpCopyObject %p_s_ty %103
  415. %406 = OpFunctionCall %void %300
  416. OpReturn
  417. OpFunctionEnd
  418. %500 = OpFunction %void None %voidfn
  419. %501 = OpLabel
  420. %502 = OpFunctionCall %void %400
  421. %503 = OpCopyObject %p_i_ty %102
  422. %504 = OpFunctionCall %void %300
  423. OpReturn
  424. OpFunctionEnd
  425. %600 = OpFunction %void None %voidfn
  426. %601 = OpLabel
  427. %602 = OpFunctionCall %void %300
  428. %603 = OpFunctionCall %void %500
  429. %604 = OpCopyObject %pu_st_ty %104
  430. OpReturn
  431. OpFunctionEnd
  432. %main = OpFunction %void None %voidfn
  433. %1000 = OpLabel
  434. %1001 = OpFunctionCall %void %600
  435. OpReturn
  436. OpFunctionEnd
  437. )";
  438. auto [disasm, status] = SinglePassRunAndMatch<ResolveBindingConflictsPass>(
  439. kTest, /* do_validation= */ true);
  440. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  441. }
  442. TEST_F(ResolveBindingConflictsTest,
  443. MultiEntryPoint_DuplicatConflicts_ResolvesOnlyOnce) {
  444. // Before:
  445. //
  446. // Binding: 0 1
  447. // Alpha: %100,%101
  448. // Beta: %100,%101
  449. //
  450. // After:
  451. //
  452. // Binding: 0 1
  453. // Alpha: %101 %100
  454. // Beta: %101 %100
  455. const std::string kTest = Preamble({"alpha", "beta"}) +
  456. R"(
  457. OpDecorate %100 DescriptorSet 0
  458. OpDecorate %100 Binding 0
  459. OpDecorate %101 DescriptorSet 0
  460. OpDecorate %101 Binding 0
  461. ; CHECK: OpDecorate %100 DescriptorSet 0
  462. ; CHECK: OpDecorate %100 Binding 1
  463. ; CHECK: OpDecorate %101 DescriptorSet 0
  464. ; CHECK: OpDecorate %101 Binding 0
  465. )" + BasicTypes() + R"(
  466. %100 = OpVariable %p_s_ty UniformConstant
  467. %101 = OpVariable %p_i_ty UniformConstant
  468. %alpha = OpFunction %void None %voidfn
  469. %1000 = OpLabel
  470. %1001 = OpCopyObject %p_s_ty %100
  471. %1002 = OpCopyObject %p_i_ty %101
  472. OpReturn
  473. OpFunctionEnd
  474. %beta = OpFunction %void None %voidfn
  475. %2000 = OpLabel
  476. %2001 = OpCopyObject %p_s_ty %100
  477. %2002 = OpCopyObject %p_i_ty %101
  478. OpReturn
  479. OpFunctionEnd
  480. )";
  481. auto [disasm, status] = SinglePassRunAndMatch<ResolveBindingConflictsPass>(
  482. kTest, /* do_validation= */ true);
  483. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  484. }
  485. TEST_F(ResolveBindingConflictsTest,
  486. MultiEntryPoint_IndependentConflicts_Resolves) {
  487. // Before:
  488. //
  489. // Binding: 0 1
  490. // Alpha: %100,%101
  491. // Beta: %102,%103
  492. //
  493. // After:
  494. //
  495. // Binding: 0 1
  496. // Alpha: %101 %100
  497. // Beta: %102 %103
  498. const std::string kTest = Preamble({"alpha", "beta"}) +
  499. R"(
  500. OpDecorate %100 DescriptorSet 0
  501. OpDecorate %100 Binding 0
  502. OpDecorate %101 DescriptorSet 0
  503. OpDecorate %101 Binding 0
  504. OpDecorate %102 DescriptorSet 0
  505. OpDecorate %102 Binding 0
  506. OpDecorate %103 DescriptorSet 0
  507. OpDecorate %103 Binding 0
  508. ; CHECK: OpDecorate %100 DescriptorSet 0
  509. ; CHECK: OpDecorate %100 Binding 1
  510. ; CHECK: OpDecorate %101 DescriptorSet 0
  511. ; CHECK: OpDecorate %101 Binding 0
  512. ; CHECK: OpDecorate %102 DescriptorSet 0
  513. ; CHECK: OpDecorate %102 Binding 0
  514. ; CHECK: OpDecorate %103 DescriptorSet 0
  515. ; CHECK: OpDecorate %103 Binding 1
  516. )" + BasicTypes() + R"(
  517. %100 = OpVariable %p_s_ty UniformConstant
  518. %101 = OpVariable %p_i_ty UniformConstant
  519. %102 = OpVariable %p_i_ty UniformConstant
  520. %103 = OpVariable %p_s_ty UniformConstant
  521. %alpha = OpFunction %void None %voidfn
  522. %1000 = OpLabel
  523. %1001 = OpCopyObject %p_s_ty %100
  524. %1002 = OpCopyObject %p_i_ty %101
  525. OpReturn
  526. OpFunctionEnd
  527. %beta = OpFunction %void None %voidfn
  528. %2000 = OpLabel
  529. %2001 = OpCopyObject %p_i_ty %102
  530. %2002 = OpCopyObject %p_s_ty %103
  531. OpReturn
  532. OpFunctionEnd
  533. )";
  534. auto [disasm, status] = SinglePassRunAndMatch<ResolveBindingConflictsPass>(
  535. kTest, /* do_validation= */ true);
  536. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  537. }
  538. TEST_F(ResolveBindingConflictsTest,
  539. MultiEntryPoint_SameVarConflictsAcrossMultiEntryPoints_Resolves) {
  540. // A sampler variable is bumped, causing potential conflicts in other shaders.
  541. //
  542. // Before:
  543. //
  544. // Binding: 0 1 2
  545. // Alpha: %100,%101
  546. // Beta: %100 %102
  547. // Gamma: %100 %103
  548. //
  549. // After:
  550. //
  551. // Binding: 0 1 2
  552. // Alpha: %101 %100
  553. // Beta: %100 %102
  554. // Gamma: %100 %103
  555. //
  556. const std::string kTest = Preamble({"alpha", "beta", "gamma"}) +
  557. R"(
  558. OpDecorate %100 DescriptorSet 0 ; The sampler
  559. OpDecorate %100 Binding 0
  560. OpDecorate %101 DescriptorSet 0
  561. OpDecorate %101 Binding 0
  562. OpDecorate %102 DescriptorSet 0
  563. OpDecorate %102 Binding 1
  564. OpDecorate %103 DescriptorSet 0
  565. OpDecorate %103 Binding 2
  566. ; bumped once
  567. ; CHECK: OpDecorate %100 DescriptorSet 0
  568. ; CHECK: OpDecorate %100 Binding 1
  569. ; CHECK: OpDecorate %101 DescriptorSet 0
  570. ; CHECK: OpDecorate %101 Binding 0
  571. ; pushed back from bump of %100
  572. ; CHECK: OpDecorate %102 DescriptorSet 0
  573. ; CHECK: OpDecorate %102 Binding 2
  574. ; does not need to be bumped
  575. ; CHECK: OpDecorate %103 DescriptorSet 0
  576. ; CHECK: OpDecorate %103 Binding 2
  577. )" + BasicTypes() + R"(
  578. %100 = OpVariable %p_s_ty UniformConstant ; used in alpha, beta, gamma
  579. %101 = OpVariable %p_i_ty UniformConstant ; used in alpha
  580. %102 = OpVariable %pu_st_ty Uniform ; used in beta
  581. %103 = OpVariable %pb_st_ty StorageBuffer ; used in gamma
  582. %alpha = OpFunction %void None %voidfn
  583. %1000 = OpLabel
  584. %1001 = OpCopyObject %p_s_ty %100
  585. %1002 = OpCopyObject %p_i_ty %101
  586. OpReturn
  587. OpFunctionEnd
  588. %beta = OpFunction %void None %voidfn
  589. %2000 = OpLabel
  590. %2001 = OpCopyObject %p_s_ty %100
  591. %2002 = OpCopyObject %pu_st_ty %102
  592. OpReturn
  593. OpFunctionEnd
  594. %gamma = OpFunction %void None %voidfn
  595. %3000 = OpLabel
  596. %3001 = OpCopyObject %p_s_ty %100
  597. %3002 = OpCopyObject %pb_st_ty %103
  598. OpReturn
  599. OpFunctionEnd
  600. )";
  601. auto [disasm, status] = SinglePassRunAndMatch<ResolveBindingConflictsPass>(
  602. kTest, /* do_validation= */ true);
  603. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  604. }
  605. TEST_F(ResolveBindingConflictsTest, MultiEntryPoint_ConflictCascade_Resolves) {
  606. // Before:
  607. //
  608. // Binding: 0 1 2 3
  609. // Alpha: %100,%101
  610. // Beta: %100 %102
  611. // Gamma: %102 %103
  612. // Delta: %103 %104
  613. //
  614. // After:
  615. //
  616. // Binding: 0 1 2 3 4
  617. // Alpha: %101 %100
  618. // Beta: %100 %102
  619. // Gamma: %102 %103
  620. // Delta: %103 %104
  621. //
  622. const std::string kTest = Preamble({"alpha", "beta", "gamma", "delta"}) +
  623. R"(
  624. OpDecorate %100 DescriptorSet 0 ; The sampler
  625. OpDecorate %100 Binding 0
  626. OpDecorate %101 DescriptorSet 0
  627. OpDecorate %101 Binding 0
  628. OpDecorate %102 DescriptorSet 0
  629. OpDecorate %102 Binding 1
  630. OpDecorate %103 DescriptorSet 0
  631. OpDecorate %103 Binding 2
  632. OpDecorate %104 DescriptorSet 0
  633. OpDecorate %104 Binding 3
  634. ; %100 is bumped once:
  635. ; CHECK: OpDecorate %100 DescriptorSet 0
  636. ; CHECK: OpDecorate %100 Binding 1
  637. ; CHECK: OpDecorate %101 DescriptorSet 0
  638. ; CHECK: OpDecorate %101 Binding 0
  639. ; pushed back from bump of %100
  640. ; CHECK: OpDecorate %102 DescriptorSet 0
  641. ; CHECK: OpDecorate %102 Binding 2
  642. ; pushed back from bump of %102
  643. ; CHECK: OpDecorate %103 DescriptorSet 0
  644. ; CHECK: OpDecorate %103 Binding 3
  645. ; pushed back from bump of %103
  646. ; CHECK: OpDecorate %104 DescriptorSet 0
  647. ; CHECK: OpDecorate %104 Binding 4
  648. )" + BasicTypes() + R"(
  649. %100 = OpVariable %p_s_ty UniformConstant ; used in alpha, beta
  650. %101 = OpVariable %p_i_ty UniformConstant ; used in alpha
  651. %102 = OpVariable %pu_st_ty Uniform ; used in beta, gamma
  652. %103 = OpVariable %pb_st_ty StorageBuffer ; used in gamma, delta
  653. %104 = OpVariable %p_si_ty UniformConstant ; used delta
  654. %alpha = OpFunction %void None %voidfn
  655. %1000 = OpLabel
  656. %1001 = OpCopyObject %p_s_ty %100
  657. %1002 = OpCopyObject %p_i_ty %101
  658. OpReturn
  659. OpFunctionEnd
  660. %beta = OpFunction %void None %voidfn
  661. %2000 = OpLabel
  662. %2001 = OpCopyObject %p_s_ty %100
  663. %2002 = OpCopyObject %pu_st_ty %102
  664. OpReturn
  665. OpFunctionEnd
  666. %gamma = OpFunction %void None %voidfn
  667. %3000 = OpLabel
  668. %3001 = OpCopyObject %pu_st_ty %102
  669. %3002 = OpCopyObject %pb_st_ty %103
  670. OpReturn
  671. OpFunctionEnd
  672. %delta = OpFunction %void None %voidfn
  673. %4000 = OpLabel
  674. %4001 = OpCopyObject %pb_st_ty %103
  675. %4002 = OpCopyObject %p_si_ty %104
  676. OpReturn
  677. OpFunctionEnd
  678. )";
  679. auto [disasm, status] = SinglePassRunAndMatch<ResolveBindingConflictsPass>(
  680. kTest, /* do_validation= */ true);
  681. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  682. }
  683. TEST_F(ResolveBindingConflictsTest,
  684. MultiEntryPoint_ConflictCascade_RevisitEntryPoint) {
  685. // Prove that the settling algorithm knows to revisit entry points that
  686. // already had all their own conflicts resolved.
  687. //
  688. // Before:
  689. //
  690. // Binding: 0 1 2 3 4
  691. // Alpha: %100,%101 %103 %104 %105
  692. // Beta: %101 %102 %103 %105
  693. //
  694. // After:
  695. //
  696. // Binding: 0 1 2 3 4 5
  697. // Alpha: %100 %101 %103 %104 %105
  698. // Beta: %101 %102 %103 %105
  699. const std::string kTest = Preamble({"alpha", "beta"}) +
  700. R"(
  701. OpDecorate %100 DescriptorSet 0
  702. OpDecorate %100 Binding 0
  703. OpDecorate %101 DescriptorSet 0 ; the sampler
  704. OpDecorate %101 Binding 0
  705. OpDecorate %102 DescriptorSet 0
  706. OpDecorate %102 Binding 1
  707. OpDecorate %103 DescriptorSet 0
  708. OpDecorate %103 Binding 2
  709. OpDecorate %104 DescriptorSet 0
  710. OpDecorate %104 Binding 3
  711. OpDecorate %105 DescriptorSet 0
  712. OpDecorate %105 Binding 4
  713. ; CHECK: OpDecorate %100 DescriptorSet 0
  714. ; CHECK: OpDecorate %100 Binding 0
  715. ; CHECK: OpDecorate %101 DescriptorSet 0
  716. ; CHECK: OpDecorate %101 Binding 1
  717. ; CHECK: OpDecorate %102 DescriptorSet 0
  718. ; CHECK: OpDecorate %102 Binding 2
  719. ; CHECK: OpDecorate %103 DescriptorSet 0
  720. ; CHECK: OpDecorate %103 Binding 3
  721. ; CHECK: OpDecorate %104 DescriptorSet 0
  722. ; CHECK: OpDecorate %104 Binding 4
  723. ; CHECK: OpDecorate %105 DescriptorSet 0
  724. ; CHECK: OpDecorate %105 Binding 5
  725. )" + BasicTypes() + R"(
  726. %100 = OpVariable %p_i_ty UniformConstant
  727. %101 = OpVariable %p_s_ty UniformConstant
  728. %102 = OpVariable %pu_st_ty Uniform
  729. %103 = OpVariable %pb_st_ty StorageBuffer
  730. %104 = OpVariable %p_si_ty UniformConstant
  731. %105 = OpVariable %p_s_ty UniformConstant
  732. %alpha = OpFunction %void None %voidfn
  733. %1000 = OpLabel
  734. %1001 = OpCopyObject %p_i_ty %100
  735. %1002 = OpCopyObject %p_s_ty %101
  736. %1003 = OpCopyObject %pb_st_ty %103
  737. %1004 = OpCopyObject %p_si_ty %104
  738. %1005 = OpCopyObject %p_s_ty %105
  739. OpReturn
  740. OpFunctionEnd
  741. %beta = OpFunction %void None %voidfn
  742. %2000 = OpLabel
  743. %2001 = OpCopyObject %p_s_ty %101
  744. %2002 = OpCopyObject %pu_st_ty %102
  745. %2003 = OpCopyObject %pb_st_ty %103
  746. %2004 = OpCopyObject %p_s_ty %105
  747. OpReturn
  748. OpFunctionEnd
  749. )";
  750. auto [disasm, status] = SinglePassRunAndMatch<ResolveBindingConflictsPass>(
  751. kTest, /* do_validation= */ true);
  752. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  753. }
  754. } // namespace
  755. } // namespace opt
  756. } // namespace spvtools