1 // Copyright (c) 2020 Google LLC
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 "source/opt/debug_info_manager.h"
16 
17 #include <memory>
18 #include <vector>
19 
20 #include "gtest/gtest.h"
21 #include "source/opt/build_module.h"
22 #include "source/opt/instruction.h"
23 #include "spirv-tools/libspirv.hpp"
24 
25 // Constants for OpenCL.DebugInfo.100 extension instructions.
26 
27 static const uint32_t kDebugFunctionOperandFunctionIndex = 13;
28 static const uint32_t kDebugInlinedAtOperandLineIndex = 4;
29 static const uint32_t kDebugInlinedAtOperandScopeIndex = 5;
30 static const uint32_t kDebugInlinedAtOperandInlinedIndex = 6;
31 static const uint32_t kOpLineInOperandFileIndex = 0;
32 static const uint32_t kOpLineInOperandLineIndex = 1;
33 static const uint32_t kOpLineInOperandColumnIndex = 2;
34 
35 namespace spvtools {
36 namespace opt {
37 namespace analysis {
38 namespace {
39 
TEST(DebugInfoManager,GetDebugInlinedAt)40 TEST(DebugInfoManager, GetDebugInlinedAt) {
41   const std::string text = R"(
42                OpCapability Shader
43           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
44                OpMemoryModel Logical GLSL450
45                OpEntryPoint Fragment %main "main" %in_var_COLOR
46                OpExecutionMode %main OriginUpperLeft
47           %5 = OpString "ps.hlsl"
48          %14 = OpString "#line 1 \"ps.hlsl\"
49 void main(float in_var_color : COLOR) {
50   float color = in_var_color;
51 }
52 "
53          %17 = OpString "float"
54          %21 = OpString "main"
55          %24 = OpString "color"
56                OpName %in_var_COLOR "in.var.COLOR"
57                OpName %main "main"
58                OpDecorate %in_var_COLOR Location 0
59        %uint = OpTypeInt 32 0
60     %uint_32 = OpConstant %uint 32
61       %float = OpTypeFloat 32
62 %_ptr_Input_float = OpTypePointer Input %float
63        %void = OpTypeVoid
64          %27 = OpTypeFunction %void
65 %_ptr_Function_float = OpTypePointer Function %float
66 %in_var_COLOR = OpVariable %_ptr_Input_float Input
67          %13 = OpExtInst %void %1 DebugExpression
68          %15 = OpExtInst %void %1 DebugSource %5 %14
69          %16 = OpExtInst %void %1 DebugCompilationUnit 1 4 %15 HLSL
70          %18 = OpExtInst %void %1 DebugTypeBasic %17 %uint_32 Float
71          %20 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %18 %18
72          %22 = OpExtInst %void %1 DebugFunction %21 %20 %15 1 1 %16 %21 FlagIsProtected|FlagIsPrivate 1 %main
73         %100 = OpExtInst %void %1 DebugInlinedAt 7 %22
74        %main = OpFunction %void None %27
75          %28 = OpLabel
76          %31 = OpLoad %float %in_var_COLOR
77                OpStore %100 %31
78                OpReturn
79                OpFunctionEnd
80   )";
81 
82   std::unique_ptr<IRContext> context =
83       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
84                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
85   DebugInfoManager manager(context.get());
86 
87   EXPECT_EQ(manager.GetDebugInlinedAt(150), nullptr);
88   EXPECT_EQ(manager.GetDebugInlinedAt(31), nullptr);
89   EXPECT_EQ(manager.GetDebugInlinedAt(22), nullptr);
90 
91   auto* inst = manager.GetDebugInlinedAt(100);
92   EXPECT_EQ(inst->GetSingleWordOperand(kDebugInlinedAtOperandLineIndex), 7);
93   EXPECT_EQ(inst->GetSingleWordOperand(kDebugInlinedAtOperandScopeIndex), 22);
94 }
95 
96 TEST(DebugInfoManager, CreateDebugInlinedAt) {
97   const std::string text = R"(
98                OpCapability Shader
99           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
100                OpMemoryModel Logical GLSL450
101                OpEntryPoint Fragment %main "main" %in_var_COLOR
102                OpExecutionMode %main OriginUpperLeft
103           %5 = OpString "ps.hlsl"
104          %14 = OpString "#line 1 \"ps.hlsl\"
105 void main(float in_var_color : COLOR) {
106   float color = in_var_color;
107 }
108 "
109          %17 = OpString "float"
110          %21 = OpString "main"
111          %24 = OpString "color"
112                OpName %in_var_COLOR "in.var.COLOR"
113                OpName %main "main"
114                OpDecorate %in_var_COLOR Location 0
115        %uint = OpTypeInt 32 0
116     %uint_32 = OpConstant %uint 32
117       %float = OpTypeFloat 32
118 %_ptr_Input_float = OpTypePointer Input %float
119        %void = OpTypeVoid
120          %27 = OpTypeFunction %void
121 %_ptr_Function_float = OpTypePointer Function %float
122 %in_var_COLOR = OpVariable %_ptr_Input_float Input
123          %13 = OpExtInst %void %1 DebugExpression
124          %15 = OpExtInst %void %1 DebugSource %5 %14
125          %16 = OpExtInst %void %1 DebugCompilationUnit 1 4 %15 HLSL
126          %18 = OpExtInst %void %1 DebugTypeBasic %17 %uint_32 Float
127          %20 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %18 %18
128          %22 = OpExtInst %void %1 DebugFunction %21 %20 %15 1 1 %16 %21 FlagIsProtected|FlagIsPrivate 1 %main
129         %100 = OpExtInst %void %1 DebugInlinedAt 7 %22
130        %main = OpFunction %void None %27
131          %28 = OpLabel
132          %31 = OpLoad %float %in_var_COLOR
133                OpStore %100 %31
134                OpReturn
135                OpFunctionEnd
136   )";
137 
138   DebugScope scope(22U, 0U);
139 
140   std::unique_ptr<IRContext> context =
141       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
142                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
143   DebugInfoManager manager(context.get());
144 
145   uint32_t inlined_at_id = manager.CreateDebugInlinedAt(nullptr, scope);
146   auto* inlined_at = manager.GetDebugInlinedAt(inlined_at_id);
147   EXPECT_NE(inlined_at, nullptr);
148   EXPECT_EQ(inlined_at->GetSingleWordOperand(kDebugInlinedAtOperandLineIndex),
149             1);
150   EXPECT_EQ(inlined_at->GetSingleWordOperand(kDebugInlinedAtOperandScopeIndex),
151             22);
152   EXPECT_EQ(inlined_at->NumOperands(), kDebugInlinedAtOperandScopeIndex + 1);
153 
154   const uint32_t line_number = 77U;
155   Instruction line(context.get(), spv::Op::OpLine);
156   line.SetInOperands({
157       {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {5U}},
158       {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {line_number}},
159       {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {0U}},
160   });
161 
162   inlined_at_id = manager.CreateDebugInlinedAt(&line, scope);
163   inlined_at = manager.GetDebugInlinedAt(inlined_at_id);
164   EXPECT_NE(inlined_at, nullptr);
165   EXPECT_EQ(inlined_at->GetSingleWordOperand(kDebugInlinedAtOperandLineIndex),
166             line_number);
167   EXPECT_EQ(inlined_at->GetSingleWordOperand(kDebugInlinedAtOperandScopeIndex),
168             22);
169   EXPECT_EQ(inlined_at->NumOperands(), kDebugInlinedAtOperandScopeIndex + 1);
170 
171   scope.SetInlinedAt(100U);
172   inlined_at_id = manager.CreateDebugInlinedAt(&line, scope);
173   inlined_at = manager.GetDebugInlinedAt(inlined_at_id);
174   EXPECT_NE(inlined_at, nullptr);
175   EXPECT_EQ(inlined_at->GetSingleWordOperand(kDebugInlinedAtOperandLineIndex),
176             line_number);
177   EXPECT_EQ(inlined_at->GetSingleWordOperand(kDebugInlinedAtOperandScopeIndex),
178             22);
179   EXPECT_EQ(inlined_at->NumOperands(), kDebugInlinedAtOperandInlinedIndex + 1);
180   EXPECT_EQ(
181       inlined_at->GetSingleWordOperand(kDebugInlinedAtOperandInlinedIndex),
182       100U);
183 }
184 
185 TEST(DebugInfoManager, CreateDebugInlinedAtWithConstantManager) {
186   // Show that CreateDebugInlinedAt will use the Constant manager to generate
187   // its line operand if the Constant and DefUse managers are valid. This is
188   // proven by checking that the id for the line operand 7 is the same as the
189   // existing constant 7.
190   //
191   // int function1() {
192   //   return 1;
193   // }
194   //
195   // void main() {
196   //   function1();
197   // }
198   const std::string text = R"(OpCapability Shader
199 OpExtension "SPV_KHR_non_semantic_info"
200 %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
201 OpMemoryModel Logical GLSL450
202 OpEntryPoint Fragment %main "main"
203 OpExecutionMode %main OriginUpperLeft
204 %3 = OpString "parent3.hlsl"
205 %8 = OpString "int"
206 %19 = OpString "function1"
207 %20 = OpString ""
208 %26 = OpString "main"
209 OpName %main "main"
210 OpName %src_main "src.main"
211 OpName %bb_entry "bb.entry"
212 OpName %function1 "function1"
213 OpName %bb_entry_0 "bb.entry"
214 %int = OpTypeInt 32 1
215 %int_1 = OpConstant %int 1
216 %uint = OpTypeInt 32 0
217 %uint_32 = OpConstant %uint 32
218 %void = OpTypeVoid
219 %uint_4 = OpConstant %uint 4
220 %uint_0 = OpConstant %uint 0
221 %uint_3 = OpConstant %uint 3
222 %uint_1 = OpConstant %uint 1
223 %uint_5 = OpConstant %uint 5
224 %uint_2 = OpConstant %uint 2
225 %uint_17 = OpConstant %uint 17
226 %uint_6 = OpConstant %uint 6
227 %uint_13 = OpConstant %uint 13
228 %100 = OpConstant %uint 7
229 %31 = OpTypeFunction %void
230 %42 = OpTypeFunction %int
231 %10 = OpExtInst %void %1 DebugTypeBasic %8 %uint_32 %uint_4 %uint_0
232 %13 = OpExtInst %void %1 DebugTypeFunction %uint_3 %10
233 %15 = OpExtInst %void %1 DebugSource %3
234 %16 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %15 %uint_5
235 %21 = OpExtInst %void %1 DebugFunction %19 %13 %15 %uint_2 %uint_1 %16 %20 %uint_3 %uint_2
236 %23 = OpExtInst %void %1 DebugLexicalBlock %15 %uint_2 %uint_17 %21
237 %25 = OpExtInst %void %1 DebugTypeFunction %uint_3 %void
238 %27 = OpExtInst %void %1 DebugFunction %26 %25 %15 %uint_6 %uint_1 %16 %20 %uint_3 %uint_6
239 %29 = OpExtInst %void %1 DebugLexicalBlock %15 %uint_6 %uint_13 %27
240 %main = OpFunction %void None %31
241 %32 = OpLabel
242 %33 = OpFunctionCall %void %src_main
243 OpLine %3 8 1
244 OpReturn
245 OpFunctionEnd
246 OpLine %3 6 1
247 %src_main = OpFunction %void None %31
248 OpNoLine
249 %bb_entry = OpLabel
250 %47 = OpExtInst %void %1 DebugScope %27
251 %37 = OpExtInst %void %1 DebugFunctionDefinition %27 %src_main
252 %48 = OpExtInst %void %1 DebugScope %29
253 OpLine %3 7 3
254 %39 = OpFunctionCall %int %function1
255 %49 = OpExtInst %void %1 DebugScope %27
256 OpLine %3 8 1
257 OpReturn
258 %50 = OpExtInst %void %1 DebugNoScope
259 OpFunctionEnd
260 OpLine %3 2 1
261 %function1 = OpFunction %int None %42
262 OpNoLine
263 %bb_entry_0 = OpLabel
264 %51 = OpExtInst %void %1 DebugScope %21
265 %45 = OpExtInst %void %1 DebugFunctionDefinition %21 %function1
266 %52 = OpExtInst %void %1 DebugScope %23
267 OpLine %3 3 3
268 OpReturnValue %int_1
269 %53 = OpExtInst %void %1 DebugNoScope
270 OpFunctionEnd
271   )";
272 
273   std::unique_ptr<IRContext> context =
274       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
275                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
276 
277   const uint32_t line_number = 7U;
278   Instruction line(context.get(), spv::Op::OpLine);
279   line.SetInOperands({
280       {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {5U}},
281       {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {line_number}},
282       {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {0U}},
283   });
284 
285   DebugScope scope(29U, 0U);
286 
287   auto db_manager = context.get()->get_debug_info_mgr();
288   auto du_manager = context.get()->get_def_use_mgr();
289   auto c_manager = context.get()->get_constant_mgr();
290 
291   (void)du_manager;
292   (void)c_manager;
293 
294   uint32_t inlined_at_id = db_manager->CreateDebugInlinedAt(&line, scope);
295   auto* inlined_at = db_manager->GetDebugInlinedAt(inlined_at_id);
296   EXPECT_NE(inlined_at, nullptr);
297   EXPECT_EQ(inlined_at->GetSingleWordOperand(kDebugInlinedAtOperandLineIndex),
298             100);
299 }
300 
301 TEST(DebugInfoManager, GetDebugInfoNone) {
302   const std::string text = R"(
303                OpCapability Shader
304           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
305                OpMemoryModel Logical GLSL450
306                OpEntryPoint Fragment %main "main" %in_var_COLOR
307                OpExecutionMode %main OriginUpperLeft
308           %5 = OpString "ps.hlsl"
309          %14 = OpString "#line 1 \"ps.hlsl\"
310 void main(float in_var_color : COLOR) {
311   float color = in_var_color;
312 }
313 "
314          %17 = OpString "float"
315          %21 = OpString "main"
316          %24 = OpString "color"
317                OpName %in_var_COLOR "in.var.COLOR"
318                OpName %main "main"
319                OpDecorate %in_var_COLOR Location 0
320        %uint = OpTypeInt 32 0
321     %uint_32 = OpConstant %uint 32
322       %float = OpTypeFloat 32
323 %_ptr_Input_float = OpTypePointer Input %float
324        %void = OpTypeVoid
325          %27 = OpTypeFunction %void
326 %_ptr_Function_float = OpTypePointer Function %float
327 %in_var_COLOR = OpVariable %_ptr_Input_float Input
328          %13 = OpExtInst %void %1 DebugExpression
329          %15 = OpExtInst %void %1 DebugSource %5 %14
330          %16 = OpExtInst %void %1 DebugCompilationUnit 1 4 %15 HLSL
331          %18 = OpExtInst %void %1 DebugTypeBasic %17 %uint_32 Float
332          %20 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %18 %18
333          %22 = OpExtInst %void %1 DebugFunction %21 %20 %15 1 1 %16 %21 FlagIsProtected|FlagIsPrivate 1 %main
334          %12 = OpExtInst %void %1 DebugInfoNone
335          %25 = OpExtInst %void %1 DebugLocalVariable %24 %18 %15 1 20 %22 FlagIsLocal 0
336        %main = OpFunction %void None %27
337          %28 = OpLabel
338         %100 = OpVariable %_ptr_Function_float Function
339          %31 = OpLoad %float %in_var_COLOR
340                OpStore %100 %31
341          %36 = OpExtInst %void %1 DebugDeclare %25 %100 %13
342                OpReturn
343                OpFunctionEnd
344   )";
345 
346   std::unique_ptr<IRContext> context =
347       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
348                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
349   DebugInfoManager manager(context.get());
350 
351   Instruction* debug_info_none_inst = manager.GetDebugInfoNone();
352   EXPECT_NE(debug_info_none_inst, nullptr);
353   EXPECT_EQ(debug_info_none_inst->GetOpenCL100DebugOpcode(),
354             OpenCLDebugInfo100DebugInfoNone);
355   EXPECT_EQ(debug_info_none_inst->PreviousNode(), nullptr);
356 }
357 
358 TEST(DebugInfoManager, CreateDebugInfoNone) {
359   const std::string text = R"(
360                OpCapability Shader
361           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
362                OpMemoryModel Logical GLSL450
363                OpEntryPoint Fragment %main "main" %in_var_COLOR
364                OpExecutionMode %main OriginUpperLeft
365           %5 = OpString "ps.hlsl"
366          %14 = OpString "#line 1 \"ps.hlsl\"
367 void main(float in_var_color : COLOR) {
368   float color = in_var_color;
369 }
370 "
371          %17 = OpString "float"
372          %21 = OpString "main"
373          %24 = OpString "color"
374                OpName %in_var_COLOR "in.var.COLOR"
375                OpName %main "main"
376                OpDecorate %in_var_COLOR Location 0
377        %uint = OpTypeInt 32 0
378     %uint_32 = OpConstant %uint 32
379       %float = OpTypeFloat 32
380 %_ptr_Input_float = OpTypePointer Input %float
381        %void = OpTypeVoid
382          %27 = OpTypeFunction %void
383 %_ptr_Function_float = OpTypePointer Function %float
384 %in_var_COLOR = OpVariable %_ptr_Input_float Input
385          %13 = OpExtInst %void %1 DebugExpression
386          %15 = OpExtInst %void %1 DebugSource %5 %14
387          %16 = OpExtInst %void %1 DebugCompilationUnit 1 4 %15 HLSL
388          %18 = OpExtInst %void %1 DebugTypeBasic %17 %uint_32 Float
389          %20 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %18 %18
390          %22 = OpExtInst %void %1 DebugFunction %21 %20 %15 1 1 %16 %21 FlagIsProtected|FlagIsPrivate 1 %main
391          %25 = OpExtInst %void %1 DebugLocalVariable %24 %18 %15 1 20 %22 FlagIsLocal 0
392        %main = OpFunction %void None %27
393          %28 = OpLabel
394         %100 = OpVariable %_ptr_Function_float Function
395          %31 = OpLoad %float %in_var_COLOR
396                OpStore %100 %31
397          %36 = OpExtInst %void %1 DebugDeclare %25 %100 %13
398                OpReturn
399                OpFunctionEnd
400   )";
401 
402   std::unique_ptr<IRContext> context =
403       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
404                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
405   DebugInfoManager manager(context.get());
406 
407   Instruction* debug_info_none_inst = manager.GetDebugInfoNone();
408   EXPECT_NE(debug_info_none_inst, nullptr);
409   EXPECT_EQ(debug_info_none_inst->GetOpenCL100DebugOpcode(),
410             OpenCLDebugInfo100DebugInfoNone);
411   EXPECT_EQ(debug_info_none_inst->PreviousNode(), nullptr);
412 }
413 
414 TEST(DebugInfoManager, GetDebugFunction) {
415   const std::string text = R"(
416                OpCapability Shader
417           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
418                OpMemoryModel Logical GLSL450
419                OpEntryPoint Fragment %200 "200" %in_var_COLOR
420                OpExecutionMode %200 OriginUpperLeft
421           %5 = OpString "ps.hlsl"
422          %14 = OpString "#line 1 \"ps.hlsl\"
423 void 200(float in_var_color : COLOR) {
424   float color = in_var_color;
425 }
426 "
427          %17 = OpString "float"
428          %21 = OpString "200"
429          %24 = OpString "color"
430                OpName %in_var_COLOR "in.var.COLOR"
431                OpName %200 "200"
432                OpDecorate %in_var_COLOR Location 0
433        %uint = OpTypeInt 32 0
434     %uint_32 = OpConstant %uint 32
435       %float = OpTypeFloat 32
436 %_ptr_Input_float = OpTypePointer Input %float
437        %void = OpTypeVoid
438          %27 = OpTypeFunction %void
439 %_ptr_Function_float = OpTypePointer Function %float
440 %in_var_COLOR = OpVariable %_ptr_Input_float Input
441          %13 = OpExtInst %void %1 DebugExpression
442          %15 = OpExtInst %void %1 DebugSource %5 %14
443          %16 = OpExtInst %void %1 DebugCompilationUnit 1 4 %15 HLSL
444          %18 = OpExtInst %void %1 DebugTypeBasic %17 %uint_32 Float
445          %20 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %18 %18
446          %22 = OpExtInst %void %1 DebugFunction %21 %20 %15 1 1 %16 %21 FlagIsProtected|FlagIsPrivate 1 %200
447          %25 = OpExtInst %void %1 DebugLocalVariable %24 %18 %15 1 20 %22 FlagIsLocal 0
448        %200 = OpFunction %void None %27
449          %28 = OpLabel
450         %100 = OpVariable %_ptr_Function_float Function
451          %31 = OpLoad %float %in_var_COLOR
452                OpStore %100 %31
453          %36 = OpExtInst %void %1 DebugDeclare %25 %100 %13
454                OpReturn
455                OpFunctionEnd
456   )";
457 
458   std::unique_ptr<IRContext> context =
459       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
460                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
461   DebugInfoManager manager(context.get());
462 
463   EXPECT_EQ(manager.GetDebugFunction(100), nullptr);
464   EXPECT_EQ(manager.GetDebugFunction(150), nullptr);
465 
466   Instruction* dbg_fn = manager.GetDebugFunction(200);
467 
468   EXPECT_EQ(dbg_fn->GetOpenCL100DebugOpcode(), OpenCLDebugInfo100DebugFunction);
469   EXPECT_EQ(dbg_fn->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex),
470             200);
471 }
472 
473 TEST(DebugInfoManager, GetDebugFunction_InlinedAway) {
474   // struct PS_INPUT
475   // {
476   //   float4 iColor : COLOR;
477   // };
478   //
479   // struct PS_OUTPUT
480   // {
481   //   float4 oColor : SV_Target0;
482   // };
483   //
484   // float4 foo(float4 ic)
485   // {
486   //   float4 c = ic / 2.0;
487   //   return c;
488   // }
489   //
490   // PS_OUTPUT MainPs(PS_INPUT i)
491   // {
492   //   PS_OUTPUT ps_output;
493   //   float4 ic = i.iColor;
494   //   ps_output.oColor = foo(ic);
495   //   return ps_output;
496   // }
497   const std::string text = R"(
498                OpCapability Shader
499           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
500                OpMemoryModel Logical GLSL450
501                OpEntryPoint Fragment %MainPs "MainPs" %in_var_COLOR %out_var_SV_Target0
502                OpExecutionMode %MainPs OriginUpperLeft
503          %15 = OpString "foo2.frag"
504          %19 = OpString "PS_OUTPUT"
505          %23 = OpString "float"
506          %26 = OpString "oColor"
507          %28 = OpString "PS_INPUT"
508          %31 = OpString "iColor"
509          %33 = OpString "foo"
510          %37 = OpString "c"
511          %39 = OpString "ic"
512          %42 = OpString "src.MainPs"
513          %47 = OpString "ps_output"
514          %50 = OpString "i"
515                OpName %in_var_COLOR "in.var.COLOR"
516                OpName %out_var_SV_Target0 "out.var.SV_Target0"
517                OpName %MainPs "MainPs"
518                OpDecorate %in_var_COLOR Location 0
519                OpDecorate %out_var_SV_Target0 Location 0
520         %int = OpTypeInt 32 1
521       %int_0 = OpConstant %int 0
522       %float = OpTypeFloat 32
523     %v4float = OpTypeVector %float 4
524        %uint = OpTypeInt 32 0
525     %uint_32 = OpConstant %uint 32
526 %_ptr_Input_v4float = OpTypePointer Input %v4float
527 %_ptr_Output_v4float = OpTypePointer Output %v4float
528        %void = OpTypeVoid
529    %uint_128 = OpConstant %uint 128
530      %uint_0 = OpConstant %uint 0
531          %52 = OpTypeFunction %void
532 %in_var_COLOR = OpVariable %_ptr_Input_v4float Input
533 %out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output
534   %float_0_5 = OpConstant %float 0.5
535         %130 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5
536         %115 = OpExtInst %void %1 DebugInfoNone
537          %49 = OpExtInst %void %1 DebugExpression
538          %17 = OpExtInst %void %1 DebugSource %15
539          %18 = OpExtInst %void %1 DebugCompilationUnit 1 4 %17 HLSL
540          %21 = OpExtInst %void %1 DebugTypeComposite %19 Structure %17 6 1 %18 %19 %uint_128 FlagIsProtected|FlagIsPrivate %22
541          %24 = OpExtInst %void %1 DebugTypeBasic %23 %uint_32 Float
542          %25 = OpExtInst %void %1 DebugTypeVector %24 4
543          %22 = OpExtInst %void %1 DebugTypeMember %26 %25 %17 8 5 %21 %uint_0 %uint_128 FlagIsProtected|FlagIsPrivate
544          %29 = OpExtInst %void %1 DebugTypeComposite %28 Structure %17 1 1 %18 %28 %uint_128 FlagIsProtected|FlagIsPrivate %30
545          %30 = OpExtInst %void %1 DebugTypeMember %31 %25 %17 3 5 %29 %uint_0 %uint_128 FlagIsProtected|FlagIsPrivate
546          %32 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %25 %25
547          %34 = OpExtInst %void %1 DebugFunction %33 %32 %17 11 1 %18 %33 FlagIsProtected|FlagIsPrivate 12 %115
548          %36 = OpExtInst %void %1 DebugLexicalBlock %17 12 1 %34
549          %38 = OpExtInst %void %1 DebugLocalVariable %37 %25 %17 13 12 %36 FlagIsLocal
550          %41 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %21 %29
551          %43 = OpExtInst %void %1 DebugFunction %42 %41 %17 17 1 %18 %42 FlagIsProtected|FlagIsPrivate 18 %115
552          %45 = OpExtInst %void %1 DebugLexicalBlock %17 18 1 %43
553          %46 = OpExtInst %void %1 DebugLocalVariable %39 %25 %17 20 12 %45 FlagIsLocal
554          %48 = OpExtInst %void %1 DebugLocalVariable %47 %21 %17 19 15 %45 FlagIsLocal
555         %107 = OpExtInst %void %1 DebugInlinedAt 21 %45
556      %MainPs = OpFunction %void None %52
557          %53 = OpLabel
558          %57 = OpLoad %v4float %in_var_COLOR
559         %131 = OpExtInst %void %1 DebugScope %45
560                OpLine %15 20 12
561         %117 = OpExtInst %void %1 DebugValue %46 %57 %49
562         %132 = OpExtInst %void %1 DebugScope %36 %107
563                OpLine %15 13 19
564         %112 = OpFMul %v4float %57 %130
565                OpLine %15 13 12
566         %116 = OpExtInst %void %1 DebugValue %38 %112 %49
567         %133 = OpExtInst %void %1 DebugScope %45
568         %128 = OpExtInst %void %1 DebugValue %48 %112 %49 %int_0
569         %134 = OpExtInst %void %1 DebugNoScope
570                OpStore %out_var_SV_Target0 %112
571                OpReturn
572                OpFunctionEnd
573   )";
574 
575   std::unique_ptr<IRContext> context =
576       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
577                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
578   DebugInfoManager manager(context.get());
579 
580   EXPECT_EQ(manager.GetDebugFunction(115), nullptr);
581 }
582 
583 TEST(DebugInfoManager, CloneDebugInlinedAt) {
584   const std::string text = R"(
585                OpCapability Shader
586           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
587                OpMemoryModel Logical GLSL450
588                OpEntryPoint Fragment %main "main" %in_var_COLOR
589                OpExecutionMode %main OriginUpperLeft
590           %5 = OpString "ps.hlsl"
591          %14 = OpString "#line 1 \"ps.hlsl\"
592 void main(float in_var_color : COLOR) {
593   float color = in_var_color;
594 }
595 "
596          %17 = OpString "float"
597          %21 = OpString "main"
598          %24 = OpString "color"
599                OpName %in_var_COLOR "in.var.COLOR"
600                OpName %main "main"
601                OpDecorate %in_var_COLOR Location 0
602        %uint = OpTypeInt 32 0
603     %uint_32 = OpConstant %uint 32
604       %float = OpTypeFloat 32
605 %_ptr_Input_float = OpTypePointer Input %float
606        %void = OpTypeVoid
607          %27 = OpTypeFunction %void
608 %_ptr_Function_float = OpTypePointer Function %float
609 %in_var_COLOR = OpVariable %_ptr_Input_float Input
610          %13 = OpExtInst %void %1 DebugExpression
611          %15 = OpExtInst %void %1 DebugSource %5 %14
612          %16 = OpExtInst %void %1 DebugCompilationUnit 1 4 %15 HLSL
613          %18 = OpExtInst %void %1 DebugTypeBasic %17 %uint_32 Float
614          %20 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %18 %18
615          %22 = OpExtInst %void %1 DebugFunction %21 %20 %15 1 1 %16 %21 FlagIsProtected|FlagIsPrivate 1 %main
616         %100 = OpExtInst %void %1 DebugInlinedAt 7 %22
617        %main = OpFunction %void None %27
618          %28 = OpLabel
619          %31 = OpLoad %float %in_var_COLOR
620                OpStore %100 %31
621                OpReturn
622                OpFunctionEnd
623   )";
624 
625   std::unique_ptr<IRContext> context =
626       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
627                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
628   DebugInfoManager manager(context.get());
629 
630   EXPECT_EQ(manager.CloneDebugInlinedAt(150), nullptr);
631   EXPECT_EQ(manager.CloneDebugInlinedAt(22), nullptr);
632 
633   auto* inst = manager.CloneDebugInlinedAt(100);
634   EXPECT_EQ(inst->GetSingleWordOperand(kDebugInlinedAtOperandLineIndex), 7);
635   EXPECT_EQ(inst->GetSingleWordOperand(kDebugInlinedAtOperandScopeIndex), 22);
636   EXPECT_EQ(inst->NumOperands(), kDebugInlinedAtOperandScopeIndex + 1);
637 
638   Instruction* before_100 = nullptr;
639   for (auto it = context->module()->ext_inst_debuginfo_begin();
640        it != context->module()->ext_inst_debuginfo_end(); ++it) {
641     if (it->result_id() == 100) break;
642     before_100 = &*it;
643   }
644   EXPECT_NE(inst, before_100);
645 
646   inst = manager.CloneDebugInlinedAt(100, manager.GetDebugInlinedAt(100));
647   EXPECT_EQ(inst->GetSingleWordOperand(kDebugInlinedAtOperandLineIndex), 7);
648   EXPECT_EQ(inst->GetSingleWordOperand(kDebugInlinedAtOperandScopeIndex), 22);
649   EXPECT_EQ(inst->NumOperands(), kDebugInlinedAtOperandScopeIndex + 1);
650 
651   before_100 = nullptr;
652   for (auto it = context->module()->ext_inst_debuginfo_begin();
653        it != context->module()->ext_inst_debuginfo_end(); ++it) {
654     if (it->result_id() == 100) break;
655     before_100 = &*it;
656   }
657   EXPECT_EQ(inst, before_100);
658 }
659 
660 TEST(DebugInfoManager, KillDebugDeclares) {
661   const std::string text = R"(
662                OpCapability Shader
663           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
664                OpMemoryModel Logical GLSL450
665                OpEntryPoint Fragment %main "main" %in_var_COLOR
666                OpExecutionMode %main OriginUpperLeft
667           %5 = OpString "ps.hlsl"
668          %14 = OpString "#line 1 \"ps.hlsl\"
669 void main(float in_var_color : COLOR) {
670   float color = in_var_color;
671 }
672 "
673          %17 = OpString "float"
674          %21 = OpString "main"
675          %24 = OpString "color"
676                OpName %in_var_COLOR "in.var.COLOR"
677                OpName %main "main"
678                OpDecorate %in_var_COLOR Location 0
679        %uint = OpTypeInt 32 0
680     %uint_32 = OpConstant %uint 32
681       %float = OpTypeFloat 32
682 %_ptr_Input_float = OpTypePointer Input %float
683        %void = OpTypeVoid
684          %27 = OpTypeFunction %void
685 %_ptr_Function_float = OpTypePointer Function %float
686 %in_var_COLOR = OpVariable %_ptr_Input_float Input
687          %13 = OpExtInst %void %1 DebugExpression
688          %15 = OpExtInst %void %1 DebugSource %5 %14
689          %16 = OpExtInst %void %1 DebugCompilationUnit 1 4 %15 HLSL
690          %18 = OpExtInst %void %1 DebugTypeBasic %17 %uint_32 Float
691          %20 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %18 %18
692          %22 = OpExtInst %void %1 DebugFunction %21 %20 %15 1 1 %16 %21 FlagIsProtected|FlagIsPrivate 1 %main
693          %12 = OpExtInst %void %1 DebugInfoNone
694          %25 = OpExtInst %void %1 DebugLocalVariable %24 %18 %15 1 20 %22 FlagIsLocal 0
695        %main = OpFunction %void None %27
696          %28 = OpLabel
697         %100 = OpVariable %_ptr_Function_float Function
698          %31 = OpLoad %float %in_var_COLOR
699                OpStore %100 %31
700          %36 = OpExtInst %void %1 DebugDeclare %25 %100 %13
701          %37 = OpExtInst %void %1 DebugDeclare %25 %100 %13
702          %38 = OpExtInst %void %1 DebugDeclare %25 %100 %13
703                OpReturn
704                OpFunctionEnd
705   )";
706 
707   std::unique_ptr<IRContext> context =
708       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
709                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
710   auto* dbg_info_mgr = context->get_debug_info_mgr();
711   auto* def_use_mgr = context->get_def_use_mgr();
712 
713   EXPECT_TRUE(dbg_info_mgr->IsVariableDebugDeclared(100));
714   EXPECT_EQ(def_use_mgr->GetDef(36)->GetOpenCL100DebugOpcode(),
715             OpenCLDebugInfo100DebugDeclare);
716   EXPECT_EQ(def_use_mgr->GetDef(37)->GetOpenCL100DebugOpcode(),
717             OpenCLDebugInfo100DebugDeclare);
718   EXPECT_EQ(def_use_mgr->GetDef(38)->GetOpenCL100DebugOpcode(),
719             OpenCLDebugInfo100DebugDeclare);
720 
721   dbg_info_mgr->KillDebugDeclares(100);
722   EXPECT_EQ(def_use_mgr->GetDef(36), nullptr);
723   EXPECT_EQ(def_use_mgr->GetDef(37), nullptr);
724   EXPECT_EQ(def_use_mgr->GetDef(38), nullptr);
725   EXPECT_FALSE(dbg_info_mgr->IsVariableDebugDeclared(100));
726 }
727 
728 TEST(DebugInfoManager, AddDebugValueForDecl) {
729   const std::string text = R"(
730                OpCapability Shader
731           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
732                OpMemoryModel Logical GLSL450
733                OpEntryPoint Fragment %main "main" %in_var_COLOR
734                OpExecutionMode %main OriginUpperLeft
735           %5 = OpString "ps.hlsl"
736          %14 = OpString "#line 1 \"ps.hlsl\"
737 void main(float in_var_color : COLOR) {
738   float color = in_var_color;
739 }
740 "
741          %17 = OpString "float"
742          %21 = OpString "main"
743          %24 = OpString "color"
744                OpName %in_var_COLOR "in.var.COLOR"
745                OpName %main "main"
746                OpDecorate %in_var_COLOR Location 0
747        %uint = OpTypeInt 32 0
748     %uint_32 = OpConstant %uint 32
749       %float = OpTypeFloat 32
750 %_ptr_Input_float = OpTypePointer Input %float
751        %void = OpTypeVoid
752          %27 = OpTypeFunction %void
753 %_ptr_Function_float = OpTypePointer Function %float
754 %in_var_COLOR = OpVariable %_ptr_Input_float Input
755          %13 = OpExtInst %void %1 DebugExpression
756          %15 = OpExtInst %void %1 DebugSource %5 %14
757          %16 = OpExtInst %void %1 DebugCompilationUnit 1 4 %15 HLSL
758          %18 = OpExtInst %void %1 DebugTypeBasic %17 %uint_32 Float
759          %20 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %18 %18
760          %22 = OpExtInst %void %1 DebugFunction %21 %20 %15 1 1 %16 %21 FlagIsProtected|FlagIsPrivate 1 %main
761          %12 = OpExtInst %void %1 DebugInfoNone
762          %25 = OpExtInst %void %1 DebugLocalVariable %24 %18 %15 1 20 %22 FlagIsLocal 0
763        %main = OpFunction %void None %27
764          %28 = OpLabel
765         %100 = OpVariable %_ptr_Function_float Function
766          %31 = OpLoad %float %in_var_COLOR
767         %101 = OpExtInst %void %1 DebugScope %22
768                OpLine %5 13 7
769                OpStore %100 %31
770                OpNoLine
771         %102 = OpExtInst %void %1 DebugNoScope
772          %36 = OpExtInst %void %1 DebugDeclare %25 %100 %13
773                OpReturn
774                OpFunctionEnd
775   )";
776 
777   std::unique_ptr<IRContext> context =
778       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
779                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
780   auto* def_use_mgr = context->get_def_use_mgr();
781   auto* dbg_decl = def_use_mgr->GetDef(36);
782   EXPECT_EQ(dbg_decl->GetOpenCL100DebugOpcode(),
783             OpenCLDebugInfo100DebugDeclare);
784 
785   auto* dbg_info_mgr = context->get_debug_info_mgr();
786   Instruction* store = dbg_decl->PreviousNode();
787   auto* dbg_value =
788       dbg_info_mgr->AddDebugValueForDecl(dbg_decl, 100, dbg_decl, store);
789 
790   EXPECT_EQ(dbg_value->GetOpenCL100DebugOpcode(), OpenCLDebugInfo100DebugValue);
791   EXPECT_EQ(dbg_value->dbg_line_inst()->GetSingleWordInOperand(
792                 kOpLineInOperandFileIndex),
793             5);
794   EXPECT_EQ(dbg_value->dbg_line_inst()->GetSingleWordInOperand(
795                 kOpLineInOperandLineIndex),
796             13);
797   EXPECT_EQ(dbg_value->dbg_line_inst()->GetSingleWordInOperand(
798                 kOpLineInOperandColumnIndex),
799             7);
800 }
801 
802 }  // namespace
803 }  // namespace analysis
804 }  // namespace opt
805 }  // namespace spvtools
806