ccp_test.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902
  1. // Copyright (c) 2017 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 <string>
  15. #include "gmock/gmock.h"
  16. #include "gtest/gtest.h"
  17. #include "source/opt/ccp_pass.h"
  18. #include "test/opt/pass_fixture.h"
  19. #include "test/opt/pass_utils.h"
  20. namespace spvtools {
  21. namespace opt {
  22. namespace {
  23. using CCPTest = PassTest<::testing::Test>;
  24. TEST_F(CCPTest, PropagateThroughPhis) {
  25. const std::string spv_asm = R"(
  26. OpCapability Shader
  27. %1 = OpExtInstImport "GLSL.std.450"
  28. OpMemoryModel Logical GLSL450
  29. OpEntryPoint Fragment %main "main" %x %outparm
  30. OpExecutionMode %main OriginUpperLeft
  31. OpSource GLSL 450
  32. OpName %main "main"
  33. OpName %x "x"
  34. OpName %outparm "outparm"
  35. OpDecorate %x Flat
  36. OpDecorate %x Location 0
  37. OpDecorate %outparm Location 0
  38. %void = OpTypeVoid
  39. %3 = OpTypeFunction %void
  40. %int = OpTypeInt 32 1
  41. %bool = OpTypeBool
  42. %_ptr_Function_int = OpTypePointer Function %int
  43. %int_4 = OpConstant %int 4
  44. %int_3 = OpConstant %int 3
  45. %int_1 = OpConstant %int 1
  46. %_ptr_Input_int = OpTypePointer Input %int
  47. %x = OpVariable %_ptr_Input_int Input
  48. %_ptr_Output_int = OpTypePointer Output %int
  49. %outparm = OpVariable %_ptr_Output_int Output
  50. %main = OpFunction %void None %3
  51. %4 = OpLabel
  52. %5 = OpLoad %int %x
  53. %9 = OpIAdd %int %int_1 %int_3
  54. %6 = OpSGreaterThan %bool %5 %int_3
  55. OpSelectionMerge %25 None
  56. OpBranchConditional %6 %22 %23
  57. %22 = OpLabel
  58. ; CHECK: OpCopyObject %int %int_4
  59. %7 = OpCopyObject %int %9
  60. OpBranch %25
  61. %23 = OpLabel
  62. %8 = OpCopyObject %int %int_4
  63. OpBranch %25
  64. %25 = OpLabel
  65. ; %int_4 should have propagated to both OpPhi operands.
  66. ; CHECK: OpPhi %int %int_4 {{%\d+}} %int_4 {{%\d+}}
  67. %35 = OpPhi %int %7 %22 %8 %23
  68. ; This function always returns 4. DCE should get rid of everything else.
  69. ; CHECK OpStore %outparm %int_4
  70. OpStore %outparm %35
  71. OpReturn
  72. OpFunctionEnd
  73. )";
  74. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  75. }
  76. TEST_F(CCPTest, SimplifyConditionals) {
  77. const std::string spv_asm = R"(
  78. OpCapability Shader
  79. %1 = OpExtInstImport "GLSL.std.450"
  80. OpMemoryModel Logical GLSL450
  81. OpEntryPoint Fragment %main "main" %outparm
  82. OpExecutionMode %main OriginUpperLeft
  83. OpSource GLSL 450
  84. OpName %main "main"
  85. OpName %outparm "outparm"
  86. OpDecorate %outparm Location 0
  87. %void = OpTypeVoid
  88. %3 = OpTypeFunction %void
  89. %int = OpTypeInt 32 1
  90. %bool = OpTypeBool
  91. %_ptr_Function_int = OpTypePointer Function %int
  92. %int_4 = OpConstant %int 4
  93. %int_3 = OpConstant %int 3
  94. %int_1 = OpConstant %int 1
  95. %_ptr_Output_int = OpTypePointer Output %int
  96. %outparm = OpVariable %_ptr_Output_int Output
  97. %main = OpFunction %void None %3
  98. %4 = OpLabel
  99. %9 = OpIAdd %int %int_4 %int_3
  100. %6 = OpSGreaterThan %bool %9 %int_3
  101. OpSelectionMerge %25 None
  102. ; CHECK: OpBranchConditional %true [[bb_taken:%\d+]] [[bb_not_taken:%\d+]]
  103. OpBranchConditional %6 %22 %23
  104. ; CHECK: [[bb_taken]] = OpLabel
  105. %22 = OpLabel
  106. ; CHECK: OpCopyObject %int %int_7
  107. %7 = OpCopyObject %int %9
  108. OpBranch %25
  109. ; CHECK: [[bb_not_taken]] = OpLabel
  110. %23 = OpLabel
  111. ; CHECK: [[id_not_evaluated:%\d+]] = OpCopyObject %int %int_4
  112. %8 = OpCopyObject %int %int_4
  113. OpBranch %25
  114. %25 = OpLabel
  115. ; %int_7 should have propagated to the first OpPhi operand. But the else branch
  116. ; is not executable (conditional is always true), so no values should be
  117. ; propagated there and the value of the OpPhi should always be %int_7.
  118. ; CHECK: OpPhi %int %int_7 [[bb_taken]] [[id_not_evaluated]] [[bb_not_taken]]
  119. %35 = OpPhi %int %7 %22 %8 %23
  120. ; Only the true path of the conditional is ever executed. The output of this
  121. ; function is always %int_7.
  122. ; CHECK: OpStore %outparm %int_7
  123. OpStore %outparm %35
  124. OpReturn
  125. OpFunctionEnd
  126. )";
  127. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  128. }
  129. TEST_F(CCPTest, SimplifySwitches) {
  130. const std::string spv_asm = R"(
  131. OpCapability Shader
  132. %1 = OpExtInstImport "GLSL.std.450"
  133. OpMemoryModel Logical GLSL450
  134. OpEntryPoint Fragment %main "main" %outparm
  135. OpExecutionMode %main OriginUpperLeft
  136. OpSource GLSL 450
  137. OpName %main "main"
  138. OpName %outparm "outparm"
  139. OpDecorate %outparm Location 0
  140. %void = OpTypeVoid
  141. %6 = OpTypeFunction %void
  142. %int = OpTypeInt 32 1
  143. %_ptr_Function_int = OpTypePointer Function %int
  144. %int_23 = OpConstant %int 23
  145. %int_42 = OpConstant %int 42
  146. %int_14 = OpConstant %int 14
  147. %int_15 = OpConstant %int 15
  148. %int_4 = OpConstant %int 4
  149. %_ptr_Output_int = OpTypePointer Output %int
  150. %outparm = OpVariable %_ptr_Output_int Output
  151. %main = OpFunction %void None %6
  152. %15 = OpLabel
  153. OpSelectionMerge %17 None
  154. OpSwitch %int_23 %17 10 %18 13 %19 23 %20
  155. %18 = OpLabel
  156. OpBranch %17
  157. %19 = OpLabel
  158. OpBranch %17
  159. %20 = OpLabel
  160. OpBranch %17
  161. %17 = OpLabel
  162. %24 = OpPhi %int %int_23 %15 %int_42 %18 %int_14 %19 %int_15 %20
  163. ; The switch will always jump to label %20, which carries the value %int_15.
  164. ; CHECK: OpIAdd %int %int_15 %int_4
  165. %22 = OpIAdd %int %24 %int_4
  166. ; Consequently, the return value will always be %int_19.
  167. ; CHECK: OpStore %outparm %int_19
  168. OpStore %outparm %22
  169. OpReturn
  170. OpFunctionEnd
  171. )";
  172. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  173. }
  174. TEST_F(CCPTest, SimplifySwitchesDefaultBranch) {
  175. const std::string spv_asm = R"(
  176. OpCapability Shader
  177. %1 = OpExtInstImport "GLSL.std.450"
  178. OpMemoryModel Logical GLSL450
  179. OpEntryPoint Fragment %main "main" %outparm
  180. OpExecutionMode %main OriginUpperLeft
  181. OpSource GLSL 450
  182. OpName %main "main"
  183. OpName %outparm "outparm"
  184. OpDecorate %outparm Location 0
  185. %void = OpTypeVoid
  186. %6 = OpTypeFunction %void
  187. %int = OpTypeInt 32 1
  188. %_ptr_Function_int = OpTypePointer Function %int
  189. %int_42 = OpConstant %int 42
  190. %int_4 = OpConstant %int 4
  191. %int_1 = OpConstant %int 1
  192. %_ptr_Output_int = OpTypePointer Output %int
  193. %outparm = OpVariable %_ptr_Output_int Output
  194. %main = OpFunction %void None %6
  195. %13 = OpLabel
  196. %15 = OpIAdd %int %int_42 %int_4
  197. OpSelectionMerge %16 None
  198. ; CHECK: OpSwitch %int_46 {{%\d+}} 10 {{%\d+}}
  199. OpSwitch %15 %17 10 %18
  200. %18 = OpLabel
  201. OpBranch %16
  202. %17 = OpLabel
  203. OpBranch %16
  204. %16 = OpLabel
  205. %22 = OpPhi %int %int_42 %18 %int_1 %17
  206. ; The switch will always jump to the default label %17. This carries the value
  207. ; %int_1.
  208. ; CHECK: OpIAdd %int %int_1 %int_4
  209. %20 = OpIAdd %int %22 %int_4
  210. ; Resulting in a return value of %int_5.
  211. ; CHECK: OpStore %outparm %int_5
  212. OpStore %outparm %20
  213. OpReturn
  214. OpFunctionEnd
  215. )";
  216. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  217. }
  218. TEST_F(CCPTest, SimplifyIntVector) {
  219. const std::string spv_asm = R"(
  220. OpCapability Shader
  221. %1 = OpExtInstImport "GLSL.std.450"
  222. OpMemoryModel Logical GLSL450
  223. OpEntryPoint Fragment %main "main" %OutColor
  224. OpExecutionMode %main OriginUpperLeft
  225. OpSource GLSL 450
  226. OpName %main "main"
  227. OpName %v "v"
  228. OpName %OutColor "OutColor"
  229. OpDecorate %OutColor Location 0
  230. %void = OpTypeVoid
  231. %3 = OpTypeFunction %void
  232. %int = OpTypeInt 32 1
  233. %v4int = OpTypeVector %int 4
  234. %_ptr_Function_v4int = OpTypePointer Function %v4int
  235. %int_1 = OpConstant %int 1
  236. %int_2 = OpConstant %int 2
  237. %int_3 = OpConstant %int 3
  238. %int_4 = OpConstant %int 4
  239. %14 = OpConstantComposite %v4int %int_1 %int_2 %int_3 %int_4
  240. %uint = OpTypeInt 32 0
  241. %uint_0 = OpConstant %uint 0
  242. %_ptr_Function_int = OpTypePointer Function %int
  243. %_ptr_Output_v4int = OpTypePointer Output %v4int
  244. %OutColor = OpVariable %_ptr_Output_v4int Output
  245. %main = OpFunction %void None %3
  246. %5 = OpLabel
  247. %v = OpVariable %_ptr_Function_v4int Function
  248. OpStore %v %14
  249. %18 = OpAccessChain %_ptr_Function_int %v %uint_0
  250. %19 = OpLoad %int %18
  251. ; The constant folder does not see through access chains. To get this, the
  252. ; vector would have to be scalarized.
  253. ; CHECK: [[result_id:%\d+]] = OpIAdd %int {{%\d+}} %int_1
  254. %20 = OpIAdd %int %19 %int_1
  255. %21 = OpAccessChain %_ptr_Function_int %v %uint_0
  256. ; CHECK: OpStore {{%\d+}} [[result_id]]
  257. OpStore %21 %20
  258. %24 = OpLoad %v4int %v
  259. OpStore %OutColor %24
  260. OpReturn
  261. OpFunctionEnd
  262. )";
  263. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  264. }
  265. TEST_F(CCPTest, BadSimplifyFloatVector) {
  266. const std::string spv_asm = R"(
  267. OpCapability Shader
  268. %1 = OpExtInstImport "GLSL.std.450"
  269. OpMemoryModel Logical GLSL450
  270. OpEntryPoint Fragment %main "main" %OutColor
  271. OpExecutionMode %main OriginUpperLeft
  272. OpSource GLSL 450
  273. OpName %main "main"
  274. OpName %v "v"
  275. OpName %OutColor "OutColor"
  276. OpDecorate %OutColor Location 0
  277. %void = OpTypeVoid
  278. %3 = OpTypeFunction %void
  279. %float = OpTypeFloat 32
  280. %v4float = OpTypeVector %float 4
  281. %_ptr_Function_v4float = OpTypePointer Function %v4float
  282. %float_1 = OpConstant %float 1
  283. %float_2 = OpConstant %float 2
  284. %float_3 = OpConstant %float 3
  285. %float_4 = OpConstant %float 4
  286. %14 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
  287. %uint = OpTypeInt 32 0
  288. %uint_0 = OpConstant %uint 0
  289. %_ptr_Function_float = OpTypePointer Function %float
  290. %_ptr_Output_v4float = OpTypePointer Output %v4float
  291. %OutColor = OpVariable %_ptr_Output_v4float Output
  292. %main = OpFunction %void None %3
  293. %5 = OpLabel
  294. %v = OpVariable %_ptr_Function_v4float Function
  295. OpStore %v %14
  296. %18 = OpAccessChain %_ptr_Function_float %v %uint_0
  297. %19 = OpLoad %float %18
  298. ; NOTE: This test should start failing once floating point folding is
  299. ; implemented (https://github.com/KhronosGroup/SPIRV-Tools/issues/943).
  300. ; This should be checking that we are adding %float_1 + %float_1.
  301. ; CHECK: [[result_id:%\d+]] = OpFAdd %float {{%\d+}} %float_1
  302. %20 = OpFAdd %float %19 %float_1
  303. %21 = OpAccessChain %_ptr_Function_float %v %uint_0
  304. ; This should be checkint that we are storing %float_2 instead of result_it.
  305. ; CHECK: OpStore {{%\d+}} [[result_id]]
  306. OpStore %21 %20
  307. %24 = OpLoad %v4float %v
  308. OpStore %OutColor %24
  309. OpReturn
  310. OpFunctionEnd
  311. )";
  312. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  313. }
  314. TEST_F(CCPTest, NoLoadStorePropagation) {
  315. const std::string spv_asm = R"(
  316. OpCapability Shader
  317. %1 = OpExtInstImport "GLSL.std.450"
  318. OpMemoryModel Logical GLSL450
  319. OpEntryPoint Fragment %main "main" %outparm
  320. OpExecutionMode %main OriginUpperLeft
  321. OpSource GLSL 450
  322. OpName %main "main"
  323. OpName %x "x"
  324. OpName %outparm "outparm"
  325. OpDecorate %outparm Location 0
  326. %void = OpTypeVoid
  327. %3 = OpTypeFunction %void
  328. %int = OpTypeInt 32 1
  329. %_ptr_Function_int = OpTypePointer Function %int
  330. %int_23 = OpConstant %int 23
  331. %_ptr_Output_int = OpTypePointer Output %int
  332. %outparm = OpVariable %_ptr_Output_int Output
  333. %main = OpFunction %void None %3
  334. %5 = OpLabel
  335. %x = OpVariable %_ptr_Function_int Function
  336. OpStore %x %int_23
  337. ; int_23 should not propagate into this load.
  338. ; CHECK: [[load_id:%\d+]] = OpLoad %int %x
  339. %12 = OpLoad %int %x
  340. ; Nor into this copy operation.
  341. ; CHECK: [[copy_id:%\d+]] = OpCopyObject %int [[load_id]]
  342. %13 = OpCopyObject %int %12
  343. ; Likewise here.
  344. ; CHECK: OpStore %outparm [[copy_id]]
  345. OpStore %outparm %13
  346. OpReturn
  347. OpFunctionEnd
  348. )";
  349. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  350. }
  351. TEST_F(CCPTest, HandleAbortInstructions) {
  352. const std::string spv_asm = R"(
  353. OpCapability Shader
  354. %1 = OpExtInstImport "GLSL.std.450"
  355. OpMemoryModel Logical GLSL450
  356. OpEntryPoint Fragment %main "main"
  357. OpExecutionMode %main OriginUpperLeft
  358. OpSource HLSL 500
  359. OpName %main "main"
  360. %void = OpTypeVoid
  361. %3 = OpTypeFunction %void
  362. %int = OpTypeInt 32 1
  363. %bool = OpTypeBool
  364. ; CHECK: %true = OpConstantTrue %bool
  365. %int_3 = OpConstant %int 3
  366. %int_1 = OpConstant %int 1
  367. %main = OpFunction %void None %3
  368. %4 = OpLabel
  369. %9 = OpIAdd %int %int_3 %int_1
  370. %6 = OpSGreaterThan %bool %9 %int_3
  371. OpSelectionMerge %23 None
  372. ; CHECK: OpBranchConditional %true {{%\d+}} {{%\d+}}
  373. OpBranchConditional %6 %22 %23
  374. %22 = OpLabel
  375. OpKill
  376. %23 = OpLabel
  377. OpReturn
  378. OpFunctionEnd
  379. )";
  380. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  381. }
  382. TEST_F(CCPTest, SSAWebCycles) {
  383. // Test reduced from https://github.com/KhronosGroup/SPIRV-Tools/issues/1159
  384. // When there is a cycle in the SSA def-use web, the propagator was getting
  385. // into an infinite loop. SSA edges for Phi instructions should not be
  386. // added to the edges to simulate.
  387. const std::string spv_asm = R"(
  388. OpCapability Shader
  389. %1 = OpExtInstImport "GLSL.std.450"
  390. OpMemoryModel Logical GLSL450
  391. OpEntryPoint Fragment %main "main"
  392. OpExecutionMode %main OriginUpperLeft
  393. OpSource GLSL 450
  394. OpName %main "main"
  395. %void = OpTypeVoid
  396. %3 = OpTypeFunction %void
  397. %int = OpTypeInt 32 1
  398. %_ptr_Function_int = OpTypePointer Function %int
  399. %int_0 = OpConstant %int 0
  400. %int_4 = OpConstant %int 4
  401. %bool = OpTypeBool
  402. %int_1 = OpConstant %int 1
  403. %_ptr_Output_int = OpTypePointer Output %int
  404. %main = OpFunction %void None %3
  405. %5 = OpLabel
  406. OpBranch %11
  407. %11 = OpLabel
  408. %29 = OpPhi %int %int_0 %5 %22 %14
  409. %30 = OpPhi %int %int_0 %5 %25 %14
  410. OpLoopMerge %13 %14 None
  411. OpBranch %15
  412. %15 = OpLabel
  413. %19 = OpSLessThan %bool %30 %int_4
  414. ; CHECK: OpBranchConditional %true {{%\d+}} {{%\d+}}
  415. OpBranchConditional %19 %12 %13
  416. %12 = OpLabel
  417. ; CHECK: OpIAdd %int %int_0 %int_0
  418. %22 = OpIAdd %int %29 %30
  419. OpBranch %14
  420. %14 = OpLabel
  421. ; CHECK: OpPhi %int %int_0 {{%\d+}}
  422. %25 = OpPhi %int %30 %12
  423. OpBranch %11
  424. %13 = OpLabel
  425. OpReturn
  426. OpFunctionEnd
  427. )";
  428. SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  429. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  430. }
  431. TEST_F(CCPTest, LoopInductionVariables) {
  432. // Test reduced from https://github.com/KhronosGroup/SPIRV-Tools/issues/1143
  433. // We are failing to properly consider the induction variable for this loop
  434. // as Varying.
  435. const std::string spv_asm = R"(
  436. OpCapability Shader
  437. %1 = OpExtInstImport "GLSL.std.450"
  438. OpMemoryModel Logical GLSL450
  439. OpEntryPoint Fragment %main "main"
  440. OpExecutionMode %main OriginUpperLeft
  441. OpSource GLSL 430
  442. OpName %main "main"
  443. %void = OpTypeVoid
  444. %5 = OpTypeFunction %void
  445. %int = OpTypeInt 32 1
  446. %_ptr_Function_int = OpTypePointer Function %int
  447. %int_0 = OpConstant %int 0
  448. %int_10 = OpConstant %int 10
  449. %bool = OpTypeBool
  450. %int_1 = OpConstant %int 1
  451. %main = OpFunction %void None %5
  452. %12 = OpLabel
  453. OpBranch %13
  454. %13 = OpLabel
  455. ; This Phi should not have all constant arguments:
  456. ; CHECK: [[phi_id:%\d+]] = OpPhi %int %int_0 {{%\d+}} {{%\d+}} {{%\d+}}
  457. %22 = OpPhi %int %int_0 %12 %21 %15
  458. OpLoopMerge %14 %15 None
  459. OpBranch %16
  460. %16 = OpLabel
  461. ; The Phi should never be considered to have the value %int_0.
  462. ; CHECK: [[branch_selector:%\d+]] = OpSLessThan %bool [[phi_id]] %int_10
  463. %18 = OpSLessThan %bool %22 %int_10
  464. ; This conditional was wrongly converted into an always-true jump due to the
  465. ; bad meet evaluation of %22.
  466. ; CHECK: OpBranchConditional [[branch_selector]] {{%\d+}} {{%\d+}}
  467. OpBranchConditional %18 %19 %14
  468. %19 = OpLabel
  469. OpBranch %15
  470. %15 = OpLabel
  471. ; CHECK: OpIAdd %int [[phi_id]] %int_1
  472. %21 = OpIAdd %int %22 %int_1
  473. OpBranch %13
  474. %14 = OpLabel
  475. OpReturn
  476. OpFunctionEnd
  477. )";
  478. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  479. }
  480. TEST_F(CCPTest, HandleCompositeWithUndef) {
  481. // Check to make sure that CCP does not crash when given a "constant" struct
  482. // with an undef. If at a later time CCP is enhanced to optimize this case,
  483. // it is not wrong.
  484. const std::string spv_asm = R"(
  485. OpCapability Shader
  486. %1 = OpExtInstImport "GLSL.std.450"
  487. OpMemoryModel Logical GLSL450
  488. OpEntryPoint Fragment %main "main"
  489. OpExecutionMode %main OriginUpperLeft
  490. OpSource HLSL 500
  491. OpName %main "main"
  492. %void = OpTypeVoid
  493. %4 = OpTypeFunction %void
  494. %int = OpTypeInt 32 1
  495. %bool = OpTypeBool
  496. %_struct_7 = OpTypeStruct %int %int
  497. %int_1 = OpConstant %int 1
  498. %9 = OpUndef %int
  499. %10 = OpConstantComposite %_struct_7 %int_1 %9
  500. %main = OpFunction %void None %4
  501. %11 = OpLabel
  502. %12 = OpCompositeExtract %int %10 0
  503. %13 = OpCopyObject %int %12
  504. OpReturn
  505. OpFunctionEnd
  506. )";
  507. auto res = SinglePassRunToBinary<CCPPass>(spv_asm, true);
  508. EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange);
  509. }
  510. TEST_F(CCPTest, SkipSpecConstantInstrucitons) {
  511. const std::string spv_asm = R"(
  512. OpCapability Shader
  513. %1 = OpExtInstImport "GLSL.std.450"
  514. OpMemoryModel Logical GLSL450
  515. OpEntryPoint Fragment %main "main"
  516. OpExecutionMode %main OriginUpperLeft
  517. OpSource HLSL 500
  518. OpName %main "main"
  519. %void = OpTypeVoid
  520. %4 = OpTypeFunction %void
  521. %bool = OpTypeBool
  522. %10 = OpSpecConstantFalse %bool
  523. %main = OpFunction %void None %4
  524. %11 = OpLabel
  525. %12 = OpBranchConditional %10 %l1 %l2
  526. %l1 = OpLabel
  527. OpReturn
  528. %l2 = OpLabel
  529. OpReturn
  530. OpFunctionEnd
  531. )";
  532. auto res = SinglePassRunToBinary<CCPPass>(spv_asm, true);
  533. EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange);
  534. }
  535. TEST_F(CCPTest, UpdateSubsequentPhisToVarying) {
  536. const std::string text = R"(
  537. OpCapability Shader
  538. OpMemoryModel Logical GLSL450
  539. OpEntryPoint Fragment %func "func" %in
  540. OpExecutionMode %func OriginUpperLeft
  541. %void = OpTypeVoid
  542. %bool = OpTypeBool
  543. %int = OpTypeInt 32 1
  544. %false = OpConstantFalse %bool
  545. %int0 = OpConstant %int 0
  546. %int1 = OpConstant %int 1
  547. %int6 = OpConstant %int 6
  548. %int_ptr_Input = OpTypePointer Input %int
  549. %in = OpVariable %int_ptr_Input Input
  550. %undef = OpUndef %int
  551. %functy = OpTypeFunction %void
  552. %func = OpFunction %void None %functy
  553. %1 = OpLabel
  554. OpBranch %2
  555. %2 = OpLabel
  556. %outer_phi = OpPhi %int %int0 %1 %outer_add %15
  557. %cond1 = OpSLessThanEqual %bool %outer_phi %int6
  558. OpLoopMerge %3 %15 None
  559. OpBranchConditional %cond1 %4 %3
  560. %4 = OpLabel
  561. %ld = OpLoad %int %in
  562. %cond2 = OpSGreaterThanEqual %bool %int1 %ld
  563. OpSelectionMerge %10 None
  564. OpBranchConditional %cond2 %8 %9
  565. %8 = OpLabel
  566. OpBranch %10
  567. %9 = OpLabel
  568. OpBranch %10
  569. %10 = OpLabel
  570. %extra_phi = OpPhi %int %outer_phi %8 %outer_phi %9
  571. OpBranch %11
  572. %11 = OpLabel
  573. %inner_phi = OpPhi %int %int0 %10 %inner_add %13
  574. %cond3 = OpSLessThanEqual %bool %inner_phi %int6
  575. OpLoopMerge %14 %13 None
  576. OpBranchConditional %cond3 %12 %14
  577. %12 = OpLabel
  578. OpBranch %13
  579. %13 = OpLabel
  580. %inner_add = OpIAdd %int %inner_phi %int1
  581. OpBranch %11
  582. %14 = OpLabel
  583. OpBranch %15
  584. %15 = OpLabel
  585. %outer_add = OpIAdd %int %extra_phi %int1
  586. OpBranch %2
  587. %3 = OpLabel
  588. OpReturn
  589. OpFunctionEnd
  590. )";
  591. auto res = SinglePassRunToBinary<CCPPass>(text, true);
  592. EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange);
  593. }
  594. TEST_F(CCPTest, UndefInPhi) {
  595. const std::string text = R"(
  596. ; CHECK: [[uint1:%\w+]] = OpConstant {{%\w+}} 1
  597. ; CHECK: [[phi:%\w+]] = OpPhi
  598. ; CHECK: OpIAdd {{%\w+}} [[phi]] [[uint1]]
  599. OpCapability Kernel
  600. OpCapability Linkage
  601. OpMemoryModel Logical OpenCL
  602. OpDecorate %1 LinkageAttributes "func" Export
  603. %void = OpTypeVoid
  604. %bool = OpTypeBool
  605. %uint = OpTypeInt 32 0
  606. %uint_0 = OpConstant %uint 0
  607. %uint_1 = OpConstant %uint 1
  608. %7 = OpUndef %uint
  609. %8 = OpTypeFunction %void %bool
  610. %1 = OpFunction %void None %8
  611. %9 = OpFunctionParameter %bool
  612. %10 = OpLabel
  613. OpBranchConditional %9 %11 %12
  614. %11 = OpLabel
  615. OpBranch %13
  616. %12 = OpLabel
  617. OpBranch %14
  618. %14 = OpLabel
  619. OpBranchConditional %9 %13 %15
  620. %15 = OpLabel
  621. OpBranch %13
  622. %13 = OpLabel
  623. %16 = OpPhi %uint %uint_0 %11 %7 %14 %uint_1 %15
  624. %17 = OpIAdd %uint %16 %uint_1
  625. OpReturn
  626. OpFunctionEnd
  627. )";
  628. SinglePassRunAndMatch<CCPPass>(text, true);
  629. }
  630. // Just test to make sure the constant fold rules are being used. Will rely on
  631. // the folding test for specific testing of specific rules.
  632. TEST_F(CCPTest, UseConstantFoldingRules) {
  633. const std::string text = R"(
  634. ; CHECK: [[float1:%\w+]] = OpConstant {{%\w+}} 1
  635. ; CHECK: OpReturnValue [[float1]]
  636. OpCapability Shader
  637. OpCapability Linkage
  638. OpMemoryModel Logical GLSL450
  639. OpDecorate %1 LinkageAttributes "func" Export
  640. %void = OpTypeVoid
  641. %bool = OpTypeBool
  642. %float = OpTypeFloat 32
  643. %float_0 = OpConstant %float 0
  644. %float_1 = OpConstant %float 1
  645. %8 = OpTypeFunction %float
  646. %1 = OpFunction %float None %8
  647. %10 = OpLabel
  648. %17 = OpFAdd %float %float_0 %float_1
  649. OpReturnValue %17
  650. OpFunctionEnd
  651. )";
  652. SinglePassRunAndMatch<CCPPass>(text, true);
  653. }
  654. // Test for #1300. Previously value for %5 would not settle during simulation.
  655. TEST_F(CCPTest, SettlePhiLatticeValue) {
  656. const std::string text = R"(
  657. OpCapability Kernel
  658. OpCapability Linkage
  659. OpMemoryModel Logical OpenCL
  660. OpDecorate %func LinkageAttributes "func" Export
  661. %void = OpTypeVoid
  662. %bool = OpTypeBool
  663. %true = OpConstantTrue %bool
  664. %false = OpConstantFalse %bool
  665. %functy = OpTypeFunction %void
  666. %func = OpFunction %void None %functy
  667. %1 = OpLabel
  668. OpBranchConditional %true %2 %3
  669. %3 = OpLabel
  670. OpBranch %2
  671. %2 = OpLabel
  672. %5 = OpPhi %bool %true %1 %false %3
  673. OpReturn
  674. OpFunctionEnd
  675. )";
  676. SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  677. SinglePassRunToBinary<CCPPass>(text, true);
  678. }
  679. TEST_F(CCPTest, NullBranchCondition) {
  680. const std::string text = R"(
  681. ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
  682. ; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
  683. ; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
  684. OpCapability Shader
  685. OpMemoryModel Logical GLSL450
  686. OpEntryPoint Fragment %func "func"
  687. OpExecutionMode %func OriginUpperLeft
  688. %void = OpTypeVoid
  689. %bool = OpTypeBool
  690. %int = OpTypeInt 32 1
  691. %null = OpConstantNull %bool
  692. %int_1 = OpConstant %int 1
  693. %int_2 = OpConstant %int 2
  694. %functy = OpTypeFunction %void
  695. %func = OpFunction %void None %functy
  696. %1 = OpLabel
  697. OpSelectionMerge %2 None
  698. OpBranchConditional %null %2 %3
  699. %3 = OpLabel
  700. OpBranch %2
  701. %2 = OpLabel
  702. %phi = OpPhi %int %int_1 %1 %int_2 %3
  703. %add = OpIAdd %int %int_1 %phi
  704. OpReturn
  705. OpFunctionEnd
  706. )";
  707. SinglePassRunAndMatch<CCPPass>(text, true);
  708. }
  709. TEST_F(CCPTest, UndefBranchCondition) {
  710. const std::string text = R"(
  711. ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
  712. ; CHECK: [[phi:%\w+]] = OpPhi
  713. ; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
  714. OpCapability Shader
  715. OpMemoryModel Logical GLSL450
  716. OpEntryPoint Fragment %func "func"
  717. OpExecutionMode %func OriginUpperLeft
  718. %void = OpTypeVoid
  719. %bool = OpTypeBool
  720. %int = OpTypeInt 32 1
  721. %undef = OpUndef %bool
  722. %int_1 = OpConstant %int 1
  723. %int_2 = OpConstant %int 2
  724. %functy = OpTypeFunction %void
  725. %func = OpFunction %void None %functy
  726. %1 = OpLabel
  727. OpSelectionMerge %2 None
  728. OpBranchConditional %undef %2 %3
  729. %3 = OpLabel
  730. OpBranch %2
  731. %2 = OpLabel
  732. %phi = OpPhi %int %int_1 %1 %int_2 %3
  733. %add = OpIAdd %int %int_1 %phi
  734. OpReturn
  735. OpFunctionEnd
  736. )";
  737. SinglePassRunAndMatch<CCPPass>(text, true);
  738. }
  739. TEST_F(CCPTest, NullSwitchCondition) {
  740. const std::string text = R"(
  741. ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
  742. ; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
  743. ; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
  744. OpCapability Shader
  745. OpMemoryModel Logical GLSL450
  746. OpEntryPoint Fragment %func "func"
  747. OpExecutionMode %func OriginUpperLeft
  748. %void = OpTypeVoid
  749. %int = OpTypeInt 32 1
  750. %null = OpConstantNull %int
  751. %int_1 = OpConstant %int 1
  752. %int_2 = OpConstant %int 2
  753. %functy = OpTypeFunction %void
  754. %func = OpFunction %void None %functy
  755. %1 = OpLabel
  756. OpSelectionMerge %2 None
  757. OpSwitch %null %2 0 %3
  758. %3 = OpLabel
  759. OpBranch %2
  760. %2 = OpLabel
  761. %phi = OpPhi %int %int_1 %1 %int_2 %3
  762. %add = OpIAdd %int %int_1 %phi
  763. OpReturn
  764. OpFunctionEnd
  765. )";
  766. SinglePassRunAndMatch<CCPPass>(text, true);
  767. }
  768. TEST_F(CCPTest, UndefSwitchCondition) {
  769. const std::string text = R"(
  770. ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
  771. ; CHECK: [[phi:%\w+]] = OpPhi
  772. ; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
  773. OpCapability Shader
  774. OpMemoryModel Logical GLSL450
  775. OpEntryPoint Fragment %func "func"
  776. OpExecutionMode %func OriginUpperLeft
  777. %void = OpTypeVoid
  778. %int = OpTypeInt 32 1
  779. %undef = OpUndef %int
  780. %int_1 = OpConstant %int 1
  781. %int_2 = OpConstant %int 2
  782. %functy = OpTypeFunction %void
  783. %func = OpFunction %void None %functy
  784. %1 = OpLabel
  785. OpSelectionMerge %2 None
  786. OpSwitch %undef %2 0 %3
  787. %3 = OpLabel
  788. OpBranch %2
  789. %2 = OpLabel
  790. %phi = OpPhi %int %int_1 %1 %int_2 %3
  791. %add = OpIAdd %int %int_1 %phi
  792. OpReturn
  793. OpFunctionEnd
  794. )";
  795. SinglePassRunAndMatch<CCPPass>(text, true);
  796. }
  797. // Test for #1361.
  798. TEST_F(CCPTest, CompositeConstructOfGlobalValue) {
  799. const std::string text = R"(
  800. ; CHECK: [[phi:%\w+]] = OpPhi
  801. ; CHECK-NEXT: OpCompositeExtract {{%\w+}} [[phi]] 0
  802. OpCapability Shader
  803. OpMemoryModel Logical GLSL450
  804. OpEntryPoint Fragment %func "func" %in
  805. OpExecutionMode %func OriginUpperLeft
  806. %void = OpTypeVoid
  807. %int = OpTypeInt 32 1
  808. %bool = OpTypeBool
  809. %functy = OpTypeFunction %void
  810. %ptr_int_Input = OpTypePointer Input %int
  811. %in = OpVariable %ptr_int_Input Input
  812. %struct = OpTypeStruct %ptr_int_Input %ptr_int_Input
  813. %struct_null = OpConstantNull %struct
  814. %func = OpFunction %void None %functy
  815. %1 = OpLabel
  816. OpBranch %2
  817. %2 = OpLabel
  818. %phi = OpPhi %struct %struct_null %1 %5 %4
  819. %extract = OpCompositeExtract %ptr_int_Input %phi 0
  820. OpLoopMerge %3 %4 None
  821. OpBranch %4
  822. %4 = OpLabel
  823. %5 = OpCompositeConstruct %struct %in %in
  824. OpBranch %2
  825. %3 = OpLabel
  826. OpReturn
  827. OpFunctionEnd
  828. )";
  829. SinglePassRunAndMatch<CCPPass>(text, true);
  830. }
  831. } // namespace
  832. } // namespace opt
  833. } // namespace spvtools