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