1 // Copyright (c) 2017 Valve Corporation
2 // Copyright (c) 2017 LunarG Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include <string>
17 
18 #include "test/opt/pass_fixture.h"
19 #include "test/opt/pass_utils.h"
20 
21 namespace spvtools {
22 namespace opt {
23 namespace {
24 
25 using InlineOpaqueTest = PassTest<::testing::Test>;
26 
TEST_F(InlineOpaqueTest,InlineCallWithStructArgContainingSampledImage)27 TEST_F(InlineOpaqueTest, InlineCallWithStructArgContainingSampledImage) {
28   // Function with opaque argument is inlined.
29   // TODO(greg-lunarg): Add HLSL code
30 
31   const std::string predefs =
32       R"(OpCapability Shader
33 %1 = OpExtInstImport "GLSL.std.450"
34 OpMemoryModel Logical GLSL450
35 OpEntryPoint Fragment %main "main" %outColor %texCoords
36 OpExecutionMode %main OriginUpperLeft
37 OpSource GLSL 140
38 OpName %main "main"
39 OpName %S_t "S_t"
40 OpMemberName %S_t 0 "v0"
41 OpMemberName %S_t 1 "v1"
42 OpMemberName %S_t 2 "smp"
43 OpName %foo_struct_S_t_vf2_vf21_ "foo(struct-S_t-vf2-vf21;"
44 OpName %s "s"
45 OpName %outColor "outColor"
46 OpName %sampler15 "sampler15"
47 OpName %s0 "s0"
48 OpName %texCoords "texCoords"
49 OpName %param "param"
50 OpDecorate %sampler15 DescriptorSet 0
51 %void = OpTypeVoid
52 %12 = OpTypeFunction %void
53 %float = OpTypeFloat 32
54 %v2float = OpTypeVector %float 2
55 %v4float = OpTypeVector %float 4
56 %_ptr_Output_v4float = OpTypePointer Output %v4float
57 %outColor = OpVariable %_ptr_Output_v4float Output
58 %17 = OpTypeImage %float 2D 0 0 0 1 Unknown
59 %18 = OpTypeSampledImage %17
60 %S_t = OpTypeStruct %v2float %v2float %18
61 %_ptr_Function_S_t = OpTypePointer Function %S_t
62 %20 = OpTypeFunction %void %_ptr_Function_S_t
63 %_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
64 %_ptr_Function_18 = OpTypePointer Function %18
65 %sampler15 = OpVariable %_ptr_UniformConstant_18 UniformConstant
66 %int = OpTypeInt 32 1
67 %int_0 = OpConstant %int 0
68 %int_2 = OpConstant %int 2
69 %_ptr_Function_v2float = OpTypePointer Function %v2float
70 %_ptr_Input_v2float = OpTypePointer Input %v2float
71 %texCoords = OpVariable %_ptr_Input_v2float Input
72 )";
73 
74   const std::string before =
75       R"(%main = OpFunction %void None %12
76 %28 = OpLabel
77 %s0 = OpVariable %_ptr_Function_S_t Function
78 %param = OpVariable %_ptr_Function_S_t Function
79 %29 = OpLoad %v2float %texCoords
80 %30 = OpAccessChain %_ptr_Function_v2float %s0 %int_0
81 OpStore %30 %29
82 %31 = OpLoad %18 %sampler15
83 %32 = OpAccessChain %_ptr_Function_18 %s0 %int_2
84 OpStore %32 %31
85 %33 = OpLoad %S_t %s0
86 OpStore %param %33
87 %34 = OpFunctionCall %void %foo_struct_S_t_vf2_vf21_ %param
88 OpReturn
89 OpFunctionEnd
90 )";
91 
92   const std::string after =
93       R"(%main = OpFunction %void None %12
94 %28 = OpLabel
95 %s0 = OpVariable %_ptr_Function_S_t Function
96 %param = OpVariable %_ptr_Function_S_t Function
97 %29 = OpLoad %v2float %texCoords
98 %30 = OpAccessChain %_ptr_Function_v2float %s0 %int_0
99 OpStore %30 %29
100 %31 = OpLoad %18 %sampler15
101 %32 = OpAccessChain %_ptr_Function_18 %s0 %int_2
102 OpStore %32 %31
103 %33 = OpLoad %S_t %s0
104 OpStore %param %33
105 %41 = OpAccessChain %_ptr_Function_18 %param %int_2
106 %42 = OpLoad %18 %41
107 %43 = OpAccessChain %_ptr_Function_v2float %param %int_0
108 %44 = OpLoad %v2float %43
109 %45 = OpImageSampleImplicitLod %v4float %42 %44
110 OpStore %outColor %45
111 OpReturn
112 OpFunctionEnd
113 )";
114 
115   const std::string post_defs =
116       R"(%foo_struct_S_t_vf2_vf21_ = OpFunction %void None %20
117 %s = OpFunctionParameter %_ptr_Function_S_t
118 %35 = OpLabel
119 %36 = OpAccessChain %_ptr_Function_18 %s %int_2
120 %37 = OpLoad %18 %36
121 %38 = OpAccessChain %_ptr_Function_v2float %s %int_0
122 %39 = OpLoad %v2float %38
123 %40 = OpImageSampleImplicitLod %v4float %37 %39
124 OpStore %outColor %40
125 OpReturn
126 OpFunctionEnd
127 )";
128 
129   SinglePassRunAndCheck<InlineOpaquePass>(
130       predefs + before + post_defs, predefs + after + post_defs, true, true);
131 }
132 
TEST_F(InlineOpaqueTest,InlineOpaqueReturn)133 TEST_F(InlineOpaqueTest, InlineOpaqueReturn) {
134   // Function with opaque return value is inlined.
135   // TODO(greg-lunarg): Add HLSL code
136 
137   const std::string predefs =
138       R"(OpCapability Shader
139 %1 = OpExtInstImport "GLSL.std.450"
140 OpMemoryModel Logical GLSL450
141 OpEntryPoint Fragment %main "main" %texCoords %outColor
142 OpExecutionMode %main OriginUpperLeft
143 OpSource GLSL 140
144 OpName %main "main"
145 OpName %foo_ "foo("
146 OpName %texCoords "texCoords"
147 OpName %outColor "outColor"
148 OpName %sampler15 "sampler15"
149 OpName %sampler16 "sampler16"
150 OpDecorate %sampler15 DescriptorSet 0
151 OpDecorate %sampler16 DescriptorSet 0
152 %void = OpTypeVoid
153 %9 = OpTypeFunction %void
154 %float = OpTypeFloat 32
155 %v2float = OpTypeVector %float 2
156 %bool = OpTypeBool
157 %false = OpConstantFalse %bool
158 %_ptr_Input_v2float = OpTypePointer Input %v2float
159 %texCoords = OpVariable %_ptr_Input_v2float Input
160 %float_0 = OpConstant %float 0
161 %16 = OpConstantComposite %v2float %float_0 %float_0
162 %v4float = OpTypeVector %float 4
163 %_ptr_Output_v4float = OpTypePointer Output %v4float
164 %outColor = OpVariable %_ptr_Output_v4float Output
165 %19 = OpTypeImage %float 2D 0 0 0 1 Unknown
166 %20 = OpTypeSampledImage %19
167 %21 = OpTypeFunction %20
168 %_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
169 %_ptr_Function_20 = OpTypePointer Function %20
170 %sampler15 = OpVariable %_ptr_UniformConstant_20 UniformConstant
171 %sampler16 = OpVariable %_ptr_UniformConstant_20 UniformConstant
172 )";
173 
174   const std::string before =
175       R"(%main = OpFunction %void None %9
176 %24 = OpLabel
177 %25 = OpVariable %_ptr_Function_20 Function
178 %26 = OpFunctionCall %20 %foo_
179 OpStore %25 %26
180 %27 = OpLoad %20 %25
181 %28 = OpLoad %v2float %texCoords
182 %29 = OpImageSampleImplicitLod %v4float %27 %28
183 OpStore %outColor %29
184 OpReturn
185 OpFunctionEnd
186 )";
187 
188   const std::string after =
189       R"(%main = OpFunction %void None %9
190 %24 = OpLabel
191 %34 = OpVariable %_ptr_Function_20 Function
192 %35 = OpVariable %_ptr_Function_20 Function
193 %25 = OpVariable %_ptr_Function_20 Function
194 %36 = OpLoad %20 %sampler16
195 OpStore %34 %36
196 %37 = OpLoad %20 %34
197 OpStore %35 %37
198 %26 = OpLoad %20 %35
199 OpStore %25 %26
200 %27 = OpLoad %20 %25
201 %28 = OpLoad %v2float %texCoords
202 %29 = OpImageSampleImplicitLod %v4float %27 %28
203 OpStore %outColor %29
204 OpReturn
205 OpFunctionEnd
206 )";
207 
208   const std::string post_defs =
209       R"(%foo_ = OpFunction %20 None %21
210 %30 = OpLabel
211 %31 = OpVariable %_ptr_Function_20 Function
212 %32 = OpLoad %20 %sampler16
213 OpStore %31 %32
214 %33 = OpLoad %20 %31
215 OpReturnValue %33
216 OpFunctionEnd
217 )";
218 
219   SinglePassRunAndCheck<InlineOpaquePass>(
220       predefs + before + post_defs, predefs + after + post_defs, true, true);
221 }
222 
TEST_F(InlineOpaqueTest,InlineInNonEntryPointFunction)223 TEST_F(InlineOpaqueTest, InlineInNonEntryPointFunction) {
224   // This demonstrates opaque inlining in a function that is not
225   // an entry point function (main2) but is in the call tree of an
226   // entry point function (main).
227   // TODO(greg-lunarg): Add HLSL code
228 
229   const std::string predefs =
230       R"(OpCapability Shader
231 %1 = OpExtInstImport "GLSL.std.450"
232 OpMemoryModel Logical GLSL450
233 OpEntryPoint Fragment %main "main" %outColor %texCoords
234 OpExecutionMode %main OriginUpperLeft
235 OpSource GLSL 140
236 OpName %main "main"
237 OpName %main2 "main2"
238 OpName %S_t "S_t"
239 OpMemberName %S_t 0 "v0"
240 OpMemberName %S_t 1 "v1"
241 OpMemberName %S_t 2 "smp"
242 OpName %foo_struct_S_t_vf2_vf21_ "foo(struct-S_t-vf2-vf21;"
243 OpName %s "s"
244 OpName %outColor "outColor"
245 OpName %sampler15 "sampler15"
246 OpName %s0 "s0"
247 OpName %texCoords "texCoords"
248 OpName %param "param"
249 OpDecorate %sampler15 DescriptorSet 0
250 %void = OpTypeVoid
251 %13 = OpTypeFunction %void
252 %float = OpTypeFloat 32
253 %v2float = OpTypeVector %float 2
254 %v4float = OpTypeVector %float 4
255 %_ptr_Output_v4float = OpTypePointer Output %v4float
256 %outColor = OpVariable %_ptr_Output_v4float Output
257 %18 = OpTypeImage %float 2D 0 0 0 1 Unknown
258 %19 = OpTypeSampledImage %18
259 %S_t = OpTypeStruct %v2float %v2float %19
260 %_ptr_Function_S_t = OpTypePointer Function %S_t
261 %21 = OpTypeFunction %void %_ptr_Function_S_t
262 %_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
263 %_ptr_Function_19 = OpTypePointer Function %19
264 %sampler15 = OpVariable %_ptr_UniformConstant_19 UniformConstant
265 %int = OpTypeInt 32 1
266 %int_0 = OpConstant %int 0
267 %int_2 = OpConstant %int 2
268 %_ptr_Function_v2float = OpTypePointer Function %v2float
269 %_ptr_Input_v2float = OpTypePointer Input %v2float
270 %texCoords = OpVariable %_ptr_Input_v2float Input
271 )";
272 
273   const std::string before =
274       R"(%main2 = OpFunction %void None %13
275 %29 = OpLabel
276 %s0 = OpVariable %_ptr_Function_S_t Function
277 %param = OpVariable %_ptr_Function_S_t Function
278 %30 = OpLoad %v2float %texCoords
279 %31 = OpAccessChain %_ptr_Function_v2float %s0 %int_0
280 OpStore %31 %30
281 %32 = OpLoad %19 %sampler15
282 %33 = OpAccessChain %_ptr_Function_19 %s0 %int_2
283 OpStore %33 %32
284 %34 = OpLoad %S_t %s0
285 OpStore %param %34
286 %35 = OpFunctionCall %void %foo_struct_S_t_vf2_vf21_ %param
287 OpReturn
288 OpFunctionEnd
289 )";
290 
291   const std::string after =
292       R"(%main2 = OpFunction %void None %13
293 %29 = OpLabel
294 %s0 = OpVariable %_ptr_Function_S_t Function
295 %param = OpVariable %_ptr_Function_S_t Function
296 %30 = OpLoad %v2float %texCoords
297 %31 = OpAccessChain %_ptr_Function_v2float %s0 %int_0
298 OpStore %31 %30
299 %32 = OpLoad %19 %sampler15
300 %33 = OpAccessChain %_ptr_Function_19 %s0 %int_2
301 OpStore %33 %32
302 %34 = OpLoad %S_t %s0
303 OpStore %param %34
304 %44 = OpAccessChain %_ptr_Function_19 %param %int_2
305 %45 = OpLoad %19 %44
306 %46 = OpAccessChain %_ptr_Function_v2float %param %int_0
307 %47 = OpLoad %v2float %46
308 %48 = OpImageSampleImplicitLod %v4float %45 %47
309 OpStore %outColor %48
310 OpReturn
311 OpFunctionEnd
312 )";
313 
314   const std::string post_defs =
315       R"(%main = OpFunction %void None %13
316 %36 = OpLabel
317 %37 = OpFunctionCall %void %main2
318 OpReturn
319 OpFunctionEnd
320 %foo_struct_S_t_vf2_vf21_ = OpFunction %void None %21
321 %s = OpFunctionParameter %_ptr_Function_S_t
322 %38 = OpLabel
323 %39 = OpAccessChain %_ptr_Function_19 %s %int_2
324 %40 = OpLoad %19 %39
325 %41 = OpAccessChain %_ptr_Function_v2float %s %int_0
326 %42 = OpLoad %v2float %41
327 %43 = OpImageSampleImplicitLod %v4float %40 %42
328 OpStore %outColor %43
329 OpReturn
330 OpFunctionEnd
331 )";
332 
333   SinglePassRunAndCheck<InlineOpaquePass>(
334       predefs + before + post_defs, predefs + after + post_defs, true, true);
335 }
336 
TEST_F(InlineOpaqueTest,NoInlineNoOpaque)337 TEST_F(InlineOpaqueTest, NoInlineNoOpaque) {
338   // Function without opaque interface is not inlined.
339   // #version 140
340   //
341   // in vec4 BaseColor;
342   //
343   // float foo(vec4 bar)
344   // {
345   //     return bar.x + bar.y;
346   // }
347   //
348   // void main()
349   // {
350   //     vec4 color = vec4(foo(BaseColor));
351   //     gl_FragColor = color;
352   // }
353 
354   const std::string assembly =
355       R"(OpCapability Shader
356 %1 = OpExtInstImport "GLSL.std.450"
357 OpMemoryModel Logical GLSL450
358 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
359 OpExecutionMode %main OriginUpperLeft
360 OpSource GLSL 140
361 OpName %main "main"
362 OpName %foo_vf4_ "foo(vf4;"
363 OpName %bar "bar"
364 OpName %color "color"
365 OpName %BaseColor "BaseColor"
366 OpName %param "param"
367 OpName %gl_FragColor "gl_FragColor"
368 %void = OpTypeVoid
369 %10 = OpTypeFunction %void
370 %float = OpTypeFloat 32
371 %v4float = OpTypeVector %float 4
372 %_ptr_Function_v4float = OpTypePointer Function %v4float
373 %14 = OpTypeFunction %float %_ptr_Function_v4float
374 %uint = OpTypeInt 32 0
375 %uint_0 = OpConstant %uint 0
376 %_ptr_Function_float = OpTypePointer Function %float
377 %uint_1 = OpConstant %uint 1
378 %_ptr_Input_v4float = OpTypePointer Input %v4float
379 %BaseColor = OpVariable %_ptr_Input_v4float Input
380 %_ptr_Output_v4float = OpTypePointer Output %v4float
381 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
382 %main = OpFunction %void None %10
383 %21 = OpLabel
384 %color = OpVariable %_ptr_Function_v4float Function
385 %param = OpVariable %_ptr_Function_v4float Function
386 %22 = OpLoad %v4float %BaseColor
387 OpStore %param %22
388 %23 = OpFunctionCall %float %foo_vf4_ %param
389 %24 = OpCompositeConstruct %v4float %23 %23 %23 %23
390 OpStore %color %24
391 %25 = OpLoad %v4float %color
392 OpStore %gl_FragColor %25
393 OpReturn
394 OpFunctionEnd
395 %foo_vf4_ = OpFunction %float None %14
396 %bar = OpFunctionParameter %_ptr_Function_v4float
397 %26 = OpLabel
398 %27 = OpAccessChain %_ptr_Function_float %bar %uint_0
399 %28 = OpLoad %float %27
400 %29 = OpAccessChain %_ptr_Function_float %bar %uint_1
401 %30 = OpLoad %float %29
402 %31 = OpFAdd %float %28 %30
403 OpReturnValue %31
404 OpFunctionEnd
405 )";
406 
407   SinglePassRunAndCheck<InlineOpaquePass>(assembly, assembly, true, true);
408 }
409 
410 }  // namespace
411 }  // namespace opt
412 }  // namespace spvtools
413