ccp_test.cpp 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347
  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 "gtest/gtest.h"
  16. #include "source/opt/ccp_pass.h"
  17. #include "test/opt/pass_fixture.h"
  18. #include "test/opt/pass_utils.h"
  19. namespace spvtools {
  20. namespace opt {
  21. namespace {
  22. using CCPTest = PassTest<::testing::Test>;
  23. TEST_F(CCPTest, PropagateThroughPhis) {
  24. const std::string spv_asm = R"(
  25. OpCapability Shader
  26. %1 = OpExtInstImport "GLSL.std.450"
  27. OpMemoryModel Logical GLSL450
  28. OpEntryPoint Fragment %main "main" %x %outparm
  29. OpExecutionMode %main OriginUpperLeft
  30. OpSource GLSL 450
  31. OpName %main "main"
  32. OpName %x "x"
  33. OpName %outparm "outparm"
  34. OpDecorate %x Flat
  35. OpDecorate %x Location 0
  36. OpDecorate %outparm Location 0
  37. %void = OpTypeVoid
  38. %3 = OpTypeFunction %void
  39. %int = OpTypeInt 32 1
  40. %bool = OpTypeBool
  41. %_ptr_Function_int = OpTypePointer Function %int
  42. %int_4 = OpConstant %int 4
  43. %int_3 = OpConstant %int 3
  44. %int_1 = OpConstant %int 1
  45. %_ptr_Input_int = OpTypePointer Input %int
  46. %x = OpVariable %_ptr_Input_int Input
  47. %_ptr_Output_int = OpTypePointer Output %int
  48. %outparm = OpVariable %_ptr_Output_int Output
  49. %main = OpFunction %void None %3
  50. %4 = OpLabel
  51. %5 = OpLoad %int %x
  52. %9 = OpIAdd %int %int_1 %int_3
  53. %6 = OpSGreaterThan %bool %5 %int_3
  54. OpSelectionMerge %25 None
  55. OpBranchConditional %6 %22 %23
  56. %22 = OpLabel
  57. ; CHECK: OpCopyObject %int %int_4
  58. %7 = OpCopyObject %int %9
  59. OpBranch %25
  60. %23 = OpLabel
  61. %8 = OpCopyObject %int %int_4
  62. OpBranch %25
  63. %25 = OpLabel
  64. ; %int_4 should have propagated to both OpPhi operands.
  65. ; CHECK: OpPhi %int %int_4 {{%\d+}} %int_4 {{%\d+}}
  66. %35 = OpPhi %int %7 %22 %8 %23
  67. ; This function always returns 4. DCE should get rid of everything else.
  68. ; CHECK OpStore %outparm %int_4
  69. OpStore %outparm %35
  70. OpReturn
  71. OpFunctionEnd
  72. )";
  73. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  74. }
  75. TEST_F(CCPTest, SimplifyConditionals) {
  76. const std::string spv_asm = R"(
  77. OpCapability Shader
  78. %1 = OpExtInstImport "GLSL.std.450"
  79. OpMemoryModel Logical GLSL450
  80. OpEntryPoint Fragment %main "main" %outparm
  81. OpExecutionMode %main OriginUpperLeft
  82. OpSource GLSL 450
  83. OpName %main "main"
  84. OpName %outparm "outparm"
  85. OpDecorate %outparm Location 0
  86. %void = OpTypeVoid
  87. %3 = OpTypeFunction %void
  88. %int = OpTypeInt 32 1
  89. %bool = OpTypeBool
  90. %_ptr_Function_int = OpTypePointer Function %int
  91. %int_4 = OpConstant %int 4
  92. %int_3 = OpConstant %int 3
  93. %int_1 = OpConstant %int 1
  94. %_ptr_Output_int = OpTypePointer Output %int
  95. %outparm = OpVariable %_ptr_Output_int Output
  96. %main = OpFunction %void None %3
  97. %4 = OpLabel
  98. %9 = OpIAdd %int %int_4 %int_3
  99. %6 = OpSGreaterThan %bool %9 %int_3
  100. OpSelectionMerge %25 None
  101. ; CHECK: OpBranchConditional %true [[bb_taken:%\d+]] [[bb_not_taken:%\d+]]
  102. OpBranchConditional %6 %22 %23
  103. ; CHECK: [[bb_taken]] = OpLabel
  104. %22 = OpLabel
  105. ; CHECK: OpCopyObject %int %int_7
  106. %7 = OpCopyObject %int %9
  107. OpBranch %25
  108. ; CHECK: [[bb_not_taken]] = OpLabel
  109. %23 = OpLabel
  110. ; CHECK: [[id_not_evaluated:%\d+]] = OpCopyObject %int %int_4
  111. %8 = OpCopyObject %int %int_4
  112. OpBranch %25
  113. %25 = OpLabel
  114. ; %int_7 should have propagated to the first OpPhi operand. But the else branch
  115. ; is not executable (conditional is always true), so no values should be
  116. ; propagated there and the value of the OpPhi should always be %int_7.
  117. ; CHECK: OpPhi %int %int_7 [[bb_taken]] [[id_not_evaluated]] [[bb_not_taken]]
  118. %35 = OpPhi %int %7 %22 %8 %23
  119. ; Only the true path of the conditional is ever executed. The output of this
  120. ; function is always %int_7.
  121. ; CHECK: OpStore %outparm %int_7
  122. OpStore %outparm %35
  123. OpReturn
  124. OpFunctionEnd
  125. )";
  126. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  127. }
  128. TEST_F(CCPTest, SimplifySwitches) {
  129. const std::string spv_asm = R"(
  130. OpCapability Shader
  131. %1 = OpExtInstImport "GLSL.std.450"
  132. OpMemoryModel Logical GLSL450
  133. OpEntryPoint Fragment %main "main" %outparm
  134. OpExecutionMode %main OriginUpperLeft
  135. OpSource GLSL 450
  136. OpName %main "main"
  137. OpName %outparm "outparm"
  138. OpDecorate %outparm Location 0
  139. %void = OpTypeVoid
  140. %6 = OpTypeFunction %void
  141. %int = OpTypeInt 32 1
  142. %_ptr_Function_int = OpTypePointer Function %int
  143. %int_23 = OpConstant %int 23
  144. %int_42 = OpConstant %int 42
  145. %int_14 = OpConstant %int 14
  146. %int_15 = OpConstant %int 15
  147. %int_4 = OpConstant %int 4
  148. %_ptr_Output_int = OpTypePointer Output %int
  149. %outparm = OpVariable %_ptr_Output_int Output
  150. %main = OpFunction %void None %6
  151. %15 = OpLabel
  152. OpSelectionMerge %17 None
  153. OpSwitch %int_23 %17 10 %18 13 %19 23 %20
  154. %18 = OpLabel
  155. OpBranch %17
  156. %19 = OpLabel
  157. OpBranch %17
  158. %20 = OpLabel
  159. OpBranch %17
  160. %17 = OpLabel
  161. %24 = OpPhi %int %int_23 %15 %int_42 %18 %int_14 %19 %int_15 %20
  162. ; The switch will always jump to label %20, which carries the value %int_15.
  163. ; CHECK: OpIAdd %int %int_15 %int_4
  164. %22 = OpIAdd %int %24 %int_4
  165. ; Consequently, the return value will always be %int_19.
  166. ; CHECK: OpStore %outparm %int_19
  167. OpStore %outparm %22
  168. OpReturn
  169. OpFunctionEnd
  170. )";
  171. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  172. }
  173. TEST_F(CCPTest, SimplifySwitchesDefaultBranch) {
  174. const std::string spv_asm = R"(
  175. OpCapability Shader
  176. %1 = OpExtInstImport "GLSL.std.450"
  177. OpMemoryModel Logical GLSL450
  178. OpEntryPoint Fragment %main "main" %outparm
  179. OpExecutionMode %main OriginUpperLeft
  180. OpSource GLSL 450
  181. OpName %main "main"
  182. OpName %outparm "outparm"
  183. OpDecorate %outparm Location 0
  184. %void = OpTypeVoid
  185. %6 = OpTypeFunction %void
  186. %int = OpTypeInt 32 1
  187. %_ptr_Function_int = OpTypePointer Function %int
  188. %int_42 = OpConstant %int 42
  189. %int_4 = OpConstant %int 4
  190. %int_1 = OpConstant %int 1
  191. %_ptr_Output_int = OpTypePointer Output %int
  192. %outparm = OpVariable %_ptr_Output_int Output
  193. %main = OpFunction %void None %6
  194. %13 = OpLabel
  195. %15 = OpIAdd %int %int_42 %int_4
  196. OpSelectionMerge %16 None
  197. ; CHECK: OpSwitch %int_46 {{%\d+}} 10 {{%\d+}}
  198. OpSwitch %15 %17 10 %18
  199. %18 = OpLabel
  200. OpBranch %16
  201. %17 = OpLabel
  202. OpBranch %16
  203. %16 = OpLabel
  204. %22 = OpPhi %int %int_42 %18 %int_1 %17
  205. ; The switch will always jump to the default label %17. This carries the value
  206. ; %int_1.
  207. ; CHECK: OpIAdd %int %int_1 %int_4
  208. %20 = OpIAdd %int %22 %int_4
  209. ; Resulting in a return value of %int_5.
  210. ; CHECK: OpStore %outparm %int_5
  211. OpStore %outparm %20
  212. OpReturn
  213. OpFunctionEnd
  214. )";
  215. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  216. }
  217. TEST_F(CCPTest, SimplifyIntVector) {
  218. const std::string spv_asm = R"(
  219. OpCapability Shader
  220. %1 = OpExtInstImport "GLSL.std.450"
  221. OpMemoryModel Logical GLSL450
  222. OpEntryPoint Fragment %main "main" %OutColor
  223. OpExecutionMode %main OriginUpperLeft
  224. OpSource GLSL 450
  225. OpName %main "main"
  226. OpName %v "v"
  227. OpName %OutColor "OutColor"
  228. OpDecorate %OutColor Location 0
  229. %void = OpTypeVoid
  230. %3 = OpTypeFunction %void
  231. %int = OpTypeInt 32 1
  232. %v4int = OpTypeVector %int 4
  233. %_ptr_Function_v4int = OpTypePointer Function %v4int
  234. %int_1 = OpConstant %int 1
  235. %int_2 = OpConstant %int 2
  236. %int_3 = OpConstant %int 3
  237. %int_4 = OpConstant %int 4
  238. %14 = OpConstantComposite %v4int %int_1 %int_2 %int_3 %int_4
  239. %uint = OpTypeInt 32 0
  240. %uint_0 = OpConstant %uint 0
  241. %_ptr_Function_int = OpTypePointer Function %int
  242. %_ptr_Output_v4int = OpTypePointer Output %v4int
  243. %OutColor = OpVariable %_ptr_Output_v4int Output
  244. %main = OpFunction %void None %3
  245. %5 = OpLabel
  246. %v = OpVariable %_ptr_Function_v4int Function
  247. OpStore %v %14
  248. %18 = OpAccessChain %_ptr_Function_int %v %uint_0
  249. %19 = OpLoad %int %18
  250. ; The constant folder does not see through access chains. To get this, the
  251. ; vector would have to be scalarized.
  252. ; CHECK: [[result_id:%\d+]] = OpIAdd %int {{%\d+}} %int_1
  253. %20 = OpIAdd %int %19 %int_1
  254. %21 = OpAccessChain %_ptr_Function_int %v %uint_0
  255. ; CHECK: OpStore {{%\d+}} [[result_id]]
  256. OpStore %21 %20
  257. %24 = OpLoad %v4int %v
  258. OpStore %OutColor %24
  259. OpReturn
  260. OpFunctionEnd
  261. )";
  262. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  263. }
  264. TEST_F(CCPTest, BadSimplifyFloatVector) {
  265. const std::string spv_asm = R"(
  266. OpCapability Shader
  267. %1 = OpExtInstImport "GLSL.std.450"
  268. OpMemoryModel Logical GLSL450
  269. OpEntryPoint Fragment %main "main" %OutColor
  270. OpExecutionMode %main OriginUpperLeft
  271. OpSource GLSL 450
  272. OpName %main "main"
  273. OpName %v "v"
  274. OpName %OutColor "OutColor"
  275. OpDecorate %OutColor Location 0
  276. %void = OpTypeVoid
  277. %3 = OpTypeFunction %void
  278. %float = OpTypeFloat 32
  279. %v4float = OpTypeVector %float 4
  280. %_ptr_Function_v4float = OpTypePointer Function %v4float
  281. %float_1 = OpConstant %float 1
  282. %float_2 = OpConstant %float 2
  283. %float_3 = OpConstant %float 3
  284. %float_4 = OpConstant %float 4
  285. %14 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
  286. %uint = OpTypeInt 32 0
  287. %uint_0 = OpConstant %uint 0
  288. %_ptr_Function_float = OpTypePointer Function %float
  289. %_ptr_Output_v4float = OpTypePointer Output %v4float
  290. %OutColor = OpVariable %_ptr_Output_v4float Output
  291. %main = OpFunction %void None %3
  292. %5 = OpLabel
  293. %v = OpVariable %_ptr_Function_v4float Function
  294. OpStore %v %14
  295. %18 = OpAccessChain %_ptr_Function_float %v %uint_0
  296. %19 = OpLoad %float %18
  297. ; NOTE: This test should start failing once floating point folding is
  298. ; implemented (https://github.com/KhronosGroup/SPIRV-Tools/issues/943).
  299. ; This should be checking that we are adding %float_1 + %float_1.
  300. ; CHECK: [[result_id:%\d+]] = OpFAdd %float {{%\d+}} %float_1
  301. %20 = OpFAdd %float %19 %float_1
  302. %21 = OpAccessChain %_ptr_Function_float %v %uint_0
  303. ; This should be checkint that we are storing %float_2 instead of result_it.
  304. ; CHECK: OpStore {{%\d+}} [[result_id]]
  305. OpStore %21 %20
  306. %24 = OpLoad %v4float %v
  307. OpStore %OutColor %24
  308. OpReturn
  309. OpFunctionEnd
  310. )";
  311. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  312. }
  313. TEST_F(CCPTest, NoLoadStorePropagation) {
  314. const std::string spv_asm = R"(
  315. OpCapability Shader
  316. %1 = OpExtInstImport "GLSL.std.450"
  317. OpMemoryModel Logical GLSL450
  318. OpEntryPoint Fragment %main "main" %outparm
  319. OpExecutionMode %main OriginUpperLeft
  320. OpSource GLSL 450
  321. OpName %main "main"
  322. OpName %x "x"
  323. OpName %outparm "outparm"
  324. OpDecorate %outparm Location 0
  325. %void = OpTypeVoid
  326. %3 = OpTypeFunction %void
  327. %int = OpTypeInt 32 1
  328. %_ptr_Function_int = OpTypePointer Function %int
  329. %int_23 = OpConstant %int 23
  330. %_ptr_Output_int = OpTypePointer Output %int
  331. %outparm = OpVariable %_ptr_Output_int Output
  332. %main = OpFunction %void None %3
  333. %5 = OpLabel
  334. %x = OpVariable %_ptr_Function_int Function
  335. OpStore %x %int_23
  336. ; int_23 should not propagate into this load.
  337. ; CHECK: [[load_id:%\d+]] = OpLoad %int %x
  338. %12 = OpLoad %int %x
  339. ; Nor into this copy operation.
  340. ; CHECK: [[copy_id:%\d+]] = OpCopyObject %int [[load_id]]
  341. %13 = OpCopyObject %int %12
  342. ; Likewise here.
  343. ; CHECK: OpStore %outparm [[copy_id]]
  344. OpStore %outparm %13
  345. OpReturn
  346. OpFunctionEnd
  347. )";
  348. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  349. }
  350. TEST_F(CCPTest, HandleAbortInstructions) {
  351. const std::string spv_asm = R"(
  352. OpCapability Shader
  353. %1 = OpExtInstImport "GLSL.std.450"
  354. OpMemoryModel Logical GLSL450
  355. OpEntryPoint Fragment %main "main"
  356. OpExecutionMode %main OriginUpperLeft
  357. OpSource HLSL 500
  358. OpName %main "main"
  359. %void = OpTypeVoid
  360. %3 = OpTypeFunction %void
  361. %int = OpTypeInt 32 1
  362. %bool = OpTypeBool
  363. ; CHECK: %true = OpConstantTrue %bool
  364. %int_3 = OpConstant %int 3
  365. %int_1 = OpConstant %int 1
  366. %main = OpFunction %void None %3
  367. %4 = OpLabel
  368. %9 = OpIAdd %int %int_3 %int_1
  369. %6 = OpSGreaterThan %bool %9 %int_3
  370. OpSelectionMerge %23 None
  371. ; CHECK: OpBranchConditional %true {{%\d+}} {{%\d+}}
  372. OpBranchConditional %6 %22 %23
  373. %22 = OpLabel
  374. OpKill
  375. %23 = OpLabel
  376. OpReturn
  377. OpFunctionEnd
  378. )";
  379. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  380. }
  381. TEST_F(CCPTest, SSAWebCycles) {
  382. // Test reduced from https://github.com/KhronosGroup/SPIRV-Tools/issues/1159
  383. // When there is a cycle in the SSA def-use web, the propagator was getting
  384. // into an infinite loop. SSA edges for Phi instructions should not be
  385. // added to the edges to simulate.
  386. const std::string spv_asm = R"(
  387. OpCapability Shader
  388. %1 = OpExtInstImport "GLSL.std.450"
  389. OpMemoryModel Logical GLSL450
  390. OpEntryPoint Fragment %main "main"
  391. OpExecutionMode %main OriginUpperLeft
  392. OpSource GLSL 450
  393. OpName %main "main"
  394. %void = OpTypeVoid
  395. %3 = OpTypeFunction %void
  396. %int = OpTypeInt 32 1
  397. %_ptr_Function_int = OpTypePointer Function %int
  398. %int_0 = OpConstant %int 0
  399. %int_4 = OpConstant %int 4
  400. %bool = OpTypeBool
  401. %int_1 = OpConstant %int 1
  402. %_ptr_Output_int = OpTypePointer Output %int
  403. %main = OpFunction %void None %3
  404. %5 = OpLabel
  405. OpBranch %11
  406. %11 = OpLabel
  407. %29 = OpPhi %int %int_0 %5 %22 %14
  408. %30 = OpPhi %int %int_0 %5 %25 %14
  409. OpLoopMerge %13 %14 None
  410. OpBranch %15
  411. %15 = OpLabel
  412. %19 = OpSLessThan %bool %30 %int_4
  413. ; CHECK: OpBranchConditional %true {{%\d+}} {{%\d+}}
  414. OpBranchConditional %19 %12 %13
  415. %12 = OpLabel
  416. ; CHECK: OpIAdd %int %int_0 %int_0
  417. %22 = OpIAdd %int %29 %30
  418. OpBranch %14
  419. %14 = OpLabel
  420. ; CHECK: OpPhi %int %int_0 {{%\d+}}
  421. %25 = OpPhi %int %30 %12
  422. OpBranch %11
  423. %13 = OpLabel
  424. OpReturn
  425. OpFunctionEnd
  426. )";
  427. SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  428. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  429. }
  430. TEST_F(CCPTest, LoopInductionVariables) {
  431. // Test reduced from https://github.com/KhronosGroup/SPIRV-Tools/issues/1143
  432. // We are failing to properly consider the induction variable for this loop
  433. // as Varying.
  434. const std::string spv_asm = R"(
  435. OpCapability Shader
  436. %1 = OpExtInstImport "GLSL.std.450"
  437. OpMemoryModel Logical GLSL450
  438. OpEntryPoint Fragment %main "main"
  439. OpExecutionMode %main OriginUpperLeft
  440. OpSource GLSL 430
  441. OpName %main "main"
  442. %void = OpTypeVoid
  443. %5 = OpTypeFunction %void
  444. %int = OpTypeInt 32 1
  445. %_ptr_Function_int = OpTypePointer Function %int
  446. %int_0 = OpConstant %int 0
  447. %int_10 = OpConstant %int 10
  448. %bool = OpTypeBool
  449. %int_1 = OpConstant %int 1
  450. %main = OpFunction %void None %5
  451. %12 = OpLabel
  452. OpBranch %13
  453. %13 = OpLabel
  454. ; This Phi should not have all constant arguments:
  455. ; CHECK: [[phi_id:%\d+]] = OpPhi %int %int_0 {{%\d+}} {{%\d+}} {{%\d+}}
  456. %22 = OpPhi %int %int_0 %12 %21 %15
  457. OpLoopMerge %14 %15 None
  458. OpBranch %16
  459. %16 = OpLabel
  460. ; The Phi should never be considered to have the value %int_0.
  461. ; CHECK: [[branch_selector:%\d+]] = OpSLessThan %bool [[phi_id]] %int_10
  462. %18 = OpSLessThan %bool %22 %int_10
  463. ; This conditional was wrongly converted into an always-true jump due to the
  464. ; bad meet evaluation of %22.
  465. ; CHECK: OpBranchConditional [[branch_selector]] {{%\d+}} {{%\d+}}
  466. OpBranchConditional %18 %19 %14
  467. %19 = OpLabel
  468. OpBranch %15
  469. %15 = OpLabel
  470. ; CHECK: OpIAdd %int [[phi_id]] %int_1
  471. %21 = OpIAdd %int %22 %int_1
  472. OpBranch %13
  473. %14 = OpLabel
  474. OpReturn
  475. OpFunctionEnd
  476. )";
  477. SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  478. }
  479. TEST_F(CCPTest, HandleCompositeWithUndef) {
  480. // Check to make sure that CCP does not crash when given a "constant" struct
  481. // with an undef. If at a later time CCP is enhanced to optimize this case,
  482. // it is not wrong.
  483. const std::string spv_asm = R"(
  484. OpCapability Shader
  485. %1 = OpExtInstImport "GLSL.std.450"
  486. OpMemoryModel Logical GLSL450
  487. OpEntryPoint Fragment %main "main"
  488. OpExecutionMode %main OriginUpperLeft
  489. OpSource HLSL 500
  490. OpName %main "main"
  491. %void = OpTypeVoid
  492. %4 = OpTypeFunction %void
  493. %int = OpTypeInt 32 1
  494. %bool = OpTypeBool
  495. %_struct_7 = OpTypeStruct %int %int
  496. %int_1 = OpConstant %int 1
  497. %9 = OpUndef %int
  498. %10 = OpConstantComposite %_struct_7 %int_1 %9
  499. %main = OpFunction %void None %4
  500. %11 = OpLabel
  501. %12 = OpCompositeExtract %int %10 0
  502. %13 = OpCopyObject %int %12
  503. OpReturn
  504. OpFunctionEnd
  505. )";
  506. auto res = SinglePassRunToBinary<CCPPass>(spv_asm, true);
  507. EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange);
  508. }
  509. TEST_F(CCPTest, SkipSpecConstantInstrucitons) {
  510. const std::string spv_asm = R"(
  511. OpCapability Shader
  512. %1 = OpExtInstImport "GLSL.std.450"
  513. OpMemoryModel Logical GLSL450
  514. OpEntryPoint Fragment %main "main"
  515. OpExecutionMode %main OriginUpperLeft
  516. OpSource HLSL 500
  517. OpName %main "main"
  518. %void = OpTypeVoid
  519. %4 = OpTypeFunction %void
  520. %bool = OpTypeBool
  521. %10 = OpSpecConstantFalse %bool
  522. %main = OpFunction %void None %4
  523. %11 = OpLabel
  524. OpBranchConditional %10 %L1 %L2
  525. %L1 = OpLabel
  526. OpReturn
  527. %L2 = OpLabel
  528. OpReturn
  529. OpFunctionEnd
  530. )";
  531. auto res = SinglePassRunToBinary<CCPPass>(spv_asm, true);
  532. EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange);
  533. }
  534. TEST_F(CCPTest, FoldConstantCompositeInstrucitonsWithSpecConst) {
  535. const std::string spv_asm = R"(
  536. OpCapability Shader
  537. OpMemoryModel Logical GLSL450
  538. OpEntryPoint Fragment %1 "main"
  539. OpExecutionMode %1 OriginUpperLeft
  540. %void = OpTypeVoid
  541. %4 = OpTypeFunction %void
  542. %bool = OpTypeBool
  543. %v3bool = OpTypeVector %bool 3
  544. %_struct_8 = OpTypeStruct %v3bool
  545. %true = OpConstantTrue %bool
  546. ; CHECK: [[spec_const:%\w+]] = OpSpecConstantComposite %v3bool
  547. %11 = OpSpecConstantComposite %v3bool %true %true %true
  548. %12 = OpConstantComposite %_struct_8 %11
  549. ; CHECK: OpFunction
  550. %1 = OpFunction %void None %4
  551. %29 = OpLabel
  552. %31 = OpCompositeExtract %v3bool %12 0
  553. ; CHECK: OpCompositeExtract %bool [[spec_const]] 0
  554. %32 = OpCompositeExtract %bool %31 0
  555. OpReturn
  556. OpFunctionEnd
  557. )";
  558. auto result = SinglePassRunAndMatch<CCPPass>(spv_asm, true);
  559. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  560. }
  561. TEST_F(CCPTest, UpdateSubsequentPhisToVarying) {
  562. const std::string text = R"(
  563. OpCapability Shader
  564. OpMemoryModel Logical GLSL450
  565. OpEntryPoint Fragment %func "func" %in
  566. OpExecutionMode %func OriginUpperLeft
  567. %void = OpTypeVoid
  568. %bool = OpTypeBool
  569. %int = OpTypeInt 32 1
  570. %false = OpConstantFalse %bool
  571. %int0 = OpConstant %int 0
  572. %int1 = OpConstant %int 1
  573. %int6 = OpConstant %int 6
  574. %int_ptr_Input = OpTypePointer Input %int
  575. %in = OpVariable %int_ptr_Input Input
  576. %undef = OpUndef %int
  577. ; Although no constants are propagated in this function, the propagator
  578. ; generates a new %true value while visiting conditional statements.
  579. ; CHECK: %true = OpConstantTrue %bool
  580. %functy = OpTypeFunction %void
  581. %func = OpFunction %void None %functy
  582. %1 = OpLabel
  583. OpBranch %2
  584. %2 = OpLabel
  585. %outer_phi = OpPhi %int %int0 %1 %outer_add %15
  586. %cond1 = OpSLessThanEqual %bool %outer_phi %int6
  587. OpLoopMerge %3 %15 None
  588. OpBranchConditional %cond1 %4 %3
  589. %4 = OpLabel
  590. %ld = OpLoad %int %in
  591. %cond2 = OpSGreaterThanEqual %bool %int1 %ld
  592. OpSelectionMerge %10 None
  593. OpBranchConditional %cond2 %8 %9
  594. %8 = OpLabel
  595. OpBranch %10
  596. %9 = OpLabel
  597. OpBranch %10
  598. %10 = OpLabel
  599. %extra_phi = OpPhi %int %outer_phi %8 %outer_phi %9
  600. OpBranch %11
  601. %11 = OpLabel
  602. %inner_phi = OpPhi %int %int0 %10 %inner_add %13
  603. %cond3 = OpSLessThanEqual %bool %inner_phi %int6
  604. OpLoopMerge %14 %13 None
  605. OpBranchConditional %cond3 %12 %14
  606. %12 = OpLabel
  607. OpBranch %13
  608. %13 = OpLabel
  609. %inner_add = OpIAdd %int %inner_phi %int1
  610. OpBranch %11
  611. %14 = OpLabel
  612. OpBranch %15
  613. %15 = OpLabel
  614. %outer_add = OpIAdd %int %extra_phi %int1
  615. OpBranch %2
  616. %3 = OpLabel
  617. OpReturn
  618. OpFunctionEnd
  619. )";
  620. auto result = SinglePassRunAndMatch<CCPPass>(text, true);
  621. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  622. }
  623. TEST_F(CCPTest, UndefInPhi) {
  624. const std::string text = R"(
  625. ; CHECK: [[uint1:%\w+]] = OpConstant {{%\w+}} 1
  626. ; CHECK: [[phi:%\w+]] = OpPhi
  627. ; CHECK: OpIAdd {{%\w+}} [[phi]] [[uint1]]
  628. OpCapability Kernel
  629. OpCapability Linkage
  630. OpMemoryModel Logical OpenCL
  631. OpDecorate %1 LinkageAttributes "func" Export
  632. %void = OpTypeVoid
  633. %bool = OpTypeBool
  634. %uint = OpTypeInt 32 0
  635. %uint_0 = OpConstant %uint 0
  636. %uint_1 = OpConstant %uint 1
  637. %7 = OpUndef %uint
  638. %8 = OpTypeFunction %void %bool
  639. %1 = OpFunction %void None %8
  640. %9 = OpFunctionParameter %bool
  641. %10 = OpLabel
  642. OpBranchConditional %9 %11 %12
  643. %11 = OpLabel
  644. OpBranch %13
  645. %12 = OpLabel
  646. OpBranch %14
  647. %14 = OpLabel
  648. OpBranchConditional %9 %13 %15
  649. %15 = OpLabel
  650. OpBranch %13
  651. %13 = OpLabel
  652. %16 = OpPhi %uint %uint_0 %11 %7 %14 %uint_1 %15
  653. %17 = OpIAdd %uint %16 %uint_1
  654. OpReturn
  655. OpFunctionEnd
  656. )";
  657. SinglePassRunAndMatch<CCPPass>(text, true);
  658. }
  659. // Just test to make sure the constant fold rules are being used. Will rely on
  660. // the folding test for specific testing of specific rules.
  661. TEST_F(CCPTest, UseConstantFoldingRules) {
  662. const std::string text = R"(
  663. ; CHECK: [[float1:%\w+]] = OpConstant {{%\w+}} 1
  664. ; CHECK: OpReturnValue [[float1]]
  665. OpCapability Shader
  666. OpCapability Linkage
  667. OpMemoryModel Logical GLSL450
  668. OpDecorate %1 LinkageAttributes "func" Export
  669. %void = OpTypeVoid
  670. %bool = OpTypeBool
  671. %float = OpTypeFloat 32
  672. %float_0 = OpConstant %float 0
  673. %float_1 = OpConstant %float 1
  674. %8 = OpTypeFunction %float
  675. %1 = OpFunction %float None %8
  676. %10 = OpLabel
  677. %17 = OpFAdd %float %float_0 %float_1
  678. OpReturnValue %17
  679. OpFunctionEnd
  680. )";
  681. SinglePassRunAndMatch<CCPPass>(text, true);
  682. }
  683. // Test for #1300. Previously value for %5 would not settle during simulation.
  684. TEST_F(CCPTest, SettlePhiLatticeValue) {
  685. const std::string text = R"(
  686. OpCapability Kernel
  687. OpCapability Linkage
  688. OpMemoryModel Logical OpenCL
  689. OpDecorate %func LinkageAttributes "func" Export
  690. %void = OpTypeVoid
  691. %bool = OpTypeBool
  692. %true = OpConstantTrue %bool
  693. %false = OpConstantFalse %bool
  694. %functy = OpTypeFunction %void
  695. %func = OpFunction %void None %functy
  696. %1 = OpLabel
  697. OpBranchConditional %true %2 %3
  698. %3 = OpLabel
  699. OpBranch %2
  700. %2 = OpLabel
  701. %5 = OpPhi %bool %true %1 %false %3
  702. OpReturn
  703. OpFunctionEnd
  704. )";
  705. SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  706. SinglePassRunToBinary<CCPPass>(text, true);
  707. }
  708. TEST_F(CCPTest, NullBranchCondition) {
  709. const std::string text = R"(
  710. ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
  711. ; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
  712. ; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
  713. OpCapability Shader
  714. OpMemoryModel Logical GLSL450
  715. OpEntryPoint Fragment %func "func"
  716. OpExecutionMode %func OriginUpperLeft
  717. %void = OpTypeVoid
  718. %bool = OpTypeBool
  719. %int = OpTypeInt 32 1
  720. %null = OpConstantNull %bool
  721. %int_1 = OpConstant %int 1
  722. %int_2 = OpConstant %int 2
  723. %functy = OpTypeFunction %void
  724. %func = OpFunction %void None %functy
  725. %1 = OpLabel
  726. OpSelectionMerge %2 None
  727. OpBranchConditional %null %2 %3
  728. %3 = OpLabel
  729. OpBranch %2
  730. %2 = OpLabel
  731. %phi = OpPhi %int %int_1 %1 %int_2 %3
  732. %add = OpIAdd %int %int_1 %phi
  733. OpReturn
  734. OpFunctionEnd
  735. )";
  736. SinglePassRunAndMatch<CCPPass>(text, true);
  737. }
  738. TEST_F(CCPTest, UndefBranchCondition) {
  739. const std::string text = R"(
  740. ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
  741. ; CHECK: [[phi:%\w+]] = OpPhi
  742. ; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
  743. OpCapability Shader
  744. OpMemoryModel Logical GLSL450
  745. OpEntryPoint Fragment %func "func"
  746. OpExecutionMode %func OriginUpperLeft
  747. %void = OpTypeVoid
  748. %bool = OpTypeBool
  749. %int = OpTypeInt 32 1
  750. %undef = OpUndef %bool
  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. OpBranchConditional %undef %2 %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, NullSwitchCondition) {
  769. const std::string text = R"(
  770. ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
  771. ; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
  772. ; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
  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. %null = OpConstantNull %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 %null %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_F(CCPTest, UndefSwitchCondition) {
  798. const std::string text = R"(
  799. ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
  800. ; CHECK: [[phi:%\w+]] = OpPhi
  801. ; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
  802. OpCapability Shader
  803. OpMemoryModel Logical GLSL450
  804. OpEntryPoint Fragment %func "func"
  805. OpExecutionMode %func OriginUpperLeft
  806. %void = OpTypeVoid
  807. %int = OpTypeInt 32 1
  808. %undef = OpUndef %int
  809. %int_1 = OpConstant %int 1
  810. %int_2 = OpConstant %int 2
  811. %functy = OpTypeFunction %void
  812. %func = OpFunction %void None %functy
  813. %1 = OpLabel
  814. OpSelectionMerge %2 None
  815. OpSwitch %undef %2 0 %3
  816. %3 = OpLabel
  817. OpBranch %2
  818. %2 = OpLabel
  819. %phi = OpPhi %int %int_1 %1 %int_2 %3
  820. %add = OpIAdd %int %int_1 %phi
  821. OpReturn
  822. OpFunctionEnd
  823. )";
  824. SinglePassRunAndMatch<CCPPass>(text, true);
  825. }
  826. // Test for #1361.
  827. TEST_F(CCPTest, CompositeConstructOfGlobalValue) {
  828. const std::string text = R"(
  829. ; CHECK: [[phi:%\w+]] = OpPhi
  830. ; CHECK-NEXT: OpCompositeExtract {{%\w+}} [[phi]] 0
  831. OpCapability Shader
  832. OpMemoryModel Logical GLSL450
  833. OpEntryPoint Fragment %func "func" %in
  834. OpExecutionMode %func OriginUpperLeft
  835. %void = OpTypeVoid
  836. %int = OpTypeInt 32 1
  837. %bool = OpTypeBool
  838. %functy = OpTypeFunction %void
  839. %ptr_int_Input = OpTypePointer Input %int
  840. %in = OpVariable %ptr_int_Input Input
  841. %struct = OpTypeStruct %ptr_int_Input %ptr_int_Input
  842. %struct_null = OpConstantNull %struct
  843. %func = OpFunction %void None %functy
  844. %1 = OpLabel
  845. OpBranch %2
  846. %2 = OpLabel
  847. %phi = OpPhi %struct %struct_null %1 %5 %4
  848. %extract = OpCompositeExtract %ptr_int_Input %phi 0
  849. OpLoopMerge %3 %4 None
  850. OpBranch %4
  851. %4 = OpLabel
  852. %5 = OpCompositeConstruct %struct %in %in
  853. OpBranch %2
  854. %3 = OpLabel
  855. OpReturn
  856. OpFunctionEnd
  857. )";
  858. SinglePassRunAndMatch<CCPPass>(text, true);
  859. }
  860. TEST_F(CCPTest, FoldWithDecoration) {
  861. const std::string text = R"(
  862. ; CHECK: OpCapability
  863. ; CHECK-NOT: OpDecorate
  864. ; CHECK: OpFunctionEnd
  865. OpCapability Shader
  866. %1 = OpExtInstImport "GLSL.std.450"
  867. OpMemoryModel Logical GLSL450
  868. OpEntryPoint Fragment %2 "main"
  869. OpExecutionMode %2 OriginUpperLeft
  870. OpSource ESSL 310
  871. OpDecorate %3 RelaxedPrecision
  872. %void = OpTypeVoid
  873. %5 = OpTypeFunction %void
  874. %float = OpTypeFloat 32
  875. %v3float = OpTypeVector %float 3
  876. %float_0 = OpConstant %float 0
  877. %v4float = OpTypeVector %float 4
  878. %10 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
  879. %2 = OpFunction %void None %5
  880. %11 = OpLabel
  881. %3 = OpVectorShuffle %v3float %10 %10 0 1 2
  882. OpReturn
  883. OpFunctionEnd
  884. )";
  885. SinglePassRunAndMatch<CCPPass>(text, true);
  886. }
  887. TEST_F(CCPTest, DebugSimpleFoldConstant) {
  888. const std::string text = R"(
  889. OpCapability Shader
  890. OpCapability Linkage
  891. %ext = OpExtInstImport "OpenCL.DebugInfo.100"
  892. OpMemoryModel Logical GLSL450
  893. %file_name = OpString "test"
  894. %float_name = OpString "float"
  895. %main_name = OpString "main"
  896. %f_name = OpString "f"
  897. OpDecorate %1 LinkageAttributes "func" Export
  898. %void = OpTypeVoid
  899. %bool = OpTypeBool
  900. %float = OpTypeFloat 32
  901. %float_0 = OpConstant %float 0
  902. ; CHECK: [[float1:%\w+]] = OpConstant {{%\w+}} 1
  903. %float_1 = OpConstant %float 1
  904. %uint = OpTypeInt 32 0
  905. %uint_32 = OpConstant %uint 32
  906. %8 = OpTypeFunction %float
  907. %null_expr = OpExtInst %void %ext DebugExpression
  908. %src = OpExtInst %void %ext DebugSource %file_name
  909. %cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
  910. %dbg_tf = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
  911. %main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_tf
  912. %dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 0 0 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %1
  913. %dbg_f = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 0 0 %dbg_main FlagIsLocal
  914. %1 = OpFunction %float None %8
  915. %10 = OpLabel
  916. ; CHECK: OpExtInst %void [[ext:%\w+]] DebugScope
  917. ; CHECK: OpLine [[file:%\w+]] 1 0
  918. ; CHECK: OpExtInst %void [[ext]] DebugValue {{%\w+}} %float_1
  919. %s0 = OpExtInst %void %ext DebugScope %dbg_main
  920. OpLine %file_name 1 0
  921. %17 = OpFAdd %float %float_0 %float_1
  922. %val = OpExtInst %void %ext DebugValue %dbg_f %17 %null_expr
  923. ; CHECK: OpLine [[file]] 2 0
  924. ; CHECK: OpReturnValue [[float1]]
  925. OpLine %file_name 2 0
  926. OpReturnValue %17
  927. OpFunctionEnd
  928. )";
  929. SinglePassRunAndMatch<CCPPass>(text, true);
  930. }
  931. TEST_F(CCPTest, DebugFoldMultipleForSingleConstant) {
  932. const std::string text = R"(
  933. OpCapability Shader
  934. %1 = OpExtInstImport "GLSL.std.450"
  935. %ext = OpExtInstImport "OpenCL.DebugInfo.100"
  936. OpMemoryModel Logical GLSL450
  937. OpEntryPoint Fragment %main "main" %outparm
  938. OpExecutionMode %main OriginUpperLeft
  939. OpSource GLSL 450
  940. %file_name = OpString "test"
  941. %float_name = OpString "float"
  942. %main_name = OpString "main"
  943. %f_name = OpString "f"
  944. OpName %main "main"
  945. OpName %outparm "outparm"
  946. OpDecorate %outparm Location 0
  947. %void = OpTypeVoid
  948. %3 = OpTypeFunction %void
  949. %int = OpTypeInt 32 1
  950. %bool = OpTypeBool
  951. %_ptr_Function_int = OpTypePointer Function %int
  952. %int_4 = OpConstant %int 4
  953. %int_3 = OpConstant %int 3
  954. %int_1 = OpConstant %int 1
  955. %uint = OpTypeInt 32 0
  956. %uint_32 = OpConstant %uint 32
  957. %_ptr_Output_int = OpTypePointer Output %int
  958. %outparm = OpVariable %_ptr_Output_int Output
  959. %null_expr = OpExtInst %void %ext DebugExpression
  960. %src = OpExtInst %void %ext DebugSource %file_name
  961. %cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
  962. %dbg_tf = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
  963. %main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_tf
  964. %dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 0 0 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
  965. %bb0 = OpExtInst %void %ext DebugLexicalBlock %src 0 0 %dbg_main
  966. %bb1 = OpExtInst %void %ext DebugLexicalBlock %src 1 0 %dbg_main
  967. %bb2 = OpExtInst %void %ext DebugLexicalBlock %src 2 0 %dbg_main
  968. %bb3 = OpExtInst %void %ext DebugLexicalBlock %src 3 0 %dbg_main
  969. %dbg_f0 = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 0 0 %dbg_main FlagIsLocal
  970. %dbg_f1 = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 1 0 %dbg_main FlagIsLocal
  971. %dbg_f2 = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 2 0 %dbg_main FlagIsLocal
  972. %main = OpFunction %void None %3
  973. %4 = OpLabel
  974. ; CHECK: OpExtInst %void [[ext:%\w+]] DebugScope
  975. ; CHECK: OpLine [[file:%\w+]] 1 0
  976. ; CHECK: OpIAdd %int %int_4 %int_3
  977. ; CHECK: OpExtInst %void [[ext]] DebugValue {{%\w+}} %int_7
  978. %s0 = OpExtInst %void %ext DebugScope %bb0
  979. OpLine %file_name 1 0
  980. %9 = OpIAdd %int %int_4 %int_3
  981. %val0 = OpExtInst %void %ext DebugValue %dbg_f0 %9 %null_expr
  982. ; CHECK: OpLine [[file]] 2 0
  983. ; CHECK: OpSGreaterThan %bool %int_7 %int_3
  984. ; CHECK: OpExtInst %void [[ext]] DebugValue {{%\w+}} %true
  985. OpLine %file_name 2 0
  986. %6 = OpSGreaterThan %bool %9 %int_3
  987. %val1 = OpExtInst %void %ext DebugValue %dbg_f1 %6 %null_expr
  988. OpSelectionMerge %25 None
  989. OpBranchConditional %6 %22 %23
  990. %22 = OpLabel
  991. %s1 = OpExtInst %void %ext DebugScope %bb1
  992. %7 = OpCopyObject %int %9
  993. %val2 = OpExtInst %void %ext DebugValue %dbg_f2 %7 %null_expr
  994. OpBranch %25
  995. %23 = OpLabel
  996. %s2 = OpExtInst %void %ext DebugScope %bb2
  997. %8 = OpCopyObject %int %int_4
  998. OpBranch %25
  999. %25 = OpLabel
  1000. %s3 = OpExtInst %void %ext DebugScope %bb3
  1001. %35 = OpPhi %int %7 %22 %8 %23
  1002. OpStore %outparm %35
  1003. OpReturn
  1004. OpFunctionEnd
  1005. )";
  1006. SinglePassRunAndMatch<CCPPass>(text, true);
  1007. }
  1008. // Test from https://github.com/KhronosGroup/SPIRV-Tools/issues/3636
  1009. TEST_F(CCPTest, CCPNoChangeFailure) {
  1010. const std::string text = R"(
  1011. OpCapability Shader
  1012. %1 = OpExtInstImport "GLSL.std.450"
  1013. OpMemoryModel Logical GLSL450
  1014. OpEntryPoint Fragment %4 "main"
  1015. OpExecutionMode %4 OriginUpperLeft
  1016. OpSource ESSL 320
  1017. %2 = OpTypeVoid
  1018. %3 = OpTypeFunction %2
  1019. %6 = OpTypeInt 32 1
  1020. %7 = OpConstant %6 2
  1021. %13 = OpConstant %6 4
  1022. %21 = OpConstant %6 1
  1023. %10 = OpTypeBool
  1024. %17 = OpTypePointer Function %6
  1025. ; CCP is generating two new constants during propagation that end up being
  1026. ; dead because they cannot be replaced anywhere in the IR. CCP was wrongly
  1027. ; considering the IR to be unmodified because of this.
  1028. ; CHECK: %true = OpConstantTrue %bool
  1029. ; CHECK: %int_3 = OpConstant %int 3
  1030. %4 = OpFunction %2 None %3
  1031. %11 = OpLabel
  1032. OpBranch %5
  1033. %5 = OpLabel
  1034. %23 = OpPhi %6 %7 %11 %20 %15
  1035. %9 = OpSLessThan %10 %23 %13
  1036. OpLoopMerge %8 %15 None
  1037. OpBranchConditional %9 %15 %8
  1038. %15 = OpLabel
  1039. %20 = OpIAdd %6 %23 %21
  1040. OpBranch %5
  1041. %8 = OpLabel
  1042. OpReturn
  1043. OpFunctionEnd
  1044. )";
  1045. auto result = SinglePassRunAndMatch<CCPPass>(text, true);
  1046. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  1047. }
  1048. // Test from https://github.com/KhronosGroup/SPIRV-Tools/issues/3738
  1049. // Similar to the previous one but more than one constant is generated in a
  1050. // single call to the instruction folder.
  1051. TEST_F(CCPTest, CCPNoChangeFailureSeveralConstantsDuringFolding) {
  1052. const std::string text = R"(
  1053. OpCapability Shader
  1054. %1 = OpExtInstImport "GLSL.std.450"
  1055. OpMemoryModel Logical GLSL450
  1056. OpEntryPoint Fragment %2 "main"
  1057. OpExecutionMode %2 OriginUpperLeft
  1058. %void = OpTypeVoid
  1059. %4 = OpTypeFunction %void
  1060. %float = OpTypeFloat 32
  1061. %v3float = OpTypeVector %float 3
  1062. %uint = OpTypeInt 32 0
  1063. %uint_0 = OpConstant %uint 0
  1064. %bool = OpTypeBool
  1065. %v3bool = OpTypeVector %bool 3
  1066. %float_0 = OpConstant %float 0
  1067. %12 = OpConstantComposite %v3float %float_0 %float_0 %float_0
  1068. %float_0_300000012 = OpConstant %float 0.300000012
  1069. %14 = OpConstantComposite %v3float %float_0_300000012 %float_0_300000012 %float_0_300000012
  1070. ; CCP is generating several constants during a single instruction evaluation.
  1071. ; When folding %19, it generates the constants %true and %24. They are dead
  1072. ; because they cannot be replaced anywhere in the IR. CCP was wrongly
  1073. ; considering the IR to be unmodified because of this.
  1074. ;
  1075. ; CHECK: %true = OpConstantTrue %bool
  1076. ; CHECK: %24 = OpConstantComposite %v3bool %true %true %true
  1077. ; CHECK: %float_1 = OpConstant %float 1
  1078. ; CHECK: %float_0_699999988 = OpConstant %float 0.699999988
  1079. %2 = OpFunction %void None %4
  1080. %15 = OpLabel
  1081. OpBranch %16
  1082. %16 = OpLabel
  1083. %17 = OpPhi %v3float %12 %15 %14 %18
  1084. %19 = OpFOrdLessThan %v3bool %17 %14
  1085. %20 = OpAll %bool %19
  1086. OpLoopMerge %21 %18 None
  1087. OpBranchConditional %20 %18 %21
  1088. %18 = OpLabel
  1089. OpBranch %16
  1090. %21 = OpLabel
  1091. %22 = OpExtInst %v3float %1 FMix %12 %17 %14
  1092. OpReturn
  1093. OpFunctionEnd
  1094. )";
  1095. auto result = SinglePassRunAndMatch<CCPPass>(text, true);
  1096. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  1097. }
  1098. // Test from https://github.com/KhronosGroup/SPIRV-Tools/issues/3991
  1099. // Similar to the previous one but constants are created even when no
  1100. // instruction are ever folded during propagation.
  1101. TEST_F(CCPTest, CCPNoChangeFailureWithUnfoldableInstr) {
  1102. const std::string text = R"(
  1103. OpCapability Shader
  1104. %1 = OpExtInstImport "GLSL.std.450"
  1105. OpMemoryModel Logical GLSL450
  1106. OpEntryPoint Fragment %2 "main"
  1107. OpExecutionMode %2 OriginUpperLeft
  1108. %void = OpTypeVoid
  1109. %4 = OpTypeFunction %void
  1110. %float = OpTypeFloat 32
  1111. %v3float = OpTypeVector %float 3
  1112. %uint = OpTypeInt 32 0
  1113. %uint_0 = OpConstant %uint 0
  1114. %bool = OpTypeBool
  1115. %float_0 = OpConstant %float 0
  1116. %11 = OpConstantComposite %v3float %float_0 %float_0 %float_0
  1117. %float_0_300000012 = OpConstant %float 0.300000012
  1118. %13 = OpConstantComposite %v3float %float_0_300000012 %float_0_300000012 %float_0_300000012
  1119. ; CCP generates two constants when trying to fold an instruction, which it
  1120. ; ultimately fails to fold. The instruction folder in CCP was only
  1121. ; checking for newly added constants if the instruction folds successfully.
  1122. ;
  1123. ; CHECK: %float_1 = OpConstant %float 1
  1124. ; CHECK: %float_0_699999988 = OpConstant %float 0.69999998
  1125. %2 = OpFunction %void None %4
  1126. %14 = OpLabel
  1127. %15 = OpBitcast %uint %float_0_300000012
  1128. %16 = OpUGreaterThan %bool %15 %uint_0
  1129. OpBranch %17
  1130. %17 = OpLabel
  1131. %18 = OpPhi %v3float %11 %14 %13 %19
  1132. OpLoopMerge %20 %19 None
  1133. OpBranchConditional %16 %19 %20
  1134. %19 = OpLabel
  1135. OpBranch %17
  1136. %20 = OpLabel
  1137. %21 = OpExtInst %v3float %1 FMix %11 %18 %13
  1138. OpReturn
  1139. OpFunctionEnd
  1140. )";
  1141. auto result = SinglePassRunAndMatch<CCPPass>(text, true);
  1142. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  1143. }
  1144. TEST_F(CCPTest, FunctionDeclaration) {
  1145. // Make sure the pass works with a function declaration that is called.
  1146. const std::string text = R"(OpCapability Addresses
  1147. OpCapability Linkage
  1148. OpCapability Kernel
  1149. OpCapability Int8
  1150. %1 = OpExtInstImport "OpenCL.std"
  1151. OpMemoryModel Physical64 OpenCL
  1152. OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool"
  1153. OpExecutionMode %2 ContractionOff
  1154. OpSource Unknown 0
  1155. OpDecorate %3 LinkageAttributes "julia_error_7712" Import
  1156. %void = OpTypeVoid
  1157. %5 = OpTypeFunction %void
  1158. %3 = OpFunction %void None %5
  1159. OpFunctionEnd
  1160. %2 = OpFunction %void None %5
  1161. %6 = OpLabel
  1162. %7 = OpFunctionCall %void %3
  1163. OpReturn
  1164. OpFunctionEnd
  1165. )";
  1166. SinglePassRunAndCheck<CCPPass>(text, text, false);
  1167. }
  1168. // Test from https://github.com/KhronosGroup/SPIRV-Tools/issues/4462.
  1169. // The test was causing a lateral movement in the constant lattice, which was
  1170. // not being detected as varying by CCP. In this test, FClamp is evaluated
  1171. // twice. On the first evaluation, if computes FClamp(0.5, 0.5, -1) which
  1172. // returns -1. On the second evaluation, it computes FClamp(0.5, 0.5, VARYING)
  1173. // which returns 0.5.
  1174. //
  1175. // Both fold() computations are correct given the semantics of FClamp() but
  1176. // this causes a lateral transition in the constant lattice which was not being
  1177. // considered VARYING by CCP.
  1178. TEST_F(CCPTest, LateralLatticeTransition) {
  1179. const std::string text = R"(OpCapability Shader
  1180. %1 = OpExtInstImport "GLSL.std.450"
  1181. OpMemoryModel Logical GLSL450
  1182. OpEntryPoint Fragment %main "main" %gl_FragCoord %outColor
  1183. OpExecutionMode %main OriginUpperLeft
  1184. OpSource ESSL 310
  1185. OpName %main "main"
  1186. OpName %gl_FragCoord "gl_FragCoord"
  1187. OpName %outColor "outColor"
  1188. OpDecorate %gl_FragCoord BuiltIn FragCoord
  1189. OpDecorate %outColor Location 0
  1190. %void = OpTypeVoid
  1191. %6 = OpTypeFunction %void
  1192. %float = OpTypeFloat 32
  1193. %float_0_5 = OpConstant %float 0.5
  1194. %v4float = OpTypeVector %float 4
  1195. %_ptr_Input_v4float = OpTypePointer Input %v4float
  1196. %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
  1197. %uint = OpTypeInt 32 0
  1198. %uint_0 = OpConstant %uint 0
  1199. %_ptr_Input_float = OpTypePointer Input %float
  1200. %float_0 = OpConstant %float 0
  1201. %bool = OpTypeBool
  1202. %float_n1 = OpConstant %float -1
  1203. %float_1 = OpConstant %float 1
  1204. %_ptr_Output_v4float = OpTypePointer Output %v4float
  1205. %outColor = OpVariable %_ptr_Output_v4float Output
  1206. ; This constant is created during the first evaluation of the CompositeConstruct
  1207. ; CHECK: [[new_constant:%\d+]] = OpConstantComposite %v4float %float_n1 %float_0_5 %float_0 %float_1
  1208. %main = OpFunction %void None %6
  1209. %19 = OpLabel
  1210. %20 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0
  1211. %21 = OpLoad %float %20
  1212. %22 = OpFOrdLessThan %bool %21 %float_0
  1213. OpSelectionMerge %23 None
  1214. OpBranchConditional %22 %24 %25
  1215. %24 = OpLabel
  1216. OpBranch %23
  1217. %25 = OpLabel
  1218. OpBranch %26
  1219. %26 = OpLabel
  1220. OpBranch %23
  1221. %23 = OpLabel
  1222. %27 = OpPhi %float %float_n1 %24 %float_0_5 %26
  1223. %28 = OpExtInst %float %1 FClamp %float_0_5 %float_0_5 %27
  1224. ; On first evaluation, the result from FClamp will return 0.5.
  1225. ; But on second evaluation, FClamp should return VARYING. Check
  1226. ; that CCP is not keeping the first result.
  1227. ; CHECK-NOT: %29 = OpCompositeConstruct %v4float %float_0_5 %float_0_5 %float_0 %float_1
  1228. %29 = OpCompositeConstruct %v4float %28 %float_0_5 %float_0 %float_1
  1229. ; CHECK-NOT: OpCopyObject %v4float [[new_constant]]
  1230. %42 = OpCopyObject %v4float %29
  1231. ; CHECK-NOT: OpStore %outColor [[new_constant]]
  1232. OpStore %outColor %42
  1233. OpReturn
  1234. OpFunctionEnd
  1235. )";
  1236. auto result = SinglePassRunAndMatch<CCPPass>(text, true);
  1237. EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
  1238. }
  1239. } // namespace
  1240. } // namespace opt
  1241. } // namespace spvtools