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          "%33 = OpAccessChain %_ptr_Function_float %param %uint_0",
119          "%34 = OpLoad %float %33",
120          "%35 = OpAccessChain %_ptr_Function_float %param %uint_1",
121          "%36 = OpLoad %float %35",
122          "%37 = OpFAdd %float %34 %36",
123                "OpStore %32 %37",
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          "%57 = 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          "%49 = OpAccessChain %_ptr_Function_float %param_1 %uint_0",
260          "%50 = OpLoad %float %49",
261          "%51 = OpAccessChain %_ptr_Function_float %param_1 %uint_1",
262          "%52 = OpLoad %float %51",
263          "%53 = OpFAdd %float %50 %52",
264                "OpStore %46 %53",
265          "%54 = OpAccessChain %_ptr_Function_float %param_1 %uint_2",
266          "%55 = OpLoad %float %54",
267                "OpStore %47 %55",
268          "%58 = OpLoad %float %46",
269          "%59 = OpLoad %float %47",
270          "%60 = OpFMul %float %58 %59",
271                "OpStore %57 %60",
272          "%56 = OpLoad %float %57",
273                "OpStore %48 %56",
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          "%39 = OpAccessChain %_ptr_Function_float %param %uint_0",
394          "%40 = OpLoad %float %39",
395          "%41 = OpAccessChain %_ptr_Function_float %param %uint_1",
396          "%42 = OpLoad %float %41",
397          "%43 = OpFAdd %float %40 %42",
398          "%44 = OpAccessChain %_ptr_Function_float %param %uint_2",
399                "OpStore %44 %43",
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          "%40 = OpAccessChain %_ptr_Function_float %param %uint_0",
525          "%41 = OpLoad %float %40",
526                "OpStore %38 %41",
527          "%42 = OpLoad %float %38",
528          "%43 = OpFOrdLessThan %bool %42 %float_0",
529                "OpSelectionMerge %44 None",
530                "OpBranchConditional %43 %45 %44",
531          "%45 = OpLabel",
532          "%46 = OpLoad %float %38",
533          "%47 = OpFNegate %float %46",
534                "OpStore %38 %47",
535                "OpBranch %44",
536          "%44 = OpLabel",
537          "%48 = OpLoad %float %38",
538                "OpStore %39 %48",
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          "%62 = OpVariable %_ptr_Function_float Function",
679          "%63 = 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          "%54 = OpLoad %float %param",
691                "OpStore %52 %54",
692          "%55 = OpLoad %float %52",
693          "%56 = OpFOrdLessThan %bool %55 %float_0",
694                "OpSelectionMerge %57 None",
695                "OpBranchConditional %56 %58 %57",
696          "%58 = OpLabel",
697          "%59 = OpLoad %float %52",
698          "%60 = OpFNegate %float %59",
699                "OpStore %52 %60",
700                "OpBranch %57",
701          "%57 = OpLabel",
702          "%61 = OpLoad %float %52",
703                "OpStore %53 %61",
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          "%64 = OpLoad %float %param_0",
713                "OpStore %62 %64",
714          "%65 = OpLoad %float %62",
715          "%66 = OpFOrdLessThan %bool %65 %float_0",
716                "OpSelectionMerge %67 None",
717                "OpBranchConditional %66 %68 %67",
718          "%68 = OpLabel",
719          "%69 = OpLoad %float %62",
720          "%70 = OpFNegate %float %69",
721                "OpStore %62 %70",
722                "OpBranch %67",
723          "%67 = OpLabel",
724          "%71 = OpLoad %float %62",
725                "OpStore %63 %71",
726          "%37 = OpLoad %float %63",
727          "%38 = OpFOrdGreaterThan %bool %37 %float_2",
728                "OpBranch %33",
729          "%33 = OpLabel",
730          "%39 = OpPhi %bool %32 %57 %38 %67",
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          "%68 = OpAccessChain %_ptr_Function_float %param %uint_0",
906          "%69 = OpLoad %float %68",
907                "OpStore %66 %69",
908          "%70 = OpLoad %float %66",
909          "%71 = OpFOrdLessThan %bool %70 %float_0",
910                "OpSelectionMerge %72 None",
911                "OpBranchConditional %71 %73 %72",
912          "%73 = OpLabel",
913          "%74 = OpLoad %float %66",
914          "%75 = OpFNegate %float %74",
915                "OpStore %66 %75",
916                "OpBranch %72",
917          "%72 = OpLabel",
918          "%76 = OpLoad %float %66",
919                "OpStore %67 %76",
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          "%77 = OpSampledImage %29 %39 %40",
926          "%48 = OpImageSampleImplicitLod %v4float %77 %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          "%70 = OpAccessChain %_ptr_Function_float %param %uint_0",
1112          "%71 = OpLoad %float %70",
1113                "OpStore %68 %71",
1114          "%72 = OpLoad %float %68",
1115          "%73 = OpFOrdLessThan %bool %72 %float_0",
1116                "OpSelectionMerge %74 None",
1117                "OpBranchConditional %73 %75 %74",
1118          "%75 = OpLabel",
1119          "%76 = OpLoad %float %68",
1120          "%77 = OpFNegate %float %76",
1121                "OpStore %68 %77",
1122                "OpBranch %74",
1123          "%74 = OpLabel",
1124          "%78 = OpLoad %float %68",
1125                "OpStore %69 %78",
1126          "%47 = OpLoad %float %69",
1127          "%48 = OpCompositeConstruct %v4float %47 %47 %47 %47",
1128                "OpStore %color2 %48",
1129          "%79 = OpSampledImage %30 %40 %41",
1130          "%80 = OpImage %26 %79",
1131          "%49 = OpSampledImage %30 %80 %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          "%70 = OpAccessChain %_ptr_Function_float %param %uint_0",
1318          "%71 = OpLoad %float %70",
1319                "OpStore %68 %71",
1320          "%72 = OpLoad %float %68",
1321          "%73 = OpFOrdLessThan %bool %72 %float_0",
1322                "OpSelectionMerge %74 None",
1323                "OpBranchConditional %73 %75 %74",
1324          "%75 = OpLabel",
1325          "%76 = OpLoad %float %68",
1326          "%77 = OpFNegate %float %76",
1327                "OpStore %68 %77",
1328                "OpBranch %74",
1329          "%74 = OpLabel",
1330          "%78 = OpLoad %float %68",
1331                "OpStore %69 %78",
1332          "%48 = OpLoad %float %69",
1333          "%49 = OpCompositeConstruct %v4float %48 %48 %48 %48",
1334                "OpStore %color2 %49",
1335          "%79 = OpSampledImage %30 %40 %41",
1336          "%80 = OpImage %26 %79",
1337          "%81 = OpSampledImage %30 %80 %45",
1338          "%50 = OpImageSampleImplicitLod %v4float %81 %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,EarlyReturnFunctionInlined)1358 TEST_F(InlineTest, EarlyReturnFunctionInlined) {
1359   // #version 140
1360   //
1361   // in vec4 BaseColor;
1362   //
1363   // float foo(vec4 bar)
1364   // {
1365   //     if (bar.x < 0.0)
1366   //         return 0.0;
1367   //     return bar.x;
1368   // }
1369   //
1370   // void main()
1371   // {
1372   //     vec4 color = vec4(foo(BaseColor));
1373   //     gl_FragColor = color;
1374   // }
1375 
1376   const std::string predefs =
1377       R"(OpCapability Shader
1378 %1 = OpExtInstImport "GLSL.std.450"
1379 OpMemoryModel Logical GLSL450
1380 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
1381 OpExecutionMode %main OriginUpperLeft
1382 OpSource GLSL 140
1383 OpName %main "main"
1384 OpName %foo_vf4_ "foo(vf4;"
1385 OpName %bar "bar"
1386 OpName %color "color"
1387 OpName %BaseColor "BaseColor"
1388 OpName %param "param"
1389 OpName %gl_FragColor "gl_FragColor"
1390 %void = OpTypeVoid
1391 %10 = OpTypeFunction %void
1392 %float = OpTypeFloat 32
1393 %v4float = OpTypeVector %float 4
1394 %_ptr_Function_v4float = OpTypePointer Function %v4float
1395 %14 = OpTypeFunction %float %_ptr_Function_v4float
1396 %uint = OpTypeInt 32 0
1397 %uint_0 = OpConstant %uint 0
1398 %_ptr_Function_float = OpTypePointer Function %float
1399 %float_0 = OpConstant %float 0
1400 %bool = OpTypeBool
1401 %_ptr_Input_v4float = OpTypePointer Input %v4float
1402 %BaseColor = OpVariable %_ptr_Input_v4float Input
1403 %_ptr_Output_v4float = OpTypePointer Output %v4float
1404 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
1405 )";
1406 
1407   const std::string nonEntryFuncs =
1408       R"(%foo_vf4_ = OpFunction %float None %14
1409 %bar = OpFunctionParameter %_ptr_Function_v4float
1410 %27 = OpLabel
1411 %28 = OpAccessChain %_ptr_Function_float %bar %uint_0
1412 %29 = OpLoad %float %28
1413 %30 = OpFOrdLessThan %bool %29 %float_0
1414 OpSelectionMerge %31 None
1415 OpBranchConditional %30 %32 %31
1416 %32 = OpLabel
1417 OpReturnValue %float_0
1418 %31 = OpLabel
1419 %33 = OpAccessChain %_ptr_Function_float %bar %uint_0
1420 %34 = OpLoad %float %33
1421 OpReturnValue %34
1422 OpFunctionEnd
1423 )";
1424 
1425   const std::string before =
1426       R"(%main = OpFunction %void None %10
1427 %22 = OpLabel
1428 %color = OpVariable %_ptr_Function_v4float Function
1429 %param = OpVariable %_ptr_Function_v4float Function
1430 %23 = OpLoad %v4float %BaseColor
1431 OpStore %param %23
1432 %24 = OpFunctionCall %float %foo_vf4_ %param
1433 %25 = OpCompositeConstruct %v4float %24 %24 %24 %24
1434 OpStore %color %25
1435 %26 = OpLoad %v4float %color
1436 OpStore %gl_FragColor %26
1437 OpReturn
1438 OpFunctionEnd
1439 )";
1440 
1441   const std::string after =
1442       R"(%false = OpConstantFalse %bool
1443 %main = OpFunction %void None %10
1444 %22 = OpLabel
1445 %35 = OpVariable %_ptr_Function_float Function
1446 %color = OpVariable %_ptr_Function_v4float Function
1447 %param = OpVariable %_ptr_Function_v4float Function
1448 %23 = OpLoad %v4float %BaseColor
1449 OpStore %param %23
1450 OpBranch %36
1451 %36 = OpLabel
1452 OpLoopMerge %37 %38 None
1453 OpBranch %39
1454 %39 = OpLabel
1455 %40 = OpAccessChain %_ptr_Function_float %param %uint_0
1456 %41 = OpLoad %float %40
1457 %42 = OpFOrdLessThan %bool %41 %float_0
1458 OpSelectionMerge %43 None
1459 OpBranchConditional %42 %44 %43
1460 %44 = OpLabel
1461 OpStore %35 %float_0
1462 OpBranch %37
1463 %43 = OpLabel
1464 %45 = OpAccessChain %_ptr_Function_float %param %uint_0
1465 %46 = OpLoad %float %45
1466 OpStore %35 %46
1467 OpBranch %37
1468 %38 = OpLabel
1469 OpBranchConditional %false %36 %37
1470 %37 = OpLabel
1471 %24 = OpLoad %float %35
1472 %25 = OpCompositeConstruct %v4float %24 %24 %24 %24
1473 OpStore %color %25
1474 %26 = OpLoad %v4float %color
1475 OpStore %gl_FragColor %26
1476 OpReturn
1477 OpFunctionEnd
1478 )";
1479 
1480   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + before + nonEntryFuncs,
1481                                               predefs + after + nonEntryFuncs,
1482                                               false, true);
1483 }
1484 
TEST_F(InlineTest,EarlyReturnNotAppearingLastInFunctionInlined)1485 TEST_F(InlineTest, EarlyReturnNotAppearingLastInFunctionInlined) {
1486   // Example from https://github.com/KhronosGroup/SPIRV-Tools/issues/755
1487   //
1488   // Original example is derived from:
1489   //
1490   // #version 450
1491   //
1492   // float foo() {
1493   //     if (true) {
1494   //     }
1495   // }
1496   //
1497   // void main() { foo(); }
1498   //
1499   // But the order of basic blocks in foo is changed so that the return
1500   // block is listed second-last.  There is only one return in the callee
1501   // but it does not appear last.
1502 
1503   const std::string predefs =
1504       R"(OpCapability Shader
1505 OpMemoryModel Logical GLSL450
1506 OpEntryPoint Vertex %main "main"
1507 OpSource GLSL 450
1508 OpName %main "main"
1509 OpName %foo_ "foo("
1510 %void = OpTypeVoid
1511 %4 = OpTypeFunction %void
1512 %bool = OpTypeBool
1513 %true = OpConstantTrue %bool
1514 )";
1515 
1516   const std::string nonEntryFuncs =
1517       R"(%foo_ = OpFunction %void None %4
1518 %7 = OpLabel
1519 OpSelectionMerge %8 None
1520 OpBranchConditional %true %9 %8
1521 %8 = OpLabel
1522 OpReturn
1523 %9 = OpLabel
1524 OpBranch %8
1525 OpFunctionEnd
1526 )";
1527 
1528   const std::string before =
1529       R"(%main = OpFunction %void None %4
1530 %10 = OpLabel
1531 %11 = OpFunctionCall %void %foo_
1532 OpReturn
1533 OpFunctionEnd
1534 )";
1535 
1536   const std::string after =
1537       R"(%main = OpFunction %void None %4
1538 %10 = OpLabel
1539 OpSelectionMerge %12 None
1540 OpBranchConditional %true %13 %12
1541 %12 = OpLabel
1542 OpBranch %14
1543 %13 = OpLabel
1544 OpBranch %12
1545 %14 = OpLabel
1546 OpReturn
1547 OpFunctionEnd
1548 )";
1549 
1550   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
1551                                               predefs + nonEntryFuncs + after,
1552                                               false, true);
1553 }
1554 
TEST_F(InlineTest,ForwardReferencesInPhiInlined)1555 TEST_F(InlineTest, ForwardReferencesInPhiInlined) {
1556   // The basic structure of the test case is like this:
1557   //
1558   // int foo() {
1559   //   int result = 1;
1560   //   if (true) {
1561   //      result = 1;
1562   //   }
1563   //   return result;
1564   // }
1565   //
1566   // void main() {
1567   //  int x = foo();
1568   // }
1569   //
1570   // but with modifications: Using Phi instead of load/store, and the
1571   // return block in foo appears before the "then" block.
1572 
1573   const std::string predefs =
1574       R"(OpCapability Shader
1575 %1 = OpExtInstImport "GLSL.std.450"
1576 OpMemoryModel Logical GLSL450
1577 OpEntryPoint Vertex %main "main"
1578 OpSource GLSL 450
1579 OpName %main "main"
1580 OpName %foo_ "foo("
1581 OpName %x "x"
1582 %void = OpTypeVoid
1583 %6 = OpTypeFunction %void
1584 %int = OpTypeInt 32 1
1585 %8 = OpTypeFunction %int
1586 %bool = OpTypeBool
1587 %true = OpConstantTrue %bool
1588 %int_0 = OpConstant %int 0
1589 %_ptr_Function_int = OpTypePointer Function %int
1590 )";
1591 
1592   const std::string nonEntryFuncs =
1593       R"(%foo_ = OpFunction %int None %8
1594 %13 = OpLabel
1595 %14 = OpCopyObject %int %int_0
1596 OpSelectionMerge %15 None
1597 OpBranchConditional %true %16 %15
1598 %15 = OpLabel
1599 %17 = OpPhi %int %14 %13 %18 %16
1600 OpReturnValue %17
1601 %16 = OpLabel
1602 %18 = OpCopyObject %int %int_0
1603 OpBranch %15
1604 OpFunctionEnd
1605 )";
1606 
1607   const std::string before =
1608       R"(%main = OpFunction %void None %6
1609 %19 = OpLabel
1610 %x = OpVariable %_ptr_Function_int Function
1611 %20 = OpFunctionCall %int %foo_
1612 OpStore %x %20
1613 OpReturn
1614 OpFunctionEnd
1615 )";
1616 
1617   const std::string after =
1618       R"(%main = OpFunction %void None %6
1619 %19 = OpLabel
1620 %21 = OpVariable %_ptr_Function_int Function
1621 %x = OpVariable %_ptr_Function_int Function
1622 %22 = OpCopyObject %int %int_0
1623 OpSelectionMerge %23 None
1624 OpBranchConditional %true %24 %23
1625 %23 = OpLabel
1626 %26 = OpPhi %int %22 %19 %25 %24
1627 OpStore %21 %26
1628 OpBranch %27
1629 %24 = OpLabel
1630 %25 = OpCopyObject %int %int_0
1631 OpBranch %23
1632 %27 = OpLabel
1633 %20 = OpLoad %int %21
1634 OpStore %x %20
1635 OpReturn
1636 OpFunctionEnd
1637 )";
1638 
1639   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
1640                                               predefs + nonEntryFuncs + after,
1641                                               false, true);
1642 }
1643 
TEST_F(InlineTest,EarlyReturnInLoopIsNotInlined)1644 TEST_F(InlineTest, EarlyReturnInLoopIsNotInlined) {
1645   // #version 140
1646   //
1647   // in vec4 BaseColor;
1648   //
1649   // float foo(vec4 bar)
1650   // {
1651   //     while (true) {
1652   //         if (bar.x < 0.0)
1653   //             return 0.0;
1654   //         return bar.x;
1655   //     }
1656   // }
1657   //
1658   // void main()
1659   // {
1660   //     vec4 color = vec4(foo(BaseColor));
1661   //     gl_FragColor = color;
1662   // }
1663 
1664   const std::string assembly =
1665       R"(OpCapability Shader
1666 %1 = OpExtInstImport "GLSL.std.450"
1667 OpMemoryModel Logical GLSL450
1668 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
1669 OpExecutionMode %main OriginUpperLeft
1670 OpSource GLSL 140
1671 OpName %main "main"
1672 OpName %foo_vf4_ "foo(vf4;"
1673 OpName %bar "bar"
1674 OpName %color "color"
1675 OpName %BaseColor "BaseColor"
1676 OpName %param "param"
1677 OpName %gl_FragColor "gl_FragColor"
1678 %void = OpTypeVoid
1679 %10 = OpTypeFunction %void
1680 %float = OpTypeFloat 32
1681 %v4float = OpTypeVector %float 4
1682 %_ptr_Function_v4float = OpTypePointer Function %v4float
1683 %14 = OpTypeFunction %float %_ptr_Function_v4float
1684 %bool = OpTypeBool
1685 %true = OpConstantTrue %bool
1686 %uint = OpTypeInt 32 0
1687 %uint_0 = OpConstant %uint 0
1688 %_ptr_Function_float = OpTypePointer Function %float
1689 %float_0 = OpConstant %float 0
1690 %_ptr_Input_v4float = OpTypePointer Input %v4float
1691 %BaseColor = OpVariable %_ptr_Input_v4float Input
1692 %_ptr_Output_v4float = OpTypePointer Output %v4float
1693 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
1694 %main = OpFunction %void None %10
1695 %23 = OpLabel
1696 %color = OpVariable %_ptr_Function_v4float Function
1697 %param = OpVariable %_ptr_Function_v4float Function
1698 %24 = OpLoad %v4float %BaseColor
1699 OpStore %param %24
1700 %25 = OpFunctionCall %float %foo_vf4_ %param
1701 %26 = OpCompositeConstruct %v4float %25 %25 %25 %25
1702 OpStore %color %26
1703 %27 = OpLoad %v4float %color
1704 OpStore %gl_FragColor %27
1705 OpReturn
1706 OpFunctionEnd
1707 %foo_vf4_ = OpFunction %float None %14
1708 %bar = OpFunctionParameter %_ptr_Function_v4float
1709 %28 = OpLabel
1710 OpBranch %29
1711 %29 = OpLabel
1712 OpLoopMerge %30 %31 None
1713 OpBranch %32
1714 %32 = OpLabel
1715 OpBranchConditional %true %33 %30
1716 %33 = OpLabel
1717 %34 = OpAccessChain %_ptr_Function_float %bar %uint_0
1718 %35 = OpLoad %float %34
1719 %36 = OpFOrdLessThan %bool %35 %float_0
1720 OpSelectionMerge %37 None
1721 OpBranchConditional %36 %38 %37
1722 %38 = OpLabel
1723 OpReturnValue %float_0
1724 %37 = OpLabel
1725 %39 = OpAccessChain %_ptr_Function_float %bar %uint_0
1726 %40 = OpLoad %float %39
1727 OpReturnValue %40
1728 %31 = OpLabel
1729 OpBranch %29
1730 %30 = OpLabel
1731 %41 = OpUndef %float
1732 OpReturnValue %41
1733 OpFunctionEnd
1734 )";
1735 
1736   SinglePassRunAndCheck<InlineExhaustivePass>(assembly, assembly, false, true);
1737 }
1738 
TEST_F(InlineTest,ExternalFunctionIsNotInlined)1739 TEST_F(InlineTest, ExternalFunctionIsNotInlined) {
1740   // In particular, don't crash.
1741   // See report https://github.com/KhronosGroup/SPIRV-Tools/issues/605
1742   const std::string assembly =
1743       R"(OpCapability Addresses
1744 OpCapability Kernel
1745 OpCapability Linkage
1746 OpMemoryModel Physical32 OpenCL
1747 OpEntryPoint Kernel %1 "entry_pt"
1748 OpDecorate %2 LinkageAttributes "external" Import
1749 %void = OpTypeVoid
1750 %4 = OpTypeFunction %void
1751 %2 = OpFunction %void None %4
1752 OpFunctionEnd
1753 %1 = OpFunction %void None %4
1754 %5 = OpLabel
1755 %6 = OpFunctionCall %void %2
1756 OpReturn
1757 OpFunctionEnd
1758 )";
1759 
1760   SinglePassRunAndCheck<InlineExhaustivePass>(assembly, assembly, false, true);
1761 }
1762 
TEST_F(InlineTest,SingleBlockLoopCallsMultiBlockCallee)1763 TEST_F(InlineTest, SingleBlockLoopCallsMultiBlockCallee) {
1764   // Example from https://github.com/KhronosGroup/SPIRV-Tools/issues/787
1765   //
1766   // CFG structure is:
1767   //    foo:
1768   //       fooentry -> fooexit
1769   //
1770   //    main:
1771   //       entry -> loop
1772   //       loop -> loop, merge
1773   //         loop calls foo()
1774   //       merge
1775   //
1776   // Since the callee has multiple blocks, it will split the calling block
1777   // into at least two, resulting in a new "back-half" block that contains
1778   // the instructions after the inlined function call.  If the calling block
1779   // has an OpLoopMerge that points back to the calling block itself, then
1780   // the OpLoopMerge can't remain in the back-half block, but must be
1781   // moved to the end of the original calling block, and it continue target
1782   // operand updated to point to the back-half block.
1783 
1784   const std::string predefs =
1785       R"(OpCapability Shader
1786 OpMemoryModel Logical GLSL450
1787 OpEntryPoint GLCompute %1 "main"
1788 OpSource OpenCL_C 120
1789 %bool = OpTypeBool
1790 %true = OpConstantTrue %bool
1791 %void = OpTypeVoid
1792 )";
1793 
1794   const std::string nonEntryFuncs =
1795       R"(%5 = OpTypeFunction %void
1796 %6 = OpFunction %void None %5
1797 %7 = OpLabel
1798 OpBranch %8
1799 %8 = OpLabel
1800 OpReturn
1801 OpFunctionEnd
1802 )";
1803 
1804   const std::string before =
1805       R"(%1 = OpFunction %void None %5
1806 %9 = OpLabel
1807 OpBranch %10
1808 %10 = OpLabel
1809 %11 = OpFunctionCall %void %6
1810 OpLoopMerge %12 %10 None
1811 OpBranchConditional %true %10 %12
1812 %12 = OpLabel
1813 OpReturn
1814 OpFunctionEnd
1815 )";
1816 
1817   const std::string after =
1818       R"(%1 = OpFunction %void None %5
1819 %9 = OpLabel
1820 OpBranch %10
1821 %10 = OpLabel
1822 OpLoopMerge %12 %13 None
1823 OpBranch %13
1824 %13 = OpLabel
1825 OpBranchConditional %true %10 %12
1826 %12 = OpLabel
1827 OpReturn
1828 OpFunctionEnd
1829 )";
1830 
1831   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
1832                                               predefs + nonEntryFuncs + after,
1833                                               false, true);
1834 }
1835 
TEST_F(InlineTest,MultiBlockLoopHeaderCallsMultiBlockCallee)1836 TEST_F(InlineTest, MultiBlockLoopHeaderCallsMultiBlockCallee) {
1837   // Like SingleBlockLoopCallsMultiBlockCallee but the loop has several
1838   // blocks, but the function call still occurs in the loop header.
1839   // Example from https://github.com/KhronosGroup/SPIRV-Tools/issues/800
1840 
1841   const std::string predefs =
1842       R"(OpCapability Shader
1843 OpMemoryModel Logical GLSL450
1844 OpEntryPoint GLCompute %1 "main"
1845 OpSource OpenCL_C 120
1846 %bool = OpTypeBool
1847 %true = OpConstantTrue %bool
1848 %int = OpTypeInt 32 1
1849 %int_1 = OpConstant %int 1
1850 %int_2 = OpConstant %int 2
1851 %int_3 = OpConstant %int 3
1852 %int_4 = OpConstant %int 4
1853 %int_5 = OpConstant %int 5
1854 %void = OpTypeVoid
1855 %11 = OpTypeFunction %void
1856 )";
1857 
1858   const std::string nonEntryFuncs =
1859       R"(%12 = OpFunction %void None %11
1860 %13 = OpLabel
1861 %14 = OpCopyObject %int %int_1
1862 OpBranch %15
1863 %15 = OpLabel
1864 %16 = OpCopyObject %int %int_2
1865 OpReturn
1866 OpFunctionEnd
1867 )";
1868 
1869   const std::string before =
1870       R"(%1 = OpFunction %void None %11
1871 %17 = OpLabel
1872 OpBranch %18
1873 %18 = OpLabel
1874 %19 = OpCopyObject %int %int_3
1875 %20 = OpFunctionCall %void %12
1876 %21 = OpCopyObject %int %int_4
1877 OpLoopMerge %22 %23 None
1878 OpBranchConditional %true %23 %22
1879 %23 = OpLabel
1880 %24 = OpCopyObject %int %int_5
1881 OpBranchConditional %true %18 %22
1882 %22 = OpLabel
1883 OpReturn
1884 OpFunctionEnd
1885 )";
1886 
1887   const std::string after =
1888       R"(%1 = OpFunction %void None %11
1889 %17 = OpLabel
1890 OpBranch %18
1891 %18 = OpLabel
1892 %19 = OpCopyObject %int %int_3
1893 %25 = OpCopyObject %int %int_1
1894 OpLoopMerge %22 %23 None
1895 OpBranch %26
1896 %26 = OpLabel
1897 %27 = OpCopyObject %int %int_2
1898 %21 = OpCopyObject %int %int_4
1899 OpBranchConditional %true %23 %22
1900 %23 = OpLabel
1901 %24 = OpCopyObject %int %int_5
1902 OpBranchConditional %true %18 %22
1903 %22 = OpLabel
1904 OpReturn
1905 OpFunctionEnd
1906 )";
1907 
1908   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
1909                                               predefs + nonEntryFuncs + after,
1910                                               false, true);
1911 }
1912 
TEST_F(InlineTest,SingleBlockLoopCallsMultiBlockCalleeHavingSelectionMerge)1913 TEST_F(InlineTest, SingleBlockLoopCallsMultiBlockCalleeHavingSelectionMerge) {
1914   // This is similar to SingleBlockLoopCallsMultiBlockCallee except
1915   // that calleee block also has a merge instruction in its first block.
1916   // That merge instruction must be an OpSelectionMerge (because the entry
1917   // block of a function can't be the header of a loop since the entry
1918   // block can't be the target of a branch).
1919   //
1920   // In this case the OpLoopMerge can't be placed in the same block as
1921   // the OpSelectionMerge, so inlining must create a new block to contain
1922   // the callee contents.
1923   //
1924   // Additionally, we have two dummy OpCopyObject instructions to prove that
1925   // the OpLoopMerge is moved to the right location.
1926   //
1927   // Also ensure that OpPhis within the cloned callee code are valid.
1928   // We need to test that the predecessor blocks are remapped correctly so that
1929   // dominance rules are satisfied
1930 
1931   const std::string predefs =
1932       R"(OpCapability Shader
1933 OpMemoryModel Logical GLSL450
1934 OpEntryPoint GLCompute %1 "main"
1935 OpSource OpenCL_C 120
1936 %bool = OpTypeBool
1937 %true = OpConstantTrue %bool
1938 %false = OpConstantFalse %bool
1939 %void = OpTypeVoid
1940 %6 = OpTypeFunction %void
1941 )";
1942 
1943   // This callee has multiple blocks, and an OpPhi in the last block
1944   // that references a value from the first block.  This tests that
1945   // cloned block IDs are remapped appropriately.  The OpPhi dominance
1946   // requires that the remapped %9 must be in a block that dominates
1947   // the remapped %8.
1948   const std::string nonEntryFuncs =
1949       R"(%7 = OpFunction %void None %6
1950 %8 = OpLabel
1951 %9 = OpCopyObject %bool %true
1952 OpSelectionMerge %10 None
1953 OpBranchConditional %true %10 %10
1954 %10 = OpLabel
1955 %11 = OpPhi %bool %9 %8
1956 OpReturn
1957 OpFunctionEnd
1958 )";
1959 
1960   const std::string before =
1961       R"(%1 = OpFunction %void None %6
1962 %12 = OpLabel
1963 OpBranch %13
1964 %13 = OpLabel
1965 %14 = OpCopyObject %bool %false
1966 %15 = OpFunctionCall %void %7
1967 OpLoopMerge %16 %13 None
1968 OpBranchConditional %true %13 %16
1969 %16 = OpLabel
1970 OpReturn
1971 OpFunctionEnd
1972 )";
1973 
1974   // Note the remapped Phi uses %17 as the parent instead
1975   // of %13, demonstrating that the parent block has been remapped
1976   // correctly.
1977   const std::string after =
1978       R"(%1 = OpFunction %void None %6
1979 %12 = OpLabel
1980 OpBranch %13
1981 %13 = OpLabel
1982 %14 = OpCopyObject %bool %false
1983 OpLoopMerge %16 %19 None
1984 OpBranch %17
1985 %17 = OpLabel
1986 %18 = OpCopyObject %bool %true
1987 OpSelectionMerge %19 None
1988 OpBranchConditional %true %19 %19
1989 %19 = OpLabel
1990 %20 = OpPhi %bool %18 %17
1991 OpBranchConditional %true %13 %16
1992 %16 = OpLabel
1993 OpReturn
1994 OpFunctionEnd
1995 )";
1996 
1997   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
1998                                               predefs + nonEntryFuncs + after,
1999                                               false, true);
2000 }
2001 
TEST_F(InlineTest,MultiBlockLoopHeaderCallsFromToMultiBlockCalleeHavingSelectionMerge)2002 TEST_F(InlineTest,
2003        MultiBlockLoopHeaderCallsFromToMultiBlockCalleeHavingSelectionMerge) {
2004   // This is similar to SingleBlockLoopCallsMultiBlockCalleeHavingSelectionMerge
2005   // but the call is in the header block of a multi block loop.
2006 
2007   const std::string predefs =
2008       R"(OpCapability Shader
2009 OpMemoryModel Logical GLSL450
2010 OpEntryPoint GLCompute %1 "main"
2011 OpSource OpenCL_C 120
2012 %bool = OpTypeBool
2013 %true = OpConstantTrue %bool
2014 %int = OpTypeInt 32 1
2015 %int_1 = OpConstant %int 1
2016 %int_2 = OpConstant %int 2
2017 %int_3 = OpConstant %int 3
2018 %int_4 = OpConstant %int 4
2019 %int_5 = OpConstant %int 5
2020 %void = OpTypeVoid
2021 %11 = OpTypeFunction %void
2022 )";
2023 
2024   const std::string nonEntryFuncs =
2025       R"(%12 = OpFunction %void None %11
2026 %13 = OpLabel
2027 %14 = OpCopyObject %int %int_1
2028 OpSelectionMerge %15 None
2029 OpBranchConditional %true %15 %15
2030 %15 = OpLabel
2031 %16 = OpCopyObject %int %int_2
2032 OpReturn
2033 OpFunctionEnd
2034 )";
2035 
2036   const std::string before =
2037       R"(%1 = OpFunction %void None %11
2038 %17 = OpLabel
2039 OpBranch %18
2040 %18 = OpLabel
2041 %19 = OpCopyObject %int %int_3
2042 %20 = OpFunctionCall %void %12
2043 %21 = OpCopyObject %int %int_4
2044 OpLoopMerge %22 %23 None
2045 OpBranchConditional %true %23 %22
2046 %23 = OpLabel
2047 %24 = OpCopyObject %int %int_5
2048 OpBranchConditional %true %18 %22
2049 %22 = OpLabel
2050 OpReturn
2051 OpFunctionEnd
2052 )";
2053 
2054   const std::string after =
2055       R"(%1 = OpFunction %void None %11
2056 %17 = OpLabel
2057 OpBranch %18
2058 %18 = OpLabel
2059 %19 = OpCopyObject %int %int_3
2060 OpLoopMerge %22 %23 None
2061 OpBranch %25
2062 %25 = OpLabel
2063 %26 = OpCopyObject %int %int_1
2064 OpSelectionMerge %27 None
2065 OpBranchConditional %true %27 %27
2066 %27 = OpLabel
2067 %28 = OpCopyObject %int %int_2
2068 %21 = OpCopyObject %int %int_4
2069 OpBranchConditional %true %23 %22
2070 %23 = OpLabel
2071 %24 = OpCopyObject %int %int_5
2072 OpBranchConditional %true %18 %22
2073 %22 = OpLabel
2074 OpReturn
2075 OpFunctionEnd
2076 )";
2077 
2078   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
2079                                               predefs + nonEntryFuncs + after,
2080                                               false, true);
2081 }
2082 
TEST_F(InlineTest,SingleBlockLoopCallsMultiBlockCalleeHavingSelectionMergeAndMultiReturns)2083 TEST_F(
2084     InlineTest,
2085     SingleBlockLoopCallsMultiBlockCalleeHavingSelectionMergeAndMultiReturns) {
2086   // This is similar to SingleBlockLoopCallsMultiBlockCalleeHavingSelectionMerge
2087   // except that in addition to starting with a selection header, the
2088   // callee also has multi returns.
2089   //
2090   // So now we have to accommodate:
2091   // - The caller's OpLoopMerge (which must move to the first block)
2092   // - The single-trip loop to wrap the multi returns, and
2093   // - The callee's selection merge in its first block.
2094   // Each of these must go into their own blocks.
2095 
2096   const std::string predefs =
2097       R"(OpCapability Shader
2098 OpMemoryModel Logical GLSL450
2099 OpEntryPoint GLCompute %1 "main"
2100 OpSource OpenCL_C 120
2101 %bool = OpTypeBool
2102 %int = OpTypeInt 32 1
2103 %true = OpConstantTrue %bool
2104 %false = OpConstantFalse %bool
2105 %int_0 = OpConstant %int 0
2106 %int_1 = OpConstant %int 1
2107 %int_2 = OpConstant %int 2
2108 %int_3 = OpConstant %int 3
2109 %int_4 = OpConstant %int 4
2110 %void = OpTypeVoid
2111 %12 = OpTypeFunction %void
2112 )";
2113 
2114   const std::string nonEntryFuncs =
2115       R"(%13 = OpFunction %void None %12
2116 %14 = OpLabel
2117 %15 = OpCopyObject %int %int_0
2118 OpReturn
2119 %16 = OpLabel
2120 %17 = OpCopyObject %int %int_1
2121 OpReturn
2122 OpFunctionEnd
2123 )";
2124 
2125   const std::string before =
2126       R"(%1 = OpFunction %void None %12
2127 %18 = OpLabel
2128 OpBranch %19
2129 %19 = OpLabel
2130 %20 = OpCopyObject %int %int_2
2131 %21 = OpFunctionCall %void %13
2132 %22 = OpCopyObject %int %int_3
2133 OpLoopMerge %23 %19 None
2134 OpBranchConditional %true %19 %23
2135 %23 = OpLabel
2136 %24 = OpCopyObject %int %int_4
2137 OpReturn
2138 OpFunctionEnd
2139 )";
2140 
2141   const std::string after =
2142       R"(%1 = OpFunction %void None %12
2143 %18 = OpLabel
2144 OpBranch %19
2145 %19 = OpLabel
2146 %20 = OpCopyObject %int %int_2
2147 %25 = OpCopyObject %int %int_0
2148 OpLoopMerge %23 %26 None
2149 OpBranch %26
2150 %27 = OpLabel
2151 %28 = OpCopyObject %int %int_1
2152 OpBranch %26
2153 %26 = OpLabel
2154 %22 = OpCopyObject %int %int_3
2155 OpBranchConditional %true %19 %23
2156 %23 = OpLabel
2157 %24 = OpCopyObject %int %int_4
2158 OpReturn
2159 OpFunctionEnd
2160 )";
2161 
2162   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
2163                                               predefs + nonEntryFuncs + after,
2164                                               false, true);
2165 }
2166 
TEST_F(InlineTest,CalleeWithMultiReturnAndPhiRequiresEntryBlockRemapping)2167 TEST_F(InlineTest, CalleeWithMultiReturnAndPhiRequiresEntryBlockRemapping) {
2168   // The case from https://github.com/KhronosGroup/SPIRV-Tools/issues/790
2169   //
2170   // The callee has multiple returns, and so must be wrapped with a single-trip
2171   // loop.  That code must remap the callee entry block ID to the introduced
2172   // loop body's ID.  Otherwise you can get a dominance error in a cloned OpPhi.
2173 
2174   const std::string predefs =
2175       R"(OpCapability Shader
2176 OpMemoryModel Logical GLSL450
2177 OpEntryPoint GLCompute %1 "main"
2178 OpSource OpenCL_C 120
2179 %int = OpTypeInt 32 1
2180 %int_0 = OpConstant %int 0
2181 %int_1 = OpConstant %int 1
2182 %int_2 = OpConstant %int 2
2183 %int_3 = OpConstant %int 3
2184 %int_4 = OpConstant %int 4
2185 %void = OpTypeVoid
2186 %9 = OpTypeFunction %void
2187 %bool = OpTypeBool
2188 %false = OpConstantFalse %bool
2189 )";
2190 
2191   // This callee has multiple returns, and a Phi in the second block referencing
2192   // a value generated in the entry block.
2193   const std::string nonEntryFuncs =
2194       R"(%12 = OpFunction %void None %9
2195 %13 = OpLabel
2196 %14 = OpCopyObject %int %int_0
2197 OpBranch %15
2198 %15 = OpLabel
2199 %16 = OpPhi %int %14 %13
2200 %17 = OpCopyObject %int %int_1
2201 OpReturn
2202 %18 = OpLabel
2203 %19 = OpCopyObject %int %int_2
2204 OpReturn
2205 OpFunctionEnd
2206 )";
2207 
2208   const std::string before =
2209       R"(%1 = OpFunction %void None %9
2210 %20 = OpLabel
2211 %21 = OpCopyObject %int %int_3
2212 %22 = OpFunctionCall %void %12
2213 %23 = OpCopyObject %int %int_4
2214 OpReturn
2215 OpFunctionEnd
2216 )";
2217 
2218   const std::string after =
2219       R"(%1 = OpFunction %void None %9
2220 %20 = OpLabel
2221 %21 = OpCopyObject %int %int_3
2222 %24 = OpCopyObject %int %int_0
2223 OpBranch %25
2224 %25 = OpLabel
2225 %26 = OpPhi %int %24 %20
2226 %27 = OpCopyObject %int %int_1
2227 OpBranch %28
2228 %29 = OpLabel
2229 %30 = OpCopyObject %int %int_2
2230 OpBranch %28
2231 %28 = OpLabel
2232 %23 = OpCopyObject %int %int_4
2233 OpReturn
2234 OpFunctionEnd
2235 )";
2236 
2237   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
2238                                               predefs + nonEntryFuncs + after,
2239                                               false, true);
2240 }
2241 
TEST_F(InlineTest,NonInlinableCalleeWithSingleReturn)2242 TEST_F(InlineTest, NonInlinableCalleeWithSingleReturn) {
2243   // The case from https://github.com/KhronosGroup/SPIRV-Tools/issues/2018
2244   //
2245   // The callee has a single return, but cannot be inlined because the
2246   // return is inside a loop.
2247 
2248   const std::string predefs =
2249       R"(OpCapability Shader
2250 %1 = OpExtInstImport "GLSL.std.450"
2251 OpMemoryModel Logical GLSL450
2252 OpEntryPoint Fragment %main "main" %_GLF_color
2253 OpExecutionMode %main OriginUpperLeft
2254 OpSource ESSL 310
2255 OpName %main "main"
2256 OpName %f_ "f("
2257 OpName %i "i"
2258 OpName %_GLF_color "_GLF_color"
2259 OpDecorate %_GLF_color Location 0
2260 %void = OpTypeVoid
2261 %7 = OpTypeFunction %void
2262 %float = OpTypeFloat 32
2263 %9 = OpTypeFunction %float
2264 %float_1 = OpConstant %float 1
2265 %bool = OpTypeBool
2266 %false = OpConstantFalse %bool
2267 %int = OpTypeInt 32 1
2268 %_ptr_Function_int = OpTypePointer Function %int
2269 %int_0 = OpConstant %int 0
2270 %int_1 = OpConstant %int 1
2271 %v4float = OpTypeVector %float 4
2272 %_ptr_Output_v4float = OpTypePointer Output %v4float
2273 %_GLF_color = OpVariable %_ptr_Output_v4float Output
2274 %float_0 = OpConstant %float 0
2275 %20 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
2276 %21 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1
2277 )";
2278 
2279   const std::string caller =
2280       R"(%main = OpFunction %void None %7
2281 %22 = OpLabel
2282 %i = OpVariable %_ptr_Function_int Function
2283 OpStore %i %int_0
2284 OpBranch %23
2285 %23 = OpLabel
2286 OpLoopMerge %24 %25 None
2287 OpBranch %26
2288 %26 = OpLabel
2289 %27 = OpLoad %int %i
2290 %28 = OpSLessThan %bool %27 %int_1
2291 OpBranchConditional %28 %29 %24
2292 %29 = OpLabel
2293 OpStore %_GLF_color %20
2294 %30 = OpFunctionCall %float %f_
2295 OpBranch %25
2296 %25 = OpLabel
2297 %31 = OpLoad %int %i
2298 %32 = OpIAdd %int %31 %int_1
2299 OpStore %i %32
2300 OpBranch %23
2301 %24 = OpLabel
2302 OpStore %_GLF_color %21
2303 OpReturn
2304 OpFunctionEnd
2305 )";
2306 
2307   const std::string callee =
2308       R"(%f_ = OpFunction %float None %9
2309 %33 = OpLabel
2310 OpBranch %34
2311 %34 = OpLabel
2312 OpLoopMerge %35 %36 None
2313 OpBranch %37
2314 %37 = OpLabel
2315 OpReturnValue %float_1
2316 %36 = OpLabel
2317 OpBranch %34
2318 %35 = OpLabel
2319 OpUnreachable
2320 OpFunctionEnd
2321 )";
2322 
2323   SinglePassRunAndCheck<InlineExhaustivePass>(
2324       predefs + caller + callee, predefs + caller + callee, false, true);
2325 }
2326 
TEST_F(InlineTest,CalleeWithSingleReturnNeedsSingleTripLoopWrapper)2327 TEST_F(InlineTest, CalleeWithSingleReturnNeedsSingleTripLoopWrapper) {
2328   // The case from https://github.com/KhronosGroup/SPIRV-Tools/issues/2018
2329   //
2330   // The callee has a single return, but needs single-trip loop wrapper
2331   // to be inlined because the return is in a selection structure.
2332 
2333   const std::string predefs =
2334       R"(OpCapability Shader
2335 %1 = OpExtInstImport "GLSL.std.450"
2336 OpMemoryModel Logical GLSL450
2337 OpEntryPoint Fragment %main "main" %_GLF_color
2338 OpExecutionMode %main OriginUpperLeft
2339 OpSource ESSL 310
2340 OpName %main "main"
2341 OpName %f_ "f("
2342 OpName %i "i"
2343 OpName %_GLF_color "_GLF_color"
2344 OpDecorate %_GLF_color Location 0
2345 %void = OpTypeVoid
2346 %7 = OpTypeFunction %void
2347 %float = OpTypeFloat 32
2348 %9 = OpTypeFunction %float
2349 %float_1 = OpConstant %float 1
2350 %bool = OpTypeBool
2351 %false = OpConstantFalse %bool
2352 %true = OpConstantTrue %bool
2353 %int = OpTypeInt 32 1
2354 %_ptr_Function_int = OpTypePointer Function %int
2355 %int_0 = OpConstant %int 0
2356 %int_1 = OpConstant %int 1
2357 %v4float = OpTypeVector %float 4
2358 %_ptr_Output_v4float = OpTypePointer Output %v4float
2359 %_GLF_color = OpVariable %_ptr_Output_v4float Output
2360 %float_0 = OpConstant %float 0
2361 %21 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
2362 %22 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1
2363 )";
2364 
2365   const std::string new_predefs =
2366       R"(%_ptr_Function_float = OpTypePointer Function %float
2367 )";
2368 
2369   const std::string main_before =
2370       R"(%main = OpFunction %void None %7
2371 %23 = OpLabel
2372 %i = OpVariable %_ptr_Function_int Function
2373 OpStore %i %int_0
2374 OpBranch %24
2375 %24 = OpLabel
2376 OpLoopMerge %25 %26 None
2377 OpBranch %27
2378 %27 = OpLabel
2379 %28 = OpLoad %int %i
2380 %29 = OpSLessThan %bool %28 %int_1
2381 OpBranchConditional %29 %30 %25
2382 %30 = OpLabel
2383 OpStore %_GLF_color %21
2384 %31 = OpFunctionCall %float %f_
2385 OpBranch %26
2386 %26 = OpLabel
2387 %32 = OpLoad %int %i
2388 %33 = OpIAdd %int %32 %int_1
2389 OpStore %i %33
2390 OpBranch %24
2391 %25 = OpLabel
2392 OpStore %_GLF_color %22
2393 OpReturn
2394 OpFunctionEnd
2395 )";
2396 
2397   const std::string main_after =
2398       R"(%main = OpFunction %void None %7
2399 %23 = OpLabel
2400 %38 = OpVariable %_ptr_Function_float Function
2401 %i = OpVariable %_ptr_Function_int Function
2402 OpStore %i %int_0
2403 OpBranch %24
2404 %24 = OpLabel
2405 OpLoopMerge %25 %26 None
2406 OpBranch %27
2407 %27 = OpLabel
2408 %28 = OpLoad %int %i
2409 %29 = OpSLessThan %bool %28 %int_1
2410 OpBranchConditional %29 %30 %25
2411 %30 = OpLabel
2412 OpStore %_GLF_color %21
2413 OpBranch %39
2414 %39 = OpLabel
2415 OpLoopMerge %40 %41 None
2416 OpBranch %42
2417 %42 = OpLabel
2418 OpSelectionMerge %43 None
2419 OpBranchConditional %true %44 %43
2420 %44 = OpLabel
2421 OpStore %38 %float_1
2422 OpBranch %40
2423 %43 = OpLabel
2424 OpStore %38 %float_1
2425 OpBranch %40
2426 %41 = OpLabel
2427 OpBranchConditional %false %39 %40
2428 %40 = OpLabel
2429 %31 = OpLoad %float %38
2430 OpBranch %26
2431 %26 = OpLabel
2432 %32 = OpLoad %int %i
2433 %33 = OpIAdd %int %32 %int_1
2434 OpStore %i %33
2435 OpBranch %24
2436 %25 = OpLabel
2437 OpStore %_GLF_color %22
2438 OpReturn
2439 OpFunctionEnd
2440 )";
2441 
2442   const std::string callee =
2443       R"(%f_ = OpFunction %float None %9
2444 %34 = OpLabel
2445 OpSelectionMerge %35 None
2446 OpBranchConditional %true %36 %35
2447 %36 = OpLabel
2448 OpReturnValue %float_1
2449 %35 = OpLabel
2450 OpReturnValue %float_1
2451 OpFunctionEnd
2452 )";
2453 
2454   SinglePassRunAndCheck<InlineExhaustivePass>(
2455       predefs + main_before + callee,
2456       predefs + new_predefs + main_after + callee, false, true);
2457 }
2458 
TEST_F(InlineTest,Decorated1)2459 TEST_F(InlineTest, Decorated1) {
2460   // Same test as Simple with the difference
2461   // that OpFAdd in the outlined function is
2462   // decorated with RelaxedPrecision
2463   // Expected result is an equal decoration
2464   // of the corresponding inlined instruction
2465   //
2466   // #version 140
2467   //
2468   // in vec4 BaseColor;
2469   //
2470   // float foo(vec4 bar)
2471   // {
2472   //     return bar.x + bar.y;
2473   // }
2474   //
2475   // void main()
2476   // {
2477   //     vec4 color = vec4(foo(BaseColor));
2478   //     gl_FragColor = color;
2479   // }
2480 
2481   const std::string predefs =
2482       R"(OpCapability Shader
2483 %1 = OpExtInstImport "GLSL.std.450"
2484 OpMemoryModel Logical GLSL450
2485 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
2486 OpExecutionMode %main OriginUpperLeft
2487 OpSource GLSL 140
2488 OpName %main "main"
2489 OpName %foo_vf4_ "foo(vf4;"
2490 OpName %bar "bar"
2491 OpName %color "color"
2492 OpName %BaseColor "BaseColor"
2493 OpName %param "param"
2494 OpName %gl_FragColor "gl_FragColor"
2495 OpDecorate %9 RelaxedPrecision
2496 )";
2497 
2498   const std::string before =
2499       R"(%void = OpTypeVoid
2500 %11 = OpTypeFunction %void
2501 %float = OpTypeFloat 32
2502 %v4float = OpTypeVector %float 4
2503 %_ptr_Function_v4float = OpTypePointer Function %v4float
2504 %15 = OpTypeFunction %float %_ptr_Function_v4float
2505 %uint = OpTypeInt 32 0
2506 %uint_0 = OpConstant %uint 0
2507 %_ptr_Function_float = OpTypePointer Function %float
2508 %uint_1 = OpConstant %uint 1
2509 %_ptr_Input_v4float = OpTypePointer Input %v4float
2510 %BaseColor = OpVariable %_ptr_Input_v4float Input
2511 %_ptr_Output_v4float = OpTypePointer Output %v4float
2512 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
2513 %main = OpFunction %void None %11
2514 %22 = OpLabel
2515 %color = OpVariable %_ptr_Function_v4float Function
2516 %param = OpVariable %_ptr_Function_v4float Function
2517 %23 = OpLoad %v4float %BaseColor
2518 OpStore %param %23
2519 %24 = OpFunctionCall %float %foo_vf4_ %param
2520 %25 = OpCompositeConstruct %v4float %24 %24 %24 %24
2521 OpStore %color %25
2522 %26 = OpLoad %v4float %color
2523 OpStore %gl_FragColor %26
2524 OpReturn
2525 OpFunctionEnd
2526 )";
2527 
2528   const std::string after =
2529       R"(OpDecorate %37 RelaxedPrecision
2530 %void = OpTypeVoid
2531 %11 = OpTypeFunction %void
2532 %float = OpTypeFloat 32
2533 %v4float = OpTypeVector %float 4
2534 %_ptr_Function_v4float = OpTypePointer Function %v4float
2535 %15 = OpTypeFunction %float %_ptr_Function_v4float
2536 %uint = OpTypeInt 32 0
2537 %uint_0 = OpConstant %uint 0
2538 %_ptr_Function_float = OpTypePointer Function %float
2539 %uint_1 = OpConstant %uint 1
2540 %_ptr_Input_v4float = OpTypePointer Input %v4float
2541 %BaseColor = OpVariable %_ptr_Input_v4float Input
2542 %_ptr_Output_v4float = OpTypePointer Output %v4float
2543 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
2544 %main = OpFunction %void None %11
2545 %22 = OpLabel
2546 %32 = OpVariable %_ptr_Function_float Function
2547 %color = OpVariable %_ptr_Function_v4float Function
2548 %param = OpVariable %_ptr_Function_v4float Function
2549 %23 = OpLoad %v4float %BaseColor
2550 OpStore %param %23
2551 %33 = OpAccessChain %_ptr_Function_float %param %uint_0
2552 %34 = OpLoad %float %33
2553 %35 = OpAccessChain %_ptr_Function_float %param %uint_1
2554 %36 = OpLoad %float %35
2555 %37 = OpFAdd %float %34 %36
2556 OpStore %32 %37
2557 %24 = OpLoad %float %32
2558 %25 = OpCompositeConstruct %v4float %24 %24 %24 %24
2559 OpStore %color %25
2560 %26 = OpLoad %v4float %color
2561 OpStore %gl_FragColor %26
2562 OpReturn
2563 OpFunctionEnd
2564 )";
2565 
2566   const std::string nonEntryFuncs =
2567       R"(%foo_vf4_ = OpFunction %float None %15
2568 %bar = OpFunctionParameter %_ptr_Function_v4float
2569 %27 = OpLabel
2570 %28 = OpAccessChain %_ptr_Function_float %bar %uint_0
2571 %29 = OpLoad %float %28
2572 %30 = OpAccessChain %_ptr_Function_float %bar %uint_1
2573 %31 = OpLoad %float %30
2574 %9 = OpFAdd %float %29 %31
2575 OpReturnValue %9
2576 OpFunctionEnd
2577 )";
2578   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + before + nonEntryFuncs,
2579                                               predefs + after + nonEntryFuncs,
2580                                               false, true);
2581 }
2582 
TEST_F(InlineTest,Decorated2)2583 TEST_F(InlineTest, Decorated2) {
2584   // Same test as Simple with the difference
2585   // that the Result <id> of the outlined OpFunction
2586   // is decorated with RelaxedPrecision
2587   // Expected result is an equal decoration
2588   // of the created return variable
2589   //
2590   // #version 140
2591   //
2592   // in vec4 BaseColor;
2593   //
2594   // float foo(vec4 bar)
2595   // {
2596   //     return bar.x + bar.y;
2597   // }
2598   //
2599   // void main()
2600   // {
2601   //     vec4 color = vec4(foo(BaseColor));
2602   //     gl_FragColor = color;
2603   // }
2604 
2605   const std::string predefs =
2606       R"(OpCapability Shader
2607 %1 = OpExtInstImport "GLSL.std.450"
2608 OpMemoryModel Logical GLSL450
2609 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
2610 OpExecutionMode %main OriginUpperLeft
2611 OpSource GLSL 140
2612 OpName %main "main"
2613 OpName %foo_vf4_ "foo(vf4;"
2614 OpName %bar "bar"
2615 OpName %color "color"
2616 OpName %BaseColor "BaseColor"
2617 OpName %param "param"
2618 OpName %gl_FragColor "gl_FragColor"
2619 OpDecorate %foo_vf4_ RelaxedPrecision
2620 )";
2621 
2622   const std::string before =
2623       R"(%void = OpTypeVoid
2624 %10 = OpTypeFunction %void
2625 %float = OpTypeFloat 32
2626 %v4float = OpTypeVector %float 4
2627 %_ptr_Function_v4float = OpTypePointer Function %v4float
2628 %14 = OpTypeFunction %float %_ptr_Function_v4float
2629 %uint = OpTypeInt 32 0
2630 %uint_0 = OpConstant %uint 0
2631 %_ptr_Function_float = OpTypePointer Function %float
2632 %uint_1 = OpConstant %uint 1
2633 %_ptr_Input_v4float = OpTypePointer Input %v4float
2634 %BaseColor = OpVariable %_ptr_Input_v4float Input
2635 %_ptr_Output_v4float = OpTypePointer Output %v4float
2636 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
2637 %main = OpFunction %void None %10
2638 %21 = OpLabel
2639 %color = OpVariable %_ptr_Function_v4float Function
2640 %param = OpVariable %_ptr_Function_v4float Function
2641 %22 = OpLoad %v4float %BaseColor
2642 OpStore %param %22
2643 %23 = OpFunctionCall %float %foo_vf4_ %param
2644 %24 = OpCompositeConstruct %v4float %23 %23 %23 %23
2645 OpStore %color %24
2646 %25 = OpLoad %v4float %color
2647 OpStore %gl_FragColor %25
2648 OpReturn
2649 OpFunctionEnd
2650 )";
2651 
2652   const std::string after =
2653       R"(OpDecorate %32 RelaxedPrecision
2654 %void = OpTypeVoid
2655 %10 = OpTypeFunction %void
2656 %float = OpTypeFloat 32
2657 %v4float = OpTypeVector %float 4
2658 %_ptr_Function_v4float = OpTypePointer Function %v4float
2659 %14 = OpTypeFunction %float %_ptr_Function_v4float
2660 %uint = OpTypeInt 32 0
2661 %uint_0 = OpConstant %uint 0
2662 %_ptr_Function_float = OpTypePointer Function %float
2663 %uint_1 = OpConstant %uint 1
2664 %_ptr_Input_v4float = OpTypePointer Input %v4float
2665 %BaseColor = OpVariable %_ptr_Input_v4float Input
2666 %_ptr_Output_v4float = OpTypePointer Output %v4float
2667 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
2668 %main = OpFunction %void None %10
2669 %21 = OpLabel
2670 %32 = OpVariable %_ptr_Function_float Function
2671 %color = OpVariable %_ptr_Function_v4float Function
2672 %param = OpVariable %_ptr_Function_v4float Function
2673 %22 = OpLoad %v4float %BaseColor
2674 OpStore %param %22
2675 %33 = OpAccessChain %_ptr_Function_float %param %uint_0
2676 %34 = OpLoad %float %33
2677 %35 = OpAccessChain %_ptr_Function_float %param %uint_1
2678 %36 = OpLoad %float %35
2679 %37 = OpFAdd %float %34 %36
2680 OpStore %32 %37
2681 %23 = OpLoad %float %32
2682 %24 = OpCompositeConstruct %v4float %23 %23 %23 %23
2683 OpStore %color %24
2684 %25 = OpLoad %v4float %color
2685 OpStore %gl_FragColor %25
2686 OpReturn
2687 OpFunctionEnd
2688 )";
2689 
2690   const std::string nonEntryFuncs =
2691       R"(%foo_vf4_ = OpFunction %float None %14
2692 %bar = OpFunctionParameter %_ptr_Function_v4float
2693 %26 = OpLabel
2694 %27 = OpAccessChain %_ptr_Function_float %bar %uint_0
2695 %28 = OpLoad %float %27
2696 %29 = OpAccessChain %_ptr_Function_float %bar %uint_1
2697 %30 = OpLoad %float %29
2698 %31 = OpFAdd %float %28 %30
2699 OpReturnValue %31
2700 OpFunctionEnd
2701 )";
2702   SinglePassRunAndCheck<InlineExhaustivePass>(predefs + before + nonEntryFuncs,
2703                                               predefs + after + nonEntryFuncs,
2704                                               false, true);
2705 }
2706 
TEST_F(InlineTest,DeleteName)2707 TEST_F(InlineTest, DeleteName) {
2708   // Test that the name of the result id of the call is deleted.
2709   const std::string before =
2710       R"(
2711                OpCapability Shader
2712                OpMemoryModel Logical GLSL450
2713                OpEntryPoint Vertex %main "main"
2714                OpName %main "main"
2715                OpName %main_entry "main_entry"
2716                OpName %foo_result "foo_result"
2717                OpName %void_fn "void_fn"
2718                OpName %foo "foo"
2719                OpName %foo_entry "foo_entry"
2720        %void = OpTypeVoid
2721     %void_fn = OpTypeFunction %void
2722         %foo = OpFunction %void None %void_fn
2723   %foo_entry = OpLabel
2724                OpReturn
2725                OpFunctionEnd
2726        %main = OpFunction %void None %void_fn
2727  %main_entry = OpLabel
2728  %foo_result = OpFunctionCall %void %foo
2729                OpReturn
2730                OpFunctionEnd
2731 )";
2732 
2733   const std::string after =
2734       R"(OpCapability Shader
2735 OpMemoryModel Logical GLSL450
2736 OpEntryPoint Vertex %main "main"
2737 OpName %main "main"
2738 OpName %main_entry "main_entry"
2739 OpName %void_fn "void_fn"
2740 OpName %foo "foo"
2741 OpName %foo_entry "foo_entry"
2742 %void = OpTypeVoid
2743 %void_fn = OpTypeFunction %void
2744 %foo = OpFunction %void None %void_fn
2745 %foo_entry = OpLabel
2746 OpReturn
2747 OpFunctionEnd
2748 %main = OpFunction %void None %void_fn
2749 %main_entry = OpLabel
2750 OpReturn
2751 OpFunctionEnd
2752 )";
2753 
2754   SinglePassRunAndCheck<InlineExhaustivePass>(before, after, false, true);
2755 }
2756 
TEST_F(InlineTest,SetParent)2757 TEST_F(InlineTest, SetParent) {
2758   // Test that after inlining all basic blocks have the correct parent.
2759   const std::string text =
2760       R"(
2761                OpCapability Shader
2762                OpMemoryModel Logical GLSL450
2763                OpEntryPoint Vertex %main "main"
2764                OpName %main "main"
2765                OpName %main_entry "main_entry"
2766                OpName %foo_result "foo_result"
2767                OpName %void_fn "void_fn"
2768                OpName %foo "foo"
2769                OpName %foo_entry "foo_entry"
2770        %void = OpTypeVoid
2771     %void_fn = OpTypeFunction %void
2772         %foo = OpFunction %void None %void_fn
2773   %foo_entry = OpLabel
2774                OpReturn
2775                OpFunctionEnd
2776        %main = OpFunction %void None %void_fn
2777  %main_entry = OpLabel
2778  %foo_result = OpFunctionCall %void %foo
2779                OpReturn
2780                OpFunctionEnd
2781 )";
2782 
2783   std::unique_ptr<IRContext> context =
2784       BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
2785   InlineExhaustivePass pass;
2786   pass.Run(context.get());
2787 
2788   for (Function& func : *context->module()) {
2789     for (BasicBlock& bb : func) {
2790       EXPECT_TRUE(bb.GetParent() == &func);
2791     }
2792   }
2793 }
2794 
TEST_F(InlineTest,OpVariableWithInit)2795 TEST_F(InlineTest, OpVariableWithInit) {
2796   // Check that there is a store that corresponds to the initializer.  This
2797   // test makes sure that is a store to the variable in the loop and before any
2798   // load.
2799   const std::string text = R"(
2800 ; CHECK: OpFunction
2801 ; CHECK-NOT: OpFunctionEnd
2802 ; CHECK: [[var:%\w+]] = OpVariable %_ptr_Function_float Function %float_0
2803 ; CHECK: OpLoopMerge [[outer_merge:%\w+]]
2804 ; CHECK-NOT: OpLoad %float [[var]]
2805 ; CHECK: OpStore [[var]] %float_0
2806 ; CHECK: OpFunctionEnd
2807                OpCapability Shader
2808           %1 = OpExtInstImport "GLSL.std.450"
2809                OpMemoryModel Logical GLSL450
2810                OpEntryPoint Fragment %main "main" %o
2811                OpExecutionMode %main OriginUpperLeft
2812                OpSource GLSL 450
2813                OpDecorate %o Location 0
2814        %void = OpTypeVoid
2815           %3 = OpTypeFunction %void
2816       %float = OpTypeFloat 32
2817           %7 = OpTypeFunction %float
2818 %_ptr_Function_float = OpTypePointer Function %float
2819     %float_0 = OpConstant %float 0
2820        %bool = OpTypeBool
2821     %float_1 = OpConstant %float 1
2822 %_ptr_Output_float = OpTypePointer Output %float
2823           %o = OpVariable %_ptr_Output_float Output
2824         %int = OpTypeInt 32 1
2825 %_ptr_Function_int = OpTypePointer Function %int
2826 %_ptr_Input_int = OpTypePointer Input %int
2827       %int_0 = OpConstant %int 0
2828       %int_1 = OpConstant %int 1
2829       %int_2 = OpConstant %int 2
2830        %main = OpFunction %void None %3
2831           %5 = OpLabel
2832                OpStore %o %float_0
2833                OpBranch %34
2834          %34 = OpLabel
2835          %39 = OpPhi %int %int_0 %5 %47 %37
2836                OpLoopMerge %36 %37 None
2837                OpBranch %38
2838          %38 = OpLabel
2839          %41 = OpSLessThan %bool %39 %int_2
2840                OpBranchConditional %41 %35 %36
2841          %35 = OpLabel
2842          %42 = OpFunctionCall %float %foo_
2843          %43 = OpLoad %float %o
2844          %44 = OpFAdd %float %43 %42
2845                OpStore %o %44
2846                OpBranch %37
2847          %37 = OpLabel
2848          %47 = OpIAdd %int %39 %int_1
2849                OpBranch %34
2850          %36 = OpLabel
2851                OpReturn
2852                OpFunctionEnd
2853        %foo_ = OpFunction %float None %7
2854           %9 = OpLabel
2855           %n = OpVariable %_ptr_Function_float Function %float_0
2856          %13 = OpLoad %float %n
2857          %15 = OpFOrdEqual %bool %13 %float_0
2858                OpSelectionMerge %17 None
2859                OpBranchConditional %15 %16 %17
2860          %16 = OpLabel
2861          %19 = OpLoad %float %n
2862          %20 = OpFAdd %float %19 %float_1
2863                OpStore %n %20
2864                OpBranch %17
2865          %17 = OpLabel
2866          %21 = OpLoad %float %n
2867                OpReturnValue %21
2868                OpFunctionEnd
2869 )";
2870 
2871   SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
2872 }
2873 
TEST_F(InlineTest,DontInlineDirectlyRecursiveFunc)2874 TEST_F(InlineTest, DontInlineDirectlyRecursiveFunc) {
2875   // Test that the name of the result id of the call is deleted.
2876   const std::string test =
2877       R"(OpCapability Shader
2878 OpMemoryModel Logical GLSL450
2879 OpEntryPoint Fragment %1 "main"
2880 OpExecutionMode %1 OriginUpperLeft
2881 OpDecorate %2 DescriptorSet 439418829
2882 %void = OpTypeVoid
2883 %4 = OpTypeFunction %void
2884 %float = OpTypeFloat 32
2885 %_struct_6 = OpTypeStruct %float %float
2886 %15 = OpConstantNull %_struct_6
2887 %7 = OpTypeFunction %_struct_6
2888 %1 = OpFunction %void Pure|Const %4
2889 %8 = OpLabel
2890 %2 = OpFunctionCall %_struct_6 %9
2891 OpKill
2892 OpFunctionEnd
2893 %9 = OpFunction %_struct_6 None %7
2894 %10 = OpLabel
2895 %11 = OpFunctionCall %_struct_6 %9
2896 OpReturnValue %15
2897 OpFunctionEnd
2898 )";
2899 
2900   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2901   SinglePassRunAndCheck<InlineExhaustivePass>(test, test, false, true);
2902 }
2903 
TEST_F(InlineTest,DontInlineInDirectlyRecursiveFunc)2904 TEST_F(InlineTest, DontInlineInDirectlyRecursiveFunc) {
2905   // Test that the name of the result id of the call is deleted.
2906   const std::string test =
2907       R"(OpCapability Shader
2908 OpMemoryModel Logical GLSL450
2909 OpEntryPoint Fragment %1 "main"
2910 OpExecutionMode %1 OriginUpperLeft
2911 OpDecorate %2 DescriptorSet 439418829
2912 %void = OpTypeVoid
2913 %4 = OpTypeFunction %void
2914 %float = OpTypeFloat 32
2915 %_struct_6 = OpTypeStruct %float %float
2916 %15 = OpConstantNull %_struct_6
2917 %7 = OpTypeFunction %_struct_6
2918 %1 = OpFunction %void Pure|Const %4
2919 %8 = OpLabel
2920 %2 = OpFunctionCall %_struct_6 %9
2921 OpKill
2922 OpFunctionEnd
2923 %9 = OpFunction %_struct_6 None %7
2924 %10 = OpLabel
2925 %11 = OpFunctionCall %_struct_6 %12
2926 OpReturnValue %15
2927 OpFunctionEnd
2928 %12 = OpFunction %_struct_6 None %7
2929 %13 = OpLabel
2930 %14 = OpFunctionCall %_struct_6 %9
2931 OpReturnValue %15
2932 OpFunctionEnd
2933 )";
2934 
2935   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2936   SinglePassRunAndCheck<InlineExhaustivePass>(test, test, false, true);
2937 }
2938 
TEST_F(InlineTest,DontInlineFuncWithOpKillInContinue)2939 TEST_F(InlineTest, DontInlineFuncWithOpKillInContinue) {
2940   const std::string test =
2941       R"(OpCapability Shader
2942 %1 = OpExtInstImport "GLSL.std.450"
2943 OpMemoryModel Logical GLSL450
2944 OpEntryPoint Fragment %main "main"
2945 OpExecutionMode %main OriginUpperLeft
2946 OpSource GLSL 330
2947 OpName %main "main"
2948 OpName %kill_ "kill("
2949 %void = OpTypeVoid
2950 %3 = OpTypeFunction %void
2951 %bool = OpTypeBool
2952 %true = OpConstantTrue %bool
2953 %main = OpFunction %void None %3
2954 %5 = OpLabel
2955 OpBranch %9
2956 %9 = OpLabel
2957 OpLoopMerge %11 %12 None
2958 OpBranch %13
2959 %13 = OpLabel
2960 OpBranchConditional %true %10 %11
2961 %10 = OpLabel
2962 OpBranch %12
2963 %12 = OpLabel
2964 %16 = OpFunctionCall %void %kill_
2965 OpBranch %9
2966 %11 = OpLabel
2967 OpReturn
2968 OpFunctionEnd
2969 %kill_ = OpFunction %void None %3
2970 %7 = OpLabel
2971 OpKill
2972 OpFunctionEnd
2973 )";
2974 
2975   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2976   SinglePassRunAndCheck<InlineExhaustivePass>(test, test, false, true);
2977 }
2978 
TEST_F(InlineTest,InlineFuncWithOpKillNotInContinue)2979 TEST_F(InlineTest, InlineFuncWithOpKillNotInContinue) {
2980   const std::string before =
2981       R"(OpCapability Shader
2982 %1 = OpExtInstImport "GLSL.std.450"
2983 OpMemoryModel Logical GLSL450
2984 OpEntryPoint Fragment %main "main"
2985 OpExecutionMode %main OriginUpperLeft
2986 OpSource GLSL 330
2987 OpName %main "main"
2988 OpName %kill_ "kill("
2989 %void = OpTypeVoid
2990 %3 = OpTypeFunction %void
2991 %bool = OpTypeBool
2992 %true = OpConstantTrue %bool
2993 %main = OpFunction %void None %3
2994 %5 = OpLabel
2995 %16 = OpFunctionCall %void %kill_
2996 OpReturn
2997 OpFunctionEnd
2998 %kill_ = OpFunction %void None %3
2999 %7 = OpLabel
3000 OpKill
3001 OpFunctionEnd
3002 )";
3003 
3004   const std::string after =
3005       R"(OpCapability Shader
3006 %1 = OpExtInstImport "GLSL.std.450"
3007 OpMemoryModel Logical GLSL450
3008 OpEntryPoint Fragment %main "main"
3009 OpExecutionMode %main OriginUpperLeft
3010 OpSource GLSL 330
3011 OpName %main "main"
3012 OpName %kill_ "kill("
3013 %void = OpTypeVoid
3014 %3 = OpTypeFunction %void
3015 %bool = OpTypeBool
3016 %true = OpConstantTrue %bool
3017 %main = OpFunction %void None %3
3018 %5 = OpLabel
3019 OpKill
3020 %17 = OpLabel
3021 OpReturn
3022 OpFunctionEnd
3023 %kill_ = OpFunction %void None %3
3024 %7 = OpLabel
3025 OpKill
3026 OpFunctionEnd
3027 )";
3028 
3029   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3030   SinglePassRunAndCheck<InlineExhaustivePass>(before, after, false, true);
3031 }
3032 
3033 // TODO(greg-lunarg): Add tests to verify handling of these cases:
3034 //
3035 //    Empty modules
3036 //    Modules without function definitions
3037 //    Modules in which all functions do not call other functions
3038 //    Caller and callee both accessing the same global variable
3039 //    Functions with OpLine & OpNoLine
3040 //    Others?
3041 
3042 // TODO(dneto): Test suggestions from code review
3043 // https://github.com/KhronosGroup/SPIRV-Tools/pull/534
3044 //
3045 //    Callee function returns a value generated outside the callee,
3046 //      e.g. a constant value. This might exercise some logic not yet
3047 //      exercised by the current tests: the false branch in the "if"
3048 //      inside the SpvOpReturnValue case in InlinePass::GenInlineCode?
3049 //    SampledImage before function call, but callee is only single block.
3050 //      Then the SampledImage instruction is not cloned. Documents existing
3051 //      behaviour.
3052 //    SampledImage after function call. It is not cloned or changed.
3053 
3054 }  // namespace
3055 }  // namespace opt
3056 }  // namespace spvtools
3057