divergence_analysis_test.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. // Copyright (c) 2021 Google LLC.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "source/lint/divergence_analysis.h"
  15. #include <string>
  16. #include "gtest/gtest.h"
  17. #include "source/opt/build_module.h"
  18. #include "source/opt/ir_context.h"
  19. #include "source/opt/module.h"
  20. #include "spirv-tools/libspirv.h"
  21. namespace spvtools {
  22. namespace lint {
  23. namespace {
  24. void CLIMessageConsumer(spv_message_level_t level, const char*,
  25. const spv_position_t& position, const char* message) {
  26. switch (level) {
  27. case SPV_MSG_FATAL:
  28. case SPV_MSG_INTERNAL_ERROR:
  29. case SPV_MSG_ERROR:
  30. std::cerr << "error: line " << position.index << ": " << message
  31. << std::endl;
  32. break;
  33. case SPV_MSG_WARNING:
  34. std::cout << "warning: line " << position.index << ": " << message
  35. << std::endl;
  36. break;
  37. case SPV_MSG_INFO:
  38. std::cout << "info: line " << position.index << ": " << message
  39. << std::endl;
  40. break;
  41. default:
  42. break;
  43. }
  44. }
  45. class DivergenceTest : public ::testing::Test {
  46. protected:
  47. std::unique_ptr<opt::IRContext> context_;
  48. std::unique_ptr<DivergenceAnalysis> divergence_;
  49. void Build(std::string text, uint32_t function_id = 1) {
  50. context_ = BuildModule(SPV_ENV_UNIVERSAL_1_0, CLIMessageConsumer, text,
  51. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  52. ASSERT_NE(nullptr, context_.get());
  53. opt::Module* module = context_->module();
  54. ASSERT_NE(nullptr, module);
  55. // First function should have the given ID.
  56. ASSERT_NE(module->begin(), module->end());
  57. opt::Function* function = &*module->begin();
  58. ASSERT_EQ(function->result_id(), function_id);
  59. divergence_.reset(new DivergenceAnalysis(*context_));
  60. divergence_->Run(function);
  61. }
  62. };
  63. // Makes assertions a bit shorter.
  64. using Level = DivergenceAnalysis::DivergenceLevel;
  65. namespace {
  66. std::string Preamble() {
  67. return R"(
  68. OpCapability Shader
  69. OpMemoryModel Logical GLSL450
  70. OpEntryPoint Fragment %1 "main" %x %y
  71. OpExecutionMode %1 OriginLowerLeft
  72. OpDecorate %y Flat
  73. %void = OpTypeVoid
  74. %void_f = OpTypeFunction %void
  75. %bool = OpTypeBool
  76. %float = OpTypeFloat 32
  77. %false = OpConstantFalse %bool
  78. %true = OpConstantTrue %bool
  79. %zero = OpConstant %float 0
  80. %one = OpConstant %float 1
  81. %x_t = OpTypePointer Input %float
  82. %x = OpVariable %x_t Input
  83. %y = OpVariable %x_t Input
  84. %1 = OpFunction %void None %void_f
  85. )";
  86. }
  87. } // namespace
  88. TEST_F(DivergenceTest, SimpleTest) {
  89. // pseudocode:
  90. // %10:
  91. // %11 = load x
  92. // if (%12 = (%11 < 0)) {
  93. // %13:
  94. // // do nothing
  95. // }
  96. // %14:
  97. // return
  98. ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
  99. %10 = OpLabel
  100. %11 = OpLoad %float %x
  101. %12 = OpFOrdLessThan %bool %11 %zero
  102. OpSelectionMerge %14 None
  103. OpBranchConditional %12 %13 %14
  104. %13 = OpLabel
  105. OpBranch %14
  106. %14 = OpLabel
  107. OpReturn
  108. OpFunctionEnd
  109. )"));
  110. // Control flow divergence.
  111. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
  112. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13));
  113. EXPECT_EQ(12, divergence_->GetDivergenceSource(13));
  114. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(14));
  115. // Value divergence.
  116. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11));
  117. EXPECT_EQ(0, divergence_->GetDivergenceSource(11));
  118. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12));
  119. EXPECT_EQ(11, divergence_->GetDivergenceSource(12));
  120. }
  121. TEST_F(DivergenceTest, FlowTypesTest) {
  122. // pseudocode:
  123. // %10:
  124. // %11 = load x
  125. // %12 = x < 0 // data -> data
  126. // if (%12) {
  127. // %13: // data -> control
  128. // if (true) {
  129. // %14: // control -> control
  130. // }
  131. // %15:
  132. // %16 = 1
  133. // } else {
  134. // %17:
  135. // %18 = 2
  136. // }
  137. // %19:
  138. // %19 = phi(%16 from %15, %18 from %17) // control -> data
  139. // return
  140. ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
  141. %10 = OpLabel
  142. %11 = OpLoad %float %x
  143. %12 = OpFOrdLessThan %bool %11 %zero
  144. OpSelectionMerge %19 None
  145. OpBranchConditional %12 %13 %17
  146. %13 = OpLabel
  147. OpSelectionMerge %15 None
  148. OpBranchConditional %true %14 %15
  149. %14 = OpLabel
  150. OpBranch %15
  151. %15 = OpLabel
  152. %16 = OpFAdd %float %zero %zero
  153. OpBranch %19
  154. %17 = OpLabel
  155. %18 = OpFAdd %float %zero %one
  156. OpBranch %19
  157. %19 = OpLabel
  158. %20 = OpPhi %float %16 %15 %18 %17
  159. OpReturn
  160. OpFunctionEnd
  161. )"));
  162. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
  163. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11));
  164. EXPECT_EQ(0, divergence_->GetDivergenceSource(11));
  165. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12));
  166. EXPECT_EQ(11, divergence_->GetDivergenceSource(12));
  167. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13));
  168. EXPECT_EQ(12, divergence_->GetDivergenceSource(13));
  169. EXPECT_EQ(10, divergence_->GetDivergenceDependenceSource(13));
  170. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(14));
  171. EXPECT_EQ(13, divergence_->GetDivergenceSource(14));
  172. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(15));
  173. EXPECT_EQ(12, divergence_->GetDivergenceSource(15));
  174. EXPECT_EQ(10, divergence_->GetDivergenceDependenceSource(15));
  175. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(16));
  176. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(17));
  177. EXPECT_EQ(12, divergence_->GetDivergenceSource(17));
  178. EXPECT_EQ(10, divergence_->GetDivergenceDependenceSource(17));
  179. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(18));
  180. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(19));
  181. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(20));
  182. EXPECT_TRUE(divergence_->GetDivergenceSource(20) == 15 ||
  183. divergence_->GetDivergenceDependenceSource(20) == 17)
  184. << "Got: " << divergence_->GetDivergenceDependenceSource(20);
  185. }
  186. TEST_F(DivergenceTest, ExitDependenceTest) {
  187. // pseudocode:
  188. // %10:
  189. // %11 = load x
  190. // %12 = %11 < 0
  191. // %13:
  192. // do {
  193. // %14:
  194. // if (%12) {
  195. // %15:
  196. // continue;
  197. // }
  198. // %16:
  199. // %17:
  200. // continue;
  201. // } %18: while(false);
  202. // %19:
  203. // return
  204. ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
  205. %10 = OpLabel
  206. %11 = OpLoad %float %x
  207. %12 = OpFOrdLessThan %bool %11 %zero ; data -> data
  208. OpBranch %13
  209. %13 = OpLabel
  210. OpLoopMerge %19 %18 None
  211. OpBranch %14
  212. %14 = OpLabel
  213. OpSelectionMerge %16 None
  214. OpBranchConditional %12 %15 %16
  215. %15 = OpLabel
  216. OpBranch %18 ; continue
  217. %16 = OpLabel
  218. OpBranch %17
  219. %17 = OpLabel
  220. OpBranch %18 ; continue
  221. %18 = OpLabel
  222. OpBranchConditional %false %13 %19
  223. %19 = OpLabel
  224. OpReturn
  225. OpFunctionEnd
  226. )"));
  227. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
  228. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11));
  229. EXPECT_EQ(0, divergence_->GetDivergenceSource(11));
  230. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12));
  231. EXPECT_EQ(11, divergence_->GetDivergenceSource(12));
  232. // Since both branches continue, there's no divergent control dependence
  233. // to 13.
  234. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(13));
  235. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(14));
  236. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(15));
  237. EXPECT_EQ(12, divergence_->GetDivergenceSource(15));
  238. EXPECT_EQ(14, divergence_->GetDivergenceDependenceSource(15));
  239. // These two blocks are outside the if but are still control dependent.
  240. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(16));
  241. EXPECT_EQ(12, divergence_->GetDivergenceSource(16));
  242. EXPECT_EQ(14, divergence_->GetDivergenceDependenceSource(16));
  243. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(17));
  244. EXPECT_EQ(12, divergence_->GetDivergenceSource(17));
  245. EXPECT_EQ(14, divergence_->GetDivergenceDependenceSource(17));
  246. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(18));
  247. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(19));
  248. }
  249. TEST_F(DivergenceTest, ReconvergencePromotionTest) {
  250. // pseudocode:
  251. // %10:
  252. // %11 = load y
  253. // %12 = %11 < 0
  254. // if (%12) {
  255. // %13:
  256. // %14:
  257. // %15:
  258. // if (true) {
  259. // %16:
  260. // }
  261. // // Reconvergence *not* guaranteed as
  262. // // control is not uniform on the IG level
  263. // // at %15.
  264. // %17:
  265. // %18:
  266. // %19:
  267. // %20 = load x
  268. // }
  269. // %21:
  270. // %22 = phi(%11, %20)
  271. // return
  272. ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
  273. %10 = OpLabel
  274. %11 = OpLoad %float %y
  275. %12 = OpFOrdLessThan %bool %11 %zero
  276. OpSelectionMerge %21 None
  277. OpBranchConditional %12 %13 %21
  278. %13 = OpLabel
  279. OpBranch %14
  280. %14 = OpLabel
  281. OpBranch %15
  282. %15 = OpLabel
  283. OpSelectionMerge %17 None
  284. OpBranchConditional %true %16 %17
  285. %16 = OpLabel
  286. OpBranch %17
  287. %17 = OpLabel
  288. OpBranch %18
  289. %18 = OpLabel
  290. OpBranch %19
  291. %19 = OpLabel
  292. %20 = OpLoad %float %y
  293. OpBranch %21
  294. %21 = OpLabel
  295. %22 = OpPhi %float %11 %10 %20 %19
  296. OpReturn
  297. OpFunctionEnd
  298. )"));
  299. ASSERT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
  300. ASSERT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(21));
  301. ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(11));
  302. ASSERT_EQ(0, divergence_->GetDivergenceSource(11));
  303. ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(12));
  304. ASSERT_EQ(11, divergence_->GetDivergenceSource(12));
  305. ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(13));
  306. ASSERT_EQ(12, divergence_->GetDivergenceSource(13));
  307. ASSERT_EQ(10, divergence_->GetDivergenceDependenceSource(13));
  308. ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(14));
  309. ASSERT_EQ(12, divergence_->GetDivergenceSource(14));
  310. ASSERT_EQ(10, divergence_->GetDivergenceDependenceSource(14));
  311. ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(15));
  312. ASSERT_EQ(12, divergence_->GetDivergenceSource(15));
  313. ASSERT_EQ(10, divergence_->GetDivergenceDependenceSource(15));
  314. ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(16));
  315. ASSERT_EQ(15, divergence_->GetDivergenceSource(16));
  316. ASSERT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(17));
  317. ASSERT_EQ(12, divergence_->GetDivergenceSource(17));
  318. ASSERT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(18));
  319. ASSERT_EQ(12, divergence_->GetDivergenceSource(18));
  320. ASSERT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(19));
  321. ASSERT_EQ(12, divergence_->GetDivergenceSource(19));
  322. ASSERT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(20));
  323. ASSERT_EQ(0, divergence_->GetDivergenceSource(20));
  324. ASSERT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(22));
  325. ASSERT_EQ(19, divergence_->GetDivergenceSource(22));
  326. ASSERT_EQ(10, divergence_->GetDivergenceDependenceSource(15));
  327. }
  328. TEST_F(DivergenceTest, FunctionCallTest) {
  329. // pseudocode:
  330. // %2() {
  331. // %20:
  332. // %21 = load x
  333. // %22 = %21 < 0
  334. // if (%22) {
  335. // %23:
  336. // return
  337. // }
  338. // %24:
  339. // return
  340. // }
  341. //
  342. // main() {
  343. // %10:
  344. // %11 = %2();
  345. // // Reconvergence *not* guaranteed.
  346. // %12:
  347. // return
  348. // }
  349. ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
  350. %10 = OpLabel
  351. %11 = OpFunctionCall %void %2
  352. OpBranch %12
  353. %12 = OpLabel
  354. OpReturn
  355. OpFunctionEnd
  356. %2 = OpFunction %void None %void_f
  357. %20 = OpLabel
  358. %21 = OpLoad %float %x
  359. %22 = OpFOrdLessThan %bool %21 %zero
  360. OpSelectionMerge %24 None
  361. OpBranchConditional %22 %23 %24
  362. %23 = OpLabel
  363. OpReturn
  364. %24 = OpLabel
  365. OpReturn
  366. OpFunctionEnd
  367. )"));
  368. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
  369. // Conservatively assume function return value is uniform.
  370. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(11));
  371. // TODO(dongja): blocks reachable from diverging function calls should be
  372. // divergent.
  373. // EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12));
  374. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(12)); // Wrong!
  375. }
  376. TEST_F(DivergenceTest, LateMergeTest) {
  377. // pseudocode:
  378. // %10:
  379. // %11 = load y
  380. // %12 = %11 < 0
  381. // [merge: %15]
  382. // if (%12) {
  383. // %13:
  384. // }
  385. // %14: // Reconvergence hasn't happened by here.
  386. // %15:
  387. // return
  388. ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
  389. %10 = OpLabel
  390. %11 = OpLoad %float %x
  391. %12 = OpFOrdLessThan %bool %11 %zero
  392. OpSelectionMerge %15 None
  393. OpBranchConditional %12 %13 %14
  394. %13 = OpLabel
  395. OpBranch %14
  396. %14 = OpLabel
  397. OpBranch %15
  398. %15 = OpLabel
  399. OpReturn
  400. OpFunctionEnd
  401. )"));
  402. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
  403. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11));
  404. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12));
  405. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13));
  406. // TODO(dongja):
  407. // EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(14));
  408. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(14)); // Wrong!
  409. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(15));
  410. }
  411. // The following series of tests makes sure that we find the least fixpoint.
  412. TEST_F(DivergenceTest, UniformFixpointTest) {
  413. // pseudocode:
  414. // %10:
  415. // %20 = load x
  416. // %21 = load y
  417. // do {
  418. // %11:
  419. // %12:
  420. // %13 = phi(%zero from %11, %14 from %16)
  421. // %14 = %13 + 1
  422. // %15 = %13 < 1
  423. // } %16: while (%15)
  424. // %17:
  425. ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
  426. %10 = OpLabel
  427. %20 = OpLoad %float %x
  428. %21 = OpLoad %float %y
  429. OpBranch %11
  430. %11 = OpLabel
  431. %13 = OpPhi %float %zero %10 %14 %16
  432. OpLoopMerge %17 %16 None
  433. OpBranch %12
  434. %12 = OpLabel
  435. %14 = OpFAdd %float %13 %one
  436. %15 = OpFOrdLessThan %bool %13 %one
  437. OpBranch %16
  438. %16 = OpLabel
  439. OpBranchConditional %15 %11 %17
  440. %17 = OpLabel
  441. OpReturn
  442. OpFunctionEnd
  443. )"));
  444. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
  445. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(11));
  446. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(12));
  447. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(13));
  448. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(14));
  449. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(15));
  450. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(16));
  451. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(17));
  452. }
  453. TEST_F(DivergenceTest, PartiallyUniformFixpointTest) {
  454. // pseudocode:
  455. // %10:
  456. // %20 = load x
  457. // %21 = load y
  458. // do {
  459. // %11:
  460. // %12:
  461. // %13 = phi(%zero from %11, %14 from %16)
  462. // %14 = %13 + 1
  463. // %15 = %13 < %21
  464. // } %16: while (%15)
  465. // %17:
  466. ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
  467. %10 = OpLabel
  468. %20 = OpLoad %float %x
  469. %21 = OpLoad %float %y
  470. OpBranch %11
  471. %11 = OpLabel
  472. %13 = OpPhi %float %zero %10 %14 %16
  473. OpLoopMerge %17 %16 None
  474. OpBranch %12
  475. %12 = OpLabel
  476. %14 = OpFAdd %float %13 %one
  477. %15 = OpFOrdLessThan %bool %13 %21
  478. OpBranch %16
  479. %16 = OpLabel
  480. OpBranchConditional %15 %11 %17
  481. %17 = OpLabel
  482. OpReturn
  483. OpFunctionEnd
  484. )"));
  485. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
  486. EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(11));
  487. EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(12));
  488. EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(13));
  489. EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(14));
  490. EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(15));
  491. EXPECT_EQ(Level::kPartiallyUniform, divergence_->GetDivergenceLevel(16));
  492. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(17));
  493. }
  494. TEST_F(DivergenceTest, DivergentFixpointTest) {
  495. // pseudocode:
  496. // %10:
  497. // %20 = load x
  498. // %21 = load y
  499. // do {
  500. // %11:
  501. // %12:
  502. // %13 = phi(%zero from %11, %14 from %16)
  503. // %14 = %13 + 1
  504. // %15 = %13 < %20
  505. // } %16: while (%15)
  506. // %17:
  507. ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
  508. %10 = OpLabel
  509. %20 = OpLoad %float %x
  510. %21 = OpLoad %float %y
  511. OpBranch %11
  512. %11 = OpLabel
  513. %13 = OpPhi %float %zero %10 %14 %16
  514. OpLoopMerge %17 %16 None
  515. OpBranch %12
  516. %12 = OpLabel
  517. %14 = OpFAdd %float %13 %one
  518. %15 = OpFOrdLessThan %bool %13 %20
  519. OpBranch %16
  520. %16 = OpLabel
  521. OpBranchConditional %15 %11 %17
  522. %17 = OpLabel
  523. OpReturn
  524. OpFunctionEnd
  525. )"));
  526. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
  527. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11));
  528. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12));
  529. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13));
  530. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(14));
  531. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(15));
  532. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(16));
  533. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(17));
  534. }
  535. TEST_F(DivergenceTest, DivergentOverridesPartiallyUniformTest) {
  536. // pseudocode:
  537. // %10:
  538. // %20 = load x
  539. // %21 = load y
  540. // %11:
  541. // do {
  542. // %12:
  543. // %13 = phi(%21 from %11, %14 from %16)
  544. // %14 = %13 + 1
  545. // %15 = %13 < %20
  546. // } %16: while (%15)
  547. // %17:
  548. ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
  549. %10 = OpLabel
  550. %20 = OpLoad %float %x
  551. %21 = OpLoad %float %y
  552. OpBranch %11
  553. %11 = OpLabel
  554. %13 = OpPhi %float %zero %10 %14 %16
  555. OpLoopMerge %17 %16 None
  556. OpBranch %12
  557. %12 = OpLabel
  558. %14 = OpFAdd %float %13 %one
  559. %15 = OpFOrdLessThan %bool %13 %20
  560. OpBranch %16
  561. %16 = OpLabel
  562. OpBranchConditional %15 %11 %17
  563. %17 = OpLabel
  564. OpReturn
  565. OpFunctionEnd
  566. )"));
  567. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
  568. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11));
  569. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12));
  570. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13));
  571. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(14));
  572. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(15));
  573. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(16));
  574. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(17));
  575. }
  576. TEST_F(DivergenceTest, NestedFixpointTest) {
  577. // pseudocode:
  578. // %10:
  579. // %20 = load x
  580. // %21 = load y
  581. // do {
  582. // %22:
  583. // %23:
  584. // %24 = phi(%zero from %22, %25 from %26)
  585. // %11:
  586. // do {
  587. // %12:
  588. // %13 = phi(%zero from %11, %14 from %16)
  589. // %14 = %13 + 1
  590. // %15 = %13 < %24
  591. // } %16: while (%15)
  592. // %17:
  593. // %25 = load x
  594. // } %26: while (false)
  595. // %27:
  596. // return
  597. ASSERT_NO_FATAL_FAILURE(Build(Preamble() + R"(
  598. %10 = OpLabel
  599. %20 = OpLoad %float %x
  600. %21 = OpLoad %float %y
  601. OpBranch %22
  602. %22 = OpLabel
  603. %24 = OpPhi %float %zero %10 %25 %26
  604. OpLoopMerge %27 %26 None
  605. OpBranch %23
  606. %23 = OpLabel
  607. OpBranch %11
  608. %11 = OpLabel
  609. %13 = OpPhi %float %zero %23 %14 %16
  610. OpLoopMerge %17 %16 None
  611. OpBranch %12
  612. %12 = OpLabel
  613. %14 = OpFAdd %float %13 %one
  614. %15 = OpFOrdLessThan %bool %13 %24
  615. OpBranch %16
  616. %16 = OpLabel
  617. OpBranchConditional %15 %11 %17
  618. %17 = OpLabel
  619. %25 = OpLoad %float %x
  620. OpBranch %26
  621. %26 = OpLabel
  622. OpBranchConditional %false %22 %27
  623. %27 = OpLabel
  624. OpReturn
  625. OpFunctionEnd
  626. )"));
  627. // This test makes sure that divergent values flowing upward can influence the
  628. // fixpoint of a loop.
  629. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(10));
  630. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(11));
  631. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(12));
  632. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(13));
  633. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(14));
  634. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(15));
  635. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(16));
  636. // Control of the outer loop is still uniform.
  637. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(17));
  638. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(22));
  639. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(23));
  640. // Seed divergent values.
  641. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(24));
  642. EXPECT_EQ(Level::kDivergent, divergence_->GetDivergenceLevel(25));
  643. // Outer loop control.
  644. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(26));
  645. // Merged.
  646. EXPECT_EQ(Level::kUniform, divergence_->GetDivergenceLevel(27));
  647. }
  648. } // namespace
  649. } // namespace lint
  650. } // namespace spvtools