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