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 <memory>
17 #include <string>
18 #include <vector>
19 
20 #include "test/opt/pass_fixture.h"
21 #include "test/opt/pass_utils.h"
22 
23 namespace spvtools {
24 namespace opt {
25 namespace {
26 
27 using InlineTest = PassTest<::testing::Test>;
28 
TEST_F(InlineTest,Simple)29 TEST_F(InlineTest, Simple) {
30   // #version 140
31   //
32   // in vec4 BaseColor;
33   //
34   // float foo(vec4 bar)
35   // {
36   //     return bar.x + bar.y;
37   // }
38   //
39   // void main()
40   // {
41   //     vec4 color = vec4(foo(BaseColor));
42   //     gl_FragColor = color;
43   // }
44   const std::vector<const char*> predefs = {
45       // clang-format off
46                "OpCapability Shader",
47           "%1 = OpExtInstImport \"GLSL.std.450\"",
48                "OpMemoryModel Logical GLSL450",
49                "OpEntryPoint Fragment %main \"main\" %BaseColor %gl_FragColor",
50                "OpExecutionMode %main OriginUpperLeft",
51                "OpSource GLSL 140",
52                "OpName %main \"main\"",
53                "OpName %foo_vf4_ \"foo(vf4;\"",
54                "OpName %bar \"bar\"",
55                "OpName %color \"color\"",
56                "OpName %BaseColor \"BaseColor\"",
57                "OpName %param \"param\"",
58                "OpName %gl_FragColor \"gl_FragColor\"",
59        "%void = OpTypeVoid",
60          "%10 = OpTypeFunction %void",
61       "%float = OpTypeFloat 32",
62     "%v4float = OpTypeVector %float 4",
63 "%_ptr_Function_v4float = OpTypePointer Function %v4float",
64          "%14 = OpTypeFunction %float %_ptr_Function_v4float",
65        "%uint = OpTypeInt 32 0",
66      "%uint_0 = OpConstant %uint 0",
67 "%_ptr_Function_float = OpTypePointer Function %float",
68      "%uint_1 = OpConstant %uint 1",
69 "%_ptr_Input_v4float = OpTypePointer Input %v4float",
70   "%BaseColor = OpVariable %_ptr_Input_v4float Input",
71 "%_ptr_Output_v4float = OpTypePointer Output %v4float",
72 "%gl_FragColor = OpVariable %_ptr_Output_v4float Output",
73       // clang-format on
74   };
75 
76   const std::vector<const char*> nonEntryFuncs = {
77       // clang-format off
78    "%foo_vf4_ = OpFunction %float None %14",
79         "%bar = OpFunctionParameter %_ptr_Function_v4float",
80          "%26 = OpLabel",
81          "%27 = OpAccessChain %_ptr_Function_float %bar %uint_0",
82          "%28 = OpLoad %float %27",
83          "%29 = OpAccessChain %_ptr_Function_float %bar %uint_1",
84          "%30 = OpLoad %float %29",
85          "%31 = OpFAdd %float %28 %30",
86                "OpReturnValue %31",
87                "OpFunctionEnd",
88       // clang-format on
89   };
90 
91   const std::vector<const char*> before = {
92       // clang-format off
93        "%main = OpFunction %void None %10",
94          "%21 = OpLabel",
95       "%color = OpVariable %_ptr_Function_v4float Function",
96       "%param = OpVariable %_ptr_Function_v4float Function",
97          "%22 = OpLoad %v4float %BaseColor",
98                "OpStore %param %22",
99          "%23 = OpFunctionCall %float %foo_vf4_ %param",
100          "%24 = OpCompositeConstruct %v4float %23 %23 %23 %23",
101                "OpStore %color %24",
102          "%25 = OpLoad %v4float %color",
103                "OpStore %gl_FragColor %25",
104                "OpReturn",
105                "OpFunctionEnd",
106       // clang-format on
107   };
108 
109   const std::vector<const char*> after = {
110       // clang-format off
111        "%main = OpFunction %void None %10",
112          "%21 = OpLabel",
113          "%32 = OpVariable %_ptr_Function_float Function",
114       "%color = OpVariable %_ptr_Function_v4float Function",
115       "%param = OpVariable %_ptr_Function_v4float Function",
116          "%22 = OpLoad %v4float %BaseColor",
117                "OpStore %param %22",
118          "%34 = OpAccessChain %_ptr_Function_float %param %uint_0",
119          "%35 = OpLoad %float %34",
120          "%36 = OpAccessChain %_ptr_Function_float %param %uint_1",
121          "%37 = OpLoad %float %36",
122          "%38 = OpFAdd %float %35 %37",
123                "OpStore %32 %38",
124          "%23 = OpLoad %float %32",
125          "%24 = OpCompositeConstruct %v4float %23 %23 %23 %23",
126                "OpStore %color %24",
127          "%25 = OpLoad %v4float %color",
128                "OpStore %gl_FragColor %25",
129                "OpReturn",
130                "OpFunctionEnd",
131       // clang-format on
132   };
133   SinglePassRunAndCheck<InlineExhaustivePass>(
134       JoinAllInsts(Concat(Concat(predefs, before), nonEntryFuncs)),
135       JoinAllInsts(Concat(Concat(predefs, after), nonEntryFuncs)),
136       /* skip_nop = */ false, /* do_validate = */ true);
137 }
138 
TEST_F(InlineTest,Nested)139 TEST_F(InlineTest, Nested) {
140   // #version 140
141   //
142   // in vec4 BaseColor;
143   //
144   // float foo2(float f, float f2)
145   // {
146   //     return f * f2;
147   // }
148   //
149   // float foo(vec4 bar)
150   // {
151   //     return foo2(bar.x + bar.y, bar.z);
152   // }
153   //
154   // void main()
155   // {
156   //     vec4 color = vec4(foo(BaseColor));
157   //     gl_FragColor = color;
158   // }
159   const std::vector<const char*> predefs = {
160       // clang-format off
161                "OpCapability Shader",
162           "%1 = OpExtInstImport \"GLSL.std.450\"",
163                "OpMemoryModel Logical GLSL450",
164                "OpEntryPoint Fragment %main \"main\" %BaseColor %gl_FragColor",
165                "OpExecutionMode %main OriginUpperLeft",
166                "OpSource GLSL 140",
167                "OpName %main \"main\"",
168                "OpName %foo2_f1_f1_ \"foo2(f1;f1;\"",
169                "OpName %f \"f\"",
170                "OpName %f2 \"f2\"",
171                "OpName %foo_vf4_ \"foo(vf4;\"",
172                "OpName %bar \"bar\"",
173                "OpName %param \"param\"",
174                "OpName %param_0 \"param\"",
175                "OpName %color \"color\"",
176                "OpName %BaseColor \"BaseColor\"",
177                "OpName %param_1 \"param\"",
178                "OpName %gl_FragColor \"gl_FragColor\"",
179        "%void = OpTypeVoid",
180          "%15 = OpTypeFunction %void",
181       "%float = OpTypeFloat 32",
182 "%_ptr_Function_float = OpTypePointer Function %float",
183          "%18 = OpTypeFunction %float %_ptr_Function_float %_ptr_Function_float",
184     "%v4float = OpTypeVector %float 4",
185 "%_ptr_Function_v4float = OpTypePointer Function %v4float",
186          "%21 = OpTypeFunction %float %_ptr_Function_v4float",
187        "%uint = OpTypeInt 32 0",
188      "%uint_0 = OpConstant %uint 0",
189      "%uint_1 = OpConstant %uint 1",
190      "%uint_2 = OpConstant %uint 2",
191 "%_ptr_Input_v4float = OpTypePointer Input %v4float",
192   "%BaseColor = OpVariable %_ptr_Input_v4float Input",
193 "%_ptr_Output_v4float = OpTypePointer Output %v4float",
194 "%gl_FragColor = OpVariable %_ptr_Output_v4float Output",
195       // clang-format on
196   };
197 
198   const std::vector<const char*> nonEntryFuncs = {
199       // clang-format off
200 "%foo2_f1_f1_ = OpFunction %float None %18",
201           "%f = OpFunctionParameter %_ptr_Function_float",
202          "%f2 = OpFunctionParameter %_ptr_Function_float",
203          "%33 = OpLabel",
204          "%34 = OpLoad %float %f",
205          "%35 = OpLoad %float %f2",
206          "%36 = OpFMul %float %34 %35",
207                "OpReturnValue %36",
208                "OpFunctionEnd",
209    "%foo_vf4_ = OpFunction %float None %21",
210         "%bar = OpFunctionParameter %_ptr_Function_v4float",
211          "%37 = OpLabel",
212       "%param = OpVariable %_ptr_Function_float Function",
213     "%param_0 = OpVariable %_ptr_Function_float Function",
214          "%38 = OpAccessChain %_ptr_Function_float %bar %uint_0",
215          "%39 = OpLoad %float %38",
216          "%40 = OpAccessChain %_ptr_Function_float %bar %uint_1",
217          "%41 = OpLoad %float %40",
218          "%42 = OpFAdd %float %39 %41",
219                "OpStore %param %42",
220          "%43 = OpAccessChain %_ptr_Function_float %bar %uint_2",
221          "%44 = OpLoad %float %43",
222                "OpStore %param_0 %44",
223          "%45 = OpFunctionCall %float %foo2_f1_f1_ %param %param_0",
224                "OpReturnValue %45",
225                "OpFunctionEnd",
226       // clang-format on
227   };
228 
229   const std::vector<const char*> before = {
230       // clang-format off
231        "%main = OpFunction %void None %15",
232          "%28 = OpLabel",
233       "%color = OpVariable %_ptr_Function_v4float Function",
234     "%param_1 = OpVariable %_ptr_Function_v4float Function",
235          "%29 = OpLoad %v4float %BaseColor",
236                "OpStore %param_1 %29",
237          "%30 = OpFunctionCall %float %foo_vf4_ %param_1",
238          "%31 = OpCompositeConstruct %v4float %30 %30 %30 %30",
239                "OpStore %color %31",
240          "%32 = OpLoad %v4float %color",
241                "OpStore %gl_FragColor %32",
242                "OpReturn",
243                "OpFunctionEnd",
244       // clang-format on
245   };
246 
247   const std::vector<const char*> after = {
248       // clang-format off
249        "%main = OpFunction %void None %15",
250          "%28 = OpLabel",
251          "%58 = OpVariable %_ptr_Function_float Function",
252          "%46 = OpVariable %_ptr_Function_float Function",
253          "%47 = OpVariable %_ptr_Function_float Function",
254          "%48 = OpVariable %_ptr_Function_float Function",
255       "%color = OpVariable %_ptr_Function_v4float Function",
256     "%param_1 = OpVariable %_ptr_Function_v4float Function",
257          "%29 = OpLoad %v4float %BaseColor",
258                "OpStore %param_1 %29",
259          "%50 = OpAccessChain %_ptr_Function_float %param_1 %uint_0",
260          "%51 = OpLoad %float %50",
261          "%52 = OpAccessChain %_ptr_Function_float %param_1 %uint_1",
262          "%53 = OpLoad %float %52",
263          "%54 = OpFAdd %float %51 %53",
264                "OpStore %46 %54",
265          "%55 = OpAccessChain %_ptr_Function_float %param_1 %uint_2",
266          "%56 = OpLoad %float %55",
267                "OpStore %47 %56",
268          "%60 = OpLoad %float %46",
269          "%61 = OpLoad %float %47",
270          "%62 = OpFMul %float %60 %61",
271                "OpStore %58 %62",
272          "%57 = OpLoad %float %58",
273                "OpStore %48 %57",
274          "%30 = OpLoad %float %48",
275          "%31 = OpCompositeConstruct %v4float %30 %30 %30 %30",
276                "OpStore %color %31",
277          "%32 = OpLoad %v4float %color",
278                "OpStore %gl_FragColor %32",
279                "OpReturn",
280                "OpFunctionEnd",
281       // clang-format on
282   };
283   SinglePassRunAndCheck<InlineExhaustivePass>(
284       JoinAllInsts(Concat(Concat(predefs, before), nonEntryFuncs)),
285       JoinAllInsts(Concat(Concat(predefs, after), nonEntryFuncs)),
286       /* skip_nop = */ false, /* do_validate = */ true);
287 }
288 
TEST_F(InlineTest,InOutParameter)289 TEST_F(InlineTest, InOutParameter) {
290   // #version 400
291   //
292   // in vec4 Basecolor;
293   //
294   // void foo(inout vec4 bar)
295   // {
296   //     bar.z = bar.x + bar.y;
297   // }
298   //
299   // void main()
300   // {
301   //     vec4 b = Basecolor;
302   //     foo(b);
303   //     vec4 color = vec4(b.z);
304   //     gl_FragColor = color;
305   // }
306   const std::vector<const char*> predefs = {
307       // clang-format off
308                "OpCapability Shader",
309           "%1 = OpExtInstImport \"GLSL.std.450\"",
310                "OpMemoryModel Logical GLSL450",
311                "OpEntryPoint Fragment %main \"main\" %Basecolor %gl_FragColor",
312                "OpExecutionMode %main OriginUpperLeft",
313                "OpSource GLSL 400",
314                "OpName %main \"main\"",
315                "OpName %foo_vf4_ \"foo(vf4;\"",
316                "OpName %bar \"bar\"",
317                "OpName %b \"b\"",
318                "OpName %Basecolor \"Basecolor\"",
319                "OpName %param \"param\"",
320                "OpName %color \"color\"",
321                "OpName %gl_FragColor \"gl_FragColor\"",
322        "%void = OpTypeVoid",
323          "%11 = OpTypeFunction %void",
324       "%float = OpTypeFloat 32",
325     "%v4float = OpTypeVector %float 4",
326 "%_ptr_Function_v4float = OpTypePointer Function %v4float",
327          "%15 = OpTypeFunction %void %_ptr_Function_v4float",
328        "%uint = OpTypeInt 32 0",
329      "%uint_0 = OpConstant %uint 0",
330 "%_ptr_Function_float = OpTypePointer Function %float",
331      "%uint_1 = OpConstant %uint 1",
332      "%uint_2 = OpConstant %uint 2",
333 "%_ptr_Input_v4float = OpTypePointer Input %v4float",
334   "%Basecolor = OpVariable %_ptr_Input_v4float Input",
335 "%_ptr_Output_v4float = OpTypePointer Output %v4float",
336 "%gl_FragColor = OpVariable %_ptr_Output_v4float Output",
337       // clang-format on
338   };
339 
340   const std::vector<const char*> nonEntryFuncs = {
341       // clang-format off
342    "%foo_vf4_ = OpFunction %void None %15",
343         "%bar = OpFunctionParameter %_ptr_Function_v4float",
344          "%32 = OpLabel",
345          "%33 = OpAccessChain %_ptr_Function_float %bar %uint_0",
346          "%34 = OpLoad %float %33",
347          "%35 = OpAccessChain %_ptr_Function_float %bar %uint_1",
348          "%36 = OpLoad %float %35",
349          "%37 = OpFAdd %float %34 %36",
350          "%38 = OpAccessChain %_ptr_Function_float %bar %uint_2",
351                "OpStore %38 %37",
352                "OpReturn",
353                "OpFunctionEnd",
354       // clang-format on
355   };
356 
357   const std::vector<const char*> before = {
358       // clang-format off
359        "%main = OpFunction %void None %11",
360          "%23 = OpLabel",
361           "%b = OpVariable %_ptr_Function_v4float Function",
362       "%param = OpVariable %_ptr_Function_v4float Function",
363       "%color = OpVariable %_ptr_Function_v4float Function",
364          "%24 = OpLoad %v4float %Basecolor",
365                "OpStore %b %24",
366          "%25 = OpLoad %v4float %b",
367                "OpStore %param %25",
368          "%26 = OpFunctionCall %void %foo_vf4_ %param",
369          "%27 = OpLoad %v4float %param",
370                "OpStore %b %27",
371          "%28 = OpAccessChain %_ptr_Function_float %b %uint_2",
372          "%29 = OpLoad %float %28",
373          "%30 = OpCompositeConstruct %v4float %29 %29 %29 %29",
374                "OpStore %color %30",
375          "%31 = OpLoad %v4float %color",
376                "OpStore %gl_FragColor %31",
377                "OpReturn",
378                "OpFunctionEnd",
379       // clang-format on
380   };
381 
382   const std::vector<const char*> after = {
383       // clang-format off
384        "%main = OpFunction %void None %11",
385          "%23 = OpLabel",
386           "%b = OpVariable %_ptr_Function_v4float Function",
387       "%param = OpVariable %_ptr_Function_v4float Function",
388       "%color = OpVariable %_ptr_Function_v4float Function",
389          "%24 = OpLoad %v4float %Basecolor",
390                "OpStore %b %24",
391          "%25 = OpLoad %v4float %b",
392                "OpStore %param %25",
393          "%40 = OpAccessChain %_ptr_Function_float %param %uint_0",
394          "%41 = OpLoad %float %40",
395          "%42 = OpAccessChain %_ptr_Function_float %param %uint_1",
396          "%43 = OpLoad %float %42",
397          "%44 = OpFAdd %float %41 %43",
398          "%45 = OpAccessChain %_ptr_Function_float %param %uint_2",
399                "OpStore %45 %44",
400          "%27 = OpLoad %v4float %param",
401                "OpStore %b %27",
402          "%28 = OpAccessChain %_ptr_Function_float %b %uint_2",
403          "%29 = OpLoad %float %28",
404          "%30 = OpCompositeConstruct %v4float %29 %29 %29 %29",
405                "OpStore %color %30",
406          "%31 = OpLoad %v4float %color",
407                "OpStore %gl_FragColor %31",
408                "OpReturn",
409                "OpFunctionEnd",
410       // clang-format on
411   };
412   SinglePassRunAndCheck<InlineExhaustivePass>(
413       JoinAllInsts(Concat(Concat(predefs, before), nonEntryFuncs)),
414       JoinAllInsts(Concat(Concat(predefs, after), nonEntryFuncs)),
415       /* skip_nop = */ false, /* do_validate = */ true);
416 }
417 
TEST_F(InlineTest,BranchInCallee)418 TEST_F(InlineTest, BranchInCallee) {
419   // #version 140
420   //
421   // in vec4 BaseColor;
422   //
423   // float foo(vec4 bar)
424   // {
425   //     float r = bar.x;
426   //     if (r < 0.0)
427   //         r = -r;
428   //     return r;
429   // }
430   //
431   // void main()
432   // {
433   //     vec4 color = vec4(foo(BaseColor));
434   //
435   //     gl_FragColor = color;
436   // }
437   const std::vector<const char*> predefs = {
438       // clang-format off
439                "OpCapability Shader",
440           "%1 = OpExtInstImport \"GLSL.std.450\"",
441                "OpMemoryModel Logical GLSL450",
442                "OpEntryPoint Fragment %main \"main\" %BaseColor %gl_FragColor",
443                "OpExecutionMode %main OriginUpperLeft",
444                "OpSource GLSL 140",
445                "OpName %main \"main\"",
446                "OpName %foo_vf4_ \"foo(vf4;\"",
447                "OpName %bar \"bar\"",
448                "OpName %r \"r\"",
449                "OpName %color \"color\"",
450                "OpName %BaseColor \"BaseColor\"",
451                "OpName %param \"param\"",
452                "OpName %gl_FragColor \"gl_FragColor\"",
453        "%void = OpTypeVoid",
454          "%11 = OpTypeFunction %void",
455       "%float = OpTypeFloat 32",
456     "%v4float = OpTypeVector %float 4",
457 "%_ptr_Function_v4float = OpTypePointer Function %v4float",
458          "%15 = OpTypeFunction %float %_ptr_Function_v4float",
459 "%_ptr_Function_float = OpTypePointer Function %float",
460        "%uint = OpTypeInt 32 0",
461      "%uint_0 = OpConstant %uint 0",
462     "%float_0 = OpConstant %float 0",
463        "%bool = OpTypeBool",
464 "%_ptr_Input_v4float = OpTypePointer Input %v4float",
465   "%BaseColor = OpVariable %_ptr_Input_v4float Input",
466 "%_ptr_Output_v4float = OpTypePointer Output %v4float",
467 "%gl_FragColor = OpVariable %_ptr_Output_v4float Output",
468       // clang-format on
469   };
470 
471   const std::vector<const char*> nonEntryFuncs = {
472       // clang-format off
473    "%foo_vf4_ = OpFunction %float None %15",
474         "%bar = OpFunctionParameter %_ptr_Function_v4float",
475          "%28 = OpLabel",
476           "%r = OpVariable %_ptr_Function_float Function",
477          "%29 = OpAccessChain %_ptr_Function_float %bar %uint_0",
478          "%30 = OpLoad %float %29",
479                "OpStore %r %30",
480          "%31 = OpLoad %float %r",
481          "%32 = OpFOrdLessThan %bool %31 %float_0",
482                "OpSelectionMerge %33 None",
483                "OpBranchConditional %32 %34 %33",
484          "%34 = OpLabel",
485          "%35 = OpLoad %float %r",
486          "%36 = OpFNegate %float %35",
487                "OpStore %r %36",
488                "OpBranch %33",
489          "%33 = OpLabel",
490          "%37 = OpLoad %float %r",
491                "OpReturnValue %37",
492                "OpFunctionEnd",
493       // clang-format on
494   };
495 
496   const std::vector<const char*> before = {
497       // clang-format off
498        "%main = OpFunction %void None %11",
499          "%23 = OpLabel",
500       "%color = OpVariable %_ptr_Function_v4float Function",
501       "%param = OpVariable %_ptr_Function_v4float Function",
502          "%24 = OpLoad %v4float %BaseColor",
503                "OpStore %param %24",
504          "%25 = OpFunctionCall %float %foo_vf4_ %param",
505          "%26 = OpCompositeConstruct %v4float %25 %25 %25 %25",
506                "OpStore %color %26",
507          "%27 = OpLoad %v4float %color",
508                "OpStore %gl_FragColor %27",
509                "OpReturn",
510                "OpFunctionEnd",
511       // clang-format on
512   };
513 
514   const std::vector<const char*> after = {
515       // clang-format off
516        "%main = OpFunction %void None %11",
517          "%23 = OpLabel",
518          "%38 = OpVariable %_ptr_Function_float Function",
519          "%39 = OpVariable %_ptr_Function_float Function",
520       "%color = OpVariable %_ptr_Function_v4float Function",
521       "%param = OpVariable %_ptr_Function_v4float Function",
522          "%24 = OpLoad %v4float %BaseColor",
523                "OpStore %param %24",
524          "%41 = OpAccessChain %_ptr_Function_float %param %uint_0",
525          "%42 = OpLoad %float %41",
526                "OpStore %38 %42",
527          "%43 = OpLoad %float %38",
528          "%44 = OpFOrdLessThan %bool %43 %float_0",
529                "OpSelectionMerge %48 None",
530                "OpBranchConditional %44 %45 %48",
531          "%45 = OpLabel",
532          "%46 = OpLoad %float %38",
533          "%47 = OpFNegate %float %46",
534                "OpStore %38 %47",
535                "OpBranch %48",
536          "%48 = OpLabel",
537          "%49 = OpLoad %float %38",
538                "OpStore %39 %49",
539          "%25 = OpLoad %float %39",
540          "%26 = OpCompositeConstruct %v4float %25 %25 %25 %25",
541                "OpStore %color %26",
542          "%27 = OpLoad %v4float %color",
543                "OpStore %gl_FragColor %27",
544                "OpReturn",
545                "OpFunctionEnd",
546       // clang-format on
547   };
548   SinglePassRunAndCheck<InlineExhaustivePass>(
549       JoinAllInsts(Concat(Concat(predefs, before), nonEntryFuncs)),
550       JoinAllInsts(Concat(Concat(predefs, after), nonEntryFuncs)),
551       /* skip_nop = */ false, /* do_validate = */ true);
552 }
553 
TEST_F(InlineTest,PhiAfterCall)554 TEST_F(InlineTest, PhiAfterCall) {
555   // #version 140
556   //
557   // in vec4 BaseColor;
558   //
559   // float foo(float bar)
560   // {
561   //     float r = bar;
562   //     if (r < 0.0)
563   //         r = -r;
564   //     return r;
565   // }
566   //
567   // void main()
568   // {
569   //     vec4 color = BaseColor;
570   //     if (foo(color.x) > 2.0 && foo(color.y) > 2.0)
571   //         color = vec4(0.0);
572   //     gl_FragColor = color;
573   // }
574   const std::vector<const char*> predefs = {
575       // clang-format off
576                "OpCapability Shader",
577           "%1 = OpExtInstImport \"GLSL.std.450\"",
578                "OpMemoryModel Logical GLSL450",
579                "OpEntryPoint Fragment %main \"main\" %BaseColor %gl_FragColor",
580                "OpExecutionMode %main OriginUpperLeft",
581                "OpSource GLSL 140",
582                "OpName %main \"main\"",
583                "OpName %foo_f1_ \"foo(f1;\"",
584                "OpName %bar \"bar\"",
585                "OpName %r \"r\"",
586                "OpName %color \"color\"",
587                "OpName %BaseColor \"BaseColor\"",
588                "OpName %param \"param\"",
589                "OpName %param_0 \"param\"",
590                "OpName %gl_FragColor \"gl_FragColor\"",
591        "%void = OpTypeVoid",
592          "%12 = OpTypeFunction %void",
593       "%float = OpTypeFloat 32",
594 "%_ptr_Function_float = OpTypePointer Function %float",
595          "%15 = OpTypeFunction %float %_ptr_Function_float",
596     "%float_0 = OpConstant %float 0",
597        "%bool = OpTypeBool",
598     "%v4float = OpTypeVector %float 4",
599 "%_ptr_Function_v4float = OpTypePointer Function %v4float",
600 "%_ptr_Input_v4float = OpTypePointer Input %v4float",
601   "%BaseColor = OpVariable %_ptr_Input_v4float Input",
602        "%uint = OpTypeInt 32 0",
603      "%uint_0 = OpConstant %uint 0",
604     "%float_2 = OpConstant %float 2",
605      "%uint_1 = OpConstant %uint 1",
606          "%25 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0",
607 "%_ptr_Output_v4float = OpTypePointer Output %v4float",
608 "%gl_FragColor = OpVariable %_ptr_Output_v4float Output",
609       // clang-format on
610   };
611 
612   const std::vector<const char*> nonEntryFuncs = {
613       // clang-format off
614     "%foo_f1_ = OpFunction %float None %15",
615         "%bar = OpFunctionParameter %_ptr_Function_float",
616          "%43 = OpLabel",
617           "%r = OpVariable %_ptr_Function_float Function",
618          "%44 = OpLoad %float %bar",
619                "OpStore %r %44",
620          "%45 = OpLoad %float %r",
621          "%46 = OpFOrdLessThan %bool %45 %float_0",
622                "OpSelectionMerge %47 None",
623                "OpBranchConditional %46 %48 %47",
624          "%48 = OpLabel",
625          "%49 = OpLoad %float %r",
626          "%50 = OpFNegate %float %49",
627                "OpStore %r %50",
628                "OpBranch %47",
629          "%47 = OpLabel",
630          "%51 = OpLoad %float %r",
631                "OpReturnValue %51",
632                "OpFunctionEnd",
633       // clang-format on
634   };
635 
636   const std::vector<const char*> before = {
637       // clang-format off
638        "%main = OpFunction %void None %12",
639          "%27 = OpLabel",
640       "%color = OpVariable %_ptr_Function_v4float Function",
641       "%param = OpVariable %_ptr_Function_float Function",
642     "%param_0 = OpVariable %_ptr_Function_float Function",
643          "%28 = OpLoad %v4float %BaseColor",
644                "OpStore %color %28",
645          "%29 = OpAccessChain %_ptr_Function_float %color %uint_0",
646          "%30 = OpLoad %float %29",
647                "OpStore %param %30",
648          "%31 = OpFunctionCall %float %foo_f1_ %param",
649          "%32 = OpFOrdGreaterThan %bool %31 %float_2",
650                "OpSelectionMerge %33 None",
651                "OpBranchConditional %32 %34 %33",
652          "%34 = OpLabel",
653          "%35 = OpAccessChain %_ptr_Function_float %color %uint_1",
654          "%36 = OpLoad %float %35",
655                "OpStore %param_0 %36",
656          "%37 = OpFunctionCall %float %foo_f1_ %param_0",
657          "%38 = OpFOrdGreaterThan %bool %37 %float_2",
658                "OpBranch %33",
659          "%33 = OpLabel",
660          "%39 = OpPhi %bool %32 %27 %38 %34",
661                "OpSelectionMerge %40 None",
662                "OpBranchConditional %39 %41 %40",
663          "%41 = OpLabel",
664                "OpStore %color %25",
665                "OpBranch %40",
666          "%40 = OpLabel",
667          "%42 = OpLoad %v4float %color",
668                "OpStore %gl_FragColor %42",
669                "OpReturn",
670                "OpFunctionEnd",
671       // clang-format on
672   };
673 
674   const std::vector<const char*> after = {
675       // clang-format off
676        "%main = OpFunction %void None %12",
677          "%27 = OpLabel",
678          "%63 = OpVariable %_ptr_Function_float Function",
679          "%64 = OpVariable %_ptr_Function_float Function",
680          "%52 = OpVariable %_ptr_Function_float Function",
681          "%53 = OpVariable %_ptr_Function_float Function",
682       "%color = OpVariable %_ptr_Function_v4float Function",
683       "%param = OpVariable %_ptr_Function_float Function",
684     "%param_0 = OpVariable %_ptr_Function_float Function",
685          "%28 = OpLoad %v4float %BaseColor",
686                "OpStore %color %28",
687          "%29 = OpAccessChain %_ptr_Function_float %color %uint_0",
688          "%30 = OpLoad %float %29",
689                "OpStore %param %30",
690          "%55 = OpLoad %float %param",
691                "OpStore %52 %55",
692          "%56 = OpLoad %float %52",
693          "%57 = OpFOrdLessThan %bool %56 %float_0",
694                "OpSelectionMerge %61 None",
695                "OpBranchConditional %57 %58 %61",
696          "%58 = OpLabel",
697          "%59 = OpLoad %float %52",
698          "%60 = OpFNegate %float %59",
699                "OpStore %52 %60",
700                "OpBranch %61",
701          "%61 = OpLabel",
702          "%62 = OpLoad %float %52",
703                "OpStore %53 %62",
704          "%31 = OpLoad %float %53",
705          "%32 = OpFOrdGreaterThan %bool %31 %float_2",
706                "OpSelectionMerge %33 None",
707                "OpBranchConditional %32 %34 %33",
708          "%34 = OpLabel",
709          "%35 = OpAccessChain %_ptr_Function_float %color %uint_1",
710          "%36 = OpLoad %float %35",
711                "OpStore %param_0 %36",
712          "%66 = OpLoad %float %param_0",
713                "OpStore %63 %66",
714          "%67 = OpLoad %float %63",
715          "%68 = OpFOrdLessThan %bool %67 %float_0",
716                "OpSelectionMerge %72 None",
717                "OpBranchConditional %68 %69 %72",
718          "%69 = OpLabel",
719          "%70 = OpLoad %float %63",
720          "%71 = OpFNegate %float %70",
721                "OpStore %63 %71",
722                "OpBranch %72",
723          "%72 = OpLabel",
724          "%73 = OpLoad %float %63",
725                "OpStore %64 %73",
726          "%37 = OpLoad %float %64",
727          "%38 = OpFOrdGreaterThan %bool %37 %float_2",
728                "OpBranch %33",
729          "%33 = OpLabel",
730          "%39 = OpPhi %bool %32 %61 %38 %72",
731                "OpSelectionMerge %40 None",
732                "OpBranchConditional %39 %41 %40",
733          "%41 = OpLabel",
734                "OpStore %color %25",
735                "OpBranch %40",
736          "%40 = OpLabel",
737          "%42 = OpLoad %v4float %color",
738                "OpStore %gl_FragColor %42",
739                "OpReturn",
740                "OpFunctionEnd",
741       // clang-format on
742   };
743   SinglePassRunAndCheck<InlineExhaustivePass>(
744       JoinAllInsts(Concat(Concat(predefs, before), nonEntryFuncs)),
745       JoinAllInsts(Concat(Concat(predefs, after), nonEntryFuncs)),
746       /* skip_nop = */ false, /* do_validate = */ true);
747 }
748 
TEST_F(InlineTest,OpSampledImageOutOfBlock)749 TEST_F(InlineTest, OpSampledImageOutOfBlock) {
750   // #version 450
751   //
752   // uniform texture2D t2D;
753   // uniform sampler samp;
754   // out vec4 FragColor;
755   // in vec4 BaseColor;
756   //
757   // float foo(vec4 bar)
758   // {
759   //     float r = bar.x;
760   //     if (r < 0.0)
761   //         r = -r;
762   //     return r;
763   // }
764   //
765   // void main()
766   // {
767   //     vec4 color1 = texture(sampler2D(t2D, samp), vec2(1.0));
768   //     vec4 color2 = vec4(foo(BaseColor));
769   //     vec4 color3 = texture(sampler2D(t2D, samp), vec2(0.5));
770   //     FragColor = (color1 + color2 + color3)/3;
771   // }
772   //
773   // Note: the before SPIR-V will need to be edited to create a use of
774   // the OpSampledImage across the function call.
775   const std::vector<const char*> predefs = {
776       // clang-format off
777                "OpCapability Shader",
778           "%1 = OpExtInstImport \"GLSL.std.450\"",
779                "OpMemoryModel Logical GLSL450",
780                "OpEntryPoint Fragment %main \"main\" %BaseColor %FragColor",
781                "OpExecutionMode %main OriginUpperLeft",
782                "OpSource GLSL 450",
783                "OpName %main \"main\"",
784                "OpName %foo_vf4_ \"foo(vf4;\"",
785                "OpName %bar \"bar\"",
786                "OpName %r \"r\"",
787                "OpName %color1 \"color1\"",
788                "OpName %t2D \"t2D\"",
789                "OpName %samp \"samp\"",
790                "OpName %color2 \"color2\"",
791                "OpName %BaseColor \"BaseColor\"",
792                "OpName %param \"param\"",
793                "OpName %color3 \"color3\"",
794                "OpName %FragColor \"FragColor\"",
795                "OpDecorate %t2D DescriptorSet 0",
796                "OpDecorate %samp DescriptorSet 0",
797        "%void = OpTypeVoid",
798          "%15 = OpTypeFunction %void",
799       "%float = OpTypeFloat 32",
800     "%v4float = OpTypeVector %float 4",
801 "%_ptr_Function_v4float = OpTypePointer Function %v4float",
802          "%19 = OpTypeFunction %float %_ptr_Function_v4float",
803 "%_ptr_Function_float = OpTypePointer Function %float",
804        "%uint = OpTypeInt 32 0",
805      "%uint_0 = OpConstant %uint 0",
806     "%float_0 = OpConstant %float 0",
807        "%bool = OpTypeBool",
808          "%25 = OpTypeImage %float 2D 0 0 0 1 Unknown",
809 "%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25",
810         "%t2D = OpVariable %_ptr_UniformConstant_25 UniformConstant",
811          "%27 = OpTypeSampler",
812 "%_ptr_UniformConstant_27 = OpTypePointer UniformConstant %27",
813        "%samp = OpVariable %_ptr_UniformConstant_27 UniformConstant",
814          "%29 = OpTypeSampledImage %25",
815     "%v2float = OpTypeVector %float 2",
816     "%float_1 = OpConstant %float 1",
817          "%32 = OpConstantComposite %v2float %float_1 %float_1",
818 "%_ptr_Input_v4float = OpTypePointer Input %v4float",
819   "%BaseColor = OpVariable %_ptr_Input_v4float Input",
820   "%float_0_5 = OpConstant %float 0.5",
821          "%35 = OpConstantComposite %v2float %float_0_5 %float_0_5",
822 "%_ptr_Output_v4float = OpTypePointer Output %v4float",
823   "%FragColor = OpVariable %_ptr_Output_v4float Output",
824     "%float_3 = OpConstant %float 3",
825       // clang-format on
826   };
827 
828   const std::vector<const char*> nonEntryFuncs = {
829       // clang-format off
830    "%foo_vf4_ = OpFunction %float None %19",
831         "%bar = OpFunctionParameter %_ptr_Function_v4float",
832          "%56 = OpLabel",
833           "%r = OpVariable %_ptr_Function_float Function",
834          "%57 = OpAccessChain %_ptr_Function_float %bar %uint_0",
835          "%58 = OpLoad %float %57",
836                "OpStore %r %58",
837          "%59 = OpLoad %float %r",
838          "%60 = OpFOrdLessThan %bool %59 %float_0",
839                "OpSelectionMerge %61 None",
840                "OpBranchConditional %60 %62 %61",
841          "%62 = OpLabel",
842          "%63 = OpLoad %float %r",
843          "%64 = OpFNegate %float %63",
844                "OpStore %r %64",
845                "OpBranch %61",
846          "%61 = OpLabel",
847          "%65 = OpLoad %float %r",
848                "OpReturnValue %65",
849                "OpFunctionEnd",
850       // clang-format on
851   };
852 
853   const std::vector<const char*> before = {
854       // clang-format off
855        "%main = OpFunction %void None %15",
856          "%38 = OpLabel",
857      "%color1 = OpVariable %_ptr_Function_v4float Function",
858      "%color2 = OpVariable %_ptr_Function_v4float Function",
859       "%param = OpVariable %_ptr_Function_v4float Function",
860      "%color3 = OpVariable %_ptr_Function_v4float Function",
861          "%39 = OpLoad %25 %t2D",
862          "%40 = OpLoad %27 %samp",
863          "%41 = OpSampledImage %29 %39 %40",
864          "%42 = OpImageSampleImplicitLod %v4float %41 %32",
865                "OpStore %color1 %42",
866          "%43 = OpLoad %v4float %BaseColor",
867                "OpStore %param %43",
868          "%44 = OpFunctionCall %float %foo_vf4_ %param",
869          "%45 = OpCompositeConstruct %v4float %44 %44 %44 %44",
870                "OpStore %color2 %45",
871          "%46 = OpLoad %25 %t2D",
872          "%47 = OpLoad %27 %samp",
873          "%48 = OpImageSampleImplicitLod %v4float %41 %35",
874                "OpStore %color3 %48",
875          "%49 = OpLoad %v4float %color1",
876          "%50 = OpLoad %v4float %color2",
877          "%51 = OpFAdd %v4float %49 %50",
878          "%52 = OpLoad %v4float %color3",
879          "%53 = OpFAdd %v4float %51 %52",
880          "%54 = OpCompositeConstruct %v4float %float_3 %float_3 %float_3 %float_3",
881          "%55 = OpFDiv %v4float %53 %54",
882                "OpStore %FragColor %55",
883                "OpReturn",
884                "OpFunctionEnd",
885       // clang-format on
886   };
887 
888   const std::vector<const char*> after = {
889       // clang-format off
890        "%main = OpFunction %void None %15",
891          "%38 = OpLabel",
892          "%66 = OpVariable %_ptr_Function_float Function",
893          "%67 = OpVariable %_ptr_Function_float Function",
894      "%color1 = OpVariable %_ptr_Function_v4float Function",
895      "%color2 = OpVariable %_ptr_Function_v4float Function",
896       "%param = OpVariable %_ptr_Function_v4float Function",
897      "%color3 = OpVariable %_ptr_Function_v4float Function",
898          "%39 = OpLoad %25 %t2D",
899          "%40 = OpLoad %27 %samp",
900          "%41 = OpSampledImage %29 %39 %40",
901          "%42 = OpImageSampleImplicitLod %v4float %41 %32",
902                "OpStore %color1 %42",
903          "%43 = OpLoad %v4float %BaseColor",
904                "OpStore %param %43",
905          "%69 = OpAccessChain %_ptr_Function_float %param %uint_0",
906          "%70 = OpLoad %float %69",
907                "OpStore %66 %70",
908          "%71 = OpLoad %float %66",
909          "%72 = OpFOrdLessThan %bool %71 %float_0",
910                "OpSelectionMerge %76 None",
911                "OpBranchConditional %72 %73 %76",
912          "%73 = OpLabel",
913          "%74 = OpLoad %float %66",
914          "%75 = OpFNegate %float %74",
915                "OpStore %66 %75",
916                "OpBranch %76",
917          "%76 = OpLabel",
918          "%77 = OpLoad %float %66",
919                "OpStore %67 %77",
920          "%44 = OpLoad %float %67",
921          "%45 = OpCompositeConstruct %v4float %44 %44 %44 %44",
922                "OpStore %color2 %45",
923          "%46 = OpLoad %25 %t2D",
924          "%47 = OpLoad %27 %samp",
925          "%78 = OpSampledImage %29 %39 %40",
926          "%48 = OpImageSampleImplicitLod %v4float %78 %35",
927                "OpStore %color3 %48",
928          "%49 = OpLoad %v4float %color1",
929          "%50 = OpLoad %v4float %color2",
930          "%51 = OpFAdd %v4float %49 %50",
931          "%52 = OpLoad %v4float %color3",
932          "%53 = OpFAdd %v4float %51 %52",
933          "%54 = OpCompositeConstruct %v4float %float_3 %float_3 %float_3 %float_3",
934          "%55 = OpFDiv %v4float %53 %54",
935                "OpStore %FragColor %55",
936                "OpReturn",
937                "OpFunctionEnd",
938       // clang-format on
939   };
940   SinglePassRunAndCheck<InlineExhaustivePass>(
941       JoinAllInsts(Concat(Concat(predefs, before), nonEntryFuncs)),
942       JoinAllInsts(Concat(Concat(predefs, after), nonEntryFuncs)),
943       /* skip_nop = */ false, /* do_validate = */ true);
944 }
945 
TEST_F(InlineTest,OpImageOutOfBlock)946 TEST_F(InlineTest, OpImageOutOfBlock) {
947   // #version 450
948   //
949   // uniform texture2D t2D;
950   // uniform sampler samp;
951   // uniform sampler samp2;
952   //
953   // out vec4 FragColor;
954   //
955   // in vec4 BaseColor;
956   //
957   // float foo(vec4 bar)
958   // {
959   //     float r = bar.x;
960   //     if (r < 0.0)
961   //         r = -r;
962   //     return r;
963   // }
964   //
965   // void main()
966   // {
967   //     vec4 color1 = texture(sampler2D(t2D, samp), vec2(1.0));
968   //     vec4 color2 = vec4(foo(BaseColor));
969   //     vec4 color3 = texture(sampler2D(t2D, samp2), vec2(0.5));
970   //     FragColor = (color1 + color2 + color3)/3;
971   // }
972   // Note: the before SPIR-V will need to be edited to create an OpImage
973   // from the first OpSampledImage, place it before the call and use it
974   // in the second OpSampledImage following the call.
975   const std::vector<const char*> predefs = {
976       // clang-format off
977                "OpCapability Shader",
978           "%1 = OpExtInstImport \"GLSL.std.450\"",
979                "OpMemoryModel Logical GLSL450",
980                "OpEntryPoint Fragment %main \"main\" %BaseColor %FragColor",
981                "OpExecutionMode %main OriginUpperLeft",
982                "OpSource GLSL 450",
983                "OpName %main \"main\"",
984                "OpName %foo_vf4_ \"foo(vf4;\"",
985                "OpName %bar \"bar\"",
986                "OpName %r \"r\"",
987                "OpName %color1 \"color1\"",
988                "OpName %t2D \"t2D\"",
989                "OpName %samp \"samp\"",
990                "OpName %color2 \"color2\"",
991                "OpName %BaseColor \"BaseColor\"",
992                "OpName %param \"param\"",
993                "OpName %color3 \"color3\"",
994                "OpName %samp2 \"samp2\"",
995                "OpName %FragColor \"FragColor\"",
996                "OpDecorate %t2D DescriptorSet 0",
997                "OpDecorate %samp DescriptorSet 0",
998                "OpDecorate %samp2 DescriptorSet 0",
999        "%void = OpTypeVoid",
1000          "%16 = OpTypeFunction %void",
1001       "%float = OpTypeFloat 32",
1002     "%v4float = OpTypeVector %float 4",
1003 "%_ptr_Function_v4float = OpTypePointer Function %v4float",
1004          "%20 = OpTypeFunction %float %_ptr_Function_v4float",
1005 "%_ptr_Function_float = OpTypePointer Function %float",
1006        "%uint = OpTypeInt 32 0",
1007      "%uint_0 = OpConstant %uint 0",
1008     "%float_0 = OpConstant %float 0",
1009        "%bool = OpTypeBool",
1010          "%26 = OpTypeImage %float 2D 0 0 0 1 Unknown",
1011 "%_ptr_UniformConstant_26 = OpTypePointer UniformConstant %26",
1012         "%t2D = OpVariable %_ptr_UniformConstant_26 UniformConstant",
1013          "%28 = OpTypeSampler",
1014 "%_ptr_UniformConstant_28 = OpTypePointer UniformConstant %28",
1015        "%samp = OpVariable %_ptr_UniformConstant_28 UniformConstant",
1016          "%30 = OpTypeSampledImage %26",
1017     "%v2float = OpTypeVector %float 2",
1018     "%float_1 = OpConstant %float 1",
1019          "%33 = OpConstantComposite %v2float %float_1 %float_1",
1020 "%_ptr_Input_v4float = OpTypePointer Input %v4float",
1021   "%BaseColor = OpVariable %_ptr_Input_v4float Input",
1022       "%samp2 = OpVariable %_ptr_UniformConstant_28 UniformConstant",
1023   "%float_0_5 = OpConstant %float 0.5",
1024          "%36 = OpConstantComposite %v2float %float_0_5 %float_0_5",
1025 "%_ptr_Output_v4float = OpTypePointer Output %v4float",
1026   "%FragColor = OpVariable %_ptr_Output_v4float Output",
1027     "%float_3 = OpConstant %float 3",
1028       // clang-format on
1029   };
1030 
1031   const std::vector<const char*> nonEntryFuncs = {
1032       // clang-format off
1033    "%foo_vf4_ = OpFunction %float None %20",
1034         "%bar = OpFunctionParameter %_ptr_Function_v4float",
1035          "%58 = OpLabel",
1036           "%r = OpVariable %_ptr_Function_float Function",
1037          "%59 = OpAccessChain %_ptr_Function_float %bar %uint_0",
1038          "%60 = OpLoad %float %59",
1039                "OpStore %r %60",
1040          "%61 = OpLoad %float %r",
1041          "%62 = OpFOrdLessThan %bool %61 %float_0",
1042                "OpSelectionMerge %63 None",
1043                "OpBranchConditional %62 %64 %63",
1044          "%64 = OpLabel",
1045          "%65 = OpLoad %float %r",
1046          "%66 = OpFNegate %float %65",
1047                "OpStore %r %66",
1048                "OpBranch %63",
1049          "%63 = OpLabel",
1050          "%67 = OpLoad %float %r",
1051                "OpReturnValue %67",
1052                "OpFunctionEnd",
1053       // clang-format on
1054   };
1055 
1056   const std::vector<const char*> before = {
1057       // clang-format off
1058        "%main = OpFunction %void None %16",
1059          "%39 = OpLabel",
1060      "%color1 = OpVariable %_ptr_Function_v4float Function",
1061      "%color2 = OpVariable %_ptr_Function_v4float Function",
1062       "%param = OpVariable %_ptr_Function_v4float Function",
1063      "%color3 = OpVariable %_ptr_Function_v4float Function",
1064          "%40 = OpLoad %26 %t2D",
1065          "%41 = OpLoad %28 %samp",
1066          "%42 = OpSampledImage %30 %40 %41",
1067          "%43 = OpImageSampleImplicitLod %v4float %42 %33",
1068          "%44 = OpImage %26 %42",
1069          "%45 = OpLoad %28 %samp2",
1070                "OpStore %color1 %43",
1071          "%46 = OpLoad %v4float %BaseColor",
1072                "OpStore %param %46",
1073          "%47 = OpFunctionCall %float %foo_vf4_ %param",
1074          "%48 = OpCompositeConstruct %v4float %47 %47 %47 %47",
1075                "OpStore %color2 %48",
1076          "%49 = OpSampledImage %30 %44 %45",
1077          "%50 = OpImageSampleImplicitLod %v4float %49 %36",
1078                "OpStore %color3 %50",
1079          "%51 = OpLoad %v4float %color1",
1080          "%52 = OpLoad %v4float %color2",
1081          "%53 = OpFAdd %v4float %51 %52",
1082          "%54 = OpLoad %v4float %color3",
1083          "%55 = OpFAdd %v4float %53 %54",
1084          "%56 = OpCompositeConstruct %v4float %float_3 %float_3 %float_3 %float_3",
1085          "%57 = OpFDiv %v4float %55 %56",
1086                "OpStore %FragColor %57",
1087                "OpReturn",
1088                "OpFunctionEnd",
1089       // clang-format on
1090   };
1091 
1092   const std::vector<const char*> after = {
1093       // clang-format off
1094        "%main = OpFunction %void None %16",
1095          "%39 = OpLabel",
1096          "%68 = OpVariable %_ptr_Function_float Function",
1097          "%69 = OpVariable %_ptr_Function_float Function",
1098      "%color1 = OpVariable %_ptr_Function_v4float Function",
1099      "%color2 = OpVariable %_ptr_Function_v4float Function",
1100       "%param = OpVariable %_ptr_Function_v4float Function",
1101      "%color3 = OpVariable %_ptr_Function_v4float Function",
1102          "%40 = OpLoad %26 %t2D",
1103          "%41 = OpLoad %28 %samp",
1104          "%42 = OpSampledImage %30 %40 %41",
1105          "%43 = OpImageSampleImplicitLod %v4float %42 %33",
1106          "%44 = OpImage %26 %42",
1107          "%45 = OpLoad %28 %samp2",
1108                "OpStore %color1 %43",
1109          "%46 = OpLoad %v4float %BaseColor",
1110                "OpStore %param %46",
1111          "%71 = OpAccessChain %_ptr_Function_float %param %uint_0",
1112          "%72 = OpLoad %float %71",
1113                "OpStore %68 %72",
1114          "%73 = OpLoad %float %68",
1115          "%74 = OpFOrdLessThan %bool %73 %float_0",
1116                "OpSelectionMerge %78 None",
1117                "OpBranchConditional %74 %75 %78",
1118          "%75 = OpLabel",
1119          "%76 = OpLoad %float %68",
1120          "%77 = OpFNegate %float %76",
1121                "OpStore %68 %77",
1122                "OpBranch %78",
1123          "%78 = OpLabel",
1124          "%79 = OpLoad %float %68",
1125                "OpStore %69 %79",
1126          "%47 = OpLoad %float %69",
1127          "%48 = OpCompositeConstruct %v4float %47 %47 %47 %47",
1128                "OpStore %color2 %48",
1129          "%80 = OpSampledImage %30 %40 %41",
1130          "%81 = OpImage %26 %80",
1131          "%49 = OpSampledImage %30 %81 %45",
1132          "%50 = OpImageSampleImplicitLod %v4float %49 %36",
1133                "OpStore %color3 %50",
1134          "%51 = OpLoad %v4float %color1",
1135          "%52 = OpLoad %v4float %color2",
1136          "%53 = OpFAdd %v4float %51 %52",
1137          "%54 = OpLoad %v4float %color3",
1138          "%55 = OpFAdd %v4float %53 %54",
1139          "%56 = OpCompositeConstruct %v4float %float_3 %float_3 %float_3 %float_3",
1140          "%57 = OpFDiv %v4float %55 %56",
1141                "OpStore %FragColor %57",
1142                "OpReturn",
1143                "OpFunctionEnd",
1144       // clang-format on
1145   };
1146   SinglePassRunAndCheck<InlineExhaustivePass>(
1147       JoinAllInsts(Concat(Concat(predefs, before), nonEntryFuncs)),
1148       JoinAllInsts(Concat(Concat(predefs, after), nonEntryFuncs)),
1149       /* skip_nop = */ false, /* do_validate = */ true);
1150 }
1151 
TEST_F(InlineTest,OpImageAndOpSampledImageOutOfBlock)1152 TEST_F(InlineTest, OpImageAndOpSampledImageOutOfBlock) {
1153   // #version 450
1154   //
1155   // uniform texture2D t2D;
1156   // uniform sampler samp;
1157   // uniform sampler samp2;
1158   //
1159   // out vec4 FragColor;
1160   //
1161   // in vec4 BaseColor;
1162   //
1163   // float foo(vec4 bar)
1164   // {
1165   //     float r = bar.x;
1166   //     if (r < 0.0)
1167   //         r = -r;
1168   //     return r;
1169   // }
1170   //
1171   // void main()
1172   // {
1173   //     vec4 color1 = texture(sampler2D(t2D, samp), vec2(1.0));
1174   //     vec4 color2 = vec4(foo(BaseColor));
1175   //     vec4 color3 = texture(sampler2D(t2D, samp2), vec2(0.5));
1176   //     FragColor = (color1 + color2 + color3)/3;
1177   // }
1178   // Note: the before SPIR-V will need to be edited to create an OpImage
1179   // and subsequent OpSampledImage that is used across the function call.
1180   const std::vector<const char*> predefs = {
1181       // clang-format off
1182                "OpCapability Shader",
1183           "%1 = OpExtInstImport \"GLSL.std.450\"",
1184                "OpMemoryModel Logical GLSL450",
1185                "OpEntryPoint Fragment %main \"main\" %BaseColor %FragColor",
1186                "OpExecutionMode %main OriginUpperLeft",
1187                "OpSource GLSL 450",
1188                "OpName %main \"main\"",
1189                "OpName %foo_vf4_ \"foo(vf4;\"",
1190                "OpName %bar \"bar\"",
1191                "OpName %r \"r\"",
1192                "OpName %color1 \"color1\"",
1193                "OpName %t2D \"t2D\"",
1194                "OpName %samp \"samp\"",
1195                "OpName %color2 \"color2\"",
1196                "OpName %BaseColor \"BaseColor\"",
1197                "OpName %param \"param\"",
1198                "OpName %color3 \"color3\"",
1199                "OpName %samp2 \"samp2\"",
1200                "OpName %FragColor \"FragColor\"",
1201                "OpDecorate %t2D DescriptorSet 0",
1202                "OpDecorate %samp DescriptorSet 0",
1203                "OpDecorate %samp2 DescriptorSet 0",
1204        "%void = OpTypeVoid",
1205          "%16 = OpTypeFunction %void",
1206       "%float = OpTypeFloat 32",
1207     "%v4float = OpTypeVector %float 4",
1208 "%_ptr_Function_v4float = OpTypePointer Function %v4float",
1209          "%20 = OpTypeFunction %float %_ptr_Function_v4float",
1210 "%_ptr_Function_float = OpTypePointer Function %float",
1211        "%uint = OpTypeInt 32 0",
1212      "%uint_0 = OpConstant %uint 0",
1213     "%float_0 = OpConstant %float 0",
1214        "%bool = OpTypeBool",
1215          "%26 = OpTypeImage %float 2D 0 0 0 1 Unknown",
1216 "%_ptr_UniformConstant_26 = OpTypePointer UniformConstant %26",
1217         "%t2D = OpVariable %_ptr_UniformConstant_26 UniformConstant",
1218          "%28 = OpTypeSampler",
1219 "%_ptr_UniformConstant_28 = OpTypePointer UniformConstant %28",
1220        "%samp = OpVariable %_ptr_UniformConstant_28 UniformConstant",
1221          "%30 = OpTypeSampledImage %26",
1222     "%v2float = OpTypeVector %float 2",
1223     "%float_1 = OpConstant %float 1",
1224          "%33 = OpConstantComposite %v2float %float_1 %float_1",
1225 "%_ptr_Input_v4float = OpTypePointer Input %v4float",
1226   "%BaseColor = OpVariable %_ptr_Input_v4float Input",
1227       "%samp2 = OpVariable %_ptr_UniformConstant_28 UniformConstant",
1228   "%float_0_5 = OpConstant %float 0.5",
1229          "%36 = OpConstantComposite %v2float %float_0_5 %float_0_5",
1230 "%_ptr_Output_v4float = OpTypePointer Output %v4float",
1231   "%FragColor = OpVariable %_ptr_Output_v4float Output",
1232     "%float_3 = OpConstant %float 3",
1233       // clang-format on
1234   };
1235 
1236   const std::vector<const char*> nonEntryFuncs = {
1237       // clang-format off
1238    "%foo_vf4_ = OpFunction %float None %20",
1239         "%bar = OpFunctionParameter %_ptr_Function_v4float",
1240          "%58 = OpLabel",
1241           "%r = OpVariable %_ptr_Function_float Function",
1242          "%59 = OpAccessChain %_ptr_Function_float %bar %uint_0",
1243          "%60 = OpLoad %float %59",
1244                "OpStore %r %60",
1245          "%61 = OpLoad %float %r",
1246          "%62 = OpFOrdLessThan %bool %61 %float_0",
1247                "OpSelectionMerge %63 None",
1248                "OpBranchConditional %62 %64 %63",
1249          "%64 = OpLabel",
1250          "%65 = OpLoad %float %r",
1251          "%66 = OpFNegate %float %65",
1252                "OpStore %r %66",
1253                "OpBranch %63",
1254          "%63 = OpLabel",
1255          "%67 = OpLoad %float %r",
1256                "OpReturnValue %67",
1257                "OpFunctionEnd",
1258       // clang-format on
1259   };
1260 
1261   const std::vector<const char*> before = {
1262       // clang-format off
1263        "%main = OpFunction %void None %16",
1264          "%39 = OpLabel",
1265      "%color1 = OpVariable %_ptr_Function_v4float Function",
1266      "%color2 = OpVariable %_ptr_Function_v4float Function",
1267       "%param = OpVariable %_ptr_Function_v4float Function",
1268      "%color3 = OpVariable %_ptr_Function_v4float Function",
1269          "%40 = OpLoad %26 %t2D",
1270          "%41 = OpLoad %28 %samp",
1271          "%42 = OpSampledImage %30 %40 %41",
1272          "%43 = OpImageSampleImplicitLod %v4float %42 %33",
1273          "%44 = OpImage %26 %42",
1274          "%45 = OpLoad %28 %samp2",
1275          "%46 = OpSampledImage %30 %44 %45",
1276                "OpStore %color1 %43",
1277          "%47 = OpLoad %v4float %BaseColor",
1278                "OpStore %param %47",
1279          "%48 = OpFunctionCall %float %foo_vf4_ %param",
1280          "%49 = OpCompositeConstruct %v4float %48 %48 %48 %48",
1281                "OpStore %color2 %49",
1282          "%50 = OpImageSampleImplicitLod %v4float %46 %36",
1283                "OpStore %color3 %50",
1284          "%51 = OpLoad %v4float %color1",
1285          "%52 = OpLoad %v4float %color2",
1286          "%53 = OpFAdd %v4float %51 %52",
1287          "%54 = OpLoad %v4float %color3",
1288          "%55 = OpFAdd %v4float %53 %54",
1289          "%56 = OpCompositeConstruct %v4float %float_3 %float_3 %float_3 %float_3",
1290          "%57 = OpFDiv %v4float %55 %56",
1291                "OpStore %FragColor %57",
1292                "OpReturn",
1293                "OpFunctionEnd",
1294       // clang-format on
1295   };
1296 
1297   const std::vector<const char*> after = {
1298       // clang-format off
1299        "%main = OpFunction %void None %16",
1300          "%39 = OpLabel",
1301          "%68 = OpVariable %_ptr_Function_float Function",
1302          "%69 = OpVariable %_ptr_Function_float Function",
1303      "%color1 = OpVariable %_ptr_Function_v4float Function",
1304      "%color2 = OpVariable %_ptr_Function_v4float Function",
1305       "%param = OpVariable %_ptr_Function_v4float Function",
1306      "%color3 = OpVariable %_ptr_Function_v4float Function",
1307          "%40 = OpLoad %26 %t2D",
1308          "%41 = OpLoad %28 %samp",
1309          "%42 = OpSampledImage %30 %40 %41",
1310          "%43 = OpImageSampleImplicitLod %v4float %42 %33",
1311          "%44 = OpImage %26 %42",
1312          "%45 = OpLoad %28 %samp2",
1313          "%46 = OpSampledImage %30 %44 %45",
1314                "OpStore %color1 %43",
1315          "%47 = OpLoad %v4float %BaseColor",
1316                "OpStore %param %47",
1317          "%71 = OpAccessChain %_ptr_Function_float %param %uint_0",
1318          "%72 = OpLoad %float %71",
1319                "OpStore %68 %72",
1320          "%73 = OpLoad %float %68",
1321          "%74 = OpFOrdLessThan %bool %73 %float_0",
1322                "OpSelectionMerge %78 None",
1323                "OpBranchConditional %74 %75 %78",
1324          "%75 = OpLabel",
1325          "%76 = OpLoad %float %68",
1326          "%77 = OpFNegate %float %76",
1327                "OpStore %68 %77",
1328                "OpBranch %78",
1329          "%78 = OpLabel",
1330          "%79 = OpLoad %float %68",
1331                "OpStore %69 %79",
1332          "%48 = OpLoad %float %69",
1333          "%49 = OpCompositeConstruct %v4float %48 %48 %48 %48",
1334                "OpStore %color2 %49",
1335          "%80 = OpSampledImage %30 %40 %41",
1336          "%81 = OpImage %26 %80",
1337          "%82 = OpSampledImage %30 %81 %45",
1338          "%50 = OpImageSampleImplicitLod %v4float %82 %36",
1339                "OpStore %color3 %50",
1340          "%51 = OpLoad %v4float %color1",
1341          "%52 = OpLoad %v4float %color2",
1342          "%53 = OpFAdd %v4float %51 %52",
1343          "%54 = OpLoad %v4float %color3",
1344          "%55 = OpFAdd %v4float %53 %54",
1345          "%56 = OpCompositeConstruct %v4float %float_3 %float_3 %float_3 %float_3",
1346          "%57 = OpFDiv %v4float %55 %56",
1347                "OpStore %FragColor %57",
1348                "OpReturn",
1349                "OpFunctionEnd",
1350       // clang-format on
1351   };
1352   SinglePassRunAndCheck<InlineExhaustivePass>(
1353       JoinAllInsts(Concat(Concat(predefs, before), nonEntryFuncs)),
1354       JoinAllInsts(Concat(Concat(predefs, after), nonEntryFuncs)),
1355       /* skip_nop = */ false, /* do_validate = */ true);
1356 }
1357 
TEST_F(InlineTest,EarlyReturnInLoopIsNotInlined)1358 TEST_F(InlineTest, EarlyReturnInLoopIsNotInlined) {
1359   // #version 140
1360   //
1361   // in vec4 BaseColor;
1362   //
1363   // float foo(vec4 bar)
1364   // {
1365   //     while (true) {
1366   //         if (bar.x < 0.0)
1367   //             return 0.0;
1368   //         return bar.x;
1369   //     }
1370   // }
1371   //
1372   // void main()
1373   // {
1374   //     vec4 color = vec4(foo(BaseColor));
1375   //     gl_FragColor = color;
1376   // }
1377 
1378   const std::string assembly =
1379       R"(OpCapability Shader
1380 %1 = OpExtInstImport "GLSL.std.450"
1381 OpMemoryModel Logical GLSL450
1382 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
1383 OpExecutionMode %main OriginUpperLeft
1384 OpSource GLSL 140
1385 OpName %main "main"
1386 OpName %foo_vf4_ "foo(vf4;"
1387 OpName %bar "bar"
1388 OpName %color "color"
1389 OpName %BaseColor "BaseColor"
1390 OpName %param "param"
1391 OpName %gl_FragColor "gl_FragColor"
1392 %void = OpTypeVoid
1393 %10 = OpTypeFunction %void
1394 %float = OpTypeFloat 32
1395 %v4float = OpTypeVector %float 4
1396 %_ptr_Function_v4float = OpTypePointer Function %v4float
1397 %14 = OpTypeFunction %float %_ptr_Function_v4float
1398 %bool = OpTypeBool
1399 %true = OpConstantTrue %bool
1400 %uint = OpTypeInt 32 0
1401 %uint_0 = OpConstant %uint 0
1402 %_ptr_Function_float = OpTypePointer Function %float
1403 %float_0 = OpConstant %float 0
1404 %_ptr_Input_v4float = OpTypePointer Input %v4float
1405 %BaseColor = OpVariable %_ptr_Input_v4float Input
1406 %_ptr_Output_v4float = OpTypePointer Output %v4float
1407 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
1408 %main = OpFunction %void None %10
1409 %23 = OpLabel
1410 %color = OpVariable %_ptr_Function_v4float Function
1411 %param = OpVariable %_ptr_Function_v4float Function
1412 %24 = OpLoad %v4float %BaseColor
1413 OpStore %param %24
1414 %25 = OpFunctionCall %float %foo_vf4_ %param
1415 %26 = OpCompositeConstruct %v4float %25 %25 %25 %25
1416 OpStore %color %26
1417 %27 = OpLoad %v4float %color
1418 OpStore %gl_FragColor %27
1419 OpReturn
1420 OpFunctionEnd
1421 %foo_vf4_ = OpFunction %float None %14
1422 %bar = OpFunctionParameter %_ptr_Function_v4float
1423 %28 = OpLabel
1424 OpBranch %29
1425 %29 = OpLabel
1426 OpLoopMerge %30 %31 None
1427 OpBranch %32
1428 %32 = OpLabel
1429 OpBranchConditional %true %33 %30
1430 %33 = OpLabel
1431 %34 = OpAccessChain %_ptr_Function_float %bar %uint_0
1432 %35 = OpLoad %float %34
1433 %36 = OpFOrdLessThan %bool %35 %float_0
1434 OpSelectionMerge %37 None
1435 OpBranchConditional %36 %38 %37
1436 %38 = OpLabel
1437 OpReturnValue %float_0
1438 %37 = OpLabel
1439 %39 = OpAccessChain %_ptr_Function_float %bar %uint_0
1440 %40 = OpLoad %float %39
1441 OpReturnValue %40
1442 %31 = OpLabel
1443 OpBranch %29
1444 %30 = OpLabel
1445 %41 = OpUndef %float
1446 OpReturnValue %41
1447 OpFunctionEnd
1448 )";
1449 
1450   SinglePassRunAndCheck<InlineExhaustivePass>(assembly, assembly, false, true);
1451 }
1452 
TEST_F(InlineTest,ExternalFunctionIsNotInlined)1453 TEST_F(InlineTest, ExternalFunctionIsNotInlined) {
1454   // In particular, don't crash.
1455   // See report https://github.com/KhronosGroup/SPIRV-Tools/issues/605
1456   const std::string assembly =
1457       R"(OpCapability Addresses
1458 OpCapability Kernel
1459 OpCapability Linkage
1460 OpMemoryModel Physical32 OpenCL
1461 OpEntryPoint Kernel %1 "entry_pt"
1462 OpDecorate %2 LinkageAttributes "external" Import
1463 %void = OpTypeVoid
1464 %4 = OpTypeFunction %void
1465 %2 = OpFunction %void None %4
1466 OpFunctionEnd
1467 %1 = OpFunction %void None %4
1468 %5 = OpLabel
1469 %6 = OpFunctionCall %void %2
1470 OpReturn
1471 OpFunctionEnd
1472 )";
1473 
1474   SinglePassRunAndCheck<InlineExhaustivePass>(assembly, assembly, false, true);
1475 }
1476 
TEST_F(InlineTest,SingleBlockLoopCallsMultiBlockCallee)1477 TEST_F(InlineTest, SingleBlockLoopCallsMultiBlockCallee) {
1478   // Example from https://github.com/KhronosGroup/SPIRV-Tools/issues/787
1479   //
1480   // CFG structure is:
1481   //    foo:
1482   //       fooentry -> fooexit
1483   //
1484   //    main:
1485   //       entry -> loop
1486   //       loop -> loop, merge
1487   //         loop calls foo()
1488   //       merge
1489   //
1490   // Since the callee has multiple blocks, it will split the calling block
1491   // into at least two, resulting in a new "back-half" block that contains
1492   // the instructions after the inlined function call.  If the calling block
1493   // has an OpLoopMerge that points back to the calling block itself, then
1494   // the OpLoopMerge can't remain in the back-half block, but must be
1495   // moved to the end of the original calling block, and it continue target
1496   // operand updated to point to the back-half block.
1497 
1498   const std::string predefs =
1499       R"(OpCapability Shader
1500 OpMemoryModel Logical GLSL450
1501 OpEntryPoint GLCompute %1 "main"
1502 OpSource OpenCL_C 120
1503 %bool = OpTypeBool
1504 %true = OpConstantTrue %bool
1505 %void = OpTypeVoid
1506 %5 = OpTypeFunction %void
1507 )";
1508 
1509   const std::string nonEntryFuncs =
1510       R"(%6 = OpFunction %void None %5
1511 %7 = OpLabel
1512 OpBranch %8
1513 %8 = OpLabel
1514 OpReturn
1515 OpFunctionEnd
1516 )";
1517 
1518   const std::string before =
1519       R"(%1 = OpFunction %void None %5
1520 %9 = OpLabel
1521 OpBranch %10
1522 %10 = OpLabel
1523 %11 = OpFunctionCall %void %6
1524 OpLoopMerge %12 %10 None
1525 OpBranchConditional %true %10 %12
1526 %12 = OpLabel
1527 OpReturn
1528 OpFunctionEnd
1529 )";
1530 
1531   const std::string after =
1532       R"(%1 = OpFunction %void None %5
1533 %9 = OpLabel
1534 OpBranch %10
1535 %10 = OpLabel
1536 OpLoopMerge %12 %10 None
1537 OpBranch %14
1538 %14 = OpLabel
1539 OpBranchConditional %true %10 %12
1540 %12 = OpLabel
1541 OpReturn
1542 OpFunctionEnd
1543 )";
1544 
1545   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
1546                                               predefs + nonEntryFuncs + after,
1547                                               false, true);
1548 }
1549 
TEST_F(InlineTest,MultiBlockLoopHeaderCallsMultiBlockCallee)1550 TEST_F(InlineTest, MultiBlockLoopHeaderCallsMultiBlockCallee) {
1551   // Like SingleBlockLoopCallsMultiBlockCallee but the loop has several
1552   // blocks, but the function call still occurs in the loop header.
1553   // Example from https://github.com/KhronosGroup/SPIRV-Tools/issues/800
1554 
1555   const std::string predefs =
1556       R"(OpCapability Shader
1557 OpMemoryModel Logical GLSL450
1558 OpEntryPoint GLCompute %1 "main"
1559 OpSource OpenCL_C 120
1560 %bool = OpTypeBool
1561 %true = OpConstantTrue %bool
1562 %int = OpTypeInt 32 1
1563 %int_1 = OpConstant %int 1
1564 %int_2 = OpConstant %int 2
1565 %int_3 = OpConstant %int 3
1566 %int_4 = OpConstant %int 4
1567 %int_5 = OpConstant %int 5
1568 %void = OpTypeVoid
1569 %11 = OpTypeFunction %void
1570 )";
1571 
1572   const std::string nonEntryFuncs =
1573       R"(%12 = OpFunction %void None %11
1574 %13 = OpLabel
1575 %14 = OpCopyObject %int %int_1
1576 OpBranch %15
1577 %15 = OpLabel
1578 %16 = OpCopyObject %int %int_2
1579 OpReturn
1580 OpFunctionEnd
1581 )";
1582 
1583   const std::string before =
1584       R"(%1 = OpFunction %void None %11
1585 %17 = OpLabel
1586 OpBranch %18
1587 %18 = OpLabel
1588 %19 = OpCopyObject %int %int_3
1589 %20 = OpFunctionCall %void %12
1590 %21 = OpCopyObject %int %int_4
1591 OpLoopMerge %22 %23 None
1592 OpBranchConditional %true %23 %22
1593 %23 = OpLabel
1594 %24 = OpCopyObject %int %int_5
1595 OpBranchConditional %true %18 %22
1596 %22 = OpLabel
1597 OpReturn
1598 OpFunctionEnd
1599 )";
1600 
1601   const std::string after =
1602       R"(%1 = OpFunction %void None %11
1603 %17 = OpLabel
1604 OpBranch %18
1605 %18 = OpLabel
1606 %19 = OpCopyObject %int %int_3
1607 %26 = OpCopyObject %int %int_1
1608 OpLoopMerge %22 %23 None
1609 OpBranch %27
1610 %27 = OpLabel
1611 %28 = OpCopyObject %int %int_2
1612 %21 = OpCopyObject %int %int_4
1613 OpBranchConditional %true %23 %22
1614 %23 = OpLabel
1615 %24 = OpCopyObject %int %int_5
1616 OpBranchConditional %true %18 %22
1617 %22 = OpLabel
1618 OpReturn
1619 OpFunctionEnd
1620 )";
1621 
1622   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
1623                                               predefs + nonEntryFuncs + after,
1624                                               false, true);
1625 }
1626 
TEST_F(InlineTest,SingleBlockLoopCallsMultiBlockCalleeHavingSelectionMerge)1627 TEST_F(InlineTest, SingleBlockLoopCallsMultiBlockCalleeHavingSelectionMerge) {
1628   // This is similar to SingleBlockLoopCallsMultiBlockCallee except
1629   // that calleee block also has a merge instruction in its first block.
1630   // That merge instruction must be an OpSelectionMerge (because the entry
1631   // block of a function can't be the header of a loop since the entry
1632   // block can't be the target of a branch).
1633   //
1634   // In this case the OpLoopMerge can't be placed in the same block as
1635   // the OpSelectionMerge, so inlining must create a new block to contain
1636   // the callee contents.
1637   //
1638   // Additionally, we have two extra OpCopyObject instructions to prove that
1639   // the OpLoopMerge is moved to the right location.
1640   //
1641   // Also ensure that OpPhis within the cloned callee code are valid.
1642   // We need to test that the predecessor blocks are remapped correctly so that
1643   // dominance rules are satisfied
1644 
1645   const std::string predefs =
1646       R"(OpCapability Shader
1647 OpMemoryModel Logical GLSL450
1648 OpEntryPoint GLCompute %1 "main"
1649 OpSource OpenCL_C 120
1650 %bool = OpTypeBool
1651 %true = OpConstantTrue %bool
1652 %false = OpConstantFalse %bool
1653 %void = OpTypeVoid
1654 %6 = OpTypeFunction %void
1655 )";
1656 
1657   // This callee has multiple blocks, and an OpPhi in the last block
1658   // that references a value from the first block.  This tests that
1659   // cloned block IDs are remapped appropriately.  The OpPhi dominance
1660   // requires that the remapped %9 must be in a block that dominates
1661   // the remapped %8.
1662   const std::string nonEntryFuncs =
1663       R"(%7 = OpFunction %void None %6
1664 %8 = OpLabel
1665 %9 = OpCopyObject %bool %true
1666 OpSelectionMerge %10 None
1667 OpBranchConditional %true %10 %10
1668 %10 = OpLabel
1669 %11 = OpPhi %bool %9 %8
1670 OpReturn
1671 OpFunctionEnd
1672 )";
1673 
1674   const std::string before =
1675       R"(%1 = OpFunction %void None %6
1676 %12 = OpLabel
1677 OpBranch %13
1678 %13 = OpLabel
1679 %14 = OpCopyObject %bool %false
1680 %15 = OpFunctionCall %void %7
1681 OpLoopMerge %16 %13 None
1682 OpBranchConditional %true %13 %16
1683 %16 = OpLabel
1684 OpReturn
1685 OpFunctionEnd
1686 )";
1687 
1688   // Note the remapped Phi uses %17 as the parent instead
1689   // of %13, demonstrating that the parent block has been remapped
1690   // correctly.
1691   const std::string after =
1692       R"(%1 = OpFunction %void None %6
1693 %12 = OpLabel
1694 OpBranch %13
1695 %13 = OpLabel
1696 %14 = OpCopyObject %bool %false
1697 OpLoopMerge %16 %13 None
1698 OpBranch %17
1699 %17 = OpLabel
1700 %19 = OpCopyObject %bool %true
1701 OpSelectionMerge %20 None
1702 OpBranchConditional %true %20 %20
1703 %20 = OpLabel
1704 %21 = OpPhi %bool %19 %17
1705 OpBranchConditional %true %13 %16
1706 %16 = OpLabel
1707 OpReturn
1708 OpFunctionEnd
1709 )";
1710   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
1711                                               predefs + nonEntryFuncs + after,
1712                                               false, true);
1713 }
1714 
TEST_F(InlineTest,MultiBlockLoopHeaderCallsFromToMultiBlockCalleeHavingSelectionMerge)1715 TEST_F(InlineTest,
1716        MultiBlockLoopHeaderCallsFromToMultiBlockCalleeHavingSelectionMerge) {
1717   // This is similar to SingleBlockLoopCallsMultiBlockCalleeHavingSelectionMerge
1718   // but the call is in the header block of a multi block loop.
1719 
1720   const std::string predefs =
1721       R"(OpCapability Shader
1722 OpMemoryModel Logical GLSL450
1723 OpEntryPoint GLCompute %1 "main"
1724 OpSource OpenCL_C 120
1725 %bool = OpTypeBool
1726 %true = OpConstantTrue %bool
1727 %int = OpTypeInt 32 1
1728 %int_1 = OpConstant %int 1
1729 %int_2 = OpConstant %int 2
1730 %int_3 = OpConstant %int 3
1731 %int_4 = OpConstant %int 4
1732 %int_5 = OpConstant %int 5
1733 %void = OpTypeVoid
1734 %11 = OpTypeFunction %void
1735 )";
1736 
1737   const std::string nonEntryFuncs =
1738       R"(%12 = OpFunction %void None %11
1739 %13 = OpLabel
1740 %14 = OpCopyObject %int %int_1
1741 OpSelectionMerge %15 None
1742 OpBranchConditional %true %15 %15
1743 %15 = OpLabel
1744 %16 = OpCopyObject %int %int_2
1745 OpReturn
1746 OpFunctionEnd
1747 )";
1748 
1749   const std::string before =
1750       R"(%1 = OpFunction %void None %11
1751 %17 = OpLabel
1752 OpBranch %18
1753 %18 = OpLabel
1754 %19 = OpCopyObject %int %int_3
1755 %20 = OpFunctionCall %void %12
1756 %21 = OpCopyObject %int %int_4
1757 OpLoopMerge %22 %23 None
1758 OpBranchConditional %true %23 %22
1759 %23 = OpLabel
1760 %24 = OpCopyObject %int %int_5
1761 OpBranchConditional %true %18 %22
1762 %22 = OpLabel
1763 OpReturn
1764 OpFunctionEnd
1765 )";
1766 
1767   const std::string after =
1768       R"(%1 = OpFunction %void None %11
1769 %17 = OpLabel
1770 OpBranch %18
1771 %18 = OpLabel
1772 %19 = OpCopyObject %int %int_3
1773 OpLoopMerge %22 %23 None
1774 OpBranch %25
1775 %25 = OpLabel
1776 %27 = OpCopyObject %int %int_1
1777 OpSelectionMerge %28 None
1778 OpBranchConditional %true %28 %28
1779 %28 = OpLabel
1780 %29 = OpCopyObject %int %int_2
1781 %21 = OpCopyObject %int %int_4
1782 OpBranchConditional %true %23 %22
1783 %23 = OpLabel
1784 %24 = OpCopyObject %int %int_5
1785 OpBranchConditional %true %18 %22
1786 %22 = OpLabel
1787 OpReturn
1788 OpFunctionEnd
1789 )";
1790 
1791   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
1792                                               predefs + nonEntryFuncs + after,
1793                                               false, true);
1794 }
1795 
TEST_F(InlineTest,NonInlinableCalleeWithSingleReturn)1796 TEST_F(InlineTest, NonInlinableCalleeWithSingleReturn) {
1797   // The case from https://github.com/KhronosGroup/SPIRV-Tools/issues/2018
1798   //
1799   // The callee has a single return, but cannot be inlined because the
1800   // return is inside a loop.
1801 
1802   const std::string predefs =
1803       R"(OpCapability Shader
1804 %1 = OpExtInstImport "GLSL.std.450"
1805 OpMemoryModel Logical GLSL450
1806 OpEntryPoint Fragment %main "main" %_GLF_color
1807 OpExecutionMode %main OriginUpperLeft
1808 OpSource ESSL 310
1809 OpName %main "main"
1810 OpName %f_ "f("
1811 OpName %i "i"
1812 OpName %_GLF_color "_GLF_color"
1813 OpDecorate %_GLF_color Location 0
1814 %void = OpTypeVoid
1815 %7 = OpTypeFunction %void
1816 %float = OpTypeFloat 32
1817 %9 = OpTypeFunction %float
1818 %float_1 = OpConstant %float 1
1819 %bool = OpTypeBool
1820 %false = OpConstantFalse %bool
1821 %int = OpTypeInt 32 1
1822 %_ptr_Function_int = OpTypePointer Function %int
1823 %int_0 = OpConstant %int 0
1824 %int_1 = OpConstant %int 1
1825 %v4float = OpTypeVector %float 4
1826 %_ptr_Output_v4float = OpTypePointer Output %v4float
1827 %_GLF_color = OpVariable %_ptr_Output_v4float Output
1828 %float_0 = OpConstant %float 0
1829 %20 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
1830 %21 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1
1831 )";
1832 
1833   const std::string caller =
1834       R"(%main = OpFunction %void None %7
1835 %22 = OpLabel
1836 %i = OpVariable %_ptr_Function_int Function
1837 OpStore %i %int_0
1838 OpBranch %23
1839 %23 = OpLabel
1840 OpLoopMerge %24 %25 None
1841 OpBranch %26
1842 %26 = OpLabel
1843 %27 = OpLoad %int %i
1844 %28 = OpSLessThan %bool %27 %int_1
1845 OpBranchConditional %28 %29 %24
1846 %29 = OpLabel
1847 OpStore %_GLF_color %20
1848 %30 = OpFunctionCall %float %f_
1849 OpBranch %25
1850 %25 = OpLabel
1851 %31 = OpLoad %int %i
1852 %32 = OpIAdd %int %31 %int_1
1853 OpStore %i %32
1854 OpBranch %23
1855 %24 = OpLabel
1856 OpStore %_GLF_color %21
1857 OpReturn
1858 OpFunctionEnd
1859 )";
1860 
1861   const std::string callee =
1862       R"(%f_ = OpFunction %float None %9
1863 %33 = OpLabel
1864 OpBranch %34
1865 %34 = OpLabel
1866 OpLoopMerge %35 %36 None
1867 OpBranch %37
1868 %37 = OpLabel
1869 OpReturnValue %float_1
1870 %36 = OpLabel
1871 OpBranch %34
1872 %35 = OpLabel
1873 OpUnreachable
1874 OpFunctionEnd
1875 )";
1876 
1877   SinglePassRunAndCheck<InlineExhaustivePass>(
1878       predefs + caller + callee, predefs + caller + callee, false, true);
1879 }
1880 
TEST_F(InlineTest,Decorated1)1881 TEST_F(InlineTest, Decorated1) {
1882   // Same test as Simple with the difference
1883   // that OpFAdd in the outlined function is
1884   // decorated with RelaxedPrecision
1885   // Expected result is an equal decoration
1886   // of the corresponding inlined instruction
1887   //
1888   // #version 140
1889   //
1890   // in vec4 BaseColor;
1891   //
1892   // float foo(vec4 bar)
1893   // {
1894   //     return bar.x + bar.y;
1895   // }
1896   //
1897   // void main()
1898   // {
1899   //     vec4 color = vec4(foo(BaseColor));
1900   //     gl_FragColor = color;
1901   // }
1902 
1903   const std::string predefs =
1904       R"(OpCapability Shader
1905 %1 = OpExtInstImport "GLSL.std.450"
1906 OpMemoryModel Logical GLSL450
1907 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
1908 OpExecutionMode %main OriginUpperLeft
1909 OpSource GLSL 140
1910 OpName %main "main"
1911 OpName %foo_vf4_ "foo(vf4;"
1912 OpName %bar "bar"
1913 OpName %color "color"
1914 OpName %BaseColor "BaseColor"
1915 OpName %param "param"
1916 OpName %gl_FragColor "gl_FragColor"
1917 OpDecorate %9 RelaxedPrecision
1918 )";
1919 
1920   const std::string before =
1921       R"(%void = OpTypeVoid
1922 %11 = OpTypeFunction %void
1923 %float = OpTypeFloat 32
1924 %v4float = OpTypeVector %float 4
1925 %_ptr_Function_v4float = OpTypePointer Function %v4float
1926 %15 = OpTypeFunction %float %_ptr_Function_v4float
1927 %uint = OpTypeInt 32 0
1928 %uint_0 = OpConstant %uint 0
1929 %_ptr_Function_float = OpTypePointer Function %float
1930 %uint_1 = OpConstant %uint 1
1931 %_ptr_Input_v4float = OpTypePointer Input %v4float
1932 %BaseColor = OpVariable %_ptr_Input_v4float Input
1933 %_ptr_Output_v4float = OpTypePointer Output %v4float
1934 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
1935 %main = OpFunction %void None %11
1936 %22 = OpLabel
1937 %color = OpVariable %_ptr_Function_v4float Function
1938 %param = OpVariable %_ptr_Function_v4float Function
1939 %23 = OpLoad %v4float %BaseColor
1940 OpStore %param %23
1941 %24 = OpFunctionCall %float %foo_vf4_ %param
1942 %25 = OpCompositeConstruct %v4float %24 %24 %24 %24
1943 OpStore %color %25
1944 %26 = OpLoad %v4float %color
1945 OpStore %gl_FragColor %26
1946 OpReturn
1947 OpFunctionEnd
1948 )";
1949 
1950   const std::string after =
1951       R"(OpDecorate %38 RelaxedPrecision
1952 %void = OpTypeVoid
1953 %11 = OpTypeFunction %void
1954 %float = OpTypeFloat 32
1955 %v4float = OpTypeVector %float 4
1956 %_ptr_Function_v4float = OpTypePointer Function %v4float
1957 %15 = OpTypeFunction %float %_ptr_Function_v4float
1958 %uint = OpTypeInt 32 0
1959 %uint_0 = OpConstant %uint 0
1960 %_ptr_Function_float = OpTypePointer Function %float
1961 %uint_1 = OpConstant %uint 1
1962 %_ptr_Input_v4float = OpTypePointer Input %v4float
1963 %BaseColor = OpVariable %_ptr_Input_v4float Input
1964 %_ptr_Output_v4float = OpTypePointer Output %v4float
1965 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
1966 %main = OpFunction %void None %11
1967 %22 = OpLabel
1968 %32 = OpVariable %_ptr_Function_float Function
1969 %color = OpVariable %_ptr_Function_v4float Function
1970 %param = OpVariable %_ptr_Function_v4float Function
1971 %23 = OpLoad %v4float %BaseColor
1972 OpStore %param %23
1973 %34 = OpAccessChain %_ptr_Function_float %param %uint_0
1974 %35 = OpLoad %float %34
1975 %36 = OpAccessChain %_ptr_Function_float %param %uint_1
1976 %37 = OpLoad %float %36
1977 %38 = OpFAdd %float %35 %37
1978 OpStore %32 %38
1979 %24 = OpLoad %float %32
1980 %25 = OpCompositeConstruct %v4float %24 %24 %24 %24
1981 OpStore %color %25
1982 %26 = OpLoad %v4float %color
1983 OpStore %gl_FragColor %26
1984 OpReturn
1985 OpFunctionEnd
1986 )";
1987 
1988   const std::string nonEntryFuncs =
1989       R"(%foo_vf4_ = OpFunction %float None %15
1990 %bar = OpFunctionParameter %_ptr_Function_v4float
1991 %27 = OpLabel
1992 %28 = OpAccessChain %_ptr_Function_float %bar %uint_0
1993 %29 = OpLoad %float %28
1994 %30 = OpAccessChain %_ptr_Function_float %bar %uint_1
1995 %31 = OpLoad %float %30
1996 %9 = OpFAdd %float %29 %31
1997 OpReturnValue %9
1998 OpFunctionEnd
1999 )";
2000   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + before + nonEntryFuncs,
2001                                               predefs + after + nonEntryFuncs,
2002                                               false, true);
2003 }
2004 
TEST_F(InlineTest,Decorated2)2005 TEST_F(InlineTest, Decorated2) {
2006   // Same test as Simple with the difference
2007   // that the Result <id> of the outlined OpFunction
2008   // is decorated with RelaxedPrecision
2009   // Expected result is an equal decoration
2010   // of the created return variable
2011   //
2012   // #version 140
2013   //
2014   // in vec4 BaseColor;
2015   //
2016   // float foo(vec4 bar)
2017   // {
2018   //     return bar.x + bar.y;
2019   // }
2020   //
2021   // void main()
2022   // {
2023   //     vec4 color = vec4(foo(BaseColor));
2024   //     gl_FragColor = color;
2025   // }
2026 
2027   const std::string predefs =
2028       R"(OpCapability Shader
2029 %1 = OpExtInstImport "GLSL.std.450"
2030 OpMemoryModel Logical GLSL450
2031 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
2032 OpExecutionMode %main OriginUpperLeft
2033 OpSource GLSL 140
2034 OpName %main "main"
2035 OpName %foo_vf4_ "foo(vf4;"
2036 OpName %bar "bar"
2037 OpName %color "color"
2038 OpName %BaseColor "BaseColor"
2039 OpName %param "param"
2040 OpName %gl_FragColor "gl_FragColor"
2041 OpDecorate %foo_vf4_ RelaxedPrecision
2042 )";
2043 
2044   const std::string before =
2045       R"(%void = OpTypeVoid
2046 %10 = OpTypeFunction %void
2047 %float = OpTypeFloat 32
2048 %v4float = OpTypeVector %float 4
2049 %_ptr_Function_v4float = OpTypePointer Function %v4float
2050 %14 = OpTypeFunction %float %_ptr_Function_v4float
2051 %uint = OpTypeInt 32 0
2052 %uint_0 = OpConstant %uint 0
2053 %_ptr_Function_float = OpTypePointer Function %float
2054 %uint_1 = OpConstant %uint 1
2055 %_ptr_Input_v4float = OpTypePointer Input %v4float
2056 %BaseColor = OpVariable %_ptr_Input_v4float Input
2057 %_ptr_Output_v4float = OpTypePointer Output %v4float
2058 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
2059 %main = OpFunction %void None %10
2060 %21 = OpLabel
2061 %color = OpVariable %_ptr_Function_v4float Function
2062 %param = OpVariable %_ptr_Function_v4float Function
2063 %22 = OpLoad %v4float %BaseColor
2064 OpStore %param %22
2065 %23 = OpFunctionCall %float %foo_vf4_ %param
2066 %24 = OpCompositeConstruct %v4float %23 %23 %23 %23
2067 OpStore %color %24
2068 %25 = OpLoad %v4float %color
2069 OpStore %gl_FragColor %25
2070 OpReturn
2071 OpFunctionEnd
2072 )";
2073 
2074   const std::string after =
2075       R"(OpDecorate %32 RelaxedPrecision
2076 %void = OpTypeVoid
2077 %10 = OpTypeFunction %void
2078 %float = OpTypeFloat 32
2079 %v4float = OpTypeVector %float 4
2080 %_ptr_Function_v4float = OpTypePointer Function %v4float
2081 %14 = OpTypeFunction %float %_ptr_Function_v4float
2082 %uint = OpTypeInt 32 0
2083 %uint_0 = OpConstant %uint 0
2084 %_ptr_Function_float = OpTypePointer Function %float
2085 %uint_1 = OpConstant %uint 1
2086 %_ptr_Input_v4float = OpTypePointer Input %v4float
2087 %BaseColor = OpVariable %_ptr_Input_v4float Input
2088 %_ptr_Output_v4float = OpTypePointer Output %v4float
2089 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
2090 %main = OpFunction %void None %10
2091 %21 = OpLabel
2092 %32 = OpVariable %_ptr_Function_float Function
2093 %color = OpVariable %_ptr_Function_v4float Function
2094 %param = OpVariable %_ptr_Function_v4float Function
2095 %22 = OpLoad %v4float %BaseColor
2096 OpStore %param %22
2097 %34 = OpAccessChain %_ptr_Function_float %param %uint_0
2098 %35 = OpLoad %float %34
2099 %36 = OpAccessChain %_ptr_Function_float %param %uint_1
2100 %37 = OpLoad %float %36
2101 %38 = OpFAdd %float %35 %37
2102 OpStore %32 %38
2103 %23 = OpLoad %float %32
2104 %24 = OpCompositeConstruct %v4float %23 %23 %23 %23
2105 OpStore %color %24
2106 %25 = OpLoad %v4float %color
2107 OpStore %gl_FragColor %25
2108 OpReturn
2109 OpFunctionEnd
2110 )";
2111 
2112   const std::string nonEntryFuncs =
2113       R"(%foo_vf4_ = OpFunction %float None %14
2114 %bar = OpFunctionParameter %_ptr_Function_v4float
2115 %26 = OpLabel
2116 %27 = OpAccessChain %_ptr_Function_float %bar %uint_0
2117 %28 = OpLoad %float %27
2118 %29 = OpAccessChain %_ptr_Function_float %bar %uint_1
2119 %30 = OpLoad %float %29
2120 %31 = OpFAdd %float %28 %30
2121 OpReturnValue %31
2122 OpFunctionEnd
2123 )";
2124   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + before + nonEntryFuncs,
2125                                               predefs + after + nonEntryFuncs,
2126                                               false, true);
2127 }
2128 
TEST_F(InlineTest,DeleteName)2129 TEST_F(InlineTest, DeleteName) {
2130   // Test that the name of the result id of the call is deleted.
2131   const std::string before =
2132       R"(
2133                OpCapability Shader
2134                OpMemoryModel Logical GLSL450
2135                OpEntryPoint Vertex %main "main"
2136                OpName %main "main"
2137                OpName %main_entry "main_entry"
2138                OpName %foo_result "foo_result"
2139                OpName %void_fn "void_fn"
2140                OpName %foo "foo"
2141                OpName %foo_entry "foo_entry"
2142        %void = OpTypeVoid
2143     %void_fn = OpTypeFunction %void
2144         %foo = OpFunction %void None %void_fn
2145   %foo_entry = OpLabel
2146                OpReturn
2147                OpFunctionEnd
2148        %main = OpFunction %void None %void_fn
2149  %main_entry = OpLabel
2150  %foo_result = OpFunctionCall %void %foo
2151                OpReturn
2152                OpFunctionEnd
2153 )";
2154 
2155   const std::string after =
2156       R"(OpCapability Shader
2157 OpMemoryModel Logical GLSL450
2158 OpEntryPoint Vertex %main "main"
2159 OpName %main "main"
2160 OpName %main_entry "main_entry"
2161 OpName %void_fn "void_fn"
2162 OpName %foo "foo"
2163 OpName %foo_entry "foo_entry"
2164 %void = OpTypeVoid
2165 %void_fn = OpTypeFunction %void
2166 %foo = OpFunction %void None %void_fn
2167 %foo_entry = OpLabel
2168 OpReturn
2169 OpFunctionEnd
2170 %main = OpFunction %void None %void_fn
2171 %main_entry = OpLabel
2172 OpReturn
2173 OpFunctionEnd
2174 )";
2175 
2176   SinglePassRunAndCheck<InlineExhaustivePass>(before, after, false, true);
2177 }
2178 
TEST_F(InlineTest,SetParent)2179 TEST_F(InlineTest, SetParent) {
2180   // Test that after inlining all basic blocks have the correct parent.
2181   const std::string text =
2182       R"(
2183                OpCapability Shader
2184                OpMemoryModel Logical GLSL450
2185                OpEntryPoint Vertex %main "main"
2186                OpName %main "main"
2187                OpName %main_entry "main_entry"
2188                OpName %foo_result "foo_result"
2189                OpName %void_fn "void_fn"
2190                OpName %foo "foo"
2191                OpName %foo_entry "foo_entry"
2192        %void = OpTypeVoid
2193     %void_fn = OpTypeFunction %void
2194         %foo = OpFunction %void None %void_fn
2195   %foo_entry = OpLabel
2196                OpReturn
2197                OpFunctionEnd
2198        %main = OpFunction %void None %void_fn
2199  %main_entry = OpLabel
2200  %foo_result = OpFunctionCall %void %foo
2201                OpReturn
2202                OpFunctionEnd
2203 )";
2204 
2205   std::unique_ptr<IRContext> context =
2206       BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
2207   InlineExhaustivePass pass;
2208   pass.Run(context.get());
2209 
2210   for (Function& func : *context->module()) {
2211     for (BasicBlock& bb : func) {
2212       EXPECT_TRUE(bb.GetParent() == &func);
2213     }
2214   }
2215 }
2216 
TEST_F(InlineTest,OpVariableWithInit)2217 TEST_F(InlineTest, OpVariableWithInit) {
2218   // Check that there is a store that corresponds to the initializer.  This
2219   // test makes sure that is a store to the variable in the loop and before any
2220   // load.
2221   const std::string text = R"(
2222 ; CHECK: OpFunction
2223 ; CHECK-NOT: OpFunctionEnd
2224 ; CHECK: [[var:%\w+]] = OpVariable %_ptr_Function_float Function %float_0
2225 ; CHECK: OpLoopMerge [[outer_merge:%\w+]]
2226 ; CHECK-NOT: OpLoad %float [[var]]
2227 ; CHECK: OpStore [[var]] %float_0
2228 ; CHECK: OpFunctionEnd
2229                OpCapability Shader
2230           %1 = OpExtInstImport "GLSL.std.450"
2231                OpMemoryModel Logical GLSL450
2232                OpEntryPoint Fragment %main "main" %o
2233                OpExecutionMode %main OriginUpperLeft
2234                OpSource GLSL 450
2235                OpDecorate %o Location 0
2236        %void = OpTypeVoid
2237           %3 = OpTypeFunction %void
2238       %float = OpTypeFloat 32
2239           %7 = OpTypeFunction %float
2240 %_ptr_Function_float = OpTypePointer Function %float
2241     %float_0 = OpConstant %float 0
2242        %bool = OpTypeBool
2243     %float_1 = OpConstant %float 1
2244 %_ptr_Output_float = OpTypePointer Output %float
2245           %o = OpVariable %_ptr_Output_float Output
2246         %int = OpTypeInt 32 1
2247 %_ptr_Function_int = OpTypePointer Function %int
2248 %_ptr_Input_int = OpTypePointer Input %int
2249       %int_0 = OpConstant %int 0
2250       %int_1 = OpConstant %int 1
2251       %int_2 = OpConstant %int 2
2252        %main = OpFunction %void None %3
2253           %5 = OpLabel
2254                OpStore %o %float_0
2255                OpBranch %34
2256          %34 = OpLabel
2257          %39 = OpPhi %int %int_0 %5 %47 %37
2258                OpLoopMerge %36 %37 None
2259                OpBranch %38
2260          %38 = OpLabel
2261          %41 = OpSLessThan %bool %39 %int_2
2262                OpBranchConditional %41 %35 %36
2263          %35 = OpLabel
2264          %42 = OpFunctionCall %float %foo_
2265          %43 = OpLoad %float %o
2266          %44 = OpFAdd %float %43 %42
2267                OpStore %o %44
2268                OpBranch %37
2269          %37 = OpLabel
2270          %47 = OpIAdd %int %39 %int_1
2271                OpBranch %34
2272          %36 = OpLabel
2273                OpReturn
2274                OpFunctionEnd
2275        %foo_ = OpFunction %float None %7
2276           %9 = OpLabel
2277           %n = OpVariable %_ptr_Function_float Function %float_0
2278          %13 = OpLoad %float %n
2279          %15 = OpFOrdEqual %bool %13 %float_0
2280                OpSelectionMerge %17 None
2281                OpBranchConditional %15 %16 %17
2282          %16 = OpLabel
2283          %19 = OpLoad %float %n
2284          %20 = OpFAdd %float %19 %float_1
2285                OpStore %n %20
2286                OpBranch %17
2287          %17 = OpLabel
2288          %21 = OpLoad %float %n
2289                OpReturnValue %21
2290                OpFunctionEnd
2291 )";
2292 
2293   SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
2294 }
2295 
TEST_F(InlineTest,DontInlineDirectlyRecursiveFunc)2296 TEST_F(InlineTest, DontInlineDirectlyRecursiveFunc) {
2297   // Test that the name of the result id of the call is deleted.
2298   const std::string test =
2299       R"(OpCapability Shader
2300 OpMemoryModel Logical GLSL450
2301 OpEntryPoint Fragment %1 "main"
2302 OpExecutionMode %1 OriginUpperLeft
2303 OpDecorate %2 DescriptorSet 439418829
2304 %void = OpTypeVoid
2305 %4 = OpTypeFunction %void
2306 %float = OpTypeFloat 32
2307 %_struct_6 = OpTypeStruct %float %float
2308 %15 = OpConstantNull %_struct_6
2309 %7 = OpTypeFunction %_struct_6
2310 %1 = OpFunction %void Pure|Const %4
2311 %8 = OpLabel
2312 %2 = OpFunctionCall %_struct_6 %9
2313 OpKill
2314 OpFunctionEnd
2315 %9 = OpFunction %_struct_6 None %7
2316 %10 = OpLabel
2317 %11 = OpFunctionCall %_struct_6 %9
2318 OpReturnValue %15
2319 OpFunctionEnd
2320 )";
2321 
2322   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2323   SinglePassRunAndCheck<InlineExhaustivePass>(test, test, false, true);
2324 }
2325 
TEST_F(InlineTest,DontInlineInDirectlyRecursiveFunc)2326 TEST_F(InlineTest, DontInlineInDirectlyRecursiveFunc) {
2327   // Test that the name of the result id of the call is deleted.
2328   const std::string test =
2329       R"(OpCapability Shader
2330 OpMemoryModel Logical GLSL450
2331 OpEntryPoint Fragment %1 "main"
2332 OpExecutionMode %1 OriginUpperLeft
2333 OpDecorate %2 DescriptorSet 439418829
2334 %void = OpTypeVoid
2335 %4 = OpTypeFunction %void
2336 %float = OpTypeFloat 32
2337 %_struct_6 = OpTypeStruct %float %float
2338 %15 = OpConstantNull %_struct_6
2339 %7 = OpTypeFunction %_struct_6
2340 %1 = OpFunction %void Pure|Const %4
2341 %8 = OpLabel
2342 %2 = OpFunctionCall %_struct_6 %9
2343 OpKill
2344 OpFunctionEnd
2345 %9 = OpFunction %_struct_6 None %7
2346 %10 = OpLabel
2347 %11 = OpFunctionCall %_struct_6 %12
2348 OpReturnValue %15
2349 OpFunctionEnd
2350 %12 = OpFunction %_struct_6 None %7
2351 %13 = OpLabel
2352 %14 = OpFunctionCall %_struct_6 %9
2353 OpReturnValue %15
2354 OpFunctionEnd
2355 )";
2356 
2357   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2358   SinglePassRunAndCheck<InlineExhaustivePass>(test, test, false, true);
2359 }
2360 
TEST_F(InlineTest,DontInlineFuncWithOpKillInContinue)2361 TEST_F(InlineTest, DontInlineFuncWithOpKillInContinue) {
2362   const std::string test =
2363       R"(OpCapability Shader
2364 %1 = OpExtInstImport "GLSL.std.450"
2365 OpMemoryModel Logical GLSL450
2366 OpEntryPoint Fragment %main "main"
2367 OpExecutionMode %main OriginUpperLeft
2368 OpSource GLSL 330
2369 OpName %main "main"
2370 OpName %kill_ "kill("
2371 %void = OpTypeVoid
2372 %3 = OpTypeFunction %void
2373 %bool = OpTypeBool
2374 %true = OpConstantTrue %bool
2375 %main = OpFunction %void None %3
2376 %5 = OpLabel
2377 OpBranch %9
2378 %9 = OpLabel
2379 OpLoopMerge %11 %12 None
2380 OpBranch %13
2381 %13 = OpLabel
2382 OpBranchConditional %true %10 %11
2383 %10 = OpLabel
2384 OpBranch %12
2385 %12 = OpLabel
2386 %16 = OpFunctionCall %void %kill_
2387 OpBranch %9
2388 %11 = OpLabel
2389 OpReturn
2390 OpFunctionEnd
2391 %kill_ = OpFunction %void None %3
2392 %7 = OpLabel
2393 OpKill
2394 OpFunctionEnd
2395 )";
2396 
2397   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2398   SinglePassRunAndCheck<InlineExhaustivePass>(test, test, false, true);
2399 }
2400 
TEST_F(InlineTest,DontInlineFuncWithDontInline)2401 TEST_F(InlineTest, DontInlineFuncWithDontInline) {
2402   // Check that the function with DontInline flag is not inlined.
2403   const std::string text = R"(
2404 ; CHECK: %foo = OpFunction %int DontInline
2405 ; CHECK: OpReturnValue %int_0
2406 
2407 OpCapability Shader
2408 OpMemoryModel Logical GLSL450
2409 OpEntryPoint Fragment %main "main"
2410 OpExecutionMode %main OriginUpperLeft
2411 OpSource HLSL 600
2412 OpName %main "main"
2413 OpName %foo "foo"
2414 %int = OpTypeInt 32 1
2415 %int_0 = OpConstant %int 0
2416 %void = OpTypeVoid
2417 %6 = OpTypeFunction %void
2418 %7 = OpTypeFunction %int
2419 %main = OpFunction %void None %6
2420 %8 = OpLabel
2421 %9 = OpFunctionCall %int %foo
2422 OpReturn
2423 OpFunctionEnd
2424 %foo = OpFunction %int DontInline %7
2425 %10 = OpLabel
2426 OpReturnValue %int_0
2427 OpFunctionEnd
2428 )";
2429 
2430   SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
2431 }
2432 
TEST_F(InlineTest,InlineFuncWithOpKillNotInContinue)2433 TEST_F(InlineTest, InlineFuncWithOpKillNotInContinue) {
2434   const std::string before =
2435       R"(OpCapability Shader
2436 %1 = OpExtInstImport "GLSL.std.450"
2437 OpMemoryModel Logical GLSL450
2438 OpEntryPoint Fragment %main "main"
2439 OpExecutionMode %main OriginUpperLeft
2440 OpSource GLSL 330
2441 OpName %main "main"
2442 OpName %kill_ "kill("
2443 %void = OpTypeVoid
2444 %3 = OpTypeFunction %void
2445 %bool = OpTypeBool
2446 %true = OpConstantTrue %bool
2447 %main = OpFunction %void None %3
2448 %5 = OpLabel
2449 %16 = OpFunctionCall %void %kill_
2450 OpReturn
2451 OpFunctionEnd
2452 %kill_ = OpFunction %void None %3
2453 %7 = OpLabel
2454 OpKill
2455 OpFunctionEnd
2456 )";
2457 
2458   const std::string after =
2459       R"(OpCapability Shader
2460 %1 = OpExtInstImport "GLSL.std.450"
2461 OpMemoryModel Logical GLSL450
2462 OpEntryPoint Fragment %main "main"
2463 OpExecutionMode %main OriginUpperLeft
2464 OpSource GLSL 330
2465 OpName %main "main"
2466 OpName %kill_ "kill("
2467 %void = OpTypeVoid
2468 %3 = OpTypeFunction %void
2469 %bool = OpTypeBool
2470 %true = OpConstantTrue %bool
2471 %main = OpFunction %void None %3
2472 %5 = OpLabel
2473 OpKill
2474 %18 = OpLabel
2475 OpReturn
2476 OpFunctionEnd
2477 %kill_ = OpFunction %void None %3
2478 %7 = OpLabel
2479 OpKill
2480 OpFunctionEnd
2481 )";
2482 
2483   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2484   SinglePassRunAndCheck<InlineExhaustivePass>(before, after, false, true);
2485 }
2486 
TEST_F(InlineTest,DontInlineFuncWithOpTerminateInvocationInContinue)2487 TEST_F(InlineTest, DontInlineFuncWithOpTerminateInvocationInContinue) {
2488   const std::string test =
2489       R"(OpCapability Shader
2490 OpExtension "SPV_KHR_terminate_invocation"
2491 %1 = OpExtInstImport "GLSL.std.450"
2492 OpMemoryModel Logical GLSL450
2493 OpEntryPoint Fragment %main "main"
2494 OpExecutionMode %main OriginUpperLeft
2495 OpSource GLSL 330
2496 OpName %main "main"
2497 OpName %kill_ "kill("
2498 %void = OpTypeVoid
2499 %3 = OpTypeFunction %void
2500 %bool = OpTypeBool
2501 %true = OpConstantTrue %bool
2502 %main = OpFunction %void None %3
2503 %5 = OpLabel
2504 OpBranch %9
2505 %9 = OpLabel
2506 OpLoopMerge %11 %12 None
2507 OpBranch %13
2508 %13 = OpLabel
2509 OpBranchConditional %true %10 %11
2510 %10 = OpLabel
2511 OpBranch %12
2512 %12 = OpLabel
2513 %16 = OpFunctionCall %void %kill_
2514 OpBranch %9
2515 %11 = OpLabel
2516 OpReturn
2517 OpFunctionEnd
2518 %kill_ = OpFunction %void None %3
2519 %7 = OpLabel
2520 OpTerminateInvocation
2521 OpFunctionEnd
2522 )";
2523 
2524   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2525   SinglePassRunAndCheck<InlineExhaustivePass>(test, test, false, true);
2526 }
2527 
TEST_F(InlineTest,InlineFuncWithOpTerminateInvocationNotInContinue)2528 TEST_F(InlineTest, InlineFuncWithOpTerminateInvocationNotInContinue) {
2529   const std::string before =
2530       R"(OpCapability Shader
2531 OpExtension "SPV_KHR_terminate_invocation"
2532 %1 = OpExtInstImport "GLSL.std.450"
2533 OpMemoryModel Logical GLSL450
2534 OpEntryPoint Fragment %main "main"
2535 OpExecutionMode %main OriginUpperLeft
2536 OpSource GLSL 330
2537 OpName %main "main"
2538 OpName %kill_ "kill("
2539 %void = OpTypeVoid
2540 %3 = OpTypeFunction %void
2541 %bool = OpTypeBool
2542 %true = OpConstantTrue %bool
2543 %main = OpFunction %void None %3
2544 %5 = OpLabel
2545 %16 = OpFunctionCall %void %kill_
2546 OpReturn
2547 OpFunctionEnd
2548 %kill_ = OpFunction %void None %3
2549 %7 = OpLabel
2550 OpTerminateInvocation
2551 OpFunctionEnd
2552 )";
2553 
2554   const std::string after =
2555       R"(OpCapability Shader
2556 OpExtension "SPV_KHR_terminate_invocation"
2557 %1 = OpExtInstImport "GLSL.std.450"
2558 OpMemoryModel Logical GLSL450
2559 OpEntryPoint Fragment %main "main"
2560 OpExecutionMode %main OriginUpperLeft
2561 OpSource GLSL 330
2562 OpName %main "main"
2563 OpName %kill_ "kill("
2564 %void = OpTypeVoid
2565 %3 = OpTypeFunction %void
2566 %bool = OpTypeBool
2567 %true = OpConstantTrue %bool
2568 %main = OpFunction %void None %3
2569 %5 = OpLabel
2570 OpTerminateInvocation
2571 %18 = OpLabel
2572 OpReturn
2573 OpFunctionEnd
2574 %kill_ = OpFunction %void None %3
2575 %7 = OpLabel
2576 OpTerminateInvocation
2577 OpFunctionEnd
2578 )";
2579 
2580   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2581   SinglePassRunAndCheck<InlineExhaustivePass>(before, after, false, true);
2582 }
2583 
TEST_F(InlineTest,InlineFuncWithOpTerminateRayNotInContinue)2584 TEST_F(InlineTest, InlineFuncWithOpTerminateRayNotInContinue) {
2585   const std::string text =
2586       R"(
2587                OpCapability RayTracingKHR
2588                OpExtension "SPV_KHR_ray_tracing"
2589                OpMemoryModel Logical GLSL450
2590                OpEntryPoint AnyHitKHR %MyAHitMain2 "MyAHitMain2" %a
2591                OpSource HLSL 630
2592                OpName %a "a"
2593                OpName %MyAHitMain2 "MyAHitMain2"
2594                OpName %param_var_a "param.var.a"
2595                OpName %src_MyAHitMain2 "src.MyAHitMain2"
2596                OpName %a_0 "a"
2597                OpName %bb_entry "bb.entry"
2598         %int = OpTypeInt 32 1
2599 %_ptr_IncomingRayPayloadKHR_int = OpTypePointer IncomingRayPayloadKHR %int
2600        %void = OpTypeVoid
2601           %6 = OpTypeFunction %void
2602 %_ptr_Function_int = OpTypePointer Function %int
2603          %14 = OpTypeFunction %void %_ptr_Function_int
2604           %a = OpVariable %_ptr_IncomingRayPayloadKHR_int IncomingRayPayloadKHR
2605 %MyAHitMain2 = OpFunction %void None %6
2606           %7 = OpLabel
2607 %param_var_a = OpVariable %_ptr_Function_int Function
2608          %10 = OpLoad %int %a
2609                OpStore %param_var_a %10
2610          %11 = OpFunctionCall %void %src_MyAHitMain2 %param_var_a
2611          %13 = OpLoad %int %param_var_a
2612                OpStore %a %13
2613                OpReturn
2614                OpFunctionEnd
2615 %src_MyAHitMain2 = OpFunction %void None %14
2616         %a_0 = OpFunctionParameter %_ptr_Function_int
2617    %bb_entry = OpLabel
2618          %17 = OpLoad %int %a_0
2619                OpStore %a %17
2620                OpTerminateRayKHR
2621                OpFunctionEnd
2622 
2623 ; CHECK:      %MyAHitMain2 = OpFunction %void None
2624 ; CHECK-NEXT: OpLabel
2625 ; CHECK-NEXT:   %param_var_a = OpVariable %_ptr_Function_int Function
2626 ; CHECK-NEXT:   OpLoad %int %a
2627 ; CHECK-NEXT:   OpStore %param_var_a {{%\d+}}
2628 ; CHECK-NEXT:   OpLoad %int %param_var_a
2629 ; CHECK-NEXT:   OpStore %a {{%\d+}}
2630 ; CHECK-NEXT:   OpTerminateRayKHR
2631 ; CHECK-NEXT: OpLabel
2632 ; CHECK-NEXT:   OpLoad %int %param_var_a
2633 ; CHECK-NEXT:   OpStore %a %16
2634 ; CHECK-NEXT:   OpReturn
2635 ; CHECK-NEXT: OpFunctionEnd
2636 )";
2637 
2638   SinglePassRunAndMatch<InlineExhaustivePass>(text, false);
2639 }
2640 
TEST_F(InlineTest,EarlyReturnFunctionInlined)2641 TEST_F(InlineTest, EarlyReturnFunctionInlined) {
2642   // #version 140
2643   //
2644   // in vec4 BaseColor;
2645   //
2646   // float foo(vec4 bar)
2647   // {
2648   //     if (bar.x < 0.0)
2649   //         return 0.0;
2650   //     return bar.x;
2651   // }
2652   //
2653   // void main()
2654   // {
2655   //     vec4 color = vec4(foo(BaseColor));
2656   //     gl_FragColor = color;
2657   // }
2658 
2659   const std::string predefs =
2660       R"(OpCapability Shader
2661 %1 = OpExtInstImport "GLSL.std.450"
2662 OpMemoryModel Logical GLSL450
2663 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
2664 OpExecutionMode %main OriginUpperLeft
2665 OpSource GLSL 140
2666 OpName %main "main"
2667 OpName %foo_vf4_ "foo(vf4;"
2668 OpName %bar "bar"
2669 OpName %color "color"
2670 OpName %BaseColor "BaseColor"
2671 OpName %param "param"
2672 OpName %gl_FragColor "gl_FragColor"
2673 %void = OpTypeVoid
2674 %10 = OpTypeFunction %void
2675 %float = OpTypeFloat 32
2676 %v4float = OpTypeVector %float 4
2677 %_ptr_Function_v4float = OpTypePointer Function %v4float
2678 %14 = OpTypeFunction %float %_ptr_Function_v4float
2679 %uint = OpTypeInt 32 0
2680 %uint_0 = OpConstant %uint 0
2681 %_ptr_Function_float = OpTypePointer Function %float
2682 %float_0 = OpConstant %float 0
2683 %bool = OpTypeBool
2684 %_ptr_Input_v4float = OpTypePointer Input %v4float
2685 %BaseColor = OpVariable %_ptr_Input_v4float Input
2686 %_ptr_Output_v4float = OpTypePointer Output %v4float
2687 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
2688 )";
2689 
2690   const std::string foo =
2691       R"(%foo_vf4_ = OpFunction %float None %14
2692 %bar = OpFunctionParameter %_ptr_Function_v4float
2693 %27 = OpLabel
2694 %28 = OpAccessChain %_ptr_Function_float %bar %uint_0
2695 %29 = OpLoad %float %28
2696 %30 = OpFOrdLessThan %bool %29 %float_0
2697 OpSelectionMerge %31 None
2698 OpBranchConditional %30 %32 %31
2699 %32 = OpLabel
2700 OpReturnValue %float_0
2701 %31 = OpLabel
2702 %33 = OpAccessChain %_ptr_Function_float %bar %uint_0
2703 %34 = OpLoad %float %33
2704 OpReturnValue %34
2705 OpFunctionEnd
2706 )";
2707 
2708   const std::string fooMergeReturn =
2709       R"(%foo_vf4_ = OpFunction %float None %14
2710 %bar = OpFunctionParameter %_ptr_Function_v4float
2711 %27 = OpLabel
2712 %41 = OpVariable %_ptr_Function_bool Function %false
2713 %36 = OpVariable %_ptr_Function_float Function
2714 OpSelectionMerge %35 None
2715 OpSwitch %uint_0 %38
2716 %38 = OpLabel
2717 %28 = OpAccessChain %_ptr_Function_float %bar %uint_0
2718 %29 = OpLoad %float %28
2719 %30 = OpFOrdLessThan %bool %29 %float_0
2720 OpSelectionMerge %31 None
2721 OpBranchConditional %30 %32 %31
2722 %32 = OpLabel
2723 OpStore %41 %true
2724 OpStore %36 %float_0
2725 OpBranch %35
2726 %31 = OpLabel
2727 %33 = OpAccessChain %_ptr_Function_float %bar %uint_0
2728 %34 = OpLoad %float %33
2729 OpStore %41 %true
2730 OpStore %36 %34
2731 OpBranch %35
2732 %35 = OpLabel
2733 %37 = OpLoad %float %36
2734 OpReturnValue %37
2735 OpFunctionEnd
2736 )";
2737 
2738   const std::string before =
2739       R"(%main = OpFunction %void None %10
2740 %22 = OpLabel
2741 %color = OpVariable %_ptr_Function_v4float Function
2742 %param = OpVariable %_ptr_Function_v4float Function
2743 %23 = OpLoad %v4float %BaseColor
2744 OpStore %param %23
2745 %24 = OpFunctionCall %float %foo_vf4_ %param
2746 %25 = OpCompositeConstruct %v4float %24 %24 %24 %24
2747 OpStore %color %25
2748 %26 = OpLoad %v4float %color
2749 OpStore %gl_FragColor %26
2750 OpReturn
2751 OpFunctionEnd
2752 )";
2753 
2754   const std::string after =
2755       R"(%false = OpConstantFalse %bool
2756 %_ptr_Function_bool = OpTypePointer Function %bool
2757 %true = OpConstantTrue %bool
2758 %main = OpFunction %void None %10
2759 %22 = OpLabel
2760 %43 = OpVariable %_ptr_Function_bool Function %false
2761 %44 = OpVariable %_ptr_Function_float Function
2762 %45 = OpVariable %_ptr_Function_float Function
2763 %color = OpVariable %_ptr_Function_v4float Function
2764 %param = OpVariable %_ptr_Function_v4float Function
2765 %23 = OpLoad %v4float %BaseColor
2766 OpStore %param %23
2767 OpStore %43 %false
2768 OpSelectionMerge %55 None
2769 OpSwitch %uint_0 %47
2770 %47 = OpLabel
2771 %48 = OpAccessChain %_ptr_Function_float %param %uint_0
2772 %49 = OpLoad %float %48
2773 %50 = OpFOrdLessThan %bool %49 %float_0
2774 OpSelectionMerge %52 None
2775 OpBranchConditional %50 %51 %52
2776 %51 = OpLabel
2777 OpStore %43 %true
2778 OpStore %44 %float_0
2779 OpBranch %55
2780 %52 = OpLabel
2781 %53 = OpAccessChain %_ptr_Function_float %param %uint_0
2782 %54 = OpLoad %float %53
2783 OpStore %43 %true
2784 OpStore %44 %54
2785 OpBranch %55
2786 %55 = OpLabel
2787 %56 = OpLoad %float %44
2788 OpStore %45 %56
2789 %24 = OpLoad %float %45
2790 %25 = OpCompositeConstruct %v4float %24 %24 %24 %24
2791 OpStore %color %25
2792 %26 = OpLoad %v4float %color
2793 OpStore %gl_FragColor %26
2794 OpReturn
2795 OpFunctionEnd
2796 )";
2797 
2798   // The early return case must be handled by merge-return first.
2799   AddPass<MergeReturnPass>();
2800   AddPass<InlineExhaustivePass>();
2801   RunAndCheck(predefs + before + foo, predefs + after + fooMergeReturn);
2802 }
2803 
TEST_F(InlineTest,EarlyReturnNotAppearingLastInFunctionInlined)2804 TEST_F(InlineTest, EarlyReturnNotAppearingLastInFunctionInlined) {
2805   // Example from https://github.com/KhronosGroup/SPIRV-Tools/issues/755
2806   //
2807   // Original example is derived from:
2808   //
2809   // #version 450
2810   //
2811   // float foo() {
2812   //     if (true) {
2813   //     }
2814   // }
2815   //
2816   // void main() { foo(); }
2817   //
2818   // But the order of basic blocks in foo is changed so that the return
2819   // block is listed second-last.  There is only one return in the callee
2820   // but it does not appear last.
2821 
2822   const std::string predefs =
2823       R"(OpCapability Shader
2824 OpMemoryModel Logical GLSL450
2825 OpEntryPoint Vertex %main "main"
2826 OpSource GLSL 450
2827 OpName %main "main"
2828 OpName %foo_ "foo("
2829 %void = OpTypeVoid
2830 %4 = OpTypeFunction %void
2831 %bool = OpTypeBool
2832 %true = OpConstantTrue %bool
2833 )";
2834 
2835   const std::string foo =
2836       R"(%foo_ = OpFunction %void None %4
2837 %7 = OpLabel
2838 OpSelectionMerge %8 None
2839 OpBranchConditional %true %9 %8
2840 %8 = OpLabel
2841 OpReturn
2842 %9 = OpLabel
2843 OpBranch %8
2844 OpFunctionEnd
2845 )";
2846 
2847   const std::string fooMergeReturn =
2848       R"(%uint = OpTypeInt 32 0
2849 %uint_0 = OpConstant %uint 0
2850 %false = OpConstantFalse %bool
2851 %_ptr_Function_bool = OpTypePointer Function %bool
2852 %foo_ = OpFunction %void None %4
2853 %7 = OpLabel
2854 %18 = OpVariable %_ptr_Function_bool Function %false
2855 OpSelectionMerge %12 None
2856 OpSwitch %uint_0 %13
2857 %13 = OpLabel
2858 OpSelectionMerge %8 None
2859 OpBranchConditional %true %9 %8
2860 %8 = OpLabel
2861 OpStore %18 %true
2862 OpBranch %12
2863 %9 = OpLabel
2864 OpBranch %8
2865 %12 = OpLabel
2866 OpReturn
2867 OpFunctionEnd
2868 )";
2869 
2870   const std::string before =
2871       R"(%main = OpFunction %void None %4
2872 %10 = OpLabel
2873 %11 = OpFunctionCall %void %foo_
2874 OpReturn
2875 OpFunctionEnd
2876 )";
2877 
2878   const std::string after =
2879       R"(%main = OpFunction %void None %4
2880 %10 = OpLabel
2881 %19 = OpVariable %_ptr_Function_bool Function %false
2882 OpStore %19 %false
2883 OpSelectionMerge %24 None
2884 OpSwitch %uint_0 %21
2885 %21 = OpLabel
2886 OpSelectionMerge %22 None
2887 OpBranchConditional %true %23 %22
2888 %22 = OpLabel
2889 OpStore %19 %true
2890 OpBranch %24
2891 %23 = OpLabel
2892 OpBranch %22
2893 %24 = OpLabel
2894 OpReturn
2895 OpFunctionEnd
2896 )";
2897 
2898   // The early return case must be handled by merge-return first.
2899   AddPass<MergeReturnPass>();
2900   AddPass<InlineExhaustivePass>();
2901   RunAndCheck(predefs + foo + before, predefs + fooMergeReturn + after);
2902 }
2903 
TEST_F(InlineTest,CalleeWithSingleReturnNeedsSingleTripLoopWrapper)2904 TEST_F(InlineTest, CalleeWithSingleReturnNeedsSingleTripLoopWrapper) {
2905   // The case from https://github.com/KhronosGroup/SPIRV-Tools/issues/2018
2906   //
2907   // The callee has a single return, but needs single-trip loop wrapper
2908   // to be inlined because the return is in a selection structure.
2909 
2910   const std::string predefs =
2911       R"(OpCapability Shader
2912 %1 = OpExtInstImport "GLSL.std.450"
2913 OpMemoryModel Logical GLSL450
2914 OpEntryPoint Fragment %main "main" %_GLF_color
2915 OpExecutionMode %main OriginUpperLeft
2916 OpSource ESSL 310
2917 OpName %main "main"
2918 OpName %f_ "f("
2919 OpName %i "i"
2920 OpName %_GLF_color "_GLF_color"
2921 OpDecorate %_GLF_color Location 0
2922 %void = OpTypeVoid
2923 %7 = OpTypeFunction %void
2924 %float = OpTypeFloat 32
2925 %9 = OpTypeFunction %float
2926 %float_1 = OpConstant %float 1
2927 %bool = OpTypeBool
2928 %false = OpConstantFalse %bool
2929 %true = OpConstantTrue %bool
2930 %int = OpTypeInt 32 1
2931 %_ptr_Function_int = OpTypePointer Function %int
2932 %int_0 = OpConstant %int 0
2933 %int_1 = OpConstant %int 1
2934 %v4float = OpTypeVector %float 4
2935 %_ptr_Output_v4float = OpTypePointer Output %v4float
2936 %_GLF_color = OpVariable %_ptr_Output_v4float Output
2937 %float_0 = OpConstant %float 0
2938 %21 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
2939 %22 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1
2940 )";
2941 
2942   const std::string new_predefs =
2943       R"(%_ptr_Function_float = OpTypePointer Function %float
2944 %uint = OpTypeInt 32 0
2945 %uint_0 = OpConstant %uint 0
2946 %_ptr_Function_bool = OpTypePointer Function %bool
2947 )";
2948 
2949   const std::string main_before =
2950       R"(%main = OpFunction %void None %7
2951 %23 = OpLabel
2952 %i = OpVariable %_ptr_Function_int Function
2953 OpStore %i %int_0
2954 OpBranch %24
2955 %24 = OpLabel
2956 OpLoopMerge %25 %26 None
2957 OpBranch %27
2958 %27 = OpLabel
2959 %28 = OpLoad %int %i
2960 %29 = OpSLessThan %bool %28 %int_1
2961 OpBranchConditional %29 %30 %25
2962 %30 = OpLabel
2963 OpStore %_GLF_color %21
2964 %31 = OpFunctionCall %float %f_
2965 OpBranch %26
2966 %26 = OpLabel
2967 %32 = OpLoad %int %i
2968 %33 = OpIAdd %int %32 %int_1
2969 OpStore %i %33
2970 OpBranch %24
2971 %25 = OpLabel
2972 OpStore %_GLF_color %22
2973 OpReturn
2974 OpFunctionEnd
2975 )";
2976 
2977   const std::string main_after =
2978       R"(%main = OpFunction %void None %7
2979 %23 = OpLabel
2980 %46 = OpVariable %_ptr_Function_bool Function %false
2981 %47 = OpVariable %_ptr_Function_float Function
2982 %48 = OpVariable %_ptr_Function_float Function
2983 %i = OpVariable %_ptr_Function_int Function
2984 OpStore %i %int_0
2985 OpBranch %24
2986 %24 = OpLabel
2987 OpLoopMerge %25 %26 None
2988 OpBranch %27
2989 %27 = OpLabel
2990 %28 = OpLoad %int %i
2991 %29 = OpSLessThan %bool %28 %int_1
2992 OpBranchConditional %29 %30 %25
2993 %30 = OpLabel
2994 OpStore %_GLF_color %21
2995 OpStore %46 %false
2996 OpSelectionMerge %53 None
2997 OpSwitch %uint_0 %50
2998 %50 = OpLabel
2999 OpSelectionMerge %52 None
3000 OpBranchConditional %true %51 %52
3001 %51 = OpLabel
3002 OpStore %46 %true
3003 OpStore %47 %float_1
3004 OpBranch %53
3005 %52 = OpLabel
3006 OpStore %46 %true
3007 OpStore %47 %float_1
3008 OpBranch %53
3009 %53 = OpLabel
3010 %54 = OpLoad %float %47
3011 OpStore %48 %54
3012 %31 = OpLoad %float %48
3013 OpBranch %26
3014 %26 = OpLabel
3015 %32 = OpLoad %int %i
3016 %33 = OpIAdd %int %32 %int_1
3017 OpStore %i %33
3018 OpBranch %24
3019 %25 = OpLabel
3020 OpStore %_GLF_color %22
3021 OpReturn
3022 OpFunctionEnd
3023 )";
3024 
3025   const std::string callee =
3026       R"(%f_ = OpFunction %float None %9
3027 %34 = OpLabel
3028 OpSelectionMerge %35 None
3029 OpBranchConditional %true %36 %35
3030 %36 = OpLabel
3031 OpReturnValue %float_1
3032 %35 = OpLabel
3033 OpReturnValue %float_1
3034 OpFunctionEnd
3035 )";
3036 
3037   const std::string calleeMergeReturn =
3038       R"(%f_ = OpFunction %float None %9
3039 %34 = OpLabel
3040 %45 = OpVariable %_ptr_Function_bool Function %false
3041 %39 = OpVariable %_ptr_Function_float Function
3042 OpSelectionMerge %37 None
3043 OpSwitch %uint_0 %41
3044 %41 = OpLabel
3045 OpSelectionMerge %35 None
3046 OpBranchConditional %true %36 %35
3047 %36 = OpLabel
3048 OpStore %45 %true
3049 OpStore %39 %float_1
3050 OpBranch %37
3051 %35 = OpLabel
3052 OpStore %45 %true
3053 OpStore %39 %float_1
3054 OpBranch %37
3055 %37 = OpLabel
3056 %40 = OpLoad %float %39
3057 OpReturnValue %40
3058 OpFunctionEnd
3059 )";
3060 
3061   // The early return case must be handled by merge-return first.
3062   AddPass<MergeReturnPass>();
3063   AddPass<InlineExhaustivePass>();
3064   RunAndCheck(predefs + main_before + callee,
3065               predefs + new_predefs + main_after + calleeMergeReturn);
3066 }
3067 
TEST_F(InlineTest,ForwardReferencesInPhiInlined)3068 TEST_F(InlineTest, ForwardReferencesInPhiInlined) {
3069   // The basic structure of the test case is like this:
3070   //
3071   // int foo() {
3072   //   int result = 1;
3073   //   if (true) {
3074   //      result = 1;
3075   //   }
3076   //   return result;
3077   // }
3078   //
3079   // void main() {
3080   //  int x = foo();
3081   // }
3082   //
3083   // but with modifications: Using Phi instead of load/store, and the
3084   // return block in foo appears before the "then" block.
3085 
3086   const std::string predefs =
3087       R"(OpCapability Shader
3088 %1 = OpExtInstImport "GLSL.std.450"
3089 OpMemoryModel Logical GLSL450
3090 OpEntryPoint Vertex %main "main"
3091 OpSource GLSL 450
3092 OpName %main "main"
3093 OpName %foo_ "foo("
3094 OpName %x "x"
3095 %void = OpTypeVoid
3096 %6 = OpTypeFunction %void
3097 %int = OpTypeInt 32 1
3098 %8 = OpTypeFunction %int
3099 %bool = OpTypeBool
3100 %true = OpConstantTrue %bool
3101 %int_0 = OpConstant %int 0
3102 %_ptr_Function_int = OpTypePointer Function %int
3103 )";
3104 
3105   const std::string callee =
3106       R"(%foo_ = OpFunction %int None %8
3107 %13 = OpLabel
3108 %14 = OpCopyObject %int %int_0
3109 OpSelectionMerge %15 None
3110 OpBranchConditional %true %16 %15
3111 %15 = OpLabel
3112 %17 = OpPhi %int %14 %13 %18 %16
3113 OpReturnValue %17
3114 %16 = OpLabel
3115 %18 = OpCopyObject %int %int_0
3116 OpBranch %15
3117 OpFunctionEnd
3118 )";
3119 
3120   const std::string calleeMergeReturn =
3121       R"(%uint = OpTypeInt 32 0
3122 %uint_0 = OpConstant %uint 0
3123 %false = OpConstantFalse %bool
3124 %_ptr_Function_bool = OpTypePointer Function %bool
3125 %foo_ = OpFunction %int None %8
3126 %13 = OpLabel
3127 %29 = OpVariable %_ptr_Function_bool Function %false
3128 %22 = OpVariable %_ptr_Function_int Function
3129 OpSelectionMerge %21 None
3130 OpSwitch %uint_0 %24
3131 %24 = OpLabel
3132 %14 = OpCopyObject %int %int_0
3133 OpSelectionMerge %15 None
3134 OpBranchConditional %true %16 %15
3135 %15 = OpLabel
3136 %17 = OpPhi %int %14 %24 %18 %16
3137 OpStore %29 %true
3138 OpStore %22 %17
3139 OpBranch %21
3140 %16 = OpLabel
3141 %18 = OpCopyObject %int %int_0
3142 OpBranch %15
3143 %21 = OpLabel
3144 %23 = OpLoad %int %22
3145 OpReturnValue %23
3146 OpFunctionEnd
3147 )";
3148 
3149   const std::string before =
3150       R"(%main = OpFunction %void None %6
3151 %19 = OpLabel
3152 %x = OpVariable %_ptr_Function_int Function
3153 %20 = OpFunctionCall %int %foo_
3154 OpStore %x %20
3155 OpReturn
3156 OpFunctionEnd
3157 )";
3158 
3159   const std::string after =
3160       R"(%main = OpFunction %void None %6
3161 %19 = OpLabel
3162 %30 = OpVariable %_ptr_Function_bool Function %false
3163 %31 = OpVariable %_ptr_Function_int Function
3164 %32 = OpVariable %_ptr_Function_int Function
3165 %x = OpVariable %_ptr_Function_int Function
3166 OpStore %30 %false
3167 OpSelectionMerge %40 None
3168 OpSwitch %uint_0 %34
3169 %34 = OpLabel
3170 %35 = OpCopyObject %int %int_0
3171 OpSelectionMerge %36 None
3172 OpBranchConditional %true %38 %36
3173 %36 = OpLabel
3174 %37 = OpPhi %int %35 %34 %39 %38
3175 OpStore %30 %true
3176 OpStore %31 %37
3177 OpBranch %40
3178 %38 = OpLabel
3179 %39 = OpCopyObject %int %int_0
3180 OpBranch %36
3181 %40 = OpLabel
3182 %41 = OpLoad %int %31
3183 OpStore %32 %41
3184 %20 = OpLoad %int %32
3185 OpStore %x %20
3186 OpReturn
3187 OpFunctionEnd
3188 )";
3189 
3190   AddPass<MergeReturnPass>();
3191   AddPass<InlineExhaustivePass>();
3192   RunAndCheck(predefs + callee + before, predefs + calleeMergeReturn + after);
3193 }
3194 
TEST_F(InlineTest,DebugSimple)3195 TEST_F(InlineTest, DebugSimple) {
3196   // Check that it correctly generates DebugInlinedAt and maps it to DebugScope
3197   // for the inlined function foo().
3198   const std::string text = R"(
3199 ; CHECK: [[main_name:%\d+]] = OpString "main"
3200 ; CHECK: [[foo_name:%\d+]] = OpString "foo"
3201 ; CHECK: [[dbg_main:%\d+]] = OpExtInst %void {{%\d+}} DebugFunction [[main_name]] {{%\d+}} {{%\d+}} 4 1 {{%\d+}} [[main_name]] FlagIsProtected|FlagIsPrivate 4 [[main:%\d+]]
3202 ; CHECK: [[dbg_foo:%\d+]] = OpExtInst %void {{%\d+}} DebugFunction [[foo_name]] {{%\d+}} {{%\d+}} 1 1 {{%\d+}} [[foo_name]] FlagIsProtected|FlagIsPrivate 1 [[foo:%\d+]]
3203 ; CHECK: [[foo_bb:%\d+]] = OpExtInst %void {{%\d+}} DebugLexicalBlock {{%\d+}} 1 14 [[dbg_foo]]
3204 ; CHECK: [[inlined_at:%\d+]] = OpExtInst %void {{%\d+}} DebugInlinedAt 4 [[dbg_main]]
3205 ; CHECK: [[main]] = OpFunction %void None
3206 ; CHECK: {{%\d+}} = OpExtInst %void {{%\d+}} DebugScope [[foo_bb]] [[inlined_at]]
3207 ; CHECK: [[foo]] = OpFunction %v4float None
3208                OpCapability Shader
3209           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
3210                OpMemoryModel Logical GLSL450
3211                OpEntryPoint Fragment %main "main" %3 %4
3212                OpExecutionMode %main OriginUpperLeft
3213           %5 = OpString "ps.hlsl"
3214                OpSource HLSL 600 %5
3215           %6 = OpString "float"
3216   %main_name = OpString "main"
3217    %foo_name = OpString "foo"
3218                OpDecorate %3 Location 0
3219                OpDecorate %4 Location 0
3220        %uint = OpTypeInt 32 0
3221     %uint_32 = OpConstant %uint 32
3222       %float = OpTypeFloat 32
3223     %float_1 = OpConstant %float 1
3224     %v4float = OpTypeVector %float 4
3225          %14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
3226 %_ptr_Input_v4float = OpTypePointer Input %v4float
3227 %_ptr_Output_v4float = OpTypePointer Output %v4float
3228        %void = OpTypeVoid
3229          %18 = OpTypeFunction %void
3230          %19 = OpTypeFunction %v4float
3231           %3 = OpVariable %_ptr_Input_v4float Input
3232           %4 = OpVariable %_ptr_Output_v4float Output
3233          %20 = OpExtInst %void %1 DebugSource %5
3234          %21 = OpExtInst %void %1 DebugCompilationUnit 1 4 %20 HLSL
3235          %22 = OpExtInst %void %1 DebugTypeBasic %6 %uint_32 Float
3236          %23 = OpExtInst %void %1 DebugTypeVector %22 4
3237          %24 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %23 %23
3238          %25 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %23
3239    %dbg_main = OpExtInst %void %1 DebugFunction %main_name %24 %20 4 1 %21 %main_name FlagIsProtected|FlagIsPrivate 4 %main
3240     %dbg_foo = OpExtInst %void %1 DebugFunction %foo_name %25 %20 1 1 %21 %foo_name FlagIsProtected|FlagIsPrivate 1 %foo
3241          %29 = OpExtInst %void %1 DebugLexicalBlock %20 1 14 %dbg_foo
3242        %main = OpFunction %void None %18
3243          %30 = OpLabel
3244          %31 = OpExtInst %void %1 DebugScope %dbg_main
3245          %32 = OpFunctionCall %v4float %foo
3246          %33 = OpLoad %v4float %3
3247          %34 = OpFAdd %v4float %32 %33
3248                OpStore %4 %34
3249                OpReturn
3250                OpFunctionEnd
3251         %foo = OpFunction %v4float None %19
3252          %35 = OpExtInst %void %1 DebugScope %dbg_foo
3253          %36 = OpLabel
3254          %37 = OpExtInst %void %1 DebugScope %29
3255                OpReturnValue %14
3256                OpFunctionEnd
3257 )";
3258 
3259   SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
3260 }
3261 
TEST_F(InlineTest,DebugNested)3262 TEST_F(InlineTest, DebugNested) {
3263   // When function main() calls function zoo() and function zoo() calls
3264   // function bar() and function bar() calls function foo(), check that
3265   // the inline pass correctly generates DebugInlinedAt instructions
3266   // for the nested function calls.
3267   const std::string text = R"(
3268 ; CHECK: [[v4f1:%\d+]] = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
3269 ; CHECK: [[v4f2:%\d+]] = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
3270 ; CHECK: [[v4f3:%\d+]] = OpConstantComposite %v4float %float_3 %float_3 %float_3 %float_3
3271 ; CHECK: [[color:%\d+]] = OpVariable %_ptr_Input_v4float Input
3272 ; CHECK: [[dbg_main:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction {{%\d+}} {{%\d+}} {{%\d+}} 10 1 {{%\d+}} {{%\d+}} FlagIsProtected|FlagIsPrivate 10 [[main:%\d+]]
3273 ; CHECK: [[dbg_foo:%\d+]] = OpExtInst %void [[ext]] DebugFunction {{%\d+}} {{%\d+}} {{%\d+}} 1 1 {{%\d+}} {{%\d+}} FlagIsProtected|FlagIsPrivate 1 [[foo:%\d+]]
3274 ; CHECK: [[dbg_bar:%\d+]] = OpExtInst %void [[ext]] DebugFunction {{%\d+}} {{%\d+}} {{%\d+}} 4 1 {{%\d+}} {{%\d+}} FlagIsProtected|FlagIsPrivate 4 [[bar:%\d+]]
3275 ; CHECK: [[dbg_zoo:%\d+]] = OpExtInst %void [[ext]] DebugFunction {{%\d+}} {{%\d+}} {{%\d+}} 7 1 {{%\d+}} {{%\d+}} FlagIsProtected|FlagIsPrivate 7 [[zoo:%\d+]]
3276 ; CHECK: [[inlined_to_main:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 600 [[dbg_main]]
3277 ; CHECK: [[inlined_to_zoo:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 700 [[dbg_zoo]] [[inlined_to_main]]
3278 ; CHECK: [[inlined_to_bar:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 300 [[dbg_bar]] [[inlined_to_zoo]]
3279 ; CHECK: [[main]] = OpFunction %void None
3280 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_foo]] [[inlined_to_bar]]
3281 ; CHECK-NEXT: OpLine {{%\d+}} 100 0
3282 ; CHECK-NEXT: OpStore {{%\d+}} [[v4f1]]
3283 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_bar]] [[inlined_to_zoo]]
3284 ; CHECK-NEXT: OpLine {{%\d+}} 300 0
3285 ; CHECK-NEXT: [[foo_ret:%\d+]] = OpLoad %v4float
3286 ; CHECK-NEXT: OpLine {{%\d+}} 400 0
3287 ; CHECK-NEXT: {{%\d+}} = OpFAdd %v4float [[foo_ret]] [[v4f2]]
3288 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_zoo]] [[inlined_to_main]]
3289 ; CHECK-NEXT: OpLine {{%\d+}} 700 0
3290 ; CHECK-NEXT: [[bar_ret:%\d+]] = OpLoad %v4float
3291 ; CHECK-NEXT: {{%\d+}} = OpFAdd %v4float [[bar_ret]] [[v4f3]]
3292 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_main]]
3293 ; CHECK-NEXT: OpLine {{%\d+}} 600 0
3294 ; CHECK-NEXT: [[zoo_ret:%\d+]] = OpLoad %v4float
3295 ; CHECK-NEXT: [[color_val:%\d+]] = OpLoad %v4float [[color]]
3296 ; CHECK-NEXT: {{%\d+}} = OpFAdd %v4float [[zoo_ret]] [[color_val]]
3297 ; CHECK: [[foo]] = OpFunction %v4float None
3298 ; CHECK: [[bar]] = OpFunction %v4float None
3299 ; CHECK: [[zoo]] = OpFunction %v4float None
3300                OpCapability Shader
3301           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
3302                OpMemoryModel Logical GLSL450
3303                OpEntryPoint Fragment %main "main" %3 %4
3304                OpExecutionMode %main OriginUpperLeft
3305           %5 = OpString "ps.hlsl"
3306                OpSource HLSL 600 %5
3307           %6 = OpString "float"
3308           %7 = OpString "main"
3309           %8 = OpString "foo"
3310           %9 = OpString "bar"
3311          %10 = OpString "zoo"
3312                OpDecorate %3 Location 0
3313                OpDecorate %4 Location 0
3314        %uint = OpTypeInt 32 0
3315     %uint_32 = OpConstant %uint 32
3316       %float = OpTypeFloat 32
3317     %float_1 = OpConstant %float 1
3318     %float_2 = OpConstant %float 2
3319     %float_3 = OpConstant %float 3
3320     %v4float = OpTypeVector %float 4
3321          %18 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
3322          %19 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
3323          %20 = OpConstantComposite %v4float %float_3 %float_3 %float_3 %float_3
3324 %_ptr_Input_v4float = OpTypePointer Input %v4float
3325 %_ptr_Output_v4float = OpTypePointer Output %v4float
3326        %void = OpTypeVoid
3327          %24 = OpTypeFunction %void
3328          %25 = OpTypeFunction %v4float
3329           %3 = OpVariable %_ptr_Input_v4float Input
3330           %4 = OpVariable %_ptr_Output_v4float Output
3331          %26 = OpExtInst %void %1 DebugSource %5
3332          %27 = OpExtInst %void %1 DebugCompilationUnit 1 4 %26 HLSL
3333          %28 = OpExtInst %void %1 DebugTypeBasic %6 %uint_32 Float
3334          %29 = OpExtInst %void %1 DebugTypeVector %28 4
3335          %30 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %29 %29
3336          %31 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %29
3337          %32 = OpExtInst %void %1 DebugFunction %7 %30 %26 10 1 %27 %7 FlagIsProtected|FlagIsPrivate 10 %main
3338          %33 = OpExtInst %void %1 DebugFunction %8 %31 %26 1 1 %27 %8 FlagIsProtected|FlagIsPrivate 1 %foo
3339          %35 = OpExtInst %void %1 DebugFunction %9 %31 %26 4 1 %27 %9 FlagIsProtected|FlagIsPrivate 4 %bar
3340          %37 = OpExtInst %void %1 DebugFunction %10 %31 %26 7 1 %27 %10 FlagIsProtected|FlagIsPrivate 7 %zoo
3341        %main = OpFunction %void None %24
3342          %39 = OpLabel
3343          %40 = OpExtInst %void %1 DebugScope %32
3344                OpLine %5 600 0
3345          %41 = OpFunctionCall %v4float %zoo
3346          %42 = OpLoad %v4float %3
3347          %43 = OpFAdd %v4float %41 %42
3348                OpStore %4 %43
3349                OpReturn
3350                OpFunctionEnd
3351         %foo = OpFunction %v4float None %25
3352          %44 = OpExtInst %void %1 DebugScope %33
3353          %45 = OpLabel
3354                OpLine %5 100 0
3355                OpReturnValue %18
3356                OpFunctionEnd
3357                OpLine %5 200 0
3358         %bar = OpFunction %v4float None %25
3359          %46 = OpExtInst %void %1 DebugScope %35
3360          %47 = OpLabel
3361                OpLine %5 300 0
3362          %48 = OpFunctionCall %v4float %foo
3363                OpLine %5 400 0
3364          %49 = OpFAdd %v4float %48 %19
3365                OpLine %5 500 0
3366                OpReturnValue %49
3367                OpFunctionEnd
3368         %zoo = OpFunction %v4float None %25
3369          %50 = OpExtInst %void %1 DebugScope %37
3370          %51 = OpLabel
3371                OpLine %5 700 0
3372          %52 = OpFunctionCall %v4float %bar
3373          %53 = OpFAdd %v4float %52 %20
3374                OpReturnValue %53
3375                OpFunctionEnd
3376 )";
3377 
3378   SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
3379 }
3380 
TEST_F(InlineTest,DebugSimpleHLSLPixelShader)3381 TEST_F(InlineTest, DebugSimpleHLSLPixelShader) {
3382   const std::string text = R"(
3383 ; CHECK: [[dbg_main:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction {{%\d+}} {{%\d+}} {{%\d+}} 1 1 {{%\d+}} {{%\d+}} FlagIsProtected|FlagIsPrivate 1 %src_main
3384 ; CHECK: [[lex_blk:%\d+]] = OpExtInst %void [[ext]] DebugLexicalBlock {{%\d+}} 1 47 [[dbg_main]]
3385 ; CHECK: %main = OpFunction %void None
3386 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_main]]
3387 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugDeclare {{%\d+}} %param_var_color
3388 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[lex_blk]]
3389 ; CHECK: OpLine {{%\d+}} 2 10
3390 ; CHECK: {{%\d+}} = OpLoad %v4float %param_var_color
3391 ; CHECK: OpLine {{%\d+}} 2 3
3392 ; CHECK: OpFunctionEnd
3393 ; CHECK: %src_main = OpFunction %v4float None
3394                OpCapability Shader
3395           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
3396                OpMemoryModel Logical GLSL450
3397                OpEntryPoint Fragment %main "main" %in_var_COLOR %out_var_SV_TARGET
3398                OpExecutionMode %main OriginUpperLeft
3399           %5 = OpString "ps.hlsl"
3400                OpSource HLSL 600 %5
3401          %14 = OpString "#line 1 \"ps.hlsl\"
3402 float4 main(float4 color : COLOR) : SV_TARGET {
3403   return color;
3404 }
3405 "
3406          %17 = OpString "float"
3407          %21 = OpString "src.main"
3408          %24 = OpString "color"
3409                OpName %in_var_COLOR "in.var.COLOR"
3410                OpName %out_var_SV_TARGET "out.var.SV_TARGET"
3411                OpName %main "main"
3412                OpName %param_var_color "param.var.color"
3413                OpName %src_main "src.main"
3414                OpName %color "color"
3415                OpName %bb_entry "bb.entry"
3416                OpDecorate %in_var_COLOR Location 0
3417                OpDecorate %out_var_SV_TARGET Location 0
3418        %uint = OpTypeInt 32 0
3419     %uint_32 = OpConstant %uint 32
3420       %float = OpTypeFloat 32
3421     %v4float = OpTypeVector %float 4
3422 %_ptr_Input_v4float = OpTypePointer Input %v4float
3423 %_ptr_Output_v4float = OpTypePointer Output %v4float
3424        %void = OpTypeVoid
3425          %27 = OpTypeFunction %void
3426 %_ptr_Function_v4float = OpTypePointer Function %v4float
3427          %33 = OpTypeFunction %v4float %_ptr_Function_v4float
3428 %in_var_COLOR = OpVariable %_ptr_Input_v4float Input
3429 %out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
3430          %13 = OpExtInst %void %1 DebugExpression
3431          %15 = OpExtInst %void %1 DebugSource %5 %14
3432          %16 = OpExtInst %void %1 DebugCompilationUnit 1 4 %15 HLSL
3433          %18 = OpExtInst %void %1 DebugTypeBasic %17 %uint_32 Float
3434          %19 = OpExtInst %void %1 DebugTypeVector %18 4
3435          %20 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %19 %19
3436          %22 = OpExtInst %void %1 DebugFunction %21 %20 %15 1 1 %16 %21 FlagIsProtected|FlagIsPrivate 1 %src_main
3437          %25 = OpExtInst %void %1 DebugLocalVariable %24 %19 %15 1 20 %22 FlagIsLocal 0
3438          %26 = OpExtInst %void %1 DebugLexicalBlock %15 1 47 %22
3439        %main = OpFunction %void None %27
3440          %28 = OpLabel
3441 %param_var_color = OpVariable %_ptr_Function_v4float Function
3442          %31 = OpLoad %v4float %in_var_COLOR
3443                OpStore %param_var_color %31
3444          %32 = OpFunctionCall %v4float %src_main %param_var_color
3445                OpStore %out_var_SV_TARGET %32
3446                OpReturn
3447                OpFunctionEnd
3448                OpLine %5 1 1
3449    %src_main = OpFunction %v4float None %33
3450          %34 = OpExtInst %void %1 DebugScope %22
3451       %color = OpFunctionParameter %_ptr_Function_v4float
3452          %36 = OpExtInst %void %1 DebugDeclare %25 %color %13
3453    %bb_entry = OpLabel
3454          %38 = OpExtInst %void %1 DebugScope %26
3455                OpLine %5 2 10
3456          %39 = OpLoad %v4float %color
3457                OpLine %5 2 3
3458                OpReturnValue %39
3459                OpFunctionEnd
3460 )";
3461 
3462   SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
3463 }
3464 
3465 TEST_F(InlineTest, DebugDeclareForCalleeFunctionParam) {
3466   // Check that InlinePass correctly generates DebugDeclare instructions
3467   // for callee function's parameters and maps them to corresponding
3468   // local variables of caller function.
3469   const std::string text = R"(
3470 ; CHECK: [[add:%\d+]] = OpString "add"
3471 ; CHECK: [[a:%\d+]] = OpString "a"
3472 ; CHECK: [[b:%\d+]] = OpString "b"
3473 ; CHECK: [[dbg_add:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction [[add]]
3474 ; CHECK: [[dbg_a:%\d+]] = OpExtInst %void [[ext]] DebugLocalVariable [[a]]
3475 ; CHECK: [[dbg_b:%\d+]] = OpExtInst %void [[ext]] DebugLocalVariable [[b]]
3476 ; CHECK: [[inlinedat:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 5
3477 ; CHECK: OpStore [[param_a:%\d+]]
3478 ; CHECK: OpStore [[param_b:%\d+]]
3479 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_add]] [[inlinedat]]
3480 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugDeclare [[dbg_a]] [[param_a]]
3481 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugDeclare [[dbg_b]] [[param_b]]
3482 
3483 OpCapability Shader
3484 %ext = OpExtInstImport "OpenCL.DebugInfo.100"
3485 OpMemoryModel Logical GLSL450
3486 OpEntryPoint Fragment %main "main" %in_var_COLOR %out_var_SV_TARGET
3487 OpExecutionMode %main OriginUpperLeft
3488 %file_name = OpString "ps.hlsl"
3489 OpSource HLSL 600 %file_name
3490 %float_name = OpString "float"
3491 %main_name = OpString "main"
3492 %add_name = OpString "add"
3493 %a_name = OpString "a"
3494 %b_name = OpString "b"
3495 OpDecorate %in_var_COLOR Location 0
3496 OpDecorate %out_var_SV_TARGET Location 0
3497 %uint = OpTypeInt 32 0
3498 %uint_32 = OpConstant %uint 32
3499 %float = OpTypeFloat 32
3500 %float_1 = OpConstant %float 1
3501 %float_2 = OpConstant %float 2
3502 %v4float = OpTypeVector %float 4
3503 %v4f1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
3504 %v4f2 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
3505 %_ptr_Input_v4float = OpTypePointer Input %v4float
3506 %_ptr_Output_v4float = OpTypePointer Output %v4float
3507 %_ptr_Function_v4float = OpTypePointer Function %v4float
3508 %add_fn_type = OpTypeFunction %v4float %_ptr_Function_v4float %_ptr_Function_v4float
3509 %void = OpTypeVoid
3510 %void_fn_type = OpTypeFunction %void
3511 %v4f_fn_type = OpTypeFunction %v4float
3512 %in_var_COLOR = OpVariable %_ptr_Input_v4float Input
3513 %out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
3514 %null_expr = OpExtInst %void %ext DebugExpression
3515 %src = OpExtInst %void %ext DebugSource %file_name
3516 %cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
3517 %dbg_f = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
3518 %dbg_v4f = OpExtInst %void %ext DebugTypeVector %dbg_f 4
3519 %main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f
3520 %add_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f %dbg_v4f
3521 %dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 5 1 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
3522 %dbg_add = OpExtInst %void %ext DebugFunction %add_name %add_ty %src 1 1 %cu %add_name FlagIsProtected|FlagIsPrivate 1 %add
3523 %dbg_a = OpExtInst %void %ext DebugLocalVariable %a_name %dbg_v4f %src 1 13 %dbg_add FlagIsLocal 0
3524 %dbg_b = OpExtInst %void %ext DebugLocalVariable %b_name %dbg_v4f %src 1 20 %dbg_add FlagIsLocal 1
3525 %add_lb = OpExtInst %void %ext DebugLexicalBlock %src 1 23 %dbg_add
3526 %main = OpFunction %void None %void_fn_type
3527 %main_bb = OpLabel
3528 %param_a = OpVariable %_ptr_Function_v4float Function
3529 %param_b = OpVariable %_ptr_Function_v4float Function
3530 %scope0 = OpExtInst %void %ext DebugScope %dbg_main
3531 OpStore %param_a %v4f1
3532 OpStore %param_b %v4f2
3533 %result = OpFunctionCall %v4float %add %param_a %param_b
3534 OpStore %out_var_SV_TARGET %result
3535 OpReturn
3536 OpFunctionEnd
3537 %add = OpFunction %v4float None %add_fn_type
3538 %scope1 = OpExtInst %void %ext DebugScope %dbg_add
3539 %a = OpFunctionParameter %_ptr_Function_v4float
3540 %b = OpFunctionParameter %_ptr_Function_v4float
3541 %decl0 = OpExtInst %void %ext DebugDeclare %dbg_a %a %null_expr
3542 %decl1 = OpExtInst %void %ext DebugDeclare %dbg_b %b %null_expr
3543 %add_bb = OpLabel
3544 %scope2 = OpExtInst %void %ext DebugScope %add_lb
3545 %a_val = OpLoad %v4float %a
3546 %b_val = OpLoad %v4float %b
3547 %res = OpFAdd %v4float %a_val %b_val
3548 OpReturnValue %res
3549 OpFunctionEnd
3550 )";
3551 
3552   SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
3553 }
3554 
3555 TEST_F(InlineTest, DebugDeclareForCalleeLocalVar) {
3556   // Check that InlinePass correctly generates DebugDeclare instructions
3557   // for callee function's local variables and maps them to corresponding
3558   // local variables of caller function.
3559   const std::string text = R"(
3560 ; CHECK: [[add:%\d+]] = OpString "add"
3561 ; CHECK: [[foo:%\d+]] = OpString "foo"
3562 ; CHECK: [[dbg_add:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction [[add]]
3563 ; CHECK: [[dbg_foo:%\d+]] = OpExtInst %void [[ext]] DebugLocalVariable [[foo]] {{%\d+}} {{%\d+}} 2 2 [[dbg_add]]
3564 ; CHECK: [[inlinedat:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 5
3565 
3566 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_add]] [[inlinedat]]
3567 ; CHECK: [[new_foo:%\d+]] = OpVariable %_ptr_Function_v4float Function
3568 
3569 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_add]] [[inlinedat]]
3570 ; CHECK: [[a_val:%\d+]] = OpLoad %v4float
3571 ; CHECK: [[b_val:%\d+]] = OpLoad %v4float
3572 ; CHECK: [[res:%\d+]] = OpFAdd %v4float [[a_val]] [[b_val]]
3573 ; CHECK: OpStore [[new_foo]] [[res]]
3574 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugDeclare [[dbg_foo]] [[new_foo]]
3575 
3576 OpCapability Shader
3577 %ext = OpExtInstImport "OpenCL.DebugInfo.100"
3578 OpMemoryModel Logical GLSL450
3579 OpEntryPoint Fragment %main "main" %in_var_COLOR %out_var_SV_TARGET
3580 OpExecutionMode %main OriginUpperLeft
3581 %file_name = OpString "ps.hlsl"
3582 OpSource HLSL 600 %file_name
3583 %float_name = OpString "float"
3584 %main_name = OpString "main"
3585 %add_name = OpString "add"
3586 %foo_name = OpString "foo"
3587 OpDecorate %in_var_COLOR Location 0
3588 OpDecorate %out_var_SV_TARGET Location 0
3589 %uint = OpTypeInt 32 0
3590 %uint_32 = OpConstant %uint 32
3591 %float = OpTypeFloat 32
3592 %float_1 = OpConstant %float 1
3593 %float_2 = OpConstant %float 2
3594 %v4float = OpTypeVector %float 4
3595 %v4f1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
3596 %v4f2 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
3597 %_ptr_Input_v4float = OpTypePointer Input %v4float
3598 %_ptr_Output_v4float = OpTypePointer Output %v4float
3599 %_ptr_Function_v4float = OpTypePointer Function %v4float
3600 %add_fn_type = OpTypeFunction %v4float %_ptr_Function_v4float %_ptr_Function_v4float
3601 %void = OpTypeVoid
3602 %void_fn_type = OpTypeFunction %void
3603 %v4f_fn_type = OpTypeFunction %v4float
3604 %in_var_COLOR = OpVariable %_ptr_Input_v4float Input
3605 %out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
3606 %null_expr = OpExtInst %void %ext DebugExpression
3607 %src = OpExtInst %void %ext DebugSource %file_name
3608 %cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
3609 %dbg_f = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
3610 %dbg_v4f = OpExtInst %void %ext DebugTypeVector %dbg_f 4
3611 %main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f
3612 %add_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f %dbg_v4f
3613 %dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 5 1 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
3614 %dbg_add = OpExtInst %void %ext DebugFunction %add_name %add_ty %src 1 1 %cu %add_name FlagIsProtected|FlagIsPrivate 1 %add
3615 %dbg_foo = OpExtInst %void %ext DebugLocalVariable %foo_name %dbg_v4f %src 2 2 %dbg_add FlagIsLocal
3616 %main = OpFunction %void None %void_fn_type
3617 %main_bb = OpLabel
3618 %param_a = OpVariable %_ptr_Function_v4float Function
3619 %param_b = OpVariable %_ptr_Function_v4float Function
3620 %scope0 = OpExtInst %void %ext DebugScope %dbg_main
3621 OpStore %param_a %v4f1
3622 OpStore %param_b %v4f2
3623 %result = OpFunctionCall %v4float %add %param_a %param_b
3624 OpStore %out_var_SV_TARGET %result
3625 OpReturn
3626 OpFunctionEnd
3627 %add = OpFunction %v4float None %add_fn_type
3628 %scope1 = OpExtInst %void %ext DebugScope %dbg_add
3629 %a = OpFunctionParameter %_ptr_Function_v4float
3630 %b = OpFunctionParameter %_ptr_Function_v4float
3631 %add_bb = OpLabel
3632 %foo = OpVariable %_ptr_Function_v4float Function
3633 %a_val = OpLoad %v4float %a
3634 %b_val = OpLoad %v4float %b
3635 %res = OpFAdd %v4float %a_val %b_val
3636 OpStore %foo %res
3637 %decl = OpExtInst %void %ext DebugDeclare %dbg_foo %foo %null_expr
3638 %foo_val = OpLoad %v4float %foo
3639 OpReturnValue %foo_val
3640 OpFunctionEnd
3641 )";
3642 
3643   SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
3644 }
3645 
3646 TEST_F(InlineTest, DebugDeclareMultiple) {
3647   // Check that InlinePass correctly generates DebugDeclare instructions
3648   // for callee function's parameters and maps them to corresponding
3649   // local variables of caller function.
3650   const std::string text = R"(
3651 ; CHECK: [[add:%\d+]] = OpString "add"
3652 ; CHECK: [[a:%\d+]] = OpString "a"
3653 ; CHECK: [[b:%\d+]] = OpString "b"
3654 ; CHECK: [[dbg_add:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction [[add]]
3655 ; CHECK: [[dbg_a:%\d+]] = OpExtInst %void [[ext]] DebugLocalVariable [[a]]
3656 ; CHECK: [[dbg_b:%\d+]] = OpExtInst %void [[ext]] DebugLocalVariable [[b]]
3657 ; CHECK: OpFunction
3658 ; CHECK-NOT: OpFunctionEnd
3659 ; CHECK: OpStore [[param_a:%\d+]]
3660 ; CHECK: OpStore [[param_b:%\d+]]
3661 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_add]]
3662 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugDeclare [[dbg_a]] [[param_a]]
3663 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugDeclare [[dbg_b]] [[param_b]]
3664 ; CHECK: [[a_val:%\d+]] = OpLoad %v4float [[param_a]]
3665 ; CHECK: OpStore [[foo:%\d+]] [[a_val]]
3666 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugValue [[dbg_a]] [[foo]]
3667 
3668 OpCapability Shader
3669 %ext = OpExtInstImport "OpenCL.DebugInfo.100"
3670 OpMemoryModel Logical GLSL450
3671 OpEntryPoint Fragment %main "main" %in_var_COLOR %out_var_SV_TARGET
3672 OpExecutionMode %main OriginUpperLeft
3673 %file_name = OpString "ps.hlsl"
3674 OpSource HLSL 600 %file_name
3675 %float_name = OpString "float"
3676 %main_name = OpString "main"
3677 %add_name = OpString "add"
3678 %a_name = OpString "a"
3679 %b_name = OpString "b"
3680 OpDecorate %in_var_COLOR Location 0
3681 OpDecorate %out_var_SV_TARGET Location 0
3682 %uint = OpTypeInt 32 0
3683 %uint_32 = OpConstant %uint 32
3684 %float = OpTypeFloat 32
3685 %float_1 = OpConstant %float 1
3686 %float_2 = OpConstant %float 2
3687 %v4float = OpTypeVector %float 4
3688 %v4f1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
3689 %v4f2 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
3690 %_ptr_Input_v4float = OpTypePointer Input %v4float
3691 %_ptr_Output_v4float = OpTypePointer Output %v4float
3692 %_ptr_Function_v4float = OpTypePointer Function %v4float
3693 %add_fn_type = OpTypeFunction %v4float %_ptr_Function_v4float %_ptr_Function_v4float
3694 %void = OpTypeVoid
3695 %void_fn_type = OpTypeFunction %void
3696 %v4f_fn_type = OpTypeFunction %v4float
3697 %in_var_COLOR = OpVariable %_ptr_Input_v4float Input
3698 %out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
3699 %null_expr = OpExtInst %void %ext DebugExpression
3700 %src = OpExtInst %void %ext DebugSource %file_name
3701 %cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
3702 %dbg_f = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
3703 %dbg_v4f = OpExtInst %void %ext DebugTypeVector %dbg_f 4
3704 %main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f
3705 %add_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f %dbg_v4f
3706 %dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 5 1 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
3707 %dbg_add = OpExtInst %void %ext DebugFunction %add_name %add_ty %src 1 1 %cu %add_name FlagIsProtected|FlagIsPrivate 1 %add
3708 %dbg_a = OpExtInst %void %ext DebugLocalVariable %a_name %dbg_v4f %src 1 13 %dbg_add FlagIsLocal 0
3709 %dbg_b = OpExtInst %void %ext DebugLocalVariable %b_name %dbg_v4f %src 1 20 %dbg_add FlagIsLocal 1
3710 %main = OpFunction %void None %void_fn_type
3711 %main_bb = OpLabel
3712 %param_a = OpVariable %_ptr_Function_v4float Function
3713 %param_b = OpVariable %_ptr_Function_v4float Function
3714 %scope0 = OpExtInst %void %ext DebugScope %dbg_main
3715 OpStore %param_a %v4f1
3716 OpStore %param_b %v4f2
3717 %result = OpFunctionCall %v4float %add %param_a %param_b
3718 OpStore %out_var_SV_TARGET %result
3719 OpReturn
3720 OpFunctionEnd
3721 %add = OpFunction %v4float None %add_fn_type
3722 %scope1 = OpExtInst %void %ext DebugScope %dbg_add
3723 %a = OpFunctionParameter %_ptr_Function_v4float
3724 %b = OpFunctionParameter %_ptr_Function_v4float
3725 %decl0 = OpExtInst %void %ext DebugDeclare %dbg_a %a %null_expr
3726 %add_bb = OpLabel
3727 %decl1 = OpExtInst %void %ext DebugDeclare %dbg_b %b %null_expr
3728 %foo = OpVariable %_ptr_Function_v4float Function
3729 %a_val = OpLoad %v4float %a
3730 OpStore %foo %a_val
3731 %dbg_val = OpExtInst %void %ext DebugValue %dbg_a %foo %null_expr
3732 %b_val = OpLoad %v4float %b
3733 %res = OpFAdd %v4float %a_val %b_val
3734 OpReturnValue %res
3735 OpFunctionEnd
3736 )";
3737 
3738   SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
3739 }
3740 
3741 TEST_F(InlineTest, DebugValueForFunctionCallReturn) {
3742   // Check that InlinePass correctly generates DebugValue instruction
3743   // for function call's return value and maps it to a corresponding
3744   // value in the caller function.
3745   const std::string text = R"(
3746 ; CHECK: [[main:%\d+]] = OpString "main"
3747 ; CHECK: [[add:%\d+]] = OpString "add"
3748 ; CHECK: [[result:%\d+]] = OpString "result"
3749 ; CHECK: [[dbg_main:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction [[main]]
3750 ; CHECK: [[dbg_add:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction [[add]]
3751 ; CHECK: [[dbg_result:%\d+]] = OpExtInst %void [[ext]] DebugLocalVariable [[result]] {{%\d+}} {{%\d+}} 6 2 [[dbg_main]]
3752 ; CHECK: [[inlinedat:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 5
3753 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_add]] [[inlinedat]]
3754 ; CHECK: [[a_val:%\d+]] = OpLoad %v4float
3755 ; CHECK: [[b_val:%\d+]] = OpLoad %v4float
3756 ; CHECK: [[res:%\d+]] = OpFAdd %v4float [[a_val]] [[b_val]]
3757 ; CHECK: OpStore [[new_result:%\d+]] [[res]]
3758 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_main]]
3759 ; CHECK: [[result_val:%\d+]] = OpLoad %v4float [[new_result]]
3760 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugValue [[dbg_result]] [[result_val]]
3761 
3762 OpCapability Shader
3763 %ext = OpExtInstImport "OpenCL.DebugInfo.100"
3764 OpMemoryModel Logical GLSL450
3765 OpEntryPoint Fragment %main "main" %in_var_COLOR %out_var_SV_TARGET
3766 OpExecutionMode %main OriginUpperLeft
3767 %file_name = OpString "ps.hlsl"
3768 OpSource HLSL 600 %file_name
3769 %float_name = OpString "float"
3770 %main_name = OpString "main"
3771 %add_name = OpString "add"
3772 %result_name = OpString "result"
3773 OpDecorate %in_var_COLOR Location 0
3774 OpDecorate %out_var_SV_TARGET Location 0
3775 %uint = OpTypeInt 32 0
3776 %uint_32 = OpConstant %uint 32
3777 %float = OpTypeFloat 32
3778 %float_1 = OpConstant %float 1
3779 %float_2 = OpConstant %float 2
3780 %v4float = OpTypeVector %float 4
3781 %v4f1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
3782 %v4f2 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
3783 %_ptr_Input_v4float = OpTypePointer Input %v4float
3784 %_ptr_Output_v4float = OpTypePointer Output %v4float
3785 %_ptr_Function_v4float = OpTypePointer Function %v4float
3786 %add_fn_type = OpTypeFunction %v4float %_ptr_Function_v4float %_ptr_Function_v4float
3787 %void = OpTypeVoid
3788 %void_fn_type = OpTypeFunction %void
3789 %v4f_fn_type = OpTypeFunction %v4float
3790 %in_var_COLOR = OpVariable %_ptr_Input_v4float Input
3791 %out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
3792 %null_expr = OpExtInst %void %ext DebugExpression
3793 %src = OpExtInst %void %ext DebugSource %file_name
3794 %cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
3795 %dbg_f = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
3796 %dbg_v4f = OpExtInst %void %ext DebugTypeVector %dbg_f 4
3797 %main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f
3798 %add_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f %dbg_v4f
3799 %dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 5 1 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
3800 %dbg_add = OpExtInst %void %ext DebugFunction %add_name %add_ty %src 1 1 %cu %add_name FlagIsProtected|FlagIsPrivate 1 %add
3801 %dbg_result = OpExtInst %void %ext DebugLocalVariable %result_name %dbg_v4f %src 6 2 %dbg_main FlagIsLocal
3802 %main = OpFunction %void None %void_fn_type
3803 %main_bb = OpLabel
3804 %param_a = OpVariable %_ptr_Function_v4float Function
3805 %param_b = OpVariable %_ptr_Function_v4float Function
3806 %scope0 = OpExtInst %void %ext DebugScope %dbg_main
3807 OpStore %param_a %v4f1
3808 OpStore %param_b %v4f2
3809 %result = OpFunctionCall %v4float %add %param_a %param_b
3810 %value = OpExtInst %void %ext DebugValue %dbg_result %result %null_expr
3811 OpStore %out_var_SV_TARGET %result
3812 OpReturn
3813 OpFunctionEnd
3814 %add = OpFunction %v4float None %add_fn_type
3815 %scope1 = OpExtInst %void %ext DebugScope %dbg_add
3816 %a = OpFunctionParameter %_ptr_Function_v4float
3817 %b = OpFunctionParameter %_ptr_Function_v4float
3818 %add_bb = OpLabel
3819 %a_val = OpLoad %v4float %a
3820 %b_val = OpLoad %v4float %b
3821 %res = OpFAdd %v4float %a_val %b_val
3822 OpReturnValue %res
3823 OpFunctionEnd
3824 )";
3825 
3826   SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
3827 }
3828 
3829 TEST_F(InlineTest, NestedWithAnExistingDebugInlinedAt) {
3830   // When a DebugScope instruction in a callee function already has a
3831   // DebugInlinedAt information, we have to create a recursive
3832   // DebugInlinedAt chain. See inlined_to_zoo and inlined_to_bar in
3833   // the following code.
3834   const std::string text = R"(
3835 ; CHECK: [[main:%\d+]] = OpString "main"
3836 ; CHECK: [[foo:%\d+]] = OpString "foo"
3837 ; CHECK: [[bar:%\d+]] = OpString "bar"
3838 ; CHECK: [[zoo:%\d+]] = OpString "zoo"
3839 ; CHECK: [[v4f1:%\d+]] = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
3840 ; CHECK: [[v4f2:%\d+]] = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
3841 ; CHECK: [[v4f3:%\d+]] = OpConstantComposite %v4float %float_3 %float_3 %float_3 %float_3
3842 ; CHECK: [[dbg_main:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction [[main]]
3843 ; CHECK: [[dbg_foo:%\d+]] = OpExtInst %void [[ext]] DebugFunction [[foo]]
3844 ; CHECK: [[dbg_bar:%\d+]] = OpExtInst %void [[ext]] DebugFunction [[bar]]
3845 ; CHECK: [[dbg_zoo:%\d+]] = OpExtInst %void [[ext]] DebugFunction [[zoo]]
3846 ; CHECK: [[inlined_to_main:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 10 [[dbg_main]]
3847 ; CHECK: [[inlined_to_zoo:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 7 [[dbg_zoo]] [[inlined_to_main]]
3848 ; CHECK: [[inlined_to_main:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 10 [[dbg_main]]
3849 ; CHECK: [[inlined_to_bar:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 4 [[dbg_bar]] [[inlined_to_zoo]]
3850 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_foo]] [[inlined_to_bar]]
3851 ; CHECK: OpStore [[foo_ret:%\d+]] [[v4f1]]
3852 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_bar]] [[inlined_to_zoo]]
3853 ; CHECK: [[foo_ret_val:%\d+]] = OpLoad %v4float [[foo_ret]]
3854 ; CHECK: [[bar_ret:%\d+]] = OpFAdd %v4float [[foo_ret_val]] [[v4f2]]
3855 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_zoo]] [[inlined_to_main]]
3856 ; CHECK: [[zoo_result:%\d+]] = OpFAdd %v4float [[bar_ret]] [[v4f3]]
3857 ; CHECK: OpStore [[zoo_ret:%\d+]] [[zoo_result]]
3858 ; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_main]]
3859 ; CHECK: [[zoo_ret_val:%\d+]] = OpLoad %v4float [[zoo_ret]]
3860 ; CHECK: {{%\d+}} = OpFAdd %v4float [[zoo_ret_val]] {{%\d+}}
3861 
3862 OpCapability Shader
3863 %ext = OpExtInstImport "OpenCL.DebugInfo.100"
3864 OpMemoryModel Logical GLSL450
3865 OpEntryPoint Fragment %main "main" %in_var_COLOR %out_var_SV_TARGET
3866 OpExecutionMode %main OriginUpperLeft
3867 %file_name = OpString "ps.hlsl"
3868 OpSource HLSL 600 %file_name
3869 %float_name = OpString "float"
3870 %main_name = OpString "main"
3871 %foo_name = OpString "foo"
3872 %bar_name = OpString "bar"
3873 %zoo_name = OpString "zoo"
3874 OpDecorate %in_var_COLOR Location 0
3875 OpDecorate %out_var_SV_TARGET Location 0
3876 %uint = OpTypeInt 32 0
3877 %uint_32 = OpConstant %uint 32
3878 %float = OpTypeFloat 32
3879 %float_1 = OpConstant %float 1
3880 %float_2 = OpConstant %float 2
3881 %float_3 = OpConstant %float 3
3882 %v4float = OpTypeVector %float 4
3883 %v4f1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
3884 %v4f2 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
3885 %v4f3 = OpConstantComposite %v4float %float_3 %float_3 %float_3 %float_3
3886 %_ptr_Input_v4float = OpTypePointer Input %v4float
3887 %_ptr_Output_v4float = OpTypePointer Output %v4float
3888 %void = OpTypeVoid
3889 %void_fn_type = OpTypeFunction %void
3890 %v4f_fn_type = OpTypeFunction %v4float
3891 %in_var_COLOR = OpVariable %_ptr_Input_v4float Input
3892 %out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
3893 %src = OpExtInst %void %ext DebugSource %file_name
3894 %cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
3895 %dbg_f = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
3896 %dbg_v4f = OpExtInst %void %ext DebugTypeVector %dbg_f 4
3897 %main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f
3898 %foo_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f
3899 %dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 10 1 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
3900 %dbg_foo = OpExtInst %void %ext DebugFunction %foo_name %foo_ty %src 1 1 %cu %foo_name FlagIsProtected|FlagIsPrivate 1 %foo
3901 %dbg_bar = OpExtInst %void %ext DebugFunction %bar_name %foo_ty %src 4 1 %cu %bar_name FlagIsProtected|FlagIsPrivate 4 %bar
3902 %dbg_zoo = OpExtInst %void %ext DebugFunction %zoo_name %foo_ty %src 7 1 %cu %zoo_name FlagIsProtected|FlagIsPrivate 7 %zoo
3903 %inlined_to_zoo = OpExtInst %void %ext DebugInlinedAt 7 %dbg_zoo
3904 %main = OpFunction %void None %void_fn_type
3905 %main_bb = OpLabel
3906 %scope0 = OpExtInst %void %ext DebugScope %dbg_main
3907 %zoo_val = OpFunctionCall %v4float %zoo
3908 %color = OpLoad %v4float %in_var_COLOR
3909 %result = OpFAdd %v4float %zoo_val %color
3910 OpStore %out_var_SV_TARGET %result
3911 OpReturn
3912 OpFunctionEnd
3913 %foo = OpFunction %v4float None %v4f_fn_type
3914 %scope1 = OpExtInst %void %ext DebugScope %dbg_foo
3915 %foo_bb = OpLabel
3916 OpReturnValue %v4f1
3917 OpFunctionEnd
3918 %zoo = OpFunction %v4float None %v4f_fn_type
3919 %scope3 = OpExtInst %void %ext DebugScope %dbg_zoo
3920 %zoo_bb = OpLabel
3921 %scope2 = OpExtInst %void %ext DebugScope %dbg_bar %inlined_to_zoo
3922 %foo_val = OpFunctionCall %v4float %foo
3923 %bar_val = OpFAdd %v4float %foo_val %v4f2
3924 %scope4 = OpExtInst %void %ext DebugScope %dbg_zoo
3925 %zoo_ret = OpFAdd %v4float %bar_val %v4f3
3926 OpReturnValue %zoo_ret
3927 OpFunctionEnd
3928 %bar = OpFunction %v4float None %v4f_fn_type
3929 %scope5 = OpExtInst %void %ext DebugScope %dbg_bar
3930 %bar_bb = OpLabel
3931 %foo_val0 = OpFunctionCall %v4float %foo
3932 %bar_ret = OpFAdd %v4float %foo_val0 %v4f2
3933 OpReturnValue %bar_ret
3934 OpFunctionEnd
3935 )";
3936 
3937   SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
3938 }
3939 
3940 // TODO(greg-lunarg): Add tests to verify handling of these cases:
3941 //
3942 //    Empty modules
3943 //    Modules without function definitions
3944 //    Modules in which all functions do not call other functions
3945 //    Caller and callee both accessing the same global variable
3946 //    Functions with OpLine & OpNoLine
3947 //    Others?
3948 
3949 // TODO(dneto): Test suggestions from code review
3950 // https://github.com/KhronosGroup/SPIRV-Tools/pull/534
3951 //
3952 //    Callee function returns a value generated outside the callee,
3953 //      e.g. a constant value. This might exercise some logic not yet
3954 //      exercised by the current tests: the false branch in the "if"
3955 //      inside the SpvOpReturnValue case in InlinePass::GenInlineCode?
3956 //    SampledImage before function call, but callee is only single block.
3957 //      Then the SampledImage instruction is not cloned. Documents existing
3958 //      behaviour.
3959 //    SampledImage after function call. It is not cloned or changed.
3960 
3961 }  // namespace
3962 }  // namespace opt
3963 }  // namespace spvtools
3964