invocation_interlock_placement_test.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. // Copyright (c) 2023 Google Inc.
  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 "spirv-tools/optimizer.hpp"
  15. #include "test/opt/pass_fixture.h"
  16. #include "test/opt/pass_utils.h"
  17. namespace spvtools {
  18. namespace opt {
  19. namespace {
  20. using InterlockInvocationPlacementTest = PassTest<::testing::Test>;
  21. TEST_F(InterlockInvocationPlacementTest, CheckUnchangedIfNotFragment) {
  22. const std::string kTest = R"(
  23. OpCapability Shader
  24. OpCapability FragmentShaderSampleInterlockEXT
  25. OpExtension "SPV_EXT_fragment_shader_interlock"
  26. OpMemoryModel Logical GLSL450
  27. OpEntryPoint Vertex %main "main"
  28. OpExecutionMode %main SampleInterlockOrderedEXT
  29. OpName %main "main"
  30. %void = OpTypeVoid
  31. %1 = OpTypeFunction %void
  32. %main = OpFunction %void None %1
  33. %2 = OpLabel
  34. OpBeginInvocationInterlockEXT
  35. OpBeginInvocationInterlockEXT
  36. OpEndInvocationInterlockEXT
  37. OpBeginInvocationInterlockEXT
  38. OpEndInvocationInterlockEXT
  39. OpReturn
  40. OpFunctionEnd
  41. )";
  42. SetTargetEnv(SPV_ENV_VULKAN_1_3);
  43. EXPECT_EQ(
  44. Pass::Status::SuccessWithoutChange,
  45. std::get<1>(SinglePassRunAndDisassemble<InvocationInterlockPlacementPass>(
  46. kTest, /* skip_nop= */ false, /* do_validation= */ false)));
  47. }
  48. TEST_F(InterlockInvocationPlacementTest, CheckUnchangedWithoutCapability) {
  49. const std::string kTest = R"(
  50. OpCapability Shader
  51. OpExtension "SPV_EXT_fragment_shader_interlock"
  52. OpMemoryModel Logical GLSL450
  53. OpEntryPoint Fragment %main "main"
  54. OpExecutionMode %main OriginUpperLeft
  55. OpExecutionMode %main SampleInterlockOrderedEXT
  56. OpName %main "main"
  57. %void = OpTypeVoid
  58. %1 = OpTypeFunction %void
  59. %main = OpFunction %void None %1
  60. %2 = OpLabel
  61. OpBeginInvocationInterlockEXT
  62. OpBeginInvocationInterlockEXT
  63. OpEndInvocationInterlockEXT
  64. OpBeginInvocationInterlockEXT
  65. OpEndInvocationInterlockEXT
  66. OpReturn
  67. OpFunctionEnd
  68. )";
  69. SetTargetEnv(SPV_ENV_VULKAN_1_3);
  70. EXPECT_EQ(
  71. Pass::Status::SuccessWithoutChange,
  72. std::get<1>(SinglePassRunAndDisassemble<InvocationInterlockPlacementPass>(
  73. kTest, /* skip_nop= */ false, /* do_validation= */ false)));
  74. }
  75. TEST_F(InterlockInvocationPlacementTest, CheckSingleBasicBlock) {
  76. // We're using OpNoLine as a generic standin for any other instruction, to
  77. // test that begin and end aren't moved.
  78. const std::string kTest = R"(
  79. OpCapability Shader
  80. OpCapability FragmentShaderSampleInterlockEXT
  81. OpExtension "SPV_EXT_fragment_shader_interlock"
  82. OpMemoryModel Logical GLSL450
  83. OpEntryPoint Fragment %main "main"
  84. OpExecutionMode %main OriginUpperLeft
  85. OpExecutionMode %main SampleInterlockOrderedEXT
  86. OpName %main "main"
  87. %void = OpTypeVoid
  88. %1 = OpTypeFunction %void
  89. %main = OpFunction %void None %1
  90. ; CHECK: OpLabel
  91. %2 = OpLabel
  92. ; CHECK-NEXT: OpNoLine
  93. OpNoLine
  94. ; CHECK-NEXT: OpBeginInvocationInterlockEXT
  95. OpBeginInvocationInterlockEXT
  96. OpBeginInvocationInterlockEXT
  97. OpEndInvocationInterlockEXT
  98. OpBeginInvocationInterlockEXT
  99. ; CHECK-NEXT: OpNoLine
  100. OpNoLine
  101. ; CHECK-NEXT: OpEndInvocationInterlockEXT
  102. OpEndInvocationInterlockEXT
  103. ; CHECK-NEXT: OpNoLine
  104. OpNoLine
  105. ; CHECK-NEXT: OpReturn
  106. OpReturn
  107. OpFunctionEnd
  108. )";
  109. SetTargetEnv(SPV_ENV_VULKAN_1_3);
  110. const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
  111. kTest, /* skip_nop= */ false);
  112. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  113. }
  114. TEST_F(InterlockInvocationPlacementTest, CheckFunctionCallExtractionBegin) {
  115. const std::string kTest = R"(
  116. OpCapability Shader
  117. OpCapability FragmentShaderSampleInterlockEXT
  118. OpExtension "SPV_EXT_fragment_shader_interlock"
  119. OpMemoryModel Logical GLSL450
  120. OpEntryPoint Fragment %main "main"
  121. OpExecutionMode %main OriginUpperLeft
  122. OpExecutionMode %main SampleInterlockOrderedEXT
  123. OpName %main "main"
  124. %void = OpTypeVoid
  125. %1 = OpTypeFunction %void
  126. %foo = OpFunction %void None %1
  127. ; CHECK: OpLabel
  128. ; CHECK-NOT: OpBeginInvocationInterlockEXT
  129. %2 = OpLabel
  130. OpBeginInvocationInterlockEXT
  131. OpBeginInvocationInterlockEXT
  132. OpReturn
  133. ; CHECK: OpFunctionEnd
  134. OpFunctionEnd
  135. %main = OpFunction %void None %1
  136. ; CHECK: OpLabel
  137. %3 = OpLabel
  138. ; CHECK-NEXT: OpBeginInvocationInterlockEXT
  139. ; CHECK-NEXT: OpFunctionCall
  140. %4 = OpFunctionCall %void %foo
  141. ; CHECK-NEXT: OpReturn
  142. OpReturn
  143. OpFunctionEnd
  144. )";
  145. SetTargetEnv(SPV_ENV_VULKAN_1_3);
  146. const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
  147. kTest, /* skip_nop= */ false);
  148. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  149. }
  150. TEST_F(InterlockInvocationPlacementTest, CheckFunctionCallExtractionEnd) {
  151. const std::string kTest = R"(
  152. OpCapability Shader
  153. OpCapability FragmentShaderSampleInterlockEXT
  154. OpExtension "SPV_EXT_fragment_shader_interlock"
  155. OpMemoryModel Logical GLSL450
  156. OpEntryPoint Fragment %main "main"
  157. OpExecutionMode %main OriginUpperLeft
  158. OpExecutionMode %main SampleInterlockOrderedEXT
  159. OpName %main "main"
  160. %void = OpTypeVoid
  161. %1 = OpTypeFunction %void
  162. %foo = OpFunction %void None %1
  163. ; CHECK: OpLabel
  164. ; CHECK-NOT: OpEndInvocationInterlockEXT
  165. %2 = OpLabel
  166. OpEndInvocationInterlockEXT
  167. OpEndInvocationInterlockEXT
  168. OpReturn
  169. ; CHECK: OpFunctionEnd
  170. OpFunctionEnd
  171. %main = OpFunction %void None %1
  172. ; CHECK: OpLabel
  173. %3 = OpLabel
  174. ; CHECK-NEXT: OpFunctionCall
  175. %4 = OpFunctionCall %void %foo
  176. ; CHECK-NEXT: OpEndInvocationInterlockEXT
  177. ; CHECK-NEXT: OpReturn
  178. OpReturn
  179. OpFunctionEnd
  180. )";
  181. SetTargetEnv(SPV_ENV_VULKAN_1_3);
  182. const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
  183. kTest, /* skip_nop= */ false);
  184. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  185. }
  186. TEST_F(InterlockInvocationPlacementTest,
  187. CheckFunctionCallExtractionRepeatedCall) {
  188. const std::string kTest = R"(
  189. OpCapability Shader
  190. OpCapability FragmentShaderSampleInterlockEXT
  191. OpExtension "SPV_EXT_fragment_shader_interlock"
  192. OpMemoryModel Logical GLSL450
  193. OpEntryPoint Fragment %main "main"
  194. OpExecutionMode %main OriginUpperLeft
  195. OpExecutionMode %main SampleInterlockOrderedEXT
  196. OpName %main "main"
  197. %void = OpTypeVoid
  198. %1 = OpTypeFunction %void
  199. %foo = OpFunction %void None %1
  200. ; CHECK: OpLabel
  201. ; CHECK-NOT: OpBeginInvocationInterlockEXT
  202. ; CHECK-NOT: OpEndInvocationInterlockEXT
  203. %2 = OpLabel
  204. OpBeginInvocationInterlockEXT
  205. OpEndInvocationInterlockEXT
  206. OpReturn
  207. ; CHECK: OpFunctionEnd
  208. OpFunctionEnd
  209. %main = OpFunction %void None %1
  210. ; CHECK: OpLabel
  211. %3 = OpLabel
  212. ; CHECK-NEXT: OpBeginInvocationInterlockEXT
  213. ; CHECK-NEXT: OpFunctionCall
  214. %4 = OpFunctionCall %void %foo
  215. ; CHECK-NEXT: OpFunctionCall
  216. %5 = OpFunctionCall %void %foo
  217. ; CHECK-NEXT: OpEndInvocationInterlockEXT
  218. ; CHECK-NEXT: OpReturn
  219. OpReturn
  220. OpFunctionEnd
  221. )";
  222. SetTargetEnv(SPV_ENV_VULKAN_1_3);
  223. const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
  224. kTest, /* skip_nop= */ false);
  225. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  226. }
  227. TEST_F(InterlockInvocationPlacementTest,
  228. CheckFunctionCallExtractionNestedCall) {
  229. const std::string kTest = R"(
  230. OpCapability Shader
  231. OpCapability FragmentShaderSampleInterlockEXT
  232. OpExtension "SPV_EXT_fragment_shader_interlock"
  233. OpMemoryModel Logical GLSL450
  234. OpEntryPoint Fragment %main "main"
  235. OpExecutionMode %main OriginUpperLeft
  236. OpExecutionMode %main SampleInterlockOrderedEXT
  237. OpName %main "main"
  238. %void = OpTypeVoid
  239. %1 = OpTypeFunction %void
  240. %foo = OpFunction %void None %1
  241. ; CHECK: OpLabel
  242. ; CHECK-NOT: OpBeginInvocationInterlockEXT
  243. ; CHECK-NOT: OpEndInvocationInterlockEXT
  244. %2 = OpLabel
  245. OpBeginInvocationInterlockEXT
  246. OpEndInvocationInterlockEXT
  247. OpReturn
  248. ; CHECK: OpFunctionEnd
  249. OpFunctionEnd
  250. %bar = OpFunction %void None %1
  251. ; CHECK: OpLabel
  252. ; CHECK-NOT: OpBeginInvocationInterlockEXT
  253. ; CHECK-NOT: OpEndInvocationInterlockEXT
  254. %3 = OpLabel
  255. %4 = OpFunctionCall %void %foo
  256. OpReturn
  257. ; CHECK: OpFunctionEnd
  258. OpFunctionEnd
  259. %main = OpFunction %void None %1
  260. ; CHECK: OpLabel
  261. %5 = OpLabel
  262. ; CHECK-NEXT: OpBeginInvocationInterlockEXT
  263. ; CHECK-NEXT: OpFunctionCall
  264. %6 = OpFunctionCall %void %bar
  265. ; CHECK-NEXT: OpEndInvocationInterlockEXT
  266. ; CHECK-NEXT: OpReturn
  267. OpReturn
  268. OpFunctionEnd
  269. )";
  270. SetTargetEnv(SPV_ENV_VULKAN_1_3);
  271. const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
  272. kTest, /* skip_nop= */ false);
  273. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  274. }
  275. TEST_F(InterlockInvocationPlacementTest, CheckLoopExtraction) {
  276. // Tests that any begin or end instructions in a loop are moved outside of the
  277. // loop.
  278. const std::string kTest = R"(
  279. OpCapability Shader
  280. OpCapability FragmentShaderSampleInterlockEXT
  281. OpExtension "SPV_EXT_fragment_shader_interlock"
  282. OpMemoryModel Logical GLSL450
  283. OpEntryPoint Fragment %main "main"
  284. OpExecutionMode %main OriginUpperLeft
  285. OpExecutionMode %main SampleInterlockOrderedEXT
  286. %void = OpTypeVoid
  287. %bool = OpTypeBool
  288. %true = OpConstantTrue %bool
  289. %1 = OpTypeFunction %void
  290. %main = OpFunction %void None %1
  291. %2 = OpLabel
  292. ; CHECK: OpBeginInvocationInterlockEXT
  293. ; CHECK-NOT: OpBeginInvocationInterlockEXT
  294. ; CHECK-NOT: OpEndInvocationInterlockEXT
  295. OpBranch %3
  296. %3 = OpLabel
  297. OpLoopMerge %3 %4 None
  298. ; CHECK: OpBranchConditional
  299. ; CHECK-NOT: OpBeginInvocationInterlockEXT
  300. ; CHECK-NOT: OpEndInvocationInterlockEXT
  301. OpBranchConditional %true %4 %5
  302. %4 = OpLabel
  303. OpBeginInvocationInterlockEXT
  304. OpEndInvocationInterlockEXT
  305. ; CHECK: OpBranch
  306. OpBranch %3
  307. ; CHECK-NEXT: OpLabel
  308. %5 = OpLabel
  309. ; CHECK-NEXT: OpEndInvocationInterlockEXT
  310. ; CHECK-NOT: OpEndInvocationInterlockEXT
  311. OpEndInvocationInterlockEXT
  312. OpReturn
  313. OpFunctionEnd
  314. )";
  315. SetTargetEnv(SPV_ENV_VULKAN_1_3);
  316. const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
  317. kTest, /* skip_nop= */ false);
  318. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  319. }
  320. TEST_F(InterlockInvocationPlacementTest, CheckAddBeginToElse) {
  321. // Test that if there is a begin in a single branch of a conditional, begin
  322. // will be added to the other branch.
  323. const std::string kTest = R"(
  324. OpCapability Shader
  325. OpCapability FragmentShaderSampleInterlockEXT
  326. OpExtension "SPV_EXT_fragment_shader_interlock"
  327. OpMemoryModel Logical GLSL450
  328. OpEntryPoint Fragment %main "main"
  329. OpExecutionMode %main OriginUpperLeft
  330. OpExecutionMode %main SampleInterlockOrderedEXT
  331. OpName %main "main"
  332. %void = OpTypeVoid
  333. %bool = OpTypeBool
  334. %true = OpConstantTrue %bool
  335. %1 = OpTypeFunction %void
  336. %main = OpFunction %void None %1
  337. %2 = OpLabel
  338. ; CHECK-NOT: OpBeginInvocationInterlockEXT
  339. OpSelectionMerge %5 None
  340. ; CHECK: OpBranchConditional
  341. OpBranchConditional %true %3 %4
  342. ; CHECK-NEXT: OpLabel
  343. %3 = OpLabel
  344. ; CHECK-NEXT: OpBeginInvocationInterlockEXT
  345. OpBeginInvocationInterlockEXT
  346. OpEndInvocationInterlockEXT
  347. ; CHECK-NEXT: OpBranch
  348. OpBranch %5
  349. %4 = OpLabel
  350. ; CHECK: OpBeginInvocationInterlockEXT
  351. ; CHECK-NEXT: OpBranch
  352. OpBranch %5
  353. ; CHECK-NEXT: OpLabel
  354. %5 = OpLabel
  355. OpBeginInvocationInterlockEXT
  356. ; CHECK-NEXT: OpEndInvocationInterlockEXT
  357. OpEndInvocationInterlockEXT
  358. OpReturn
  359. OpFunctionEnd
  360. )";
  361. SetTargetEnv(SPV_ENV_VULKAN_1_3);
  362. const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
  363. kTest, /* skip_nop= */ false);
  364. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  365. }
  366. TEST_F(InterlockInvocationPlacementTest, CheckAddEndToElse) {
  367. const std::string kTest = R"(
  368. OpCapability Shader
  369. OpCapability FragmentShaderSampleInterlockEXT
  370. OpExtension "SPV_EXT_fragment_shader_interlock"
  371. OpMemoryModel Logical GLSL450
  372. OpEntryPoint Fragment %main "main"
  373. OpExecutionMode %main OriginUpperLeft
  374. OpExecutionMode %main SampleInterlockOrderedEXT
  375. OpName %main "main"
  376. %void = OpTypeVoid
  377. %bool = OpTypeBool
  378. %true = OpConstantTrue %bool
  379. %1 = OpTypeFunction %void
  380. %main = OpFunction %void None %1
  381. %2 = OpLabel
  382. ; CHECK: OpBeginInvocationInterlockEXT
  383. OpBeginInvocationInterlockEXT
  384. ; CHECK-NOT: OpEndInvocationInterlockEXT
  385. OpEndInvocationInterlockEXT
  386. OpSelectionMerge %5 None
  387. ; CHECK: OpBranchConditional
  388. OpBranchConditional %true %3 %4
  389. ; CHECK-NEXT: OpLabel
  390. %3 = OpLabel
  391. OpBeginInvocationInterlockEXT
  392. ; CHECK-NEXT: OpEndInvocationInterlockEXT
  393. OpEndInvocationInterlockEXT
  394. ; CHECK-NEXT: OpBranch
  395. OpBranch %5
  396. %4 = OpLabel
  397. ; CHECK: OpEndInvocationInterlockEXT
  398. ; CHECK-NEXT: OpBranch
  399. OpBranch %5
  400. ; CHECK-NEXT: OpLabel
  401. %5 = OpLabel
  402. ; CHECK-NOT: OpEndInvocationInterlockEXT
  403. OpReturn
  404. OpFunctionEnd
  405. )";
  406. SetTargetEnv(SPV_ENV_VULKAN_1_3);
  407. const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
  408. kTest, /* skip_nop= */ false);
  409. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  410. }
  411. TEST_F(InterlockInvocationPlacementTest, CheckSplitIfWithoutElseBegin) {
  412. // Test that if there is a begin in the then branch of a conditional, and no
  413. // else branch, an else branch with a begin will created.
  414. const std::string kTest = R"(
  415. OpCapability Shader
  416. OpCapability FragmentShaderSampleInterlockEXT
  417. OpExtension "SPV_EXT_fragment_shader_interlock"
  418. OpMemoryModel Logical GLSL450
  419. OpEntryPoint Fragment %main "main"
  420. OpExecutionMode %main OriginUpperLeft
  421. OpExecutionMode %main SampleInterlockOrderedEXT
  422. OpName %main "main"
  423. %void = OpTypeVoid
  424. %bool = OpTypeBool
  425. %true = OpConstantTrue %bool
  426. %1 = OpTypeFunction %void
  427. %main = OpFunction %void None %1
  428. %2 = OpLabel
  429. ; CHECK-NOT: OpBeginInvocationInterlockEXT
  430. OpSelectionMerge %5 None
  431. ; CHECK: OpBranchConditional
  432. OpBranchConditional %true %3 %5
  433. ; CHECK-NEXT: OpLabel
  434. ; CHECK-NEXT: OpBeginInvocationInterlockEXT
  435. ; CHECK-NEXT: OpBranch
  436. ; CHECK-NEXT: OpLabel
  437. %3 = OpLabel
  438. ; CHECK-NEXT: OpBeginInvocationInterlockEXT
  439. ; CHECK-NOT: OpEndInvocationInterlockEXT
  440. OpBeginInvocationInterlockEXT
  441. OpEndInvocationInterlockEXT
  442. OpBranch %5
  443. ; CHECK: OpLabel
  444. %5 = OpLabel
  445. ; CHECK-NOT: OpBeginInvocationInterlockEXT
  446. OpBeginInvocationInterlockEXT
  447. ; CHECK-NEXT: OpEndInvocationInterlockEXT
  448. OpEndInvocationInterlockEXT
  449. OpReturn
  450. OpFunctionEnd
  451. )";
  452. SetTargetEnv(SPV_ENV_VULKAN_1_3);
  453. const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
  454. kTest, /* skip_nop= */ false);
  455. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  456. }
  457. TEST_F(InterlockInvocationPlacementTest, CheckSplitIfWithoutElseEnd) {
  458. const std::string kTest = R"(
  459. OpCapability Shader
  460. OpCapability FragmentShaderSampleInterlockEXT
  461. OpExtension "SPV_EXT_fragment_shader_interlock"
  462. OpMemoryModel Logical GLSL450
  463. OpEntryPoint Fragment %main "main"
  464. OpExecutionMode %main OriginUpperLeft
  465. OpExecutionMode %main SampleInterlockOrderedEXT
  466. OpName %main "main"
  467. %void = OpTypeVoid
  468. %bool = OpTypeBool
  469. %true = OpConstantTrue %bool
  470. %1 = OpTypeFunction %void
  471. %main = OpFunction %void None %1
  472. %2 = OpLabel
  473. ; CHECK: OpBeginInvocationInterlockEXT
  474. OpBeginInvocationInterlockEXT
  475. ; CHECK-NOT: OpEndInvocationInterlockEXT
  476. OpEndInvocationInterlockEXT
  477. ; CHECK-NEXT: OpSelectionMerge [[merge:%\d+]]
  478. OpSelectionMerge %5 None
  479. ; CHECK-NEXT: OpBranchConditional %true [[then:%\d+]] [[else:%\d+]]
  480. OpBranchConditional %true %3 %5
  481. ; CHECK-NEXT: [[else]] = OpLabel
  482. ; CHECK-NEXT: OpEndInvocationInterlockEXT
  483. ; CHECK-NEXT: OpBranch [[merge]]
  484. ; CHECK-NEXT: [[then]] = OpLabel
  485. %3 = OpLabel
  486. ; CHECK-NEXT: OpEndInvocationInterlockEXT
  487. OpBeginInvocationInterlockEXT
  488. OpEndInvocationInterlockEXT
  489. ; CHECK-NEXT: OpBranch [[merge]]
  490. OpBranch %5
  491. ; CHECK-NEXT: [[merge]] = OpLabel
  492. %5 = OpLabel
  493. ; CHECK-NEXT: OpReturn
  494. OpReturn
  495. OpFunctionEnd
  496. )";
  497. SetTargetEnv(SPV_ENV_VULKAN_1_3);
  498. const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
  499. kTest, /* skip_nop= */ false);
  500. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  501. }
  502. TEST_F(InterlockInvocationPlacementTest, CheckSplitSwitch) {
  503. // Test that if there is a begin or end in a single branch of a switch, begin
  504. // or end will be added to all the other branches.
  505. const std::string kTest = R"(
  506. OpCapability Shader
  507. OpCapability FragmentShaderSampleInterlockEXT
  508. OpExtension "SPV_EXT_fragment_shader_interlock"
  509. OpMemoryModel Logical GLSL450
  510. OpEntryPoint Fragment %main "main"
  511. OpExecutionMode %main OriginUpperLeft
  512. OpExecutionMode %main SampleInterlockOrderedEXT
  513. OpName %main "main"
  514. %void = OpTypeVoid
  515. %uint = OpTypeInt 32 0
  516. %uint_1 = OpConstant %uint 1
  517. %1 = OpTypeFunction %void
  518. %main = OpFunction %void None %1
  519. ; CHECK: OpLabel
  520. %2 = OpLabel
  521. ; CHECK-NEXT: OpSelectionMerge [[merge:%\d+]]
  522. OpSelectionMerge %8 None
  523. ; CHECK-NEXT: OpSwitch %uint_1 [[default:%\d+]] 0 [[case_0:%\d+]] 1 [[case_1:%\d+]] 2 [[case_2:%\d+]]
  524. OpSwitch %uint_1 %8 0 %4 1 %5 2 %8
  525. ; CHECK-NEXT: [[case_2]] = OpLabel
  526. ; CHECK-NEXT: OpBeginInvocationInterlockEXT
  527. ; CHECK-NEXT: OpBranch [[merge]]
  528. ; CHECK-NEXT: [[default]] = OpLabel
  529. ; CHECK-NEXT: OpBeginInvocationInterlockEXT
  530. ; CHECK-NEXT: OpBranch [[merge]]
  531. ; CHECK-NEXT: [[case_0]] = OpLabel
  532. %4 = OpLabel
  533. ; CHECK-NEXT: OpBeginInvocationInterlockEXT
  534. ; CHECK-NOT: OpEndInvocationInterlockEXT
  535. OpBeginInvocationInterlockEXT
  536. OpEndInvocationInterlockEXT
  537. ; CHECK-NEXT: OpNoLine
  538. OpNoLine
  539. ; CHECK-NEXT: OpBranch [[merge]]
  540. OpBranch %8
  541. ; CHECK-NEXT: [[case_1]] = OpLabel
  542. %5 = OpLabel
  543. ; CHECK-NEXT: OpBeginInvocationInterlockEXT
  544. ; CHECK-NOT: OpEndInvocationInterlockEXT
  545. OpBeginInvocationInterlockEXT
  546. OpEndInvocationInterlockEXT
  547. ; CHECK-NEXT: OpNoLine
  548. OpNoLine
  549. ; CHECK-NEXT: OpNoLine
  550. OpNoLine
  551. ; CHECK-NEXT: OpBranch [[merge]]
  552. OpBranch %8
  553. ; CHECK-NEXT: [[merge]] = OpLabel
  554. %8 = OpLabel
  555. ; CHECK-NOT: OpBeginInvocationInterlockEXT
  556. OpBeginInvocationInterlockEXT
  557. ; CHECK-NEXT: OpEndInvocationInterlockEXT
  558. OpEndInvocationInterlockEXT
  559. OpReturn
  560. OpFunctionEnd
  561. )";
  562. SetTargetEnv(SPV_ENV_VULKAN_1_3);
  563. const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>(
  564. kTest, /* skip_nop= */ false);
  565. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  566. }
  567. } // namespace
  568. } // namespace opt
  569. } // namespace spvtools