1 // Copyright (c) 2016 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <algorithm>
16 #include <memory>
17 #include <unordered_set>
18 #include <utility>
19 #include <vector>
20 
21 #include "gmock/gmock.h"
22 #include "source/opt/build_module.h"
23 #include "source/opt/def_use_manager.h"
24 #include "source/opt/ir_context.h"
25 #include "spirv-tools/libspirv.hpp"
26 
27 namespace spvtools {
28 namespace opt {
29 namespace {
30 
31 using ::testing::ContainerEq;
32 
33 constexpr uint32_t kOpLineOperandLineIndex = 1;
34 
DoRoundTripCheck(const std::string & text)35 void DoRoundTripCheck(const std::string& text) {
36   SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
37   std::unique_ptr<IRContext> context =
38       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text);
39   ASSERT_NE(nullptr, context) << "Failed to assemble\n" << text;
40 
41   std::vector<uint32_t> binary;
42   context->module()->ToBinary(&binary, /* skip_nop = */ false);
43 
44   std::string disassembled_text;
45   EXPECT_TRUE(t.Disassemble(binary, &disassembled_text));
46   EXPECT_EQ(text, disassembled_text);
47 }
48 
TEST(IrBuilder,RoundTrip)49 TEST(IrBuilder, RoundTrip) {
50   // #version 310 es
51   // int add(int a, int b) { return a + b; }
52   // void main() { add(1, 2); }
53   DoRoundTripCheck(
54       // clang-format off
55                "OpCapability Shader\n"
56           "%1 = OpExtInstImport \"GLSL.std.450\"\n"
57                "OpMemoryModel Logical GLSL450\n"
58                "OpEntryPoint Vertex %main \"main\"\n"
59                "OpSource ESSL 310\n"
60                "OpSourceExtension \"GL_GOOGLE_cpp_style_line_directive\"\n"
61                "OpSourceExtension \"GL_GOOGLE_include_directive\"\n"
62                "OpName %main \"main\"\n"
63                "OpName %add_i1_i1_ \"add(i1;i1;\"\n"
64                "OpName %a \"a\"\n"
65                "OpName %b \"b\"\n"
66                "OpName %param \"param\"\n"
67                "OpName %param_0 \"param\"\n"
68        "%void = OpTypeVoid\n"
69           "%9 = OpTypeFunction %void\n"
70         "%int = OpTypeInt 32 1\n"
71  "%_ptr_Function_int = OpTypePointer Function %int\n"
72          "%12 = OpTypeFunction %int %_ptr_Function_int %_ptr_Function_int\n"
73       "%int_1 = OpConstant %int 1\n"
74       "%int_2 = OpConstant %int 2\n"
75        "%main = OpFunction %void None %9\n"
76          "%15 = OpLabel\n"
77       "%param = OpVariable %_ptr_Function_int Function\n"
78     "%param_0 = OpVariable %_ptr_Function_int Function\n"
79                "OpStore %param %int_1\n"
80                "OpStore %param_0 %int_2\n"
81          "%16 = OpFunctionCall %int %add_i1_i1_ %param %param_0\n"
82                "OpReturn\n"
83                "OpFunctionEnd\n"
84  "%add_i1_i1_ = OpFunction %int None %12\n"
85           "%a = OpFunctionParameter %_ptr_Function_int\n"
86           "%b = OpFunctionParameter %_ptr_Function_int\n"
87          "%17 = OpLabel\n"
88          "%18 = OpLoad %int %a\n"
89          "%19 = OpLoad %int %b\n"
90          "%20 = OpIAdd %int %18 %19\n"
91                "OpReturnValue %20\n"
92                "OpFunctionEnd\n");
93   // clang-format on
94 }
95 
TEST(IrBuilder,RoundTripIncompleteBasicBlock)96 TEST(IrBuilder, RoundTripIncompleteBasicBlock) {
97   DoRoundTripCheck(
98       "%2 = OpFunction %1 None %3\n"
99       "%4 = OpLabel\n"
100       "OpNop\n");
101 }
102 
TEST(IrBuilder,RoundTripIncompleteFunction)103 TEST(IrBuilder, RoundTripIncompleteFunction) {
104   DoRoundTripCheck("%2 = OpFunction %1 None %3\n");
105 }
106 
TEST(IrBuilder,RoundTripFunctionPointer)107 TEST(IrBuilder, RoundTripFunctionPointer) {
108   DoRoundTripCheck(
109       "OpCapability Linkage\n"
110       "OpCapability FunctionPointersINTEL\n"
111       "OpName %some_function \"some_function\"\n"
112       "OpName %ptr_to_function \"ptr_to_function\"\n"
113       "OpDecorate %some_function LinkageAttributes \"some_function\" Import\n"
114       "%float = OpTypeFloat 32\n"
115       "%4 = OpTypeFunction %float %float\n"
116       "%_ptr_Function_4 = OpTypePointer Function %4\n"
117       "%ptr_to_function = OpConstantFunctionPointerINTEL %_ptr_Function_4 "
118       "%some_function\n"
119       "%some_function = OpFunction %float Const %4\n"
120       "%6 = OpFunctionParameter %float\n"
121       "OpFunctionEnd\n");
122 }
TEST(IrBuilder,KeepLineDebugInfo)123 TEST(IrBuilder, KeepLineDebugInfo) {
124   // #version 310 es
125   // void main() {}
126   DoRoundTripCheck(
127       // clang-format off
128                "OpCapability Shader\n"
129           "%1 = OpExtInstImport \"GLSL.std.450\"\n"
130                "OpMemoryModel Logical GLSL450\n"
131                "OpEntryPoint Vertex %main \"main\"\n"
132           "%3 = OpString \"minimal.vert\"\n"
133                "OpSource ESSL 310\n"
134                "OpName %main \"main\"\n"
135                "OpLine %3 10 10\n"
136        "%void = OpTypeVoid\n"
137                "OpLine %3 100 100\n"
138           "%5 = OpTypeFunction %void\n"
139        "%main = OpFunction %void None %5\n"
140                "OpLine %3 1 1\n"
141                "OpNoLine\n"
142                "OpLine %3 2 2\n"
143                "OpLine %3 3 3\n"
144           "%6 = OpLabel\n"
145                "OpLine %3 4 4\n"
146                "OpNoLine\n"
147                "OpReturn\n"
148                "OpFunctionEnd\n");
149   // clang-format on
150 }
151 
TEST(IrBuilder,DistributeLineDebugInfo)152 TEST(IrBuilder, DistributeLineDebugInfo) {
153   const std::string text =
154       // clang-format off
155                "OpCapability Shader\n"
156           "%1 = OpExtInstImport \"GLSL.std.450\"\n"
157                "OpMemoryModel Logical GLSL450\n"
158                "OpEntryPoint Vertex %main \"main\"\n"
159                "OpSource ESSL 310\n"
160        "%file = OpString \"test\"\n"
161                "OpName %main \"main\"\n"
162                "OpName %f_ \"f(\"\n"
163                "OpName %gv1 \"gv1\"\n"
164                "OpName %gv2 \"gv2\"\n"
165                "OpName %lv1 \"lv1\"\n"
166                "OpName %lv2 \"lv2\"\n"
167                "OpName %lv1_0 \"lv1\"\n"
168        "%void = OpTypeVoid\n"
169          "%10 = OpTypeFunction %void\n"
170                "OpLine %file 10 0\n"
171       "%float = OpTypeFloat 32\n"
172          "%12 = OpTypeFunction %float\n"
173  "%_ptr_Private_float = OpTypePointer Private %float\n"
174         "%gv1 = OpVariable %_ptr_Private_float Private\n"
175    "%float_10 = OpConstant %float 10\n"
176         "%gv2 = OpVariable %_ptr_Private_float Private\n"
177   "%float_100 = OpConstant %float 100\n"
178  "%_ptr_Function_float = OpTypePointer Function %float\n"
179        "%main = OpFunction %void None %10\n"
180          "%17 = OpLabel\n"
181       "%lv1_0 = OpVariable %_ptr_Function_float Function\n"
182                "OpStore %gv1 %float_10\n"
183                "OpStore %gv2 %float_100\n"
184                "OpLine %file 1 0\n"
185                "OpNoLine\n"
186                "OpLine %file 2 0\n"
187          "%18 = OpLoad %float %gv1\n"
188          "%19 = OpLoad %float %gv2\n"
189          "%20 = OpFSub %float %18 %19\n"
190                "OpStore %lv1_0 %20\n"
191                "OpReturn\n"
192                "OpFunctionEnd\n"
193          "%f_ = OpFunction %float None %12\n"
194          "%21 = OpLabel\n"
195         "%lv1 = OpVariable %_ptr_Function_float Function\n"
196         "%lv2 = OpVariable %_ptr_Function_float Function\n"
197                "OpLine %file 3 0\n"
198                "OpLine %file 4 0\n"
199          "%22 = OpLoad %float %gv1\n"
200          "%23 = OpLoad %float %gv2\n"
201          "%24 = OpFAdd %float %22 %23\n"
202                "OpStore %lv1 %24\n"
203                "OpLine %file 5 0\n"
204                "OpLine %file 6 0\n"
205                "OpNoLine\n"
206          "%25 = OpLoad %float %gv1\n"
207          "%26 = OpLoad %float %gv2\n"
208          "%27 = OpFMul %float %25 %26\n"
209                "OpBranch %28\n"
210          "%28 = OpLabel\n"
211                "OpStore %lv2 %27\n"
212          "%29 = OpLoad %float %lv1\n"
213                "OpLine %file 7 0\n"
214          "%30 = OpLoad %float %lv2\n"
215          "%31 = OpFDiv %float %28 %29\n"
216                "OpReturnValue %30\n"
217                "OpFunctionEnd\n";
218   // clang-format on
219 
220   std::unique_ptr<IRContext> context =
221       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
222                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
223   ASSERT_NE(nullptr, context);
224 
225   struct LineInstrCheck {
226     uint32_t id;
227     std::vector<uint32_t> line_numbers;
228   };
229   const uint32_t kNoLine = 0;
230   const LineInstrCheck line_checks[] = {
231       {12, {10}},   {18, {1, kNoLine, 2}},
232       {19, {2}},    {20, {2}},
233       {22, {3, 4}}, {23, {4}},
234       {24, {4}},    {25, {5, 6, kNoLine}},
235       {26, {}},     {27, {}},
236       {28, {}},     {29, {}},
237       {30, {7}},    {31, {7}},
238   };
239 
240   spvtools::opt::analysis::DefUseManager* def_use_mgr =
241       context->get_def_use_mgr();
242   for (const LineInstrCheck& check : line_checks) {
243     auto& lines = def_use_mgr->GetDef(check.id)->dbg_line_insts();
244     for (uint32_t i = 0; i < check.line_numbers.size(); ++i) {
245       if (check.line_numbers[i] == kNoLine) {
246         EXPECT_EQ(lines[i].opcode(), spv::Op::OpNoLine);
247         continue;
248       }
249       EXPECT_EQ(lines[i].opcode(), spv::Op::OpLine);
250       EXPECT_EQ(lines[i].GetSingleWordOperand(kOpLineOperandLineIndex),
251                 check.line_numbers[i]);
252     }
253   }
254 }
255 
TEST(IrBuilder,BuildModule_WithoutExtraLines)256 TEST(IrBuilder, BuildModule_WithoutExtraLines) {
257   const std::string text = R"(OpCapability Shader
258 OpMemoryModel Logical Simple
259 OpEntryPoint Vertex %main "main"
260 %file = OpString "my file"
261 %void = OpTypeVoid
262 %voidfn = OpTypeFunction %void
263 %float = OpTypeFloat 32
264 %float_1 = OpConstant %float 1
265 %main = OpFunction %void None %voidfn
266 %100 = OpLabel
267 %1 = OpFAdd %float %float_1 %float_1
268 OpLine %file 1 0
269 %2 = OpFMul %float %1 %1
270 %3 = OpFSub %float %2 %2
271 OpReturn
272 OpFunctionEnd
273 )";
274 
275   std::vector<uint32_t> binary;
276   SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
277   ASSERT_TRUE(t.Assemble(text, &binary,
278                          SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS));
279 
280   // This is the function we're testing.
281   std::unique_ptr<IRContext> context = BuildModule(
282       SPV_ENV_UNIVERSAL_1_5, nullptr, binary.data(), binary.size(), false);
283   ASSERT_NE(nullptr, context);
284 
285   spvtools::opt::analysis::DefUseManager* def_use_mgr =
286       context->get_def_use_mgr();
287 
288   std::vector<spv::Op> opcodes;
289   for (auto* inst = def_use_mgr->GetDef(1);
290        inst && (inst->opcode() != spv::Op::OpFunctionEnd);
291        inst = inst->NextNode()) {
292     inst->ForEachInst(
293         [&opcodes](spvtools::opt::Instruction* sub_inst) {
294           opcodes.push_back(sub_inst->opcode());
295         },
296         true);
297   }
298 
299   EXPECT_THAT(opcodes, ContainerEq(std::vector<spv::Op>{
300                            spv::Op::OpFAdd, spv::Op::OpLine, spv::Op::OpFMul,
301                            spv::Op::OpFSub, spv::Op::OpReturn}));
302 }
303 
TEST(IrBuilder,BuildModule_WithExtraLines_IsDefault)304 TEST(IrBuilder, BuildModule_WithExtraLines_IsDefault) {
305   const std::string text = R"(OpCapability Shader
306 OpMemoryModel Logical Simple
307 OpEntryPoint Vertex %main "main"
308 %file = OpString "my file"
309 %void = OpTypeVoid
310 %voidfn = OpTypeFunction %void
311 %float = OpTypeFloat 32
312 %float_1 = OpConstant %float 1
313 %main = OpFunction %void None %voidfn
314 %100 = OpLabel
315 %1 = OpFAdd %float %float_1 %float_1
316 OpLine %file 1 0
317 %2 = OpFMul %float %1 %1
318 %3 = OpFSub %float %2 %2
319 OpReturn
320 OpFunctionEnd
321 )";
322 
323   std::vector<uint32_t> binary;
324 
325   SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
326   ASSERT_TRUE(t.Assemble(text, &binary,
327                          SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS));
328 
329   // This is the function we're testing.
330   std::unique_ptr<IRContext> context =
331       BuildModule(SPV_ENV_UNIVERSAL_1_5, nullptr, binary.data(), binary.size());
332 
333   spvtools::opt::analysis::DefUseManager* def_use_mgr =
334       context->get_def_use_mgr();
335 
336   std::vector<spv::Op> opcodes;
337   for (auto* inst = def_use_mgr->GetDef(1);
338        inst && (inst->opcode() != spv::Op::OpFunctionEnd);
339        inst = inst->NextNode()) {
340     inst->ForEachInst(
341         [&opcodes](spvtools::opt::Instruction* sub_inst) {
342           opcodes.push_back(sub_inst->opcode());
343         },
344         true);
345   }
346 
347   EXPECT_THAT(opcodes, ContainerEq(std::vector<spv::Op>{
348                            spv::Op::OpFAdd, spv::Op::OpLine, spv::Op::OpFMul,
349                            spv::Op::OpLine, spv::Op::OpFSub, spv::Op::OpLine,
350                            spv::Op::OpReturn}));
351 }
352 
TEST(IrBuilder,ConsumeDebugInfoInst)353 TEST(IrBuilder, ConsumeDebugInfoInst) {
354   // /* HLSL */
355   //
356   // struct VS_OUTPUT {
357   //   float4 pos : SV_POSITION;
358   //   float4 color : COLOR;
359   // };
360   //
361   // VS_OUTPUT main(float4 pos : POSITION,
362   //                float4 color : COLOR) {
363   //   VS_OUTPUT vout;
364   //   vout.pos = pos;
365   //   vout.color = color;
366   //   return vout;
367   // }
368   DoRoundTripCheck(R"(OpCapability Shader
369 %1 = OpExtInstImport "OpenCL.DebugInfo.100"
370 OpMemoryModel Logical GLSL450
371 OpEntryPoint Vertex %main "main" %pos %color %gl_Position %out_var_COLOR
372 %7 = OpString "simple_vs.hlsl"
373 %8 = OpString "#line 1 \"simple_vs.hlsl\"
374 struct VS_OUTPUT {
375   float4 pos : SV_POSITION;
376   float4 color : COLOR;
377 };
378 
379 VS_OUTPUT main(float4 pos : POSITION,
380                float4 color : COLOR) {
381   VS_OUTPUT vout;
382   vout.pos = pos;
383   vout.color = color;
384   return vout;
385 }
386 "
387 OpSource HLSL 600 %7 "#line 1 \"simple_vs.hlsl\"
388 struct VS_OUTPUT {
389   float4 pos : SV_POSITION;
390   float4 color : COLOR;
391 };
392 
393 VS_OUTPUT main(float4 pos : POSITION,
394                float4 color : COLOR) {
395   VS_OUTPUT vout;
396   vout.pos = pos;
397   vout.color = color;
398   return vout;
399 }
400 "
401 %9 = OpString "struct VS_OUTPUT"
402 %10 = OpString "float"
403 %11 = OpString "pos : SV_POSITION"
404 %12 = OpString "color : COLOR"
405 %13 = OpString "VS_OUTPUT"
406 %14 = OpString "main"
407 %15 = OpString "VS_OUTPUT_main_v4f_v4f"
408 %16 = OpString "pos : POSITION"
409 %17 = OpString "color : COLOR"
410 %18 = OpString "vout"
411 OpName %out_var_COLOR "out.var.COLOR"
412 OpName %main "main"
413 OpName %VS_OUTPUT "VS_OUTPUT"
414 OpMemberName %VS_OUTPUT 0 "pos"
415 OpMemberName %VS_OUTPUT 1 "color"
416 OpName %pos "pos"
417 OpName %color "color"
418 OpName %vout "vout"
419 OpDecorate %gl_Position BuiltIn Position
420 OpDecorate %pos Location 0
421 OpDecorate %color Location 1
422 OpDecorate %out_var_COLOR Location 0
423 %int = OpTypeInt 32 1
424 %int_0 = OpConstant %int 0
425 %int_1 = OpConstant %int 1
426 %int_32 = OpConstant %int 32
427 %int_128 = OpConstant %int 128
428 %float = OpTypeFloat 32
429 %v4float = OpTypeVector %float 4
430 %_ptr_Input_v4float = OpTypePointer Input %v4float
431 %_ptr_Output_v4float = OpTypePointer Output %v4float
432 %void = OpTypeVoid
433 %31 = OpTypeFunction %void
434 %_ptr_Function_v4float = OpTypePointer Function %v4float
435 %VS_OUTPUT = OpTypeStruct %v4float %v4float
436 %_ptr_Function_VS_OUTPUT = OpTypePointer Function %VS_OUTPUT
437 OpLine %7 6 23
438 %pos = OpVariable %_ptr_Input_v4float Input
439 OpLine %7 7 23
440 %color = OpVariable %_ptr_Input_v4float Input
441 OpLine %7 2 16
442 %gl_Position = OpVariable %_ptr_Output_v4float Output
443 OpLine %7 3 18
444 %out_var_COLOR = OpVariable %_ptr_Output_v4float Output
445 %34 = OpExtInst %void %1 DebugSource %7 %8
446 %35 = OpExtInst %void %1 DebugCompilationUnit 2 4 %34 HLSL
447 %36 = OpExtInst %void %1 DebugTypeComposite %9 Structure %34 1 1 %35 %13 %int_128 FlagIsProtected|FlagIsPrivate %37 %38
448 %39 = OpExtInst %void %1 DebugTypeBasic %10 %int_32 Float
449 %40 = OpExtInst %void %1 DebugTypeVector %39 4
450 %37 = OpExtInst %void %1 DebugTypeMember %11 %40 %34 2 3 %36 %int_0 %int_128 FlagIsProtected|FlagIsPrivate
451 %38 = OpExtInst %void %1 DebugTypeMember %12 %40 %34 3 3 %36 %int_128 %int_128 FlagIsProtected|FlagIsPrivate
452 %41 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %36 %40 %40
453 %42 = OpExtInst %void %1 DebugExpression
454 %43 = OpExtInst %void %1 DebugFunction %14 %41 %34 6 1 %35 %15 FlagIsProtected|FlagIsPrivate 7 %main
455 %44 = OpExtInst %void %1 DebugLocalVariable %16 %40 %34 6 16 %43 FlagIsLocal 0
456 %45 = OpExtInst %void %1 DebugLocalVariable %17 %40 %34 7 16 %43 FlagIsLocal 1
457 %46 = OpExtInst %void %1 DebugLocalVariable %18 %36 %34 8 3 %43 FlagIsLocal
458 OpLine %7 6 1
459 %main = OpFunction %void None %31
460 %47 = OpLabel
461 %60 = OpExtInst %void %1 DebugScope %43
462 OpLine %7 8 13
463 %vout = OpVariable %_ptr_Function_VS_OUTPUT Function
464 %49 = OpExtInst %void %1 DebugDeclare %46 %vout %42
465 OpLine %7 9 14
466 %50 = OpLoad %v4float %pos
467 OpLine %7 9 3
468 %51 = OpAccessChain %_ptr_Function_v4float %vout %int_0
469 %52 = OpExtInst %void %1 DebugValue %46 %51 %42 %int_0
470 OpStore %51 %50
471 OpLine %7 10 16
472 %53 = OpLoad %v4float %color
473 OpLine %7 10 3
474 %54 = OpAccessChain %_ptr_Function_v4float %vout %int_1
475 %55 = OpExtInst %void %1 DebugValue %46 %54 %42 %int_1
476 OpStore %54 %53
477 OpLine %7 11 10
478 %56 = OpLoad %VS_OUTPUT %vout
479 OpLine %7 11 3
480 %57 = OpCompositeExtract %v4float %56 0
481 OpStore %gl_Position %57
482 %58 = OpCompositeExtract %v4float %56 1
483 OpStore %out_var_COLOR %58
484 %61 = OpExtInst %void %1 DebugNoScope
485 OpReturn
486 OpFunctionEnd
487 )");
488 }
489 
490 TEST(IrBuilder, ConsumeDebugInfoLexicalScopeInst) {
491   // /* HLSL */
492   //
493   // float4 func2(float arg2) {   // func2_block
494   //   return float4(arg2, 0, 0, 0);
495   // }
496   //
497   // float4 func1(float arg1) {   // func1_block
498   //   if (arg1 > 1) {       // if_true_block
499   //     return float4(0, 0, 0, 0);
500   //   }
501   //   return func2(arg1);   // if_merge_block
502   // }
503   //
504   // float4 main(float pos : POSITION) : SV_POSITION {  // main
505   //   return func1(pos);
506   // }
507   DoRoundTripCheck(R"(OpCapability Shader
508 %1 = OpExtInstImport "OpenCL.DebugInfo.100"
509 OpMemoryModel Logical GLSL450
510 OpEntryPoint Vertex %main "main" %pos %gl_Position
511 %5 = OpString "block/block.hlsl"
512 %6 = OpString "#line 1 \"block/block.hlsl\"
513 float4 func2(float arg2) {
514   return float4(arg2, 0, 0, 0);
515 }
516 
517 float4 func1(float arg1) {
518   if (arg1 > 1) {
519     return float4(0, 0, 0, 0);
520   }
521   return func2(arg1);
522 }
523 
524 float4 main(float pos : POSITION) : SV_POSITION {
525   return func1(pos);
526 }
527 "
528 OpSource HLSL 600 %5 "#line 1 \"block/block.hlsl\"
529 float4 func2(float arg2) {
530   return float4(arg2, 0, 0, 0);
531 }
532 
533 float4 func1(float arg1) {
534   if (arg1 > 1) {
535     return float4(0, 0, 0, 0);
536   }
537   return func2(arg1);
538 }
539 
540 float4 main(float pos : POSITION) : SV_POSITION {
541   return func1(pos);
542 }
543 "
544 %7 = OpString "float"
545 %8 = OpString "main"
546 %9 = OpString "v4f_main_f"
547 %10 = OpString "v4f_func1_f"
548 %11 = OpString "v4f_func2_f"
549 %12 = OpString "pos : POSITION"
550 %13 = OpString "func1"
551 %14 = OpString "func2"
552 OpName %main "main"
553 OpName %pos "pos"
554 OpName %bb_entry "bb.entry"
555 OpName %param_var_arg1 "param.var.arg1"
556 OpName %func1 "func1"
557 OpName %arg1 "arg1"
558 OpName %bb_entry_0 "bb.entry"
559 OpName %param_var_arg2 "param.var.arg2"
560 OpName %if_true "if.true"
561 OpName %if_merge "if.merge"
562 OpName %func2 "func2"
563 OpName %arg2 "arg2"
564 OpName %bb_entry_1 "bb.entry"
565 OpDecorate %gl_Position BuiltIn Position
566 OpDecorate %pos Location 0
567 %float = OpTypeFloat 32
568 %int = OpTypeInt 32 1
569 %float_1 = OpConstant %float 1
570 %float_0 = OpConstant %float 0
571 %int_32 = OpConstant %int 32
572 %v4float = OpTypeVector %float 4
573 %32 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
574 %_ptr_Input_float = OpTypePointer Input %float
575 %_ptr_Output_v4float = OpTypePointer Output %v4float
576 %void = OpTypeVoid
577 %36 = OpTypeFunction %void
578 %_ptr_Function_float = OpTypePointer Function %float
579 %38 = OpTypeFunction %v4float %_ptr_Function_float
580 %bool = OpTypeBool
581 OpLine %5 12 25
582 %pos = OpVariable %_ptr_Input_float Input
583 OpLine %5 12 37
584 %gl_Position = OpVariable %_ptr_Output_v4float Output
585 %40 = OpExtInst %void %1 DebugSource %5 %6
586 %41 = OpExtInst %void %1 DebugCompilationUnit 2 4 %40 HLSL
587 %42 = OpExtInst %void %1 DebugTypeBasic %7 %int_32 Float
588 %43 = OpExtInst %void %1 DebugTypeVector %42 4
589 %44 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42
590 %45 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42
591 %46 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42
592 %47 = OpExtInst %void %1 DebugFunction %8 %44 %40 12 1 %41 %9 FlagIsProtected|FlagIsPrivate 13 %main
593 %48 = OpExtInst %void %1 DebugFunction %13 %45 %40 5 1 %41 %10 FlagIsProtected|FlagIsPrivate 13 %func1
594 %49 = OpExtInst %void %1 DebugFunction %14 %46 %40 1 1 %41 %11 FlagIsProtected|FlagIsPrivate 13 %func2
595 %50 = OpExtInst %void %1 DebugLexicalBlock %40 6 17 %48
596 %51 = OpExtInst %void %1 DebugLexicalBlock %40 9 3 %48
597 OpLine %5 12 1
598 %main = OpFunction %void None %36
599 %bb_entry = OpLabel
600 %70 = OpExtInst %void %1 DebugScope %47
601 OpLine %5 13 16
602 %param_var_arg1 = OpVariable %_ptr_Function_float Function
603 %53 = OpLoad %float %pos
604 OpStore %param_var_arg1 %53
605 OpLine %5 13 10
606 %54 = OpFunctionCall %v4float %func1 %param_var_arg1
607 OpLine %5 13 3
608 OpStore %gl_Position %54
609 %71 = OpExtInst %void %1 DebugNoScope
610 OpReturn
611 OpFunctionEnd
612 OpLine %5 5 1
613 %func1 = OpFunction %v4float None %38
614 OpLine %5 5 20
615 %arg1 = OpFunctionParameter %_ptr_Function_float
616 %bb_entry_0 = OpLabel
617 %72 = OpExtInst %void %1 DebugScope %48
618 OpLine %5 9 16
619 %param_var_arg2 = OpVariable %_ptr_Function_float Function
620 OpLine %5 6 7
621 %57 = OpLoad %float %arg1
622 OpLine %5 6 12
623 %58 = OpFOrdGreaterThan %bool %57 %float_1
624 OpLine %5 6 17
625 %73 = OpExtInst %void %1 DebugNoScope
626 OpSelectionMerge %if_merge None
627 OpBranchConditional %58 %if_true %if_merge
628 %if_true = OpLabel
629 %74 = OpExtInst %void %1 DebugScope %50
630 OpLine %5 7 5
631 %75 = OpExtInst %void %1 DebugNoScope
632 OpReturnValue %32
633 %if_merge = OpLabel
634 %76 = OpExtInst %void %1 DebugScope %51
635 OpLine %5 9 16
636 %63 = OpLoad %float %arg1
637 OpStore %param_var_arg2 %63
638 OpLine %5 9 10
639 %64 = OpFunctionCall %v4float %func2 %param_var_arg2
640 OpLine %5 9 3
641 %77 = OpExtInst %void %1 DebugNoScope
642 OpReturnValue %64
643 OpFunctionEnd
644 OpLine %5 1 1
645 %func2 = OpFunction %v4float None %38
646 OpLine %5 1 20
647 %arg2 = OpFunctionParameter %_ptr_Function_float
648 %bb_entry_1 = OpLabel
649 %78 = OpExtInst %void %1 DebugScope %49
650 OpLine %5 2 17
651 %67 = OpLoad %float %arg2
652 %68 = OpCompositeConstruct %v4float %67 %float_0 %float_0 %float_0
653 OpLine %5 2 3
654 %79 = OpExtInst %void %1 DebugNoScope
655 OpReturnValue %68
656 OpFunctionEnd
657 )");
658 }
659 
660 TEST(IrBuilder, ConsumeDebugInlinedAt) {
661   // /* HLSL */
662   //
663   // float4 func2(float arg2) {   // func2_block
664   //   return float4(arg2, 0, 0, 0);
665   // }
666   //
667   // float4 func1(float arg1) {   // func1_block
668   //   if (arg1 > 1) {       // if_true_block
669   //     return float4(0, 0, 0, 0);
670   //   }
671   //   return func2(arg1);   // if_merge_block
672   // }
673   //
674   // float4 main(float pos : POSITION) : SV_POSITION {  // main
675   //   return func1(pos);
676   // }
677   //
678   // TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/533): In the following
679   // SPIRV code, we use DebugInfoNone to reference opted-out function from
680   // DebugFunction similar to opted-out global variable for DebugGlobalVariable,
681   // but this is not a part of the spec yet. We are still in discussion and we
682   // must correct it if our decision is different.
683   DoRoundTripCheck(R"(OpCapability Shader
684 %1 = OpExtInstImport "OpenCL.DebugInfo.100"
685 OpMemoryModel Logical GLSL450
686 OpEntryPoint Vertex %main "main" %pos %gl_Position
687 %5 = OpString "block/block.hlsl"
688 %6 = OpString "#line 1 \"block/block.hlsl\"
689 float4 func2(float arg2) {
690   return float4(arg2, 0, 0, 0);
691 }
692 
693 float4 func1(float arg1) {
694   if (arg1 > 1) {
695     return float4(0, 0, 0, 0);
696   }
697   return func2(arg1);
698 }
699 
700 float4 main(float pos : POSITION) : SV_POSITION {
701   return func1(pos);
702 }
703 "
704 OpSource HLSL 600 %5 "#line 1 \"block/block.hlsl\"
705 float4 func2(float arg2) {
706   return float4(arg2, 0, 0, 0);
707 }
708 
709 float4 func1(float arg1) {
710   if (arg1 > 1) {
711     return float4(0, 0, 0, 0);
712   }
713   return func2(arg1);
714 }
715 
716 float4 main(float pos : POSITION) : SV_POSITION {
717   return func1(pos);
718 }
719 "
720 %7 = OpString "float"
721 %8 = OpString "main"
722 %9 = OpString "v4f_main_f"
723 %10 = OpString "v4f_func1_f"
724 %11 = OpString "v4f_func2_f"
725 %12 = OpString "pos : POSITION"
726 %13 = OpString "func1"
727 %14 = OpString "func2"
728 OpName %main "main"
729 OpName %pos "pos"
730 OpName %bb_entry "bb.entry"
731 OpName %if_true "if.true"
732 OpName %if_merge "if.merge"
733 OpDecorate %gl_Position BuiltIn Position
734 OpDecorate %pos Location 0
735 %float = OpTypeFloat 32
736 %int = OpTypeInt 32 1
737 %float_1 = OpConstant %float 1
738 %float_0 = OpConstant %float 0
739 %int_32 = OpConstant %int 32
740 %v4float = OpTypeVector %float 4
741 %24 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
742 %_ptr_Input_float = OpTypePointer Input %float
743 %_ptr_Output_v4float = OpTypePointer Output %v4float
744 %void = OpTypeVoid
745 %28 = OpTypeFunction %void
746 %_ptr_Function_float = OpTypePointer Function %float
747 %30 = OpTypeFunction %v4float %_ptr_Function_float
748 %bool = OpTypeBool
749 OpLine %5 12 25
750 %pos = OpVariable %_ptr_Input_float Input
751 OpLine %5 12 37
752 %gl_Position = OpVariable %_ptr_Output_v4float Output
753 %32 = OpExtInst %void %1 DebugInfoNone
754 %33 = OpExtInst %void %1 DebugSource %5 %6
755 %34 = OpExtInst %void %1 DebugCompilationUnit 2 4 %33 HLSL
756 %35 = OpExtInst %void %1 DebugTypeBasic %7 %int_32 Float
757 %36 = OpExtInst %void %1 DebugTypeVector %35 4
758 %37 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %36 %35
759 %38 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %36 %35
760 %39 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %36 %35
761 %40 = OpExtInst %void %1 DebugFunction %8 %37 %33 12 1 %34 %9 FlagIsProtected|FlagIsPrivate 13 %main
762 %41 = OpExtInst %void %1 DebugFunction %13 %38 %33 5 1 %34 %10 FlagIsProtected|FlagIsPrivate 13 %32
763 %42 = OpExtInst %void %1 DebugFunction %14 %39 %33 1 1 %34 %11 FlagIsProtected|FlagIsPrivate 13 %32
764 %43 = OpExtInst %void %1 DebugLexicalBlock %33 12 49 %40
765 %44 = OpExtInst %void %1 DebugLexicalBlock %33 5 26 %41
766 %45 = OpExtInst %void %1 DebugLexicalBlock %33 1 26 %42
767 %46 = OpExtInst %void %1 DebugLexicalBlock %33 6 17 %44
768 %47 = OpExtInst %void %1 DebugLexicalBlock %33 9 3 %44
769 %48 = OpExtInst %void %1 DebugInlinedAt 9 %47
770 %49 = OpExtInst %void %1 DebugInlinedAt 13 %43
771 %50 = OpExtInst %void %1 DebugInlinedAt 13 %43 %48
772 OpLine %5 12 1
773 %main = OpFunction %void None %28
774 %bb_entry = OpLabel
775 %62 = OpExtInst %void %1 DebugScope %44 %49
776 OpLine %5 6 7
777 %52 = OpLoad %float %pos
778 OpLine %5 6 12
779 %53 = OpFOrdGreaterThan %bool %52 %float_1
780 OpLine %5 6 17
781 %63 = OpExtInst %void %1 DebugNoScope
782 OpSelectionMerge %if_merge None
783 OpBranchConditional %53 %if_true %if_merge
784 %if_true = OpLabel
785 %64 = OpExtInst %void %1 DebugScope %46 %49
786 OpLine %5 7 5
787 OpStore %gl_Position %24
788 %65 = OpExtInst %void %1 DebugNoScope
789 OpReturn
790 %if_merge = OpLabel
791 %66 = OpExtInst %void %1 DebugScope %45 %50
792 OpLine %5 2 17
793 %58 = OpLoad %float %pos
794 OpLine %5 2 10
795 %59 = OpCompositeConstruct %v4float %58 %float_0 %float_0 %float_0
796 %67 = OpExtInst %void %1 DebugScope %43
797 OpLine %5 13 3
798 OpStore %gl_Position %59
799 %68 = OpExtInst %void %1 DebugNoScope
800 OpReturn
801 OpFunctionEnd
802 )");
803 }
804 
805 TEST(IrBuilder, DebugInfoInstInFunctionOutOfBlock) {
806   // /* HLSL */
807   //
808   // float4 func2(float arg2) {   // func2_block
809   //   return float4(arg2, 0, 0, 0);
810   // }
811   //
812   // float4 func1(float arg1) {   // func1_block
813   //   if (arg1 > 1) {       // if_true_block
814   //     return float4(0, 0, 0, 0);
815   //   }
816   //   return func2(arg1);   // if_merge_block
817   // }
818   //
819   // float4 main(float pos : POSITION) : SV_POSITION {  // main
820   //   return func1(pos);
821   // }
822   const std::string text = R"(OpCapability Shader
823 %1 = OpExtInstImport "OpenCL.DebugInfo.100"
824 OpMemoryModel Logical GLSL450
825 OpEntryPoint Vertex %main "main" %pos %gl_Position
826 %5 = OpString "block/block.hlsl"
827 %6 = OpString "#line 1 \"block/block.hlsl\"
828 float4 func2(float arg2) {
829   return float4(arg2, 0, 0, 0);
830 }
831 
832 float4 func1(float arg1) {
833   if (arg1 > 1) {
834     return float4(0, 0, 0, 0);
835   }
836   return func2(arg1);
837 }
838 
839 float4 main(float pos : POSITION) : SV_POSITION {
840   return func1(pos);
841 }
842 "
843 OpSource HLSL 600 %5 "#line 1 \"block/block.hlsl\"
844 float4 func2(float arg2) {
845   return float4(arg2, 0, 0, 0);
846 }
847 
848 float4 func1(float arg1) {
849   if (arg1 > 1) {
850     return float4(0, 0, 0, 0);
851   }
852   return func2(arg1);
853 }
854 
855 float4 main(float pos : POSITION) : SV_POSITION {
856   return func1(pos);
857 }
858 "
859 %7 = OpString "float"
860 %8 = OpString "main"
861 %9 = OpString "v4f_main_f"
862 %10 = OpString "v4f_func1_f"
863 %11 = OpString "v4f_func2_f"
864 %12 = OpString "pos : POSITION"
865 %13 = OpString "func1"
866 %14 = OpString "func2"
867 OpName %main "main"
868 OpName %pos "pos"
869 OpName %bb_entry "bb.entry"
870 OpName %param_var_arg1 "param.var.arg1"
871 OpName %func1 "func1"
872 OpName %arg1 "arg1"
873 OpName %bb_entry_0 "bb.entry"
874 OpName %param_var_arg2 "param.var.arg2"
875 OpName %if_true "if.true"
876 OpName %if_merge "if.merge"
877 OpName %func2 "func2"
878 OpName %arg2 "arg2"
879 OpName %bb_entry_1 "bb.entry"
880 OpDecorate %gl_Position BuiltIn Position
881 OpDecorate %pos Location 0
882 %float = OpTypeFloat 32
883 %int = OpTypeInt 32 1
884 %float_1 = OpConstant %float 1
885 %float_0 = OpConstant %float 0
886 %int_32 = OpConstant %int 32
887 %v4float = OpTypeVector %float 4
888 %32 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
889 %_ptr_Input_float = OpTypePointer Input %float
890 %_ptr_Output_v4float = OpTypePointer Output %v4float
891 %void = OpTypeVoid
892 %36 = OpTypeFunction %void
893 %_ptr_Function_float = OpTypePointer Function %float
894 %38 = OpTypeFunction %v4float %_ptr_Function_float
895 %bool = OpTypeBool
896 OpLine %5 12 25
897 %pos = OpVariable %_ptr_Input_float Input
898 OpLine %5 12 37
899 %gl_Position = OpVariable %_ptr_Output_v4float Output
900 %40 = OpExtInst %void %1 DebugSource %5 %6
901 %41 = OpExtInst %void %1 DebugCompilationUnit 2 4 %40 HLSL
902 %42 = OpExtInst %void %1 DebugTypeBasic %7 %int_32 Float
903 %43 = OpExtInst %void %1 DebugTypeVector %42 4
904 %44 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42
905 %45 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42
906 %46 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42
907 %47 = OpExtInst %void %1 DebugFunction %8 %44 %40 12 1 %41 %9 FlagIsProtected|FlagIsPrivate 13 %main
908 %48 = OpExtInst %void %1 DebugFunction %13 %45 %40 5 1 %41 %10 FlagIsProtected|FlagIsPrivate 13 %func1
909 %49 = OpExtInst %void %1 DebugFunction %14 %46 %40 1 1 %41 %11 FlagIsProtected|FlagIsPrivate 13 %func2
910 %50 = OpExtInst %void %1 DebugLexicalBlock %40 6 17 %48
911 %51 = OpExtInst %void %1 DebugLexicalBlock %40 9 3 %48
912 OpLine %5 12 1
913 %main = OpFunction %void None %36
914 %bb_entry = OpLabel
915 %70 = OpExtInst %void %1 DebugScope %47
916 OpLine %5 13 16
917 %param_var_arg1 = OpVariable %_ptr_Function_float Function
918 %53 = OpLoad %float %pos
919 OpStore %param_var_arg1 %53
920 OpLine %5 13 10
921 %54 = OpFunctionCall %v4float %func1 %param_var_arg1
922 OpLine %5 13 3
923 OpStore %gl_Position %54
924 %71 = OpExtInst %void %1 DebugNoScope
925 OpReturn
926 OpFunctionEnd
927 OpLine %5 5 1
928 %func1 = OpFunction %v4float None %38
929 OpLine %5 5 20
930 %arg1 = OpFunctionParameter %_ptr_Function_float
931 %bb_entry_0 = OpLabel
932 %72 = OpExtInst %void %1 DebugScope %48
933 OpLine %5 9 16
934 %param_var_arg2 = OpVariable %_ptr_Function_float Function
935 OpLine %5 6 7
936 %57 = OpLoad %float %arg1
937 OpLine %5 6 12
938 %58 = OpFOrdGreaterThan %bool %57 %float_1
939 OpLine %5 6 17
940 %73 = OpExtInst %void %1 DebugNoScope
941 OpSelectionMerge %if_merge None
942 OpBranchConditional %58 %if_true %if_merge
943 %if_true = OpLabel
944 %74 = OpExtInst %void %1 DebugScope %50
945 OpLine %5 7 5
946 %75 = OpExtInst %void %1 DebugNoScope
947 OpReturnValue %32
948 %if_merge = OpLabel
949 %76 = OpExtInst %void %1 DebugScope %51
950 OpLine %5 9 16
951 %63 = OpLoad %float %arg1
952 OpStore %param_var_arg2 %63
953 OpLine %5 9 10
954 %64 = OpFunctionCall %v4float %func2 %param_var_arg2
955 OpLine %5 9 3
956 %77 = OpExtInst %void %1 DebugNoScope
957 OpReturnValue %64
958 OpFunctionEnd
959 OpLine %5 1 1
960 %func2 = OpFunction %v4float None %38
961 OpLine %5 1 20
962 %arg2 = OpFunctionParameter %_ptr_Function_float
963 %bb_entry_1 = OpLabel
964 %78 = OpExtInst %void %1 DebugScope %49
965 OpLine %5 2 17
966 %67 = OpLoad %float %arg2
967 %68 = OpCompositeConstruct %v4float %67 %float_0 %float_0 %float_0
968 OpLine %5 2 3
969 %79 = OpExtInst %void %1 DebugNoScope
970 OpReturnValue %68
971 OpFunctionEnd
972 )";
973 
974   SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
975   std::unique_ptr<IRContext> context =
976       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text);
977   ASSERT_NE(nullptr, context);
978 
979   std::vector<uint32_t> binary;
980   context->module()->ToBinary(&binary, /* skip_nop = */ false);
981 
982   std::string disassembled_text;
983   EXPECT_TRUE(t.Disassemble(binary, &disassembled_text));
984   EXPECT_EQ(text, disassembled_text);
985 }
986 
987 TEST(IrBuilder, DebugInfoInstInFunctionOutOfBlock2) {
988   // /* HLSL */
989   //
990   // struct VS_OUTPUT {
991   //   float4 pos : SV_POSITION;
992   //   float4 color : COLOR;
993   // };
994   //
995   // VS_OUTPUT main(float4 pos : POSITION,
996   //                float4 color : COLOR) {
997   //   VS_OUTPUT vout;
998   //   vout.pos = pos;
999   //   vout.color = color;
1000   //   return vout;
1001   // }
1002   const std::string text = R"(OpCapability Shader
1003 %1 = OpExtInstImport "OpenCL.DebugInfo.100"
1004 OpMemoryModel Logical GLSL450
1005 OpEntryPoint Vertex %main "main" %in_var_POSITION %in_var_COLOR %gl_Position %out_var_COLOR
1006 %7 = OpString "vs.hlsl"
1007 OpSource HLSL 600 %7 "#line 1 \"vs.hlsl\"
1008 struct VS_OUTPUT {
1009   float4 pos : SV_POSITION;
1010   float4 color : COLOR;
1011 };
1012 
1013 VS_OUTPUT main(float4 pos : POSITION,
1014                float4 color : COLOR) {
1015   VS_OUTPUT vout;
1016   vout.pos = pos;
1017   vout.color = color;
1018   return vout;
1019 }
1020 "
1021 %8 = OpString "#line 1 \"vs.hlsl\"
1022 struct VS_OUTPUT {
1023   float4 pos : SV_POSITION;
1024   float4 color : COLOR;
1025 };
1026 
1027 VS_OUTPUT main(float4 pos : POSITION,
1028                float4 color : COLOR) {
1029   VS_OUTPUT vout;
1030   vout.pos = pos;
1031   vout.color = color;
1032   return vout;
1033 }
1034 "
1035 %9 = OpString "VS_OUTPUT"
1036 %10 = OpString "float"
1037 %11 = OpString "src.main"
1038 %12 = OpString "pos"
1039 %13 = OpString "color"
1040 %14 = OpString "vout"
1041 OpName %in_var_POSITION "in.var.POSITION"
1042 OpName %in_var_COLOR "in.var.COLOR"
1043 OpName %out_var_COLOR "out.var.COLOR"
1044 OpName %main "main"
1045 OpName %param_var_pos "param.var.pos"
1046 OpName %param_var_color "param.var.color"
1047 OpName %VS_OUTPUT "VS_OUTPUT"
1048 OpMemberName %VS_OUTPUT 0 "pos"
1049 OpMemberName %VS_OUTPUT 1 "color"
1050 OpName %src_main "src.main"
1051 OpName %pos "pos"
1052 OpName %color "color"
1053 OpName %bb_entry "bb.entry"
1054 OpName %vout "vout"
1055 OpDecorate %gl_Position BuiltIn Position
1056 OpDecorate %in_var_POSITION Location 0
1057 OpDecorate %in_var_COLOR Location 1
1058 OpDecorate %out_var_COLOR Location 0
1059 %int = OpTypeInt 32 1
1060 %int_0 = OpConstant %int 0
1061 %int_1 = OpConstant %int 1
1062 %uint = OpTypeInt 32 0
1063 %uint_32 = OpConstant %uint 32
1064 %float = OpTypeFloat 32
1065 %v4float = OpTypeVector %float 4
1066 %_ptr_Input_v4float = OpTypePointer Input %v4float
1067 %_ptr_Output_v4float = OpTypePointer Output %v4float
1068 %void = OpTypeVoid
1069 %uint_256 = OpConstant %uint 256
1070 %uint_0 = OpConstant %uint 0
1071 %uint_128 = OpConstant %uint 128
1072 %36 = OpTypeFunction %void
1073 %_ptr_Function_v4float = OpTypePointer Function %v4float
1074 %VS_OUTPUT = OpTypeStruct %v4float %v4float
1075 %38 = OpTypeFunction %VS_OUTPUT %_ptr_Function_v4float %_ptr_Function_v4float
1076 %_ptr_Function_VS_OUTPUT = OpTypePointer Function %VS_OUTPUT
1077 OpLine %7 6 29
1078 %in_var_POSITION = OpVariable %_ptr_Input_v4float Input
1079 OpLine %7 7 31
1080 %in_var_COLOR = OpVariable %_ptr_Input_v4float Input
1081 OpLine %7 2 16
1082 %gl_Position = OpVariable %_ptr_Output_v4float Output
1083 OpLine %7 3 18
1084 %out_var_COLOR = OpVariable %_ptr_Output_v4float Output
1085 %40 = OpExtInst %void %1 DebugExpression
1086 %41 = OpExtInst %void %1 DebugSource %7 %8
1087 %42 = OpExtInst %void %1 DebugCompilationUnit 1 4 %41 HLSL
1088 %43 = OpExtInst %void %1 DebugTypeComposite %9 Structure %41 1 1 %42 %9 %uint_256 FlagIsProtected|FlagIsPrivate %44 %45
1089 %46 = OpExtInst %void %1 DebugTypeBasic %10 %uint_32 Float
1090 %47 = OpExtInst %void %1 DebugTypeVector %46 4
1091 %48 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %47 %47
1092 %49 = OpExtInst %void %1 DebugFunction %11 %48 %41 6 1 %42 %11 FlagIsProtected|FlagIsPrivate 7 %src_main
1093 %50 = OpExtInst %void %1 DebugLocalVariable %12 %47 %41 6 23 %49 FlagIsLocal 0
1094 %51 = OpExtInst %void %1 DebugLocalVariable %13 %47 %41 7 23 %49 FlagIsLocal 1
1095 %52 = OpExtInst %void %1 DebugLexicalBlock %41 7 38 %49
1096 %53 = OpExtInst %void %1 DebugLocalVariable %14 %43 %41 8 13 %52 FlagIsLocal
1097 %44 = OpExtInst %void %1 DebugTypeMember %12 %47 %41 2 3 %43 %uint_0 %uint_128 FlagIsProtected|FlagIsPrivate
1098 %45 = OpExtInst %void %1 DebugTypeMember %13 %47 %41 3 3 %43 %uint_128 %uint_128 FlagIsProtected|FlagIsPrivate
1099 OpLine %7 6 1
1100 %main = OpFunction %void None %36
1101 %54 = OpLabel
1102 %74 = OpExtInst %void %1 DebugScope %42
1103 OpLine %7 6 23
1104 %param_var_pos = OpVariable %_ptr_Function_v4float Function
1105 OpLine %7 7 23
1106 %param_var_color = OpVariable %_ptr_Function_v4float Function
1107 OpLine %7 6 23
1108 %56 = OpLoad %v4float %in_var_POSITION
1109 OpStore %param_var_pos %56
1110 OpLine %7 7 23
1111 %57 = OpLoad %v4float %in_var_COLOR
1112 OpStore %param_var_color %57
1113 OpLine %7 6 1
1114 %58 = OpFunctionCall %VS_OUTPUT %src_main %param_var_pos %param_var_color
1115 OpLine %7 6 11
1116 %59 = OpCompositeExtract %v4float %58 0
1117 OpLine %7 2 16
1118 OpStore %gl_Position %59
1119 OpLine %7 6 11
1120 %60 = OpCompositeExtract %v4float %58 1
1121 OpLine %7 3 18
1122 OpStore %out_var_COLOR %60
1123 %75 = OpExtInst %void %1 DebugNoScope
1124 OpReturn
1125 OpFunctionEnd
1126 OpLine %7 6 1
1127 %src_main = OpFunction %VS_OUTPUT None %38
1128 %76 = OpExtInst %void %1 DebugScope %49
1129 OpLine %7 6 23
1130 %pos = OpFunctionParameter %_ptr_Function_v4float
1131 OpLine %7 7 23
1132 %color = OpFunctionParameter %_ptr_Function_v4float
1133 %63 = OpExtInst %void %1 DebugDeclare %50 %pos %40
1134 %64 = OpExtInst %void %1 DebugDeclare %51 %color %40
1135 %77 = OpExtInst %void %1 DebugNoScope
1136 %bb_entry = OpLabel
1137 %78 = OpExtInst %void %1 DebugScope %52
1138 OpLine %7 8 13
1139 %vout = OpVariable %_ptr_Function_VS_OUTPUT Function
1140 %67 = OpExtInst %void %1 DebugDeclare %53 %vout %40
1141 OpLine %7 9 14
1142 %68 = OpLoad %v4float %pos
1143 OpLine %7 9 3
1144 %69 = OpAccessChain %_ptr_Function_v4float %vout %int_0
1145 OpStore %69 %68
1146 OpLine %7 10 16
1147 %70 = OpLoad %v4float %color
1148 OpLine %7 10 3
1149 %71 = OpAccessChain %_ptr_Function_v4float %vout %int_1
1150 OpStore %71 %70
1151 OpLine %7 11 10
1152 %72 = OpLoad %VS_OUTPUT %vout
1153 OpLine %7 11 3
1154 %79 = OpExtInst %void %1 DebugNoScope
1155 OpReturnValue %72
1156 OpFunctionEnd
1157 )";
1158 
1159   SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
1160   std::unique_ptr<IRContext> context =
1161       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text);
1162   ASSERT_NE(nullptr, context);
1163 
1164   std::vector<uint32_t> binary;
1165   context->module()->ToBinary(&binary, /* skip_nop = */ false);
1166 
1167   std::string disassembled_text;
1168   EXPECT_TRUE(t.Disassemble(binary, &disassembled_text));
1169   EXPECT_EQ(text, disassembled_text);
1170 }
1171 
1172 TEST(IrBuilder, DebugInfoForTerminationInsts) {
1173   // Check that DebugScope instructions for termination instructions are
1174   // preserved.
1175   DoRoundTripCheck(R"(OpCapability Shader
1176 %1 = OpExtInstImport "OpenCL.DebugInfo.100"
1177 OpMemoryModel Logical GLSL450
1178 OpEntryPoint Fragment %main "main"
1179 OpExecutionMode %main OriginUpperLeft
1180 %3 = OpString "simple_vs.hlsl"
1181 OpSource HLSL 600 %3
1182 OpName %main "main"
1183 %void = OpTypeVoid
1184 %5 = OpTypeFunction %void
1185 %6 = OpExtInst %void %1 DebugSource %3
1186 %7 = OpExtInst %void %1 DebugCompilationUnit 2 4 %6 HLSL
1187 %main = OpFunction %void None %5
1188 %8 = OpLabel
1189 %20 = OpExtInst %void %1 DebugScope %7
1190 OpBranch %10
1191 %21 = OpExtInst %void %1 DebugNoScope
1192 %10 = OpLabel
1193 %22 = OpExtInst %void %1 DebugScope %7
1194 OpKill
1195 %23 = OpExtInst %void %1 DebugNoScope
1196 %14 = OpLabel
1197 %24 = OpExtInst %void %1 DebugScope %7
1198 OpUnreachable
1199 %25 = OpExtInst %void %1 DebugNoScope
1200 %17 = OpLabel
1201 %26 = OpExtInst %void %1 DebugScope %7
1202 OpReturn
1203 %27 = OpExtInst %void %1 DebugNoScope
1204 OpFunctionEnd
1205 )");
1206 }
1207 
1208 TEST(IrBuilder, LocalGlobalVariables) {
1209   // #version 310 es
1210   //
1211   // float gv1 = 10.;
1212   // float gv2 = 100.;
1213   //
1214   // float f() {
1215   //   float lv1 = gv1 + gv2;
1216   //   float lv2 = gv1 * gv2;
1217   //   return lv1 / lv2;
1218   // }
1219   //
1220   // void main() {
1221   //   float lv1 = gv1 - gv2;
1222   // }
1223   DoRoundTripCheck(
1224       // clang-format off
1225                "OpCapability Shader\n"
1226           "%1 = OpExtInstImport \"GLSL.std.450\"\n"
1227                "OpMemoryModel Logical GLSL450\n"
1228                "OpEntryPoint Vertex %main \"main\"\n"
1229                "OpSource ESSL 310\n"
1230                "OpName %main \"main\"\n"
1231                "OpName %f_ \"f(\"\n"
1232                "OpName %gv1 \"gv1\"\n"
1233                "OpName %gv2 \"gv2\"\n"
1234                "OpName %lv1 \"lv1\"\n"
1235                "OpName %lv2 \"lv2\"\n"
1236                "OpName %lv1_0 \"lv1\"\n"
1237        "%void = OpTypeVoid\n"
1238          "%10 = OpTypeFunction %void\n"
1239       "%float = OpTypeFloat 32\n"
1240          "%12 = OpTypeFunction %float\n"
1241  "%_ptr_Private_float = OpTypePointer Private %float\n"
1242         "%gv1 = OpVariable %_ptr_Private_float Private\n"
1243    "%float_10 = OpConstant %float 10\n"
1244         "%gv2 = OpVariable %_ptr_Private_float Private\n"
1245   "%float_100 = OpConstant %float 100\n"
1246  "%_ptr_Function_float = OpTypePointer Function %float\n"
1247        "%main = OpFunction %void None %10\n"
1248          "%17 = OpLabel\n"
1249       "%lv1_0 = OpVariable %_ptr_Function_float Function\n"
1250                "OpStore %gv1 %float_10\n"
1251                "OpStore %gv2 %float_100\n"
1252          "%18 = OpLoad %float %gv1\n"
1253          "%19 = OpLoad %float %gv2\n"
1254          "%20 = OpFSub %float %18 %19\n"
1255                "OpStore %lv1_0 %20\n"
1256                "OpReturn\n"
1257                "OpFunctionEnd\n"
1258          "%f_ = OpFunction %float None %12\n"
1259          "%21 = OpLabel\n"
1260         "%lv1 = OpVariable %_ptr_Function_float Function\n"
1261         "%lv2 = OpVariable %_ptr_Function_float Function\n"
1262          "%22 = OpLoad %float %gv1\n"
1263          "%23 = OpLoad %float %gv2\n"
1264          "%24 = OpFAdd %float %22 %23\n"
1265                "OpStore %lv1 %24\n"
1266          "%25 = OpLoad %float %gv1\n"
1267          "%26 = OpLoad %float %gv2\n"
1268          "%27 = OpFMul %float %25 %26\n"
1269                "OpStore %lv2 %27\n"
1270          "%28 = OpLoad %float %lv1\n"
1271          "%29 = OpLoad %float %lv2\n"
1272          "%30 = OpFDiv %float %28 %29\n"
1273                "OpReturnValue %30\n"
1274                "OpFunctionEnd\n");
1275   // clang-format on
1276 }
1277 
TEST(IrBuilder,OpUndefOutsideFunction)1278 TEST(IrBuilder, OpUndefOutsideFunction) {
1279   // #version 310 es
1280   // void main() {}
1281   const std::string text =
1282       // clang-format off
1283                "OpMemoryModel Logical GLSL450\n"
1284         "%int = OpTypeInt 32 1\n"
1285        "%uint = OpTypeInt 32 0\n"
1286       "%float = OpTypeFloat 32\n"
1287           "%4 = OpUndef %int\n"
1288      "%int_10 = OpConstant %int 10\n"
1289           "%6 = OpUndef %uint\n"
1290        "%bool = OpTypeBool\n"
1291           "%8 = OpUndef %float\n"
1292      "%double = OpTypeFloat 64\n";
1293   // clang-format on
1294 
1295   SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
1296   std::unique_ptr<IRContext> context =
1297       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text);
1298   ASSERT_NE(nullptr, context);
1299 
1300   const auto opundef_count = std::count_if(
1301       context->module()->types_values_begin(),
1302       context->module()->types_values_end(), [](const Instruction& inst) {
1303         return inst.opcode() == spv::Op::OpUndef;
1304       });
1305   EXPECT_EQ(3, opundef_count);
1306 
1307   std::vector<uint32_t> binary;
1308   context->module()->ToBinary(&binary, /* skip_nop = */ false);
1309 
1310   std::string disassembled_text;
1311   EXPECT_TRUE(t.Disassemble(binary, &disassembled_text));
1312   EXPECT_EQ(text, disassembled_text);
1313 }
1314 
TEST(IrBuilder,OpUndefInBasicBlock)1315 TEST(IrBuilder, OpUndefInBasicBlock) {
1316   DoRoundTripCheck(
1317       // clang-format off
1318                "OpMemoryModel Logical GLSL450\n"
1319                "OpName %main \"main\"\n"
1320        "%void = OpTypeVoid\n"
1321        "%uint = OpTypeInt 32 0\n"
1322      "%double = OpTypeFloat 64\n"
1323           "%5 = OpTypeFunction %void\n"
1324        "%main = OpFunction %void None %5\n"
1325           "%6 = OpLabel\n"
1326           "%7 = OpUndef %uint\n"
1327           "%8 = OpUndef %double\n"
1328                "OpReturn\n"
1329                "OpFunctionEnd\n");
1330   // clang-format on
1331 }
1332 
TEST(IrBuilder,KeepLineDebugInfoBeforeType)1333 TEST(IrBuilder, KeepLineDebugInfoBeforeType) {
1334   DoRoundTripCheck(
1335       // clang-format off
1336                "OpCapability Shader\n"
1337                "OpMemoryModel Logical GLSL450\n"
1338           "%1 = OpString \"minimal.vert\"\n"
1339                "OpLine %1 1 1\n"
1340                "OpNoLine\n"
1341        "%void = OpTypeVoid\n"
1342                "OpLine %1 2 2\n"
1343           "%3 = OpTypeFunction %void\n");
1344   // clang-format on
1345 }
1346 
TEST(IrBuilder,KeepLineDebugInfoBeforeLabel)1347 TEST(IrBuilder, KeepLineDebugInfoBeforeLabel) {
1348   DoRoundTripCheck(
1349       // clang-format off
1350                "OpCapability Shader\n"
1351                "OpMemoryModel Logical GLSL450\n"
1352           "%1 = OpString \"minimal.vert\"\n"
1353        "%void = OpTypeVoid\n"
1354           "%3 = OpTypeFunction %void\n"
1355        "%4 = OpFunction %void None %3\n"
1356           "%5 = OpLabel\n"
1357    "OpBranch %6\n"
1358                "OpLine %1 1 1\n"
1359                "OpLine %1 2 2\n"
1360           "%6 = OpLabel\n"
1361                "OpBranch %7\n"
1362                "OpLine %1 100 100\n"
1363           "%7 = OpLabel\n"
1364                "OpReturn\n"
1365                "OpFunctionEnd\n");
1366   // clang-format on
1367 }
1368 
TEST(IrBuilder,KeepLineDebugInfoBeforeFunctionEnd)1369 TEST(IrBuilder, KeepLineDebugInfoBeforeFunctionEnd) {
1370   DoRoundTripCheck(
1371       // clang-format off
1372                "OpCapability Shader\n"
1373                "OpMemoryModel Logical GLSL450\n"
1374           "%1 = OpString \"minimal.vert\"\n"
1375        "%void = OpTypeVoid\n"
1376           "%3 = OpTypeFunction %void\n"
1377        "%4 = OpFunction %void None %3\n"
1378                "OpLine %1 1 1\n"
1379                "OpLine %1 2 2\n"
1380                "OpFunctionEnd\n");
1381   // clang-format on
1382 }
1383 
TEST(IrBuilder,KeepModuleProcessedInRightPlace)1384 TEST(IrBuilder, KeepModuleProcessedInRightPlace) {
1385   DoRoundTripCheck(
1386       // clang-format off
1387                "OpCapability Shader\n"
1388                "OpMemoryModel Logical GLSL450\n"
1389           "%1 = OpString \"minimal.vert\"\n"
1390                "OpName %void \"void\"\n"
1391                "OpModuleProcessed \"Made it faster\"\n"
1392                "OpModuleProcessed \".. and smaller\"\n"
1393        "%void = OpTypeVoid\n");
1394   // clang-format on
1395 }
1396 
1397 // Checks the given |error_message| is reported when trying to build a module
1398 // from the given |assembly|.
DoErrorMessageCheck(const std::string & assembly,const std::string & error_message,uint32_t line_num)1399 void DoErrorMessageCheck(const std::string& assembly,
1400                          const std::string& error_message, uint32_t line_num) {
1401   auto consumer = [error_message, line_num](spv_message_level_t, const char*,
1402                                             const spv_position_t& position,
1403                                             const char* m) {
1404     EXPECT_EQ(error_message, m);
1405     EXPECT_EQ(line_num, position.line);
1406   };
1407 
1408   SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
1409   std::unique_ptr<IRContext> context =
1410       BuildModule(SPV_ENV_UNIVERSAL_1_1, std::move(consumer), assembly);
1411   EXPECT_EQ(nullptr, context);
1412 }
1413 
TEST(IrBuilder,FunctionInsideFunction)1414 TEST(IrBuilder, FunctionInsideFunction) {
1415   DoErrorMessageCheck("%2 = OpFunction %1 None %3\n%5 = OpFunction %4 None %6",
1416                       "function inside function", 2);
1417 }
1418 
TEST(IrBuilder,MismatchOpFunctionEnd)1419 TEST(IrBuilder, MismatchOpFunctionEnd) {
1420   DoErrorMessageCheck("OpFunctionEnd",
1421                       "OpFunctionEnd without corresponding OpFunction", 1);
1422 }
1423 
TEST(IrBuilder,OpFunctionEndInsideBasicBlock)1424 TEST(IrBuilder, OpFunctionEndInsideBasicBlock) {
1425   DoErrorMessageCheck(
1426       "%2 = OpFunction %1 None %3\n"
1427       "%4 = OpLabel\n"
1428       "OpFunctionEnd",
1429       "OpFunctionEnd inside basic block", 3);
1430 }
1431 
TEST(IrBuilder,BasicBlockOutsideFunction)1432 TEST(IrBuilder, BasicBlockOutsideFunction) {
1433   DoErrorMessageCheck("OpCapability Shader\n%1 = OpLabel",
1434                       "OpLabel outside function", 2);
1435 }
1436 
TEST(IrBuilder,OpLabelInsideBasicBlock)1437 TEST(IrBuilder, OpLabelInsideBasicBlock) {
1438   DoErrorMessageCheck(
1439       "%2 = OpFunction %1 None %3\n"
1440       "%4 = OpLabel\n"
1441       "%5 = OpLabel",
1442       "OpLabel inside basic block", 3);
1443 }
1444 
TEST(IrBuilder,TerminatorOutsideFunction)1445 TEST(IrBuilder, TerminatorOutsideFunction) {
1446   DoErrorMessageCheck("OpReturn", "terminator instruction outside function", 1);
1447 }
1448 
TEST(IrBuilder,TerminatorOutsideBasicBlock)1449 TEST(IrBuilder, TerminatorOutsideBasicBlock) {
1450   DoErrorMessageCheck("%2 = OpFunction %1 None %3\nOpReturn",
1451                       "terminator instruction outside basic block", 2);
1452 }
1453 
TEST(IrBuilder,NotAllowedInstAppearingInFunction)1454 TEST(IrBuilder, NotAllowedInstAppearingInFunction) {
1455   DoErrorMessageCheck("%2 = OpFunction %1 None %3\n%5 = OpVariable %4 Function",
1456                       "Non-OpFunctionParameter (opcode: 59) found inside "
1457                       "function but outside basic block",
1458                       2);
1459 }
1460 
TEST(IrBuilder,UniqueIds)1461 TEST(IrBuilder, UniqueIds) {
1462   const std::string text =
1463       // clang-format off
1464                "OpCapability Shader\n"
1465           "%1 = OpExtInstImport \"GLSL.std.450\"\n"
1466                "OpMemoryModel Logical GLSL450\n"
1467                "OpEntryPoint Vertex %main \"main\"\n"
1468                "OpSource ESSL 310\n"
1469                "OpName %main \"main\"\n"
1470                "OpName %f_ \"f(\"\n"
1471                "OpName %gv1 \"gv1\"\n"
1472                "OpName %gv2 \"gv2\"\n"
1473                "OpName %lv1 \"lv1\"\n"
1474                "OpName %lv2 \"lv2\"\n"
1475                "OpName %lv1_0 \"lv1\"\n"
1476        "%void = OpTypeVoid\n"
1477          "%10 = OpTypeFunction %void\n"
1478       "%float = OpTypeFloat 32\n"
1479          "%12 = OpTypeFunction %float\n"
1480  "%_ptr_Private_float = OpTypePointer Private %float\n"
1481         "%gv1 = OpVariable %_ptr_Private_float Private\n"
1482    "%float_10 = OpConstant %float 10\n"
1483         "%gv2 = OpVariable %_ptr_Private_float Private\n"
1484   "%float_100 = OpConstant %float 100\n"
1485  "%_ptr_Function_float = OpTypePointer Function %float\n"
1486        "%main = OpFunction %void None %10\n"
1487          "%17 = OpLabel\n"
1488       "%lv1_0 = OpVariable %_ptr_Function_float Function\n"
1489                "OpStore %gv1 %float_10\n"
1490                "OpStore %gv2 %float_100\n"
1491          "%18 = OpLoad %float %gv1\n"
1492          "%19 = OpLoad %float %gv2\n"
1493          "%20 = OpFSub %float %18 %19\n"
1494                "OpStore %lv1_0 %20\n"
1495                "OpReturn\n"
1496                "OpFunctionEnd\n"
1497          "%f_ = OpFunction %float None %12\n"
1498          "%21 = OpLabel\n"
1499         "%lv1 = OpVariable %_ptr_Function_float Function\n"
1500         "%lv2 = OpVariable %_ptr_Function_float Function\n"
1501          "%22 = OpLoad %float %gv1\n"
1502          "%23 = OpLoad %float %gv2\n"
1503          "%24 = OpFAdd %float %22 %23\n"
1504                "OpStore %lv1 %24\n"
1505          "%25 = OpLoad %float %gv1\n"
1506          "%26 = OpLoad %float %gv2\n"
1507          "%27 = OpFMul %float %25 %26\n"
1508                "OpStore %lv2 %27\n"
1509          "%28 = OpLoad %float %lv1\n"
1510          "%29 = OpLoad %float %lv2\n"
1511          "%30 = OpFDiv %float %28 %29\n"
1512                "OpReturnValue %30\n"
1513                "OpFunctionEnd\n";
1514   // clang-format on
1515 
1516   std::unique_ptr<IRContext> context =
1517       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text);
1518   ASSERT_NE(nullptr, context);
1519 
1520   std::unordered_set<uint32_t> ids;
1521   context->module()->ForEachInst([&ids](const Instruction* inst) {
1522     EXPECT_TRUE(ids.insert(inst->unique_id()).second);
1523   });
1524 }
1525 
1526 }  // namespace
1527 }  // namespace opt
1528 }  // namespace spvtools
1529