split_combined_image_sampler_pass_test.cpp 75 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933
  1. // Copyright (c) 2025 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <array>
  15. #include <iostream>
  16. #include <ostream>
  17. #include "spirv-tools/optimizer.hpp"
  18. #include "test/opt/pass_fixture.h"
  19. #include "test/opt/pass_utils.h"
  20. namespace spvtools {
  21. namespace opt {
  22. namespace {
  23. struct SplitCombinedImageSamplerPassTest : public PassTest<::testing::Test> {
  24. virtual void SetUp() override {
  25. SetTargetEnv(SPV_ENV_VULKAN_1_0);
  26. SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  27. SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES |
  28. SPV_BINARY_TO_TEXT_OPTION_INDENT |
  29. SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
  30. }
  31. };
  32. struct TypeCase {
  33. const char* glsl_type;
  34. const char* image_type_decl;
  35. };
  36. std::ostream& operator<<(std::ostream& os, const TypeCase& tc) {
  37. os << tc.glsl_type;
  38. return os;
  39. }
  40. struct SplitCombinedImageSamplerPassTypeCaseTest
  41. : public PassTest<::testing::TestWithParam<TypeCase>> {
  42. virtual void SetUp() override {
  43. SetTargetEnv(SPV_ENV_VULKAN_1_0);
  44. SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  45. SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES |
  46. SPV_BINARY_TO_TEXT_OPTION_INDENT |
  47. SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
  48. }
  49. };
  50. std::vector<TypeCase> ImageTypeCases() {
  51. return std::vector<TypeCase>{
  52. {"sampler2D", "OpTypeImage %float 2D 0 0 0 1 Unknown"},
  53. {"sampler2DShadow", "OpTypeImage %float 2D 1 0 0 1 Unknown"},
  54. {"sampler2DArray", "OpTypeImage %float 2D 0 1 0 1 Unknown"},
  55. {"sampler2DArrayShadow", "OpTypeImage %float 2D 1 1 0 1 Unknown"},
  56. {"sampler2DMS", "OpTypeImage %float 2D 0 0 1 1 Unknown"},
  57. {"sampler2DMSArray", "OpTypeImage %float 2D 0 1 1 1 Unknown"},
  58. {"sampler3D", "OpTypeImage %float 3D 0 0 0 1 Unknown"},
  59. {"samplerCube", "OpTypeImage %float Cube 0 0 0 1 Unknown"},
  60. {"samplerCubeShadow", "OpTypeImage %float Cube 1 0 0 1 Unknown"},
  61. {"samplerCubeArray", "OpTypeImage %float Cube 0 1 0 1 Unknown"},
  62. {"samplerCubeArrayShadow", "OpTypeImage %float Cube 1 1 0 1 Unknown"},
  63. {"isampler2D", "OpTypeImage %int 2D 0 0 0 1 Unknown"},
  64. {"isampler2DShadow", "OpTypeImage %int 2D 1 0 0 1 Unknown"},
  65. {"isampler2DArray", "OpTypeImage %int 2D 0 1 0 1 Unknown"},
  66. {"isampler2DArrayShadow", "OpTypeImage %int 2D 1 1 0 1 Unknown"},
  67. {"isampler2DMS", "OpTypeImage %int 2D 0 0 1 1 Unknown"},
  68. {"isampler2DMSArray", "OpTypeImage %int 2D 0 1 1 1 Unknown"},
  69. {"isampler3D", "OpTypeImage %int 3D 0 0 0 1 Unknown"},
  70. {"isamplerCube", "OpTypeImage %int Cube 0 0 0 1 Unknown"},
  71. {"isamplerCubeShadow", "OpTypeImage %int Cube 1 0 0 1 Unknown"},
  72. {"isamplerCubeArray", "OpTypeImage %int Cube 0 1 0 1 Unknown"},
  73. {"isamplerCubeArrayShadow", "OpTypeImage %int Cube 1 1 0 1 Unknown"},
  74. {"usampler2D", "OpTypeImage %uint 2D 0 0 0 1 Unknown"},
  75. {"usampler2DShadow", "OpTypeImage %uint 2D 1 0 0 1 Unknown"},
  76. {"usampler2DArray", "OpTypeImage %uint 2D 0 1 0 1 Unknown"},
  77. {"usampler2DArrayShadow", "OpTypeImage %uint 2D 1 1 0 1 Unknown"},
  78. {"usampler2DMS", "OpTypeImage %uint 2D 0 0 1 1 Unknown"},
  79. {"usampler2DMSArray", "OpTypeImage %uint 2D 0 1 1 1 Unknown"},
  80. {"usampler3D", "OpTypeImage %uint 3D 0 0 0 1 Unknown"},
  81. {"usamplerCube", "OpTypeImage %uint Cube 0 0 0 1 Unknown"},
  82. {"usamplerCubeShadow", "OpTypeImage %uint Cube 1 0 0 1 Unknown"},
  83. {"usamplerCubeArray", "OpTypeImage %uint Cube 0 1 0 1 Unknown"},
  84. {"usamplerCubeArrayShadow", "OpTypeImage %uint Cube 1 1 0 1 Unknown"},
  85. };
  86. }
  87. std::string Preamble(const std::string shader_interface = "") {
  88. return R"( OpCapability Shader
  89. OpCapability RuntimeDescriptorArray
  90. OpExtension "SPV_EXT_descriptor_indexing"
  91. OpMemoryModel Logical GLSL450
  92. OpEntryPoint GLCompute %main "main")" +
  93. shader_interface + R"(
  94. OpExecutionMode %main LocalSize 1 1 1
  95. OpName %main "main"
  96. OpName %main_0 "main_0"
  97. OpName %voidfn "voidfn"
  98. )";
  99. }
  100. std::string PreambleFragment(const std::string shader_interface = "") {
  101. return R"( OpCapability Shader
  102. OpMemoryModel Logical GLSL450
  103. OpEntryPoint Fragment %main "main")" +
  104. shader_interface + R"(
  105. OpExecutionMode %main OriginUpperLeft
  106. OpName %main "main"
  107. OpName %main_0 "main_0"
  108. OpName %voidfn "voidfn"
  109. )";
  110. }
  111. std::string BasicTypes() {
  112. return R"( %float = OpTypeFloat 32
  113. %uint = OpTypeInt 32 0
  114. %int = OpTypeInt 32 1
  115. %uint_0 = OpConstant %uint 0
  116. %uint_1 = OpConstant %uint 1
  117. %uint_3 = OpConstant %uint 3
  118. %float_0 = OpConstant %float 0
  119. %v2float = OpTypeVector %float 2
  120. %v3float = OpTypeVector %float 3
  121. %v4float = OpTypeVector %float 4
  122. %13 = OpConstantNull %v2float
  123. %14 = OpConstantNull %v3float
  124. %15 = OpConstantNull %v4float
  125. %void = OpTypeVoid
  126. %voidfn = OpTypeFunction %void
  127. )";
  128. }
  129. std::string Main() {
  130. return R"(
  131. %main = OpFunction %void None %voidfn
  132. %main_0 = OpLabel
  133. OpReturn
  134. OpFunctionEnd
  135. )";
  136. }
  137. std::string NoCheck() { return "; CHECK-NOT: nothing to see"; }
  138. TEST_F(SplitCombinedImageSamplerPassTest, SamplerOnly_NoChange) {
  139. const std::string kTest = Preamble() +
  140. R"( OpDecorate %100 DescriptorSet 0
  141. OpDecorate %100 Binding 0
  142. )" + BasicTypes() + R"( %10 = OpTypeSampler
  143. %_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
  144. %100 = OpVariable %_ptr_UniformConstant_10 UniformConstant
  145. %main = OpFunction %void None %voidfn
  146. %main_0 = OpLabel
  147. %6 = OpLoad %10 %100
  148. OpReturn
  149. OpFunctionEnd
  150. )";
  151. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  152. kTest + NoCheck(), /* do_validation= */ true);
  153. EXPECT_EQ(status, Pass::Status::SuccessWithoutChange)
  154. << "status" << kTest << "\n -> \n"
  155. << disasm;
  156. EXPECT_EQ(disasm, kTest) << "disasm";
  157. }
  158. TEST_F(SplitCombinedImageSamplerPassTest, ImageOnly_NoChange) {
  159. const std::string kTest = Preamble() +
  160. R"( OpDecorate %100 DescriptorSet 0
  161. OpDecorate %100 Binding 0
  162. )" + BasicTypes() + R"( %10 = OpTypeImage %float 2D 0 0 0 1 Unknown
  163. %_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
  164. %100 = OpVariable %_ptr_UniformConstant_10 UniformConstant
  165. %main = OpFunction %void None %voidfn
  166. %main_0 = OpLabel
  167. %6 = OpLoad %10 %100
  168. OpReturn
  169. OpFunctionEnd
  170. )";
  171. SCOPED_TRACE("image only");
  172. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  173. kTest + NoCheck(), /* do_validation= */ true);
  174. EXPECT_EQ(status, Pass::Status::SuccessWithoutChange);
  175. EXPECT_EQ(disasm, kTest);
  176. }
  177. TEST_F(SplitCombinedImageSamplerPassTest, PtrSampledImageOnly_DeletesPtrType) {
  178. const std::string kTest = Preamble() + BasicTypes() + R"(
  179. ; CHECK: OpCapability Shader
  180. ; CHECK-NOT: OpTypePointer UniformConstant
  181. ; CHECK: OpFunction %void
  182. %100 = OpTypeImage %float 2D 0 0 0 1 Unknown
  183. %101 = OpTypeSampledImage %100
  184. %102 = OpTypePointer UniformConstant %101
  185. %main = OpFunction %void None %voidfn
  186. %main_0 = OpLabel
  187. OpReturn
  188. OpFunctionEnd
  189. )";
  190. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  191. kTest + NoCheck(), /* do_validation= */ true);
  192. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << "status";
  193. }
  194. TEST_F(SplitCombinedImageSamplerPassTest,
  195. PtrArraySampledImageOnly_DeletesPtrType) {
  196. const std::string kTest = Preamble() + BasicTypes() + R"(
  197. ; CHECK: OpCapability Shader
  198. ; CHECK-NOT: OpTypePointer UniformConstant
  199. ; CHECK: OpFunction %void
  200. %100 = OpTypeImage %float 2D 0 0 0 1 Unknown
  201. %101 = OpTypeSampledImage %100
  202. %103 = OpTypeArray %101 %uint_1
  203. %104 = OpTypePointer UniformConstant %103
  204. %main = OpFunction %void None %voidfn
  205. %main_0 = OpLabel
  206. OpReturn
  207. OpFunctionEnd
  208. )";
  209. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  210. kTest + NoCheck(), /* do_validation= */ true);
  211. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << "status";
  212. }
  213. TEST_F(SplitCombinedImageSamplerPassTest,
  214. PtrRtArraySampledImageOnly_DeletesPtrType) {
  215. const std::string kTest = Preamble() + BasicTypes() + R"(
  216. ; CHECK: OpCapability Shader
  217. ; CHECK-NOT: OpTypePointer UniformConstant
  218. ; CHECK: OpFunction %void
  219. %100 = OpTypeImage %float 2D 0 0 0 1 Unknown
  220. %101 = OpTypeSampledImage %100
  221. %103 = OpTypeRuntimeArray %101
  222. %104 = OpTypePointer UniformConstant %103
  223. %main = OpFunction %void None %voidfn
  224. %main_0 = OpLabel
  225. OpReturn
  226. OpFunctionEnd
  227. )";
  228. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  229. kTest + NoCheck(), /* do_validation= */ true);
  230. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << "status";
  231. }
  232. TEST_F(SplitCombinedImageSamplerPassTest,
  233. Combined_NoSampler_CreatedBeforeSampledImage) {
  234. // No OpTypeSampler to begin with.
  235. const std::string kTest = Preamble() +
  236. R"( OpDecorate %100 DescriptorSet 0
  237. OpDecorate %100 Binding 0
  238. ; A sampler type is created and placed at the start of types.
  239. ; CHECK: OpDecorate %{{\d+}} Binding 0
  240. ; CHECK: OpDecorate %{{\d+}} Binding 0
  241. ; CHECK-NOT: TypeSampledImage
  242. ; CHECK: TypeSampler
  243. ; CHECK: TypeSampledImage
  244. )" + BasicTypes() + R"( %10 = OpTypeImage %float 2D 0 0 0 1 Unknown
  245. %11 = OpTypeSampledImage %10
  246. %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
  247. %100 = OpVariable %_ptr_UniformConstant_11 UniformConstant
  248. %main = OpFunction %void None %voidfn
  249. %main_0 = OpLabel
  250. %6 = OpLoad %11 %100
  251. OpReturn
  252. OpFunctionEnd
  253. )";
  254. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  255. kTest, /* do_validation= */ true);
  256. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  257. }
  258. TEST_F(SplitCombinedImageSamplerPassTest, Combined_SynthesizeVarNames) {
  259. // Also tests binding info is copied to both variables.
  260. const std::string kTest = Preamble() +
  261. R"(
  262. OpName %orig_var "orig_var"
  263. OpDecorate %orig_var DescriptorSet 0
  264. OpDecorate %orig_var Binding 0
  265. ; The combined image variable is replaced by an image variable and a sampler variable.
  266. ; CHECK: OpCapability
  267. ; The original name is deleted
  268. ; CHECK-NOT: OpName %orig_var "
  269. ; CHECK: OpName %orig_var_image "orig_var_image"
  270. ; CHECK: OpName %orig_var_sampler "orig_var_sampler"
  271. ; CHECK-NOT: OpName %orig_var "
  272. ; CHECK: OpDecorate %orig_var_image DescriptorSet 0
  273. ; CHECK: OpDecorate %orig_var_sampler DescriptorSet 0
  274. ; CHECK: OpDecorate %orig_var_image Binding 0
  275. ; CHECK: OpDecorate %orig_var_sampler Binding 0
  276. ; CHECK: %10 = OpTypeImage %
  277. ; CHECK: %[[image_ptr_ty:\w+]] = OpTypePointer UniformConstant %10
  278. ; CHECK: %[[sampler_ty:\d+]] = OpTypeSampler
  279. ; CHECK: %[[sampler_ptr_ty:\w+]] = OpTypePointer UniformConstant %[[sampler_ty]]
  280. ; CHECK-NOT: %orig_var = OpVariable
  281. ; CHECK-DAG: %orig_var_sampler = OpVariable %[[sampler_ptr_ty]] UniformConstant
  282. ; CHECK-DAG: %orig_var_image = OpVariable %[[image_ptr_ty]] UniformConstant
  283. ; CHECK: = OpFunction
  284. )" + BasicTypes() + R"(
  285. %10 = OpTypeImage %float 2D 0 0 0 1 Unknown
  286. %11 = OpTypeSampledImage %10
  287. %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
  288. %orig_var = OpVariable %_ptr_UniformConstant_11 UniformConstant
  289. %main = OpFunction %void None %voidfn
  290. %main_0 = OpLabel
  291. %101 = OpLoad %11 %orig_var
  292. OpReturn
  293. OpFunctionEnd
  294. )";
  295. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  296. kTest, /* do_validation= */ true);
  297. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  298. }
  299. TEST_P(SplitCombinedImageSamplerPassTypeCaseTest, Combined_RemapLoad) {
  300. // Also tests binding info is copied to both variables.
  301. const std::string kTest = Preamble() +
  302. R"(
  303. OpName %combined "combined"
  304. OpDecorate %100 DescriptorSet 0
  305. OpDecorate %100 Binding 0
  306. ; CHECK: OpName
  307. ; CHECK-NOT: OpDecorate %100
  308. ; CHECK: OpDecorate %[[image_var:\d+]] DescriptorSet 0
  309. ; CHECK: OpDecorate %[[sampler_var:\d+]] DescriptorSet 0
  310. ; CHECK: OpDecorate %[[image_var]] Binding 0
  311. ; CHECK: OpDecorate %[[sampler_var]] Binding 0
  312. ; CHECK: %10 = OpTypeImage %
  313. ; CHECK: %[[image_ptr_ty:\w+]] = OpTypePointer UniformConstant %10
  314. ; CHECK: %[[sampler_ty:\d+]] = OpTypeSampler
  315. ; CHECK: %[[sampler_ptr_ty:\w+]] = OpTypePointer UniformConstant %[[sampler_ty]]
  316. ; The combined image variable is replaced by an image variable and a sampler variable.
  317. ; CHECK-NOT: %100 = OpVariable
  318. ; CHECK-DAG: %[[sampler_var]] = OpVariable %[[sampler_ptr_ty]] UniformConstant
  319. ; CHECK-DAG: %[[image_var]] = OpVariable %[[image_ptr_ty]] UniformConstant
  320. ; CHECK: = OpFunction
  321. ; The load of the combined image+sampler is replaced by a two loads, then
  322. ; a combination operation.
  323. ; CHECK: %[[im:\d+]] = OpLoad %10 %[[image_var]]
  324. ; CHECK: %[[s:\d+]] = OpLoad %[[sampler_ty]] %[[sampler_var]]
  325. ; CHECK: %combined = OpSampledImage %11 %[[im]] %[[s]]
  326. )" + BasicTypes() +
  327. " %10 = " + GetParam().image_type_decl + R"(
  328. %11 = OpTypeSampledImage %10
  329. %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
  330. %100 = OpVariable %_ptr_UniformConstant_11 UniformConstant
  331. %main = OpFunction %void None %voidfn
  332. %main_0 = OpLabel
  333. %combined = OpLoad %11 %100
  334. ; Uses of the combined image sampler are preserved.
  335. ; CHECK: OpCopyObject %11 %combined
  336. %7 = OpCopyObject %11 %combined
  337. OpReturn
  338. OpFunctionEnd
  339. )";
  340. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  341. kTest, /* do_validation= */ true);
  342. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  343. }
  344. TEST_P(SplitCombinedImageSamplerPassTypeCaseTest,
  345. Combined_RemapLoad_RelaxedPrecisionOnVarCopied) {
  346. // All decorations on the variable are copied. In this case, RelaxedPrecision
  347. const std::string kTest = Preamble() +
  348. R"(
  349. OpName %combined "combined"
  350. OpDecorate %100 DescriptorSet 0
  351. OpDecorate %100 Binding 0
  352. OpDecorate %100 RelaxedPrecision
  353. ; CHECK: OpName
  354. ; CHECK-NOT: OpDecorate %100
  355. ; CHECK: OpDecorate %[[image_var:\d+]] DescriptorSet 0
  356. ; CHECK: OpDecorate %[[sampler_var:\d+]] DescriptorSet 0
  357. ; CHECK: OpDecorate %[[image_var]] Binding 0
  358. ; CHECK: OpDecorate %[[sampler_var]] Binding 0
  359. ; CHECK: OpDecorate %[[image_var:\d+]] RelaxedPrecision
  360. ; CHECK: OpDecorate %[[sampler_var:\d+]] RelaxedPrecision
  361. ; CHECK: %10 = OpTypeImage %
  362. ; CHECK: %[[image_ptr_ty:\w+]] = OpTypePointer UniformConstant %10
  363. ; CHECK: %[[sampler_ty:\d+]] = OpTypeSampler
  364. ; CHECK: %[[sampler_ptr_ty:\w+]] = OpTypePointer UniformConstant %[[sampler_ty]]
  365. ; The combined image variable is replaced by an image variable and a sampler variable.
  366. ; CHECK-NOT: %100 = OpVariable
  367. ; CHECK-NOT: OpVariable _ptr_UniformConstant_11
  368. ; CHECK-DAG: %[[sampler_var]] = OpVariable %[[sampler_ptr_ty]] UniformConstant
  369. ; CHECK-DAG: %[[image_var]] = OpVariable %[[image_ptr_ty]] UniformConstant
  370. ; CHECK: = OpFunction
  371. ; The load of the combined image+sampler is replaced by a two loads, then
  372. ; a combination operation.
  373. ; CHECK: %[[im:\d+]] = OpLoad %10 %[[image_var]]
  374. ; CHECK: %[[s:\d+]] = OpLoad %[[sampler_ty]] %[[sampler_var]]
  375. ; CHECK: %combined = OpSampledImage %11 %[[im]] %[[s]]
  376. %bool = OpTypeBool ; location marker
  377. )" + BasicTypes() +
  378. " %10 = " + GetParam().image_type_decl + R"(
  379. %11 = OpTypeSampledImage %10
  380. %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
  381. %100 = OpVariable %_ptr_UniformConstant_11 UniformConstant
  382. %main = OpFunction %void None %voidfn
  383. %main_0 = OpLabel
  384. %combined = OpLoad %11 %100
  385. ; Uses of the combined image sampler are preserved.
  386. ; CHECK: OpCopyObject %11 %combined
  387. %7 = OpCopyObject %11 %combined
  388. OpReturn
  389. OpFunctionEnd
  390. )";
  391. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  392. kTest, /* do_validation= */ true);
  393. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  394. }
  395. TEST_P(SplitCombinedImageSamplerPassTypeCaseTest,
  396. Combined_RemapLoad_RelaxedPrecisionOnLoadCopied) {
  397. // Copy decorations form an OpLoad that is replaced.
  398. const std::string kTest = Preamble() +
  399. R"(
  400. OpName %combined "combined"
  401. OpDecorate %100 DescriptorSet 0
  402. OpDecorate %100 Binding 0
  403. OpDecorate %combined RelaxedPrecision
  404. ; CHECK: OpName
  405. ; CHECK-NOT: OpDecorate %100
  406. ; CHECK: OpDecorate %[[image_var:\d+]] DescriptorSet 0
  407. ; CHECK: OpDecorate %[[sampler_var:\d+]] DescriptorSet 0
  408. ; CHECK: OpDecorate %[[image_var]] Binding 0
  409. ; CHECK: OpDecorate %[[sampler_var]] Binding 0
  410. ; This is what we are checking in this test.
  411. ; CHECK: OpDecorate %[[im:\d+]] RelaxedPrecision
  412. ; CHECK: OpDecorate %[[s:\d+]] RelaxedPrecision
  413. ; CHECK: %10 = OpTypeImage %
  414. ; CHECK: %[[image_ptr_ty:\w+]] = OpTypePointer UniformConstant %10
  415. ; CHECK: %[[sampler_ty:\d+]] = OpTypeSampler
  416. ; CHECK: %[[sampler_ptr_ty:\w+]] = OpTypePointer UniformConstant %[[sampler_ty]]
  417. ; The combined image variable is replaced by an image variable and a sampler variable.
  418. ; CHECK-NOT: %100 = OpVariable
  419. ; CHECK-NOT: OpVariable _ptr_UniformConstant_11
  420. ; CHECK-DAG: %[[sampler_var]] = OpVariable %[[sampler_ptr_ty]] UniformConstant
  421. ; CHECK-DAG: %[[image_var]] = OpVariable %[[image_ptr_ty]] UniformConstant
  422. ; CHECK: = OpFunction
  423. ; The load of the combined image+sampler is replaced by a two loads, then
  424. ; a combination operation. The new loads get the same decorations that the
  425. ; original load had.
  426. ; CHECK: %[[im]] = OpLoad %10 %[[image_var]]
  427. ; CHECK: %[[s]] = OpLoad %[[sampler_ty]] %[[sampler_var]]
  428. ; CHECK: %combined = OpSampledImage %11 %[[im]] %[[s]]
  429. %bool = OpTypeBool ; location marker
  430. )" + BasicTypes() +
  431. " %10 = " + GetParam().image_type_decl + R"(
  432. %11 = OpTypeSampledImage %10
  433. %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
  434. %100 = OpVariable %_ptr_UniformConstant_11 UniformConstant
  435. %main = OpFunction %void None %voidfn
  436. %main_0 = OpLabel
  437. %combined = OpLoad %11 %100
  438. ; Uses of the combined image sampler are preserved.
  439. ; CHECK: OpCopyObject %11 %combined
  440. %7 = OpCopyObject %11 %combined
  441. OpReturn
  442. OpFunctionEnd
  443. )";
  444. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  445. kTest, /* do_validation= */ true);
  446. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  447. }
  448. TEST_P(SplitCombinedImageSamplerPassTypeCaseTest,
  449. Combined_DeletesCopyObjectOfPtr) {
  450. // OpCopyObject is deleted, and its uses updated.
  451. const std::string kTest = Preamble() +
  452. R"(
  453. OpDecorate %100 DescriptorSet 0
  454. OpDecorate %100 Binding 0
  455. ; CHECK: OpName
  456. ; CHECK-NOT: OpDecorate %100
  457. ; CHECK: OpDecorate %[[image_var:\d+]] DescriptorSet 0
  458. ; CHECK: OpDecorate %[[sampler_var:\d+]] DescriptorSet 0
  459. ; CHECK: OpDecorate %[[image_var]] Binding 0
  460. ; CHECK: OpDecorate %[[sampler_var]] Binding 0
  461. ; CHECK: %10 = OpTypeImage %
  462. ; CHECK: %[[image_ptr_ty:\w+]] = OpTypePointer UniformConstant %10
  463. ; CHECK: %[[sampler_ty:\d+]] = OpTypeSampler
  464. ; CHECK: %[[sampler_ptr_ty:\w+]] = OpTypePointer UniformConstant %[[sampler_ty]]
  465. ; The combined image variable is replaced by an image variable and a sampler variable.
  466. ; CHECK-NOT: %100 = OpVariable
  467. ; CHECK-DAG: %[[sampler_var]] = OpVariable %[[sampler_ptr_ty]] UniformConstant
  468. ; CHECK-DAG: %[[image_var]] = OpVariable %[[image_ptr_ty]] UniformConstant
  469. ; CHECK: = OpFunction
  470. )" + BasicTypes() +
  471. " %10 = " + GetParam().image_type_decl + R"(
  472. %11 = OpTypeSampledImage %10
  473. %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
  474. %100 = OpVariable %_ptr_UniformConstant_11 UniformConstant
  475. %main = OpFunction %void None %voidfn
  476. %main_0 = OpLabel
  477. %101 = OpCopyObject %_ptr_UniformConstant_11 %100
  478. %102 = OpLoad %11 %101
  479. %103 = OpCopyObject %_ptr_UniformConstant_11 %101
  480. %104 = OpCopyObject %11 %102 ;; this copy survives
  481. OpReturn
  482. OpFunctionEnd
  483. ; The OpCopyObject instructions are removed.
  484. ; The load of the combined image+sampler is replaced by a two loads, then
  485. ; a combination operation. The only OpCopyObject that remains is the copy
  486. ; of the copy of the sampled image value.
  487. ; CHECK: %[[im:\d+]] = OpLoad %10 %[[image_var]]
  488. ; CHECK: %[[s:\d+]] = OpLoad %[[sampler_ty]] %[[sampler_var]]
  489. ; CHECK: %[[si:\d+]] = OpSampledImage %11 %[[im]] %[[s]]
  490. ; CHECK-NEXT: OpCopyObject %11 %[[si]]
  491. ; CHECK-NEXT: OpReturn
  492. )";
  493. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  494. kTest, /* do_validation= */ true);
  495. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  496. }
  497. TEST_P(SplitCombinedImageSamplerPassTypeCaseTest, ArrayCombined_RemapLoad) {
  498. const std::string kTest = Preamble() +
  499. R"(
  500. OpName %combined "combined"
  501. OpDecorate %100 DescriptorSet 0
  502. OpDecorate %100 Binding 0
  503. ; CHECK: OpName
  504. ; CHECK-NOT: OpDecorate %100
  505. ; CHECK: OpDecorate %[[image_var:\d+]] DescriptorSet 0
  506. ; CHECK: OpDecorate %[[sampler_var:\d+]] DescriptorSet 0
  507. ; CHECK: OpDecorate %[[image_var]] Binding 0
  508. ; CHECK: OpDecorate %[[sampler_var]] Binding 0
  509. ; CHECK: %10 = OpTypeImage %
  510. ; CHECK: %[[image_ptr_ty:\w+]] = OpTypePointer UniformConstant %10
  511. ; CHECK: %[[sampler_ty:\d+]] = OpTypeSampler
  512. ; CHECK: %[[sampler_ptr_ty:\w+]] = OpTypePointer UniformConstant %[[sampler_ty]]
  513. ; The combined image variable is replaced by an image variable and a sampler variable.
  514. ; CHECK: %[[array_image_ty:\w+]] = OpTypeArray %10 %uint_3
  515. ; CHECK: %[[ptr_array_image_ty:\w+]] = OpTypePointer UniformConstant %[[array_image_ty]]
  516. ; CHECK: %[[array_sampler_ty:\w+]] = OpTypeArray %[[sampler_ty]] %uint_3
  517. ; CHECK: %[[ptr_array_sampler_ty:\w+]] = OpTypePointer UniformConstant %[[array_sampler_ty]]
  518. ; CHECK-NOT: %100 = OpVariable
  519. ; CHECK-DAG: %[[sampler_var]] = OpVariable %[[ptr_array_sampler_ty]] UniformConstant
  520. ; CHECK-DAG: %[[image_var]] = OpVariable %[[ptr_array_image_ty]] UniformConstant
  521. ; CHECK: = OpFunction
  522. ; The access chain and load is replaced by two access chains, two loads, then
  523. ; a combine operation.
  524. ; CHECK: %[[ptr_im:\d+]] = OpAccessChain %[[image_ptr_ty]] %[[image_var]] %uint_1
  525. ; CHECK: %[[ptr_s:\d+]] = OpAccessChain %[[sampler_ptr_ty]] %[[sampler_var]] %uint_1
  526. ; CHECK: %[[im:\d+]] = OpLoad %10 %[[ptr_im]]
  527. ; CHECK: %[[s:\d+]] = OpLoad %[[sampler_ty]] %[[ptr_s]]
  528. ; CHECK: %combined = OpSampledImage %11 %[[im]] %[[s]]
  529. )" + BasicTypes() +
  530. " %10 = " + GetParam().image_type_decl + R"(
  531. %11 = OpTypeSampledImage %10
  532. %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
  533. %12 = OpTypeArray %11 %uint_3
  534. %_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12
  535. %100 = OpVariable %_ptr_UniformConstant_12 UniformConstant
  536. %main = OpFunction %void None %voidfn
  537. %main_0 = OpLabel
  538. %ptr = OpAccessChain %_ptr_UniformConstant_11 %100 %uint_1
  539. %combined = OpLoad %11 %ptr
  540. ; Uses of the combined image sampler are preserved.
  541. ; CHECK: OpCopyObject %11 %combined
  542. %7 = OpCopyObject %11 %combined
  543. OpReturn
  544. OpFunctionEnd
  545. )";
  546. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  547. kTest, /* do_validation= */ true);
  548. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  549. }
  550. TEST_P(SplitCombinedImageSamplerPassTypeCaseTest, RtArrayCombined_RemapLoad) {
  551. const std::string kTest = Preamble() +
  552. R"(
  553. OpName %combined "combined"
  554. OpDecorate %100 DescriptorSet 0
  555. OpDecorate %100 Binding 0
  556. ; CHECK: OpName
  557. ; CHECK-NOT: OpDecorate %100
  558. ; CHECK: OpDecorate %[[image_var:\d+]] DescriptorSet 0
  559. ; CHECK: OpDecorate %[[sampler_var:\d+]] DescriptorSet 0
  560. ; CHECK: OpDecorate %[[image_var]] Binding 0
  561. ; CHECK: OpDecorate %[[sampler_var]] Binding 0
  562. ; CHECK: %10 = OpTypeImage %
  563. ; CHECK: %[[image_ptr_ty:\w+]] = OpTypePointer UniformConstant %10
  564. ; CHECK: %[[sampler_ty:\d+]] = OpTypeSampler
  565. ; CHECK: %[[sampler_ptr_ty:\w+]] = OpTypePointer UniformConstant %[[sampler_ty]]
  566. ; The combined image variable is replaced by an image variable and a sampler variable.
  567. ; CHECK: %[[array_image_ty:\w+]] = OpTypeRuntimeArray %10
  568. ; CHECK: %[[ptr_array_image_ty:\w+]] = OpTypePointer UniformConstant %[[array_image_ty]]
  569. ; CHECK: %[[array_sampler_ty:\w+]] = OpTypeRuntimeArray %[[sampler_ty]]
  570. ; CHECK: %[[ptr_array_sampler_ty:\w+]] = OpTypePointer UniformConstant %[[array_sampler_ty]]
  571. ; CHECK-NOT: %100 = OpVariable
  572. ; CHECK-DAG: %[[sampler_var]] = OpVariable %[[ptr_array_sampler_ty]] UniformConstant
  573. ; CHECK-DAG: %[[image_var]] = OpVariable %[[ptr_array_image_ty]] UniformConstant
  574. ; CHECK: = OpFunction
  575. ; The access chain and load is replaced by two access chains, two loads, then
  576. ; a combine operation.
  577. ; CHECK: %[[ptr_im:\d+]] = OpAccessChain %[[image_ptr_ty]] %[[image_var]] %uint_1
  578. ; CHECK: %[[ptr_s:\d+]] = OpAccessChain %[[sampler_ptr_ty]] %[[sampler_var]] %uint_1
  579. ; CHECK: %[[im:\d+]] = OpLoad %10 %[[ptr_im]]
  580. ; CHECK: %[[s:\d+]] = OpLoad %[[sampler_ty]] %[[ptr_s]]
  581. ; CHECK: %combined = OpSampledImage %11 %[[im]] %[[s]]
  582. )" + BasicTypes() +
  583. " %10 = " + GetParam().image_type_decl + R"(
  584. %11 = OpTypeSampledImage %10
  585. %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
  586. %12 = OpTypeRuntimeArray %11
  587. %_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12
  588. %100 = OpVariable %_ptr_UniformConstant_12 UniformConstant
  589. %main = OpFunction %void None %voidfn
  590. %main_0 = OpLabel
  591. %ptr = OpAccessChain %_ptr_UniformConstant_11 %100 %uint_1
  592. %combined = OpLoad %11 %ptr
  593. ; Uses of the combined image sampler are preserved.
  594. ; CHECK: OpCopyObject %11 %combined
  595. %7 = OpCopyObject %11 %combined
  596. OpReturn
  597. OpFunctionEnd
  598. )";
  599. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  600. kTest, /* do_validation= */ true);
  601. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  602. }
  603. INSTANTIATE_TEST_SUITE_P(AllCombinedTypes,
  604. SplitCombinedImageSamplerPassTypeCaseTest,
  605. ::testing::ValuesIn(ImageTypeCases()));
  606. // Remap entry point
  607. struct EntryPointRemapCase {
  608. const spv_target_env environment = SPV_ENV_VULKAN_1_0;
  609. const char* initial_interface = "";
  610. const char* expected_interface = nullptr;
  611. };
  612. std::ostream& operator<<(std::ostream& os, const EntryPointRemapCase& eprc) {
  613. os << "(env " << spvLogStringForEnv(eprc.environment) << ", init "
  614. << eprc.initial_interface << " -> expect " << eprc.expected_interface
  615. << ")";
  616. return os;
  617. }
  618. struct SplitCombinedImageSamplerPassEntryPointRemapTest
  619. : public PassTest<::testing::TestWithParam<EntryPointRemapCase>> {
  620. virtual void SetUp() override {
  621. SetTargetEnv(GetParam().environment);
  622. SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  623. SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES |
  624. SPV_BINARY_TO_TEXT_OPTION_INDENT |
  625. SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
  626. }
  627. };
  628. std::vector<EntryPointRemapCase> EntryPointInterfaceCases() {
  629. return std::vector<EntryPointRemapCase>{
  630. {SPV_ENV_VULKAN_1_0, " %in_var %out_var", " %in_var %out_var"},
  631. {SPV_ENV_VULKAN_1_4, " %combined_var",
  632. " %combined_var_image %combined_var_sampler"},
  633. {SPV_ENV_VULKAN_1_4, " %combined_var %in_var %out_var",
  634. " %combined_var_image %in_var %out_var %combined_var_sampler"},
  635. {SPV_ENV_VULKAN_1_4, " %in_var %combined_var %out_var",
  636. " %in_var %combined_var_image %out_var %combined_var_sampler"},
  637. {SPV_ENV_VULKAN_1_4, " %in_var %out_var %combined_var",
  638. " %in_var %out_var %combined_var_image %combined_var_sampler"},
  639. };
  640. }
  641. TEST_P(SplitCombinedImageSamplerPassEntryPointRemapTest,
  642. EntryPoint_Combined_UsedInShader) {
  643. const std::string kTest = PreambleFragment(GetParam().initial_interface) +
  644. R"(
  645. OpName %combined "combined"
  646. OpName %combined_var "combined_var"
  647. OpName %in_var "in_var"
  648. OpName %out_var "out_var"
  649. OpDecorate %combined_var DescriptorSet 0
  650. OpDecorate %combined_var Binding 0
  651. OpDecorate %in_var BuiltIn FragCoord
  652. OpDecorate %out_var Location 0
  653. ; CHECK: OpEntryPoint Fragment %main "main")" +
  654. GetParam().expected_interface + R"(
  655. ; These clauses ensure the expected interface is the whole interface.
  656. ; CHECK-NOT: %{{\d+}}
  657. ; CHECK-NOT: %in_var
  658. ; CHECK-NOT: %out_var
  659. ; CHECK-NOT: %combined_var
  660. ; CHECK: OpExecutionMode %main OriginUpperLeft
  661. ; Check the var names, tracing up through the types.
  662. ; CHECK: %10 = OpTypeImage %float 2D 0 0 0 1 Unknown
  663. ; CHECK: %[[image_ptr_ty:\w+]] = OpTypePointer UniformConstant %10
  664. ; CHECK: %[[sampler_ty:\d+]] = OpTypeSampler
  665. ; CHECK: %[[sampler_ptr_ty:\w+]] = OpTypePointer UniformConstant %[[sampler_ty]]
  666. ; The combined image variable is replaced by an image variable and a sampler variable.
  667. ; CHECK-DAG: %combined_var_sampler = OpVariable %[[sampler_ptr_ty]] UniformConstant
  668. ; CHECK-DAG: %combined_var_image = OpVariable %[[image_ptr_ty]] UniformConstant
  669. ; CHECK: = OpFunction
  670. %bool = OpTypeBool
  671. )" + BasicTypes() + R"( %10 = OpTypeImage %float 2D 0 0 0 1 Unknown
  672. %11 = OpTypeSampledImage %10
  673. %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
  674. %in_ptr_v4f = OpTypePointer Input %v4float
  675. %in_var = OpVariable %in_ptr_v4f Input
  676. %out_ptr_v4f = OpTypePointer Output %v4float
  677. %out_var = OpVariable %out_ptr_v4f Output
  678. %combined_var = OpVariable %_ptr_UniformConstant_11 UniformConstant
  679. %main = OpFunction %void None %voidfn
  680. ;CHECK: %main_0 = OpLabel
  681. ;CHECK: OpLoad
  682. %main_0 = OpLabel
  683. %combined = OpLoad %11 %combined_var
  684. OpReturn
  685. OpFunctionEnd
  686. )";
  687. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  688. kTest, /* do_validation= */ true);
  689. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  690. }
  691. TEST_P(SplitCombinedImageSamplerPassEntryPointRemapTest,
  692. EntryPoint_Combined_UsedOnlyInEntryPointInstruction) {
  693. // If the combined var is in the interface, that is enough to trigger
  694. // its replacement. Otherwise the entry point interface is untouched
  695. // when the combined var is not otherwise used.
  696. const bool combined_var_in_interface =
  697. std::string(GetParam().initial_interface).find("%combined_var") !=
  698. std::string::npos;
  699. if (combined_var_in_interface) {
  700. const std::string kTest = PreambleFragment(GetParam().initial_interface) +
  701. R"(
  702. OpName %combined_var "combined_var"
  703. OpName %in_var "in_var"
  704. OpName %out_var "out_var"
  705. OpDecorate %combined_var DescriptorSet 0
  706. OpDecorate %combined_var Binding 0
  707. OpDecorate %in_var BuiltIn FragCoord
  708. OpDecorate %out_var Location 0
  709. ; CHECK: OpEntryPoint Fragment %main "main")" +
  710. GetParam().expected_interface + R"(
  711. ; These clauses ensure the expected interface is the whole interface.
  712. ; CHECK-NOT: %{{\d+}}
  713. ; CHECK-NOT: %in_var
  714. ; CHECK-NOT: %out_var
  715. ; CHECK-NOT: %combined_var
  716. ; CHECK: OpExecutionMode %main OriginUpperLeft
  717. %bool = OpTypeBool
  718. )" + BasicTypes() + R"( %10 = OpTypeImage %float 2D 0 0 0 1 Unknown
  719. %11 = OpTypeSampledImage %10
  720. %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
  721. %in_ptr_v4f = OpTypePointer Input %v4float
  722. %in_var = OpVariable %in_ptr_v4f Input
  723. %out_ptr_v4f = OpTypePointer Output %v4float
  724. %out_var = OpVariable %out_ptr_v4f Output
  725. ; %combined_var is not used!
  726. %combined_var = OpVariable %_ptr_UniformConstant_11 UniformConstant
  727. %main = OpFunction %void None %voidfn
  728. %main_0 = OpLabel
  729. OpReturn
  730. OpFunctionEnd
  731. )";
  732. auto [disasm, status] =
  733. SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  734. kTest, /* do_validation= */ true);
  735. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  736. }
  737. }
  738. TEST_P(SplitCombinedImageSamplerPassEntryPointRemapTest,
  739. EntryPoint_Combined_Unused) {
  740. // If the combined var is in the interface, that is enough to trigger
  741. // its replacement. Otherwise the entry point interface is untouched
  742. // when the combined var is not otherwise used.
  743. const bool combined_var_in_interface =
  744. std::string(GetParam().initial_interface).find("%combined_var") !=
  745. std::string::npos;
  746. if (!combined_var_in_interface) {
  747. const std::string kTest = PreambleFragment(GetParam().initial_interface) +
  748. R"(
  749. ; CHECK: OpEntryPoint Fragment %main "main")" +
  750. GetParam().initial_interface // Note this is the
  751. // intial interface
  752. + R"(
  753. ; These clauses ensure the expected interface is the whole interface.
  754. ; CHECK-NOT: %{{\d+}}
  755. ; CHECK-NOT: %in_var
  756. ; CHECK-NOT: %out_var
  757. ; CHECK-NOT: %combined_var
  758. ; CHECK: OpExecutionMode %main OriginUpperLeft
  759. ; The variable disappears.
  760. ; CHECK-NOT: %combined_var =
  761. ; CHECK: OpFunctionEnd
  762. OpName %combined_var "combined_var"
  763. OpName %in_var "in_var"
  764. OpName %out_var "out_var"
  765. OpDecorate %combined_var DescriptorSet 0
  766. OpDecorate %combined_var Binding 0
  767. OpDecorate %in_var BuiltIn FragCoord
  768. OpDecorate %out_var Location 0
  769. %bool = OpTypeBool
  770. )" + BasicTypes() + R"( %10 = OpTypeImage %float 2D 0 0 0 1 Unknown
  771. %11 = OpTypeSampledImage %10
  772. %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
  773. %in_ptr_v4f = OpTypePointer Input %v4float
  774. %in_var = OpVariable %in_ptr_v4f Input
  775. %out_ptr_v4f = OpTypePointer Output %v4float
  776. %out_var = OpVariable %out_ptr_v4f Output
  777. ; %combined_var is not used!
  778. %combined_var = OpVariable %_ptr_UniformConstant_11 UniformConstant
  779. %main = OpFunction %void None %voidfn
  780. %main_0 = OpLabel
  781. OpReturn
  782. OpFunctionEnd
  783. )";
  784. auto [disasm, status] =
  785. SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  786. kTest, /* do_validation= */ true);
  787. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  788. }
  789. }
  790. INSTANTIATE_TEST_SUITE_P(EntryPointRemap,
  791. SplitCombinedImageSamplerPassEntryPointRemapTest,
  792. ::testing::ValuesIn(EntryPointInterfaceCases()));
  793. // Remap function types
  794. struct FunctionTypeCase {
  795. const char* initial_type_params = "";
  796. const char* expected_type_params = "";
  797. };
  798. std::ostream& operator<<(std::ostream& os, const FunctionTypeCase& ftc) {
  799. os << "(init " << ftc.initial_type_params << " -> expect "
  800. << ftc.expected_type_params << ")";
  801. return os;
  802. }
  803. struct SplitCombinedImageSamplerPassFunctionTypeTest
  804. : public PassTest<::testing::TestWithParam<FunctionTypeCase>> {
  805. virtual void SetUp() override {
  806. SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  807. SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES |
  808. SPV_BINARY_TO_TEXT_OPTION_INDENT |
  809. SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
  810. }
  811. };
  812. std::vector<FunctionTypeCase> FunctionTypeCases() {
  813. return std::vector<FunctionTypeCase>{
  814. {"", ""},
  815. {" %image_ty", " %image_ty"},
  816. {" %sampler_ty", " %sampler_ty"},
  817. {" %sampled_image_ty", " %image_ty %sampler_ty"},
  818. {" %uint %sampled_image_ty %float",
  819. " %uint %image_ty %sampler_ty %float"},
  820. {" %ptr_sampled_image_ty",
  821. " %_ptr_UniformConstant_image_ty %_ptr_UniformConstant_sampler_ty"},
  822. {" %uint %ptr_sampled_image_ty %float",
  823. " %uint %_ptr_UniformConstant_image_ty %_ptr_UniformConstant_sampler_ty "
  824. "%float"},
  825. {" %uint %ptr_sampled_image_ty %ptr_sampled_image_ty %float",
  826. " %uint %_ptr_UniformConstant_image_ty %_ptr_UniformConstant_sampler_ty "
  827. "%_ptr_UniformConstant_image_ty %_ptr_UniformConstant_sampler_ty "
  828. "%float"},
  829. };
  830. }
  831. TEST_P(SplitCombinedImageSamplerPassFunctionTypeTest,
  832. ReplaceCombinedImageSamplersOnly) {
  833. const std::string kTest = Preamble() + +R"(
  834. OpName %f_ty "f_ty"
  835. OpName %sampler_ty "sampler_ty"
  836. OpName %image_ty "image_ty"
  837. OpName %sampled_image_ty "sampled_image_ty"
  838. OpName %ptr_sampled_image_ty "sampled_image_ty"
  839. )" + BasicTypes() + R"(
  840. %sampler_ty = OpTypeSampler
  841. %image_ty = OpTypeImage %float 2D 0 0 0 1 Unknown
  842. %sampled_image_ty = OpTypeSampledImage %image_ty
  843. %ptr_sampled_image_ty = OpTypePointer UniformConstant %sampled_image_ty
  844. %f_ty = OpTypeFunction %float)" +
  845. GetParam().initial_type_params + R"(
  846. ; CHECK: %f_ty = OpTypeFunction %float)" +
  847. GetParam().expected_type_params + R"(
  848. )" + Main();
  849. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  850. kTest, /* do_validation= */ true);
  851. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  852. }
  853. TEST_P(SplitCombinedImageSamplerPassFunctionTypeTest, AvoidDuplicateType) {
  854. // SPIR-V does not allow duplicate non-aggregate types. That includes function
  855. // types. Test that when replacing function type parameters would cause a
  856. // collision, that the original function type is replaced with the new one.
  857. const std::string initial_params(GetParam().initial_type_params);
  858. const std::string expected_params(GetParam().expected_type_params);
  859. const std::string kTest = Preamble() + +R"(
  860. OpName %sampler_ty "sampler_ty"
  861. OpName %image_ty "image_ty"
  862. OpName %sampled_image_ty "sampled_image_ty"
  863. OpName %_ptr_UniformConstant_sampler_ty "_ptr_UniformConstant_sampler_ty"
  864. OpName %_ptr_UniformConstant_image_ty "_ptr_UniformConstant_image_ty"
  865. OpName %ptr_sampled_image_ty "sampled_image_ty"
  866. OpName %dest_ty "dest_ty"
  867. )" + BasicTypes() + R"(
  868. %sampler_ty = OpTypeSampler
  869. %image_ty = OpTypeImage %float 2D 0 0 0 1 Unknown
  870. %sampled_image_ty = OpTypeSampledImage %image_ty
  871. %ptr_sampled_image_ty = OpTypePointer UniformConstant %sampled_image_ty
  872. %_ptr_UniformConstant_image_ty = OpTypePointer UniformConstant %image_ty
  873. %_ptr_UniformConstant_sampler_ty = OpTypePointer UniformConstant %sampler_ty
  874. %100 = OpTypeFunction %float)" +
  875. initial_params + R"(
  876. %dest_ty = OpTypeFunction %float)" +
  877. expected_params + R"(
  878. ; CHECK: OpTypeSampler
  879. ; CHECK-NOT: %100 =
  880. ; CHECK: %dest_ty = OpTypeFunction %float)" +
  881. expected_params + R"(
  882. ; CHECK-NOT: %100 =
  883. ; CHECK: %main = OpFunction
  884. )" + Main();
  885. // The original source is invalid if initial and expected params are the same,
  886. // because the type is already duplicated.
  887. // Only test when they are different.
  888. if (initial_params != expected_params) {
  889. auto [disasm, status] =
  890. SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  891. kTest, /* do_validation= */ true);
  892. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  893. }
  894. }
  895. INSTANTIATE_TEST_SUITE_P(FunctionTypeRemap,
  896. SplitCombinedImageSamplerPassFunctionTypeTest,
  897. ::testing::ValuesIn(FunctionTypeCases()));
  898. // Test array and runtime-array cases for function type replacement.
  899. TEST_F(SplitCombinedImageSamplerPassTest, FunctionType_ReplaceSampledImageArg) {
  900. // The original module has a sampled image type, used only as a function
  901. // parameter. We still want to replace it. But no other sampled-image types
  902. // exist. This proves that the pass needs a sampled_image_used_as_param_
  903. // state variable.
  904. const std::string kTest = Preamble() + +R"(
  905. OpName %f_ty "f_ty"
  906. OpName %sampler_ty "sampler_ty"
  907. OpName %image_ty "image_ty"
  908. OpName %sampled_image_ty "sampled_image_ty"
  909. )" + BasicTypes() + R"(
  910. %sampler_ty = OpTypeSampler
  911. %image_ty = OpTypeImage %float 2D 0 0 0 1 Unknown
  912. %sampled_image_ty = OpTypeSampledImage %image_ty
  913. %f_ty = OpTypeFunction %float %sampled_image_ty %float
  914. ; CHECK: %f_ty = OpTypeFunction %float %image_ty %sampler_ty %float
  915. )" + Main();
  916. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  917. kTest, /* do_validation= */ true);
  918. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  919. }
  920. TEST_F(SplitCombinedImageSamplerPassTest, FunctionType_ReplaceArrayArg) {
  921. const std::string kTest = Preamble() + +R"(
  922. OpName %f_ty "f_ty"
  923. OpName %sampler_ty "sampler_ty"
  924. OpName %image_ty "image_ty"
  925. OpName %sampled_image_ty "sampled_image_ty"
  926. OpName %ptr_array_si_ty "ptr_array_si_ty"
  927. )" + BasicTypes() + R"(
  928. %sampler_ty = OpTypeSampler
  929. %image_ty = OpTypeImage %float 2D 0 0 0 1 Unknown
  930. %sampled_image_ty = OpTypeSampledImage %image_ty
  931. %array_si_ty = OpTypeArray %sampled_image_ty %uint_3
  932. %ptr_array_si_ty = OpTypePointer UniformConstant %array_si_ty
  933. ; CHECK: %[[array_i_ty:\w+]] = OpTypeArray %image_ty %uint_3
  934. ; CHECK: %[[ptr_array_i_ty:\w+]] = OpTypePointer UniformConstant %[[array_i_ty]]
  935. ; CHECK: %[[array_s_ty:\w+]] = OpTypeArray %sampler_ty %uint_3
  936. ; CHECK: %[[ptr_array_s_ty:\w+]] = OpTypePointer UniformConstant %[[array_s_ty]]
  937. %f_ty = OpTypeFunction %float %uint %ptr_array_si_ty %float
  938. ; CHECK: %f_ty = OpTypeFunction %float %uint %[[ptr_array_i_ty]] %[[ptr_array_s_ty]] %float
  939. )" + Main();
  940. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  941. kTest, /* do_validation= */ true);
  942. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  943. }
  944. TEST_F(SplitCombinedImageSamplerPassTest, FunctionType_ReplaceRtArrayArg) {
  945. const std::string kTest = Preamble() + +R"(
  946. OpName %f_ty "f_ty"
  947. OpName %sampler_ty "sampler_ty"
  948. OpName %image_ty "image_ty"
  949. OpName %sampled_image_ty "sampled_image_ty"
  950. OpName %ptr_array_si_ty "ptr_array_si_ty"
  951. )" + BasicTypes() + R"(
  952. %sampler_ty = OpTypeSampler
  953. %image_ty = OpTypeImage %float 2D 0 0 0 1 Unknown
  954. %sampled_image_ty = OpTypeSampledImage %image_ty
  955. %array_si_ty = OpTypeRuntimeArray %sampled_image_ty
  956. %ptr_array_si_ty = OpTypePointer UniformConstant %array_si_ty
  957. ; CHECK: %[[array_i_ty:\w+]] = OpTypeRuntimeArray %image_ty
  958. ; CHECK: %[[ptr_array_i_ty:\w+]] = OpTypePointer UniformConstant %[[array_i_ty]]
  959. ; CHECK: %[[array_s_ty:\w+]] = OpTypeRuntimeArray %sampler_ty
  960. ; CHECK: %[[ptr_array_s_ty:\w+]] = OpTypePointer UniformConstant %[[array_s_ty]]
  961. %f_ty = OpTypeFunction %float %uint %ptr_array_si_ty %float
  962. ; CHECK: %f_ty = OpTypeFunction %float %uint %[[ptr_array_i_ty]] %[[ptr_array_s_ty]] %float
  963. )" + Main();
  964. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  965. kTest, /* do_validation= */ true);
  966. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  967. }
  968. // Remap function bodies
  969. std::string NamedITypes() {
  970. return R"(
  971. OpName %f "f"
  972. OpName %f_ty "f_ty"
  973. OpName %i_ty "i_ty"
  974. OpName %s_ty "s_ty"
  975. OpName %p_i_ty "p_i_ty"
  976. OpName %p_s_ty "p_s_ty"
  977. )";
  978. }
  979. std::string NamedCombinedTypes() {
  980. return R"(
  981. OpName %si_ty "si_ty"
  982. OpName %p_si_ty "p_si_ty"
  983. OpName %array_si_ty "array_si_ty"
  984. OpName %rtarray_si_ty "rtarray_si_ty"
  985. OpName %p_array_si_ty "p_array_si_ty"
  986. OpName %p_rtarray_si_ty "p_rtarray_si_ty"
  987. )";
  988. }
  989. std::string NamedCaller() {
  990. return R"(
  991. OpName %caller_ty "caller_ty"
  992. OpName %caller "caller"
  993. OpName %caller_entry "caller_entry"
  994. OpName %caller_call "caller_call"
  995. OpName %caller_arg "caller_arg"
  996. )";
  997. }
  998. std::string ITypes() {
  999. return R"(
  1000. %i_ty = OpTypeImage %float 2D 0 0 0 1 Unknown
  1001. %s_ty = OpTypeSampler
  1002. %p_i_ty = OpTypePointer UniformConstant %i_ty
  1003. %p_s_ty = OpTypePointer UniformConstant %s_ty
  1004. )";
  1005. }
  1006. std::string CombinedTypes() {
  1007. return R"(
  1008. %si_ty = OpTypeSampledImage %i_ty
  1009. %p_si_ty = OpTypePointer UniformConstant %si_ty
  1010. %array_si_ty = OpTypeArray %si_ty %uint_3
  1011. %p_array_si_ty = OpTypePointer UniformConstant %array_si_ty
  1012. %rtarray_si_ty = OpTypeRuntimeArray %si_ty
  1013. %p_rtarray_si_ty = OpTypePointer UniformConstant %rtarray_si_ty
  1014. )";
  1015. }
  1016. TEST_F(SplitCombinedImageSamplerPassTest, FunctionBody_ScalarNoChange) {
  1017. const std::string kTest = Preamble() + NamedITypes() + NamedCombinedTypes() +
  1018. BasicTypes() + ITypes() + CombinedTypes() + R"(
  1019. ; CHECK: %f_ty = OpTypeFunction %float %i_ty %s_ty %p_i_ty %p_s_ty
  1020. %f_ty = OpTypeFunction %float %i_ty %s_ty %p_i_ty %p_s_ty
  1021. ; CHECK: %f = OpFunction %float None %f_ty
  1022. ; CHECK-NEXT: OpFunctionParameter %i_ty
  1023. ; CHECK-NEXT: OpFunctionParameter %s_ty
  1024. ; CHECK-NEXT: OpFunctionParameter %p_i_ty
  1025. ; CHECK-NEXT: OpFunctionParameter %p_s_ty
  1026. ; CHECK-NEXT: OpLabel
  1027. %f = OpFunction %float None %f_ty
  1028. %100 = OpFunctionParameter %i_ty
  1029. %101 = OpFunctionParameter %s_ty
  1030. %102 = OpFunctionParameter %p_i_ty
  1031. %103 = OpFunctionParameter %p_s_ty
  1032. %110 = OpLabel
  1033. OpReturnValue %float_0
  1034. OpFunctionEnd
  1035. )" + Main();
  1036. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1037. kTest, /* do_validation= */ true);
  1038. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  1039. }
  1040. TEST_F(SplitCombinedImageSamplerPassTest,
  1041. FunctionBody_SampledImage_OpImageSample) {
  1042. const std::string kTest = Preamble() + NamedITypes() + NamedCombinedTypes() +
  1043. BasicTypes() + ITypes() + CombinedTypes() + R"(
  1044. ; CHECK: %f_ty = OpTypeFunction %v4float %uint %i_ty %s_ty %float
  1045. %f_ty = OpTypeFunction %v4float %uint %si_ty %float
  1046. ; CHECK: %f = OpFunction %v4float None %f_ty
  1047. ; CHECK: OpFunctionParameter %uint
  1048. ; CHECK-NEXT: %[[i:\w+]] = OpFunctionParameter %i_ty
  1049. ; CHECK-NEXT: %[[s:\w+]] = OpFunctionParameter %s_ty
  1050. ; CHECK-NEXT: OpFunctionParameter %float
  1051. ; CHECK-NEXT: OpLabel
  1052. ; CHECK-NEXT: %[[si:\w+]] = OpSampledImage %si_ty %[[i]] %[[s]]
  1053. ; CHECK-NEXT: %200 = OpImageSampleExplicitLod %v4float %[[si]] %13 Lod %float_0
  1054. ; CHECK-NEXT: OpReturnValue %200
  1055. %f = OpFunction %v4float None %f_ty
  1056. %100 = OpFunctionParameter %uint
  1057. %101 = OpFunctionParameter %si_ty ; replace this
  1058. %110 = OpFunctionParameter %float
  1059. %120 = OpLabel
  1060. %200 = OpImageSampleExplicitLod %v4float %101 %13 Lod %float_0
  1061. OpReturnValue %200
  1062. OpFunctionEnd
  1063. )" + Main();
  1064. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1065. kTest, /* do_validation= */ true);
  1066. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  1067. }
  1068. TEST_F(SplitCombinedImageSamplerPassTest, FunctionBody_SampledImage_OpImage) {
  1069. const std::string kTest = Preamble() + NamedITypes() + NamedCombinedTypes() +
  1070. BasicTypes() + ITypes() + CombinedTypes() + R"(
  1071. ; CHECK: %f_ty = OpTypeFunction %void %uint %i_ty %s_ty %float
  1072. %f_ty = OpTypeFunction %void %uint %si_ty %float
  1073. ; CHECK: %f = OpFunction %void None %f_ty
  1074. ; CHECK: OpFunctionParameter %uint
  1075. ; CHECK-NEXT: %[[i:\w+]] = OpFunctionParameter %i_ty
  1076. ; CHECK-NEXT: %[[s:\w+]] = OpFunctionParameter %s_ty
  1077. ; CHECK-NEXT: OpFunctionParameter %float
  1078. ; CHECK-NEXT: OpLabel
  1079. ; CHECK-NEXT: %[[si:\w+]] = OpSampledImage %si_ty %[[i]] %[[s]]
  1080. ; CHECK-NEXT: %200 = OpImage %i_ty %[[si]]
  1081. ; CHECK-NEXT: OpReturn
  1082. %f = OpFunction %void None %f_ty
  1083. %100 = OpFunctionParameter %uint
  1084. %101 = OpFunctionParameter %si_ty ; replace this
  1085. %110 = OpFunctionParameter %float
  1086. %120 = OpLabel
  1087. %200 = OpImage %i_ty %101
  1088. OpReturn
  1089. OpFunctionEnd
  1090. )" + Main();
  1091. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1092. kTest, /* do_validation= */ true);
  1093. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  1094. }
  1095. TEST_F(SplitCombinedImageSamplerPassTest, FunctionBody_PtrSampledImage) {
  1096. const std::string kTest = Preamble() + NamedITypes() + NamedCombinedTypes() +
  1097. BasicTypes() + ITypes() + CombinedTypes() + R"(
  1098. ; CHECK: %f_ty = OpTypeFunction %v4float %uint %p_i_ty %p_s_ty %float
  1099. %f_ty = OpTypeFunction %v4float %uint %p_si_ty %float
  1100. ; CHECK: %f = OpFunction %v4float None %f_ty
  1101. ; CHECK-NEXT: OpFunctionParameter %uint
  1102. ; CHECK-NEXT: %[[pi:\w+]] = OpFunctionParameter %p_i_ty
  1103. ; CHECK-NEXT: %[[ps:\w+]] = OpFunctionParameter %p_s_ty
  1104. ; CHECK-NEXT: OpFunctionParameter %float
  1105. ; CHECK-NEXT: OpLabel
  1106. ; CHECK-NEXT: %[[i:\w+]] = OpLoad %i_ty %[[pi]]
  1107. ; CHECK-NEXT: %[[s:\w+]] = OpLoad %s_ty %[[ps]]
  1108. ; CHECK-NEXT: %[[si:\w+]] = OpSampledImage %si_ty %[[i]] %[[s]]
  1109. ; CHECK-NEXT: %200 = OpImageSampleExplicitLod %v4float %[[si]] %13 Lod %float_0
  1110. ; CHECK-NEXT: OpReturnValue %200
  1111. %f = OpFunction %v4float None %f_ty
  1112. %100 = OpFunctionParameter %uint
  1113. %101 = OpFunctionParameter %p_si_ty ; replace this
  1114. %110 = OpFunctionParameter %float
  1115. %120 = OpLabel
  1116. %121 = OpLoad %si_ty %101
  1117. %200 = OpImageSampleExplicitLod %v4float %121 %13 Lod %float_0
  1118. OpReturnValue %200
  1119. OpFunctionEnd
  1120. )" + Main();
  1121. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1122. kTest, /* do_validation= */ true);
  1123. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  1124. }
  1125. TEST_F(SplitCombinedImageSamplerPassTest,
  1126. FunctionCall_NoImageOrSampler_NoChange) {
  1127. const std::string kTest = Preamble() + NamedITypes() + NamedCaller() +
  1128. BasicTypes() + ITypes() + CombinedTypes() + R"(
  1129. ; CHECK: %f_ty = OpTypeFunction %void %uint %float
  1130. %f_ty = OpTypeFunction %void %uint %float
  1131. %caller_ty = OpTypeFunction %float ; make it return non-void otherwise it's just like main
  1132. ; The called function does not change
  1133. ; CHECK: %f = OpFunction %void None %f_ty
  1134. ; CHECK-NEXT: = OpFunctionParameter %uint
  1135. ; CHECK-NEXT: = OpFunctionParameter %float
  1136. ; CHECK-NEXT: = OpLabel
  1137. ; CHECK-NEXT: OpReturn
  1138. ; CHECK-NEXT: OpFunctionEnd
  1139. %f = OpFunction %void None %f_ty
  1140. %100 = OpFunctionParameter %uint
  1141. %101 = OpFunctionParameter %float
  1142. %110 = OpLabel
  1143. OpReturn
  1144. OpFunctionEnd
  1145. ; The caller does not change
  1146. ; CHECK: %caller = OpFunction %float None %caller_ty
  1147. ; CHECK-NEXT: %caller_entry = OpLabel
  1148. ; CHECK-NEXT: %caller_arg = OpCopyObject %uint %uint_0
  1149. ; CHECK-NEXT: OpFunctionCall %void %f %caller_arg %float_0
  1150. ; CHECK-NEXT: OpReturnValue %float_0
  1151. ; CHECK-NEXT: OpFunctionEnd
  1152. %caller = OpFunction %float None %caller_ty
  1153. %caller_entry = OpLabel
  1154. %caller_arg = OpCopyObject %uint %uint_0
  1155. %caller_call = OpFunctionCall %void %f %caller_arg %float_0
  1156. OpReturnValue %float_0
  1157. OpFunctionEnd
  1158. )" + Main();
  1159. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1160. kTest, /* do_validation= */ true);
  1161. // We still get a success-with-change result because the boilerplate included
  1162. // combined types, which were removed.
  1163. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  1164. }
  1165. TEST_F(SplitCombinedImageSamplerPassTest, FunctionCall_Image_NoChange) {
  1166. const std::string kTest = Preamble() + NamedITypes() + NamedCaller() +
  1167. BasicTypes() + ITypes() + R"(
  1168. ; CHECK: %f_ty = OpTypeFunction %void %i_ty
  1169. %f_ty = OpTypeFunction %void %i_ty
  1170. %caller_ty = OpTypeFunction %float %i_ty
  1171. ; The called function does not change
  1172. ; CHECK: %f = OpFunction %void None %f_ty
  1173. ; CHECK-NEXT: = OpFunctionParameter %i_ty
  1174. ; CHECK-NEXT: = OpLabel
  1175. ; CHECK-NEXT: OpReturn
  1176. ; CHECK-NEXT: OpFunctionEnd
  1177. %f = OpFunction %void None %f_ty
  1178. %100 = OpFunctionParameter %i_ty
  1179. %110 = OpLabel
  1180. OpReturn
  1181. OpFunctionEnd
  1182. ; The caller does not change
  1183. ; CHECK: %caller = OpFunction %float None %caller_ty
  1184. ; CHECK-NEXT: %caller_arg = OpFunctionParameter %i_ty
  1185. ; CHECK-NEXT: %caller_entry = OpLabel
  1186. ; CHECK-NEXT: OpFunctionCall %void %f %caller_arg
  1187. ; CHECK-NEXT: OpReturnValue %float_0
  1188. ; CHECK-NEXT: OpFunctionEnd
  1189. %caller = OpFunction %float None %caller_ty
  1190. %caller_arg = OpFunctionParameter %i_ty
  1191. %caller_entry = OpLabel
  1192. %caller_call = OpFunctionCall %void %f %caller_arg
  1193. OpReturnValue %float_0
  1194. OpFunctionEnd
  1195. )" + Main();
  1196. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1197. kTest, /* do_validation= */ true);
  1198. EXPECT_EQ(status, Pass::Status::SuccessWithoutChange) << disasm;
  1199. }
  1200. TEST_F(SplitCombinedImageSamplerPassTest, FunctionCall_Sampler_NoChange) {
  1201. const std::string kTest = Preamble() + NamedITypes() + NamedCaller() +
  1202. BasicTypes() + ITypes() + R"(
  1203. ; CHECK: %f_ty = OpTypeFunction %void %s_ty
  1204. %f_ty = OpTypeFunction %void %s_ty
  1205. %caller_ty = OpTypeFunction %float %s_ty
  1206. ; The called function does not change
  1207. ; CHECK: %f = OpFunction %void None %f_ty
  1208. ; CHECK-NEXT: = OpFunctionParameter %s_ty
  1209. ; CHECK-NEXT: = OpLabel
  1210. ; CHECK-NEXT: OpReturn
  1211. ; CHECK-NEXT: OpFunctionEnd
  1212. %f = OpFunction %void None %f_ty
  1213. %100 = OpFunctionParameter %s_ty
  1214. %110 = OpLabel
  1215. OpReturn
  1216. OpFunctionEnd
  1217. ; The caller does not change
  1218. ; CHECK: %caller = OpFunction %float None %caller_ty
  1219. ; CHECK-NEXT: %caller_arg = OpFunctionParameter %s_ty
  1220. ; CHECK-NEXT: %caller_entry = OpLabel
  1221. ; CHECK-NEXT: OpFunctionCall %void %f %caller_arg
  1222. ; CHECK-NEXT: OpReturnValue %float_0
  1223. ; CHECK-NEXT: OpFunctionEnd
  1224. %caller = OpFunction %float None %caller_ty
  1225. %caller_arg = OpFunctionParameter %s_ty
  1226. %caller_entry = OpLabel
  1227. %caller_call = OpFunctionCall %void %f %caller_arg
  1228. OpReturnValue %float_0
  1229. OpFunctionEnd
  1230. )" + Main();
  1231. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1232. kTest, /* do_validation= */ true);
  1233. EXPECT_EQ(status, Pass::Status::SuccessWithoutChange) << disasm;
  1234. }
  1235. TEST_F(SplitCombinedImageSamplerPassTest, FunctionCall_PtrImage_NoChange) {
  1236. const std::string kTest = Preamble() + NamedITypes() + NamedCaller() +
  1237. BasicTypes() + ITypes() + R"(
  1238. ; CHECK: %f_ty = OpTypeFunction %void %p_i_ty
  1239. %f_ty = OpTypeFunction %void %p_i_ty
  1240. %caller_ty = OpTypeFunction %float %p_i_ty
  1241. ; The called function does not change
  1242. ; CHECK: %f = OpFunction %void None %f_ty
  1243. ; CHECK-NEXT: = OpFunctionParameter %p_i_ty
  1244. ; CHECK-NEXT: = OpLabel
  1245. ; CHECK-NEXT: OpReturn
  1246. ; CHECK-NEXT: OpFunctionEnd
  1247. %f = OpFunction %void None %f_ty
  1248. %100 = OpFunctionParameter %p_i_ty
  1249. %110 = OpLabel
  1250. OpReturn
  1251. OpFunctionEnd
  1252. ; The caller does not change
  1253. ; CHECK: %caller = OpFunction %float None %caller_ty
  1254. ; CHECK-NEXT: %caller_arg = OpFunctionParameter %p_i_ty
  1255. ; CHECK-NEXT: %caller_entry = OpLabel
  1256. ; CHECK-NEXT: OpFunctionCall %void %f %caller_arg
  1257. ; CHECK-NEXT: OpReturnValue %float_0
  1258. ; CHECK-NEXT: OpFunctionEnd
  1259. %caller = OpFunction %float None %caller_ty
  1260. %caller_arg = OpFunctionParameter %p_i_ty
  1261. %caller_entry = OpLabel
  1262. %caller_call = OpFunctionCall %void %f %caller_arg
  1263. OpReturnValue %float_0
  1264. OpFunctionEnd
  1265. )" + Main();
  1266. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1267. kTest, /* do_validation= */ true);
  1268. EXPECT_EQ(status, Pass::Status::SuccessWithoutChange) << disasm;
  1269. }
  1270. TEST_F(SplitCombinedImageSamplerPassTest, FunctionCall_PtrSampler_NoChange) {
  1271. const std::string kTest = Preamble() + NamedITypes() + NamedCaller() +
  1272. BasicTypes() + ITypes() + R"(
  1273. ; CHECK: %f_ty = OpTypeFunction %void %p_s_ty
  1274. %f_ty = OpTypeFunction %void %p_s_ty
  1275. %caller_ty = OpTypeFunction %float %p_s_ty
  1276. ; The called function does not change
  1277. ; CHECK: %f = OpFunction %void None %f_ty
  1278. ; CHECK-NEXT: = OpFunctionParameter %p_s_ty
  1279. ; CHECK-NEXT: = OpLabel
  1280. ; CHECK-NEXT: OpReturn
  1281. ; CHECK-NEXT: OpFunctionEnd
  1282. %f = OpFunction %void None %f_ty
  1283. %100 = OpFunctionParameter %p_s_ty
  1284. %110 = OpLabel
  1285. OpReturn
  1286. OpFunctionEnd
  1287. ; The caller does not change
  1288. ; CHECK: %caller = OpFunction %float None %caller_ty
  1289. ; CHECK-NEXT: %caller_arg = OpFunctionParameter %p_s_ty
  1290. ; CHECK-NEXT: %caller_entry = OpLabel
  1291. ; CHECK-NEXT: OpFunctionCall %void %f %caller_arg
  1292. ; CHECK-NEXT: OpReturnValue %float_0
  1293. ; CHECK-NEXT: OpFunctionEnd
  1294. %caller = OpFunction %float None %caller_ty
  1295. %caller_arg = OpFunctionParameter %p_s_ty
  1296. %caller_entry = OpLabel
  1297. %caller_call = OpFunctionCall %void %f %caller_arg
  1298. OpReturnValue %float_0
  1299. OpFunctionEnd
  1300. )" + Main();
  1301. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1302. kTest, /* do_validation= */ true);
  1303. EXPECT_EQ(status, Pass::Status::SuccessWithoutChange) << disasm;
  1304. }
  1305. TEST_F(SplitCombinedImageSamplerPassTest, FunctionCall_SampledImage_Split) {
  1306. const std::string kTest = Preamble() + NamedITypes() + NamedCombinedTypes() +
  1307. NamedCaller() + BasicTypes() + ITypes() +
  1308. CombinedTypes() + R"(
  1309. ; CHECK: %f_ty = OpTypeFunction %void %i_ty %s_ty
  1310. %f_ty = OpTypeFunction %void %si_ty
  1311. %caller_ty = OpTypeFunction %float %si_ty
  1312. ; Call function arg is split. We've checked these details in other tests.
  1313. ; CHECK: %f = OpFunction %void None %f_ty
  1314. ; CHECK-NEXT: %[[callee_i:\w+]] = OpFunctionParameter %i_ty
  1315. ; CHECK-NEXT: %[[callee_s:\w+]] = OpFunctionParameter %s_ty
  1316. ; CHECK-NEXT: = OpLabel
  1317. ; CHECK-NEXT: OpReturn
  1318. ; CHECK-NEXT: OpFunctionEnd
  1319. %f = OpFunction %void None %f_ty
  1320. %100 = OpFunctionParameter %si_ty
  1321. %110 = OpLabel
  1322. OpReturn
  1323. OpFunctionEnd
  1324. ; CHECK: %caller = OpFunction %float None %caller_ty
  1325. ; CHECK-NEXT: %[[caller_i:\w+]] = OpFunctionParameter %i_ty
  1326. ; CHECK-NEXT: %[[caller_s:\w+]] = OpFunctionParameter %s_ty
  1327. ; CHECK-NEXT: %caller_entry = OpLabel
  1328. ; CHECK-NEXT: %caller_call = OpFunctionCall %void %f %[[caller_i]] %[[caller_s]]
  1329. ; CHECK-NEXT: OpReturnValue %float_0
  1330. ; CHECK-NEXT: OpFunctionEnd
  1331. %caller = OpFunction %float None %caller_ty
  1332. %caller_arg = OpFunctionParameter %si_ty
  1333. %caller_entry = OpLabel
  1334. %caller_call = OpFunctionCall %void %f %caller_arg
  1335. OpReturnValue %float_0
  1336. OpFunctionEnd
  1337. )" + Main();
  1338. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1339. kTest, /* do_validation= */ true);
  1340. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  1341. }
  1342. TEST_F(SplitCombinedImageSamplerPassTest,
  1343. FunctionCall_SampledImageDuplicatedArg_Split) {
  1344. const std::string kTest = Preamble() + NamedITypes() + NamedCombinedTypes() +
  1345. NamedCaller() + BasicTypes() + ITypes() +
  1346. CombinedTypes() + R"(
  1347. ; CHECK: %f_ty = OpTypeFunction %void %i_ty %s_ty %i_ty %s_ty
  1348. %f_ty = OpTypeFunction %void %si_ty %si_ty
  1349. %caller_ty = OpTypeFunction %float %si_ty
  1350. ; Call function arg is split. We've checked these details in other tests.
  1351. ; CHECK: %f = OpFunction %void None %f_ty
  1352. ; CHECK-NEXT: %[[callee_i_0:\w+]] = OpFunctionParameter %i_ty
  1353. ; CHECK-NEXT: %[[callee_s_0:\w+]] = OpFunctionParameter %s_ty
  1354. ; CHECK-NEXT: %[[callee_i_1:\w+]] = OpFunctionParameter %i_ty
  1355. ; CHECK-NEXT: %[[callee_s_1:\w+]] = OpFunctionParameter %s_ty
  1356. ; CHECK-NEXT: = OpLabel
  1357. ; CHECK-NEXT: OpReturn
  1358. ; CHECK-NEXT: OpFunctionEnd
  1359. %f = OpFunction %void None %f_ty
  1360. %100 = OpFunctionParameter %si_ty
  1361. %101 = OpFunctionParameter %si_ty
  1362. %110 = OpLabel
  1363. OpReturn
  1364. OpFunctionEnd
  1365. ; CHECK: %caller = OpFunction %float None %caller_ty
  1366. ; CHECK-NEXT: %[[caller_i:\w+]] = OpFunctionParameter %i_ty
  1367. ; CHECK-NEXT: %[[caller_s:\w+]] = OpFunctionParameter %s_ty
  1368. ; CHECK-NEXT: %caller_entry = OpLabel
  1369. ; CHECK-NEXT: %caller_call = OpFunctionCall %void %f %[[caller_i]] %[[caller_s]] %[[caller_i]] %[[caller_s]]
  1370. ; CHECK-NEXT: OpReturnValue %float_0
  1371. ; CHECK-NEXT: OpFunctionEnd
  1372. %caller = OpFunction %float None %caller_ty
  1373. %caller_arg = OpFunctionParameter %si_ty
  1374. %caller_entry = OpLabel
  1375. %caller_call = OpFunctionCall %void %f %caller_arg %caller_arg
  1376. OpReturnValue %float_0
  1377. OpFunctionEnd
  1378. )" + Main();
  1379. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1380. kTest, /* do_validation= */ true);
  1381. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  1382. }
  1383. TEST_F(SplitCombinedImageSamplerPassTest,
  1384. FunctionCall_SampledImageTwoDistinct_Split) {
  1385. const std::string kTest = Preamble() + NamedITypes() + NamedCombinedTypes() +
  1386. NamedCaller() + BasicTypes() + ITypes() +
  1387. CombinedTypes() + R"(
  1388. ; CHECK: %f_ty = OpTypeFunction %void %i_ty %s_ty %i_ty %s_ty
  1389. %f_ty = OpTypeFunction %void %si_ty %si_ty
  1390. %caller_ty = OpTypeFunction %float %si_ty %si_ty
  1391. ; Call function arg is split. We've checked these details in other tests.
  1392. ; CHECK: %f = OpFunction %void None %f_ty
  1393. ; CHECK-NEXT: %[[callee_i_0:\w+]] = OpFunctionParameter %i_ty
  1394. ; CHECK-NEXT: %[[callee_s_0:\w+]] = OpFunctionParameter %s_ty
  1395. ; CHECK-NEXT: %[[callee_i_1:\w+]] = OpFunctionParameter %i_ty
  1396. ; CHECK-NEXT: %[[callee_s_1:\w+]] = OpFunctionParameter %s_ty
  1397. ; CHECK-NEXT: = OpLabel
  1398. ; CHECK-NEXT: OpReturn
  1399. ; CHECK-NEXT: OpFunctionEnd
  1400. %f = OpFunction %void None %f_ty
  1401. %100 = OpFunctionParameter %si_ty
  1402. %101 = OpFunctionParameter %si_ty
  1403. %110 = OpLabel
  1404. OpReturn
  1405. OpFunctionEnd
  1406. ; CHECK: %caller = OpFunction %float None %caller_ty
  1407. ; CHECK-NEXT: %[[caller_i_0:\w+]] = OpFunctionParameter %i_ty
  1408. ; CHECK-NEXT: %[[caller_s_0:\w+]] = OpFunctionParameter %s_ty
  1409. ; CHECK-NEXT: %[[caller_i_1:\w+]] = OpFunctionParameter %i_ty
  1410. ; CHECK-NEXT: %[[caller_s_1:\w+]] = OpFunctionParameter %s_ty
  1411. ; CHECK-NEXT: %caller_entry = OpLabel
  1412. ; CHECK-NEXT: %caller_call = OpFunctionCall %void %f %[[caller_i_0]] %[[caller_s_0]] %[[caller_i_1]] %[[caller_s_1]]
  1413. ; CHECK-NEXT: OpReturnValue %float_0
  1414. ; CHECK-NEXT: OpFunctionEnd
  1415. %caller = OpFunction %float None %caller_ty
  1416. %caller_arg = OpFunctionParameter %si_ty
  1417. %201 = OpFunctionParameter %si_ty
  1418. %caller_entry = OpLabel
  1419. %caller_call = OpFunctionCall %void %f %caller_arg %201
  1420. OpReturnValue %float_0
  1421. OpFunctionEnd
  1422. )" + Main();
  1423. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1424. kTest, /* do_validation= */ true);
  1425. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  1426. }
  1427. TEST_F(SplitCombinedImageSamplerPassTest,
  1428. FunctionCall_SampledImageAndCopy_Split) {
  1429. const std::string kTest = Preamble() + NamedITypes() + NamedCombinedTypes() +
  1430. NamedCaller() + BasicTypes() + ITypes() +
  1431. CombinedTypes() + R"(
  1432. ; CHECK: %f_ty = OpTypeFunction %void %i_ty %s_ty %i_ty %s_ty
  1433. %f_ty = OpTypeFunction %void %si_ty %si_ty
  1434. ; CHECK: %caller_ty = OpTypeFunction %float %i_ty %s_ty
  1435. %caller_ty = OpTypeFunction %float %si_ty
  1436. ; Call function arg is split. We've checked these details in other tests.
  1437. ; CHECK: %f = OpFunction %void None %f_ty
  1438. ; CHECK-NEXT: %[[callee_i_0:\w+]] = OpFunctionParameter %i_ty
  1439. ; CHECK-NEXT: %[[callee_s_0:\w+]] = OpFunctionParameter %s_ty
  1440. ; CHECK-NEXT: %[[callee_i_1:\w+]] = OpFunctionParameter %i_ty
  1441. ; CHECK-NEXT: %[[callee_s_1:\w+]] = OpFunctionParameter %s_ty
  1442. ; CHECK-NEXT: = OpLabel
  1443. ; CHECK-NEXT: OpReturn
  1444. ; CHECK-NEXT: OpFunctionEnd
  1445. %f = OpFunction %void None %f_ty
  1446. %100 = OpFunctionParameter %si_ty
  1447. %101 = OpFunctionParameter %si_ty
  1448. %110 = OpLabel
  1449. OpReturn
  1450. OpFunctionEnd
  1451. ; CHECK: %caller = OpFunction %float None %caller_ty
  1452. ; CHECK-NEXT: %[[caller_i:\w+]] = OpFunctionParameter %i_ty
  1453. ; CHECK-NEXT: %[[caller_s:\w+]] = OpFunctionParameter %s_ty
  1454. ; CHECK-NEXT: %caller_entry = OpLabel
  1455. ; CHECK-NEXT: %caller_call = OpFunctionCall %void %f %[[caller_i]] %[[caller_s]] %[[caller_i]] %[[caller_s]]
  1456. ; CHECK-NEXT: OpReturnValue %float_0
  1457. ; CHECK-NEXT: OpFunctionEnd
  1458. %caller = OpFunction %float None %caller_ty
  1459. %caller_arg = OpFunctionParameter %si_ty
  1460. %caller_entry = OpLabel
  1461. %copy = OpCopyObject %si_ty %caller_arg
  1462. %caller_call = OpFunctionCall %void %f %caller_arg %copy
  1463. OpReturnValue %float_0
  1464. OpFunctionEnd
  1465. )" + Main();
  1466. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1467. kTest, /* do_validation= */ true);
  1468. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  1469. }
  1470. TEST_F(SplitCombinedImageSamplerPassTest,
  1471. FunctionCall_SampledImageSurrounded_Split) {
  1472. // Test indexing by surrounding the sampled image parameter with other
  1473. // arguments that should not be touched.
  1474. const std::string kTest = Preamble() + NamedITypes() + NamedCombinedTypes() +
  1475. NamedCaller() + BasicTypes() + ITypes() +
  1476. CombinedTypes() + R"(
  1477. ; CHECK: %f_ty = OpTypeFunction %void %float %i_ty %s_ty %uint
  1478. %f_ty = OpTypeFunction %void %float %si_ty %uint
  1479. ; CHECK: %caller_ty = OpTypeFunction %float %uint %i_ty %s_ty %float
  1480. %caller_ty = OpTypeFunction %float %uint %si_ty %float
  1481. ; Call function arg is split. We've checked these details in other tests.
  1482. ; CHECK: %f = OpFunction %void None %f_ty
  1483. ; CHECK-NEXT: %[[callee_f:\w+]] = OpFunctionParameter %float
  1484. ; CHECK-NEXT: %[[callee_i:\w+]] = OpFunctionParameter %i_ty
  1485. ; CHECK-NEXT: %[[callee_s:\w+]] = OpFunctionParameter %s_ty
  1486. ; CHECK-NEXT: %[[callee_u:\w+]] = OpFunctionParameter %uint
  1487. ; CHECK-NEXT: = OpLabel
  1488. ; CHECK-NEXT: OpReturn
  1489. ; CHECK-NEXT: OpFunctionEnd
  1490. %f = OpFunction %void None %f_ty
  1491. %99 = OpFunctionParameter %float
  1492. %100 = OpFunctionParameter %si_ty
  1493. %101 = OpFunctionParameter %uint
  1494. %110 = OpLabel
  1495. OpReturn
  1496. OpFunctionEnd
  1497. ; CHECK: %caller = OpFunction %float None %caller_ty
  1498. ; CHECK-NEXT: %[[u_param:\w+]] = OpFunctionParameter %uint
  1499. ; CHECK-NEXT: %[[caller_i:\w+]] = OpFunctionParameter %i_ty
  1500. ; CHECK-NEXT: %[[caller_s:\w+]] = OpFunctionParameter %s_ty
  1501. ; CHECK-NEXT: %[[f_param:\w+]] = OpFunctionParameter %float
  1502. ; CHECK-NEXT: %caller_entry = OpLabel
  1503. ; CHECK-NEXT: %caller_call = OpFunctionCall %void %f %[[f_param]] %[[caller_i]] %[[caller_s]] %[[u_param]]
  1504. ; CHECK-NEXT: OpReturnValue %float_0
  1505. ; CHECK-NEXT: OpFunctionEnd
  1506. %caller = OpFunction %float None %caller_ty
  1507. %200 = OpFunctionParameter %uint
  1508. %caller_arg = OpFunctionParameter %si_ty
  1509. %201 = OpFunctionParameter %float
  1510. %caller_entry = OpLabel
  1511. %caller_call = OpFunctionCall %void %f %201 %caller_arg %200
  1512. OpReturnValue %float_0
  1513. OpFunctionEnd
  1514. )" + Main();
  1515. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1516. kTest, /* do_validation= */ true);
  1517. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  1518. }
  1519. TEST_F(SplitCombinedImageSamplerPassTest, FunctionCall_PtrSampledImage_Split) {
  1520. const std::string kTest = Preamble() + NamedITypes() + NamedCombinedTypes() +
  1521. NamedCaller() + BasicTypes() + ITypes() +
  1522. CombinedTypes() + R"(
  1523. ; CHECK: %f_ty = OpTypeFunction %void %p_i_ty %p_s_ty
  1524. %f_ty = OpTypeFunction %void %p_si_ty
  1525. %caller_ty = OpTypeFunction %float %p_si_ty
  1526. ; Call function arg is split. We've checked these details in other tests.
  1527. ; CHECK: %f = OpFunction %void None %f_ty
  1528. ; CHECK-NEXT: %[[callee_i:\w+]] = OpFunctionParameter %p_i_ty
  1529. ; CHECK-NEXT: %[[callee_s:\w+]] = OpFunctionParameter %p_s_ty
  1530. ; CHECK-NEXT: = OpLabel
  1531. ; CHECK-NEXT: OpReturn
  1532. ; CHECK-NEXT: OpFunctionEnd
  1533. %f = OpFunction %void None %f_ty
  1534. %100 = OpFunctionParameter %p_si_ty
  1535. %110 = OpLabel
  1536. OpReturn
  1537. OpFunctionEnd
  1538. ; CHECK: %caller = OpFunction %float None %caller_ty
  1539. ; CHECK-NEXT: %[[caller_i:\w+]] = OpFunctionParameter %p_i_ty
  1540. ; CHECK-NEXT: %[[caller_s:\w+]] = OpFunctionParameter %p_s_ty
  1541. ; CHECK-NEXT: %caller_entry = OpLabel
  1542. ; CHECK-NEXT: %caller_call = OpFunctionCall %void %f %[[caller_i]] %[[caller_s]]
  1543. ; CHECK-NEXT: OpReturnValue %float_0
  1544. ; CHECK-NEXT: OpFunctionEnd
  1545. %caller = OpFunction %float None %caller_ty
  1546. %caller_arg = OpFunctionParameter %p_si_ty
  1547. %caller_entry = OpLabel
  1548. %caller_call = OpFunctionCall %void %f %caller_arg
  1549. OpReturnValue %float_0
  1550. OpFunctionEnd
  1551. )" + Main();
  1552. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1553. kTest, /* do_validation= */ true);
  1554. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  1555. }
  1556. TEST_F(SplitCombinedImageSamplerPassTest,
  1557. FunctionCall_PtrArraySampledImage_Split) {
  1558. const std::string kTest = Preamble() + NamedITypes() + NamedCombinedTypes() +
  1559. NamedCaller() + BasicTypes() + ITypes() +
  1560. CombinedTypes() + R"(
  1561. ; CHECK: %[[array_i_ty:\w+]] = OpTypeArray %i_ty %uint_3
  1562. ; CHECK: %[[p_array_i_ty:\w+]] = OpTypePointer UniformConstant %[[array_i_ty]]
  1563. ; CHECK: %[[array_s_ty:\w+]] = OpTypeArray %s_ty %uint_3
  1564. ; CHECK: %[[p_array_s_ty:\w+]] = OpTypePointer UniformConstant %[[array_s_ty]]
  1565. ; CHECK: %f_ty = OpTypeFunction %void %[[p_array_i_ty]] %[[p_array_s_ty]]
  1566. %f_ty = OpTypeFunction %void %p_array_si_ty
  1567. %caller_ty = OpTypeFunction %float %p_array_si_ty
  1568. ; Call function arg is split. We've checked these details in other tests.
  1569. ; CHECK: %f = OpFunction %void None %f_ty
  1570. ; CHECK-NEXT: %[[callee_i:\w+]] = OpFunctionParameter %[[p_array_i_ty]]
  1571. ; CHECK-NEXT: %[[callee_s:\w+]] = OpFunctionParameter %[[p_array_s_ty]]
  1572. ; CHECK-NEXT: = OpLabel
  1573. ; CHECK-NEXT: OpReturn
  1574. ; CHECK-NEXT: OpFunctionEnd
  1575. %f = OpFunction %void None %f_ty
  1576. %100 = OpFunctionParameter %p_array_si_ty
  1577. %110 = OpLabel
  1578. OpReturn
  1579. OpFunctionEnd
  1580. ; CHECK: %caller = OpFunction %float None %caller_ty
  1581. ; CHECK-NEXT: %[[caller_i:\w+]] = OpFunctionParameter %[[p_array_i_ty]]
  1582. ; CHECK-NEXT: %[[caller_s:\w+]] = OpFunctionParameter %[[p_array_s_ty]]
  1583. ; CHECK-NEXT: %caller_entry = OpLabel
  1584. ; CHECK-NEXT: %caller_call = OpFunctionCall %void %f %[[caller_i]] %[[caller_s]]
  1585. ; CHECK-NEXT: OpReturnValue %float_0
  1586. ; CHECK-NEXT: OpFunctionEnd
  1587. %caller = OpFunction %float None %caller_ty
  1588. %caller_arg = OpFunctionParameter %p_array_si_ty
  1589. %caller_entry = OpLabel
  1590. %caller_call = OpFunctionCall %void %f %caller_arg
  1591. OpReturnValue %float_0
  1592. OpFunctionEnd
  1593. )" + Main();
  1594. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1595. kTest, /* do_validation= */ true);
  1596. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  1597. }
  1598. TEST_F(SplitCombinedImageSamplerPassTest,
  1599. FunctionCall_PtrRtArraySampledImage_Split) {
  1600. const std::string kTest = Preamble() + NamedITypes() + NamedCombinedTypes() +
  1601. NamedCaller() + BasicTypes() + ITypes() +
  1602. CombinedTypes() + R"(
  1603. ; CHECK: %[[array_i_ty:\w+]] = OpTypeRuntimeArray %i_ty
  1604. ; CHECK: %[[p_array_i_ty:\w+]] = OpTypePointer UniformConstant %[[array_i_ty]]
  1605. ; CHECK: %[[array_s_ty:\w+]] = OpTypeRuntimeArray
  1606. ; CHECK: %[[p_array_s_ty:\w+]] = OpTypePointer UniformConstant %[[array_s_ty]]
  1607. ; CHECK: %f_ty = OpTypeFunction %void %[[p_array_i_ty]] %[[p_array_s_ty]]
  1608. %f_ty = OpTypeFunction %void %p_rtarray_si_ty
  1609. %caller_ty = OpTypeFunction %float %p_rtarray_si_ty
  1610. ; Call function arg is split. We've checked these details in other tests.
  1611. ; CHECK: %f = OpFunction %void None %f_ty
  1612. ; CHECK-NEXT: %[[callee_i:\w+]] = OpFunctionParameter %[[p_array_i_ty]]
  1613. ; CHECK-NEXT: %[[callee_s:\w+]] = OpFunctionParameter %[[p_array_s_ty]]
  1614. ; CHECK-NEXT: = OpLabel
  1615. ; CHECK-NEXT: OpReturn
  1616. ; CHECK-NEXT: OpFunctionEnd
  1617. %f = OpFunction %void None %f_ty
  1618. %100 = OpFunctionParameter %p_rtarray_si_ty
  1619. %110 = OpLabel
  1620. OpReturn
  1621. OpFunctionEnd
  1622. ; CHECK: %caller = OpFunction %float None %caller_ty
  1623. ; CHECK-NEXT: %[[caller_i:\w+]] = OpFunctionParameter %[[p_array_i_ty]]
  1624. ; CHECK-NEXT: %[[caller_s:\w+]] = OpFunctionParameter %[[p_array_s_ty]]
  1625. ; CHECK-NEXT: %caller_entry = OpLabel
  1626. ; CHECK-NEXT: %caller_call = OpFunctionCall %void %f %[[caller_i]] %[[caller_s]]
  1627. ; CHECK-NEXT: OpReturnValue %float_0
  1628. ; CHECK-NEXT: OpFunctionEnd
  1629. %caller = OpFunction %float None %caller_ty
  1630. %caller_arg = OpFunctionParameter %p_rtarray_si_ty
  1631. %caller_entry = OpLabel
  1632. %caller_call = OpFunctionCall %void %f %caller_arg
  1633. OpReturnValue %float_0
  1634. OpFunctionEnd
  1635. )" + Main();
  1636. auto [disasm, status] = SinglePassRunAndMatch<SplitCombinedImageSamplerPass>(
  1637. kTest, /* do_validation= */ true);
  1638. EXPECT_EQ(status, Pass::Status::SuccessWithChange) << disasm;
  1639. }
  1640. } // namespace
  1641. } // namespace opt
  1642. } // namespace spvtools