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