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