mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-28 14:11:04 +00:00
50b1557886
Handles the OpenCL100Debug extension in inlining. It preserves the information that is available while also adding the debug inlined at for all of the inlining that it does.
3779 lines
131 KiB
C++
3779 lines
131 KiB
C++
// Copyright (c) 2017 Valve Corporation
|
|
// Copyright (c) 2017 LunarG Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "test/opt/pass_fixture.h"
|
|
#include "test/opt/pass_utils.h"
|
|
|
|
namespace spvtools {
|
|
namespace opt {
|
|
namespace {
|
|
|
|
using InlineTest = PassTest<::testing::Test>;
|
|
|
|
TEST_F(InlineTest, Simple) {
|
|
// #version 140
|
|
//
|
|
// in vec4 BaseColor;
|
|
//
|
|
// float foo(vec4 bar)
|
|
// {
|
|
// return bar.x + bar.y;
|
|
// }
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 color = vec4(foo(BaseColor));
|
|
// gl_FragColor = color;
|
|
// }
|
|
const std::vector<const char*> predefs = {
|
|
// clang-format off
|
|
"OpCapability Shader",
|
|
"%1 = OpExtInstImport \"GLSL.std.450\"",
|
|
"OpMemoryModel Logical GLSL450",
|
|
"OpEntryPoint Fragment %main \"main\" %BaseColor %gl_FragColor",
|
|
"OpExecutionMode %main OriginUpperLeft",
|
|
"OpSource GLSL 140",
|
|
"OpName %main \"main\"",
|
|
"OpName %foo_vf4_ \"foo(vf4;\"",
|
|
"OpName %bar \"bar\"",
|
|
"OpName %color \"color\"",
|
|
"OpName %BaseColor \"BaseColor\"",
|
|
"OpName %param \"param\"",
|
|
"OpName %gl_FragColor \"gl_FragColor\"",
|
|
"%void = OpTypeVoid",
|
|
"%10 = OpTypeFunction %void",
|
|
"%float = OpTypeFloat 32",
|
|
"%v4float = OpTypeVector %float 4",
|
|
"%_ptr_Function_v4float = OpTypePointer Function %v4float",
|
|
"%14 = OpTypeFunction %float %_ptr_Function_v4float",
|
|
"%uint = OpTypeInt 32 0",
|
|
"%uint_0 = OpConstant %uint 0",
|
|
"%_ptr_Function_float = OpTypePointer Function %float",
|
|
"%uint_1 = OpConstant %uint 1",
|
|
"%_ptr_Input_v4float = OpTypePointer Input %v4float",
|
|
"%BaseColor = OpVariable %_ptr_Input_v4float Input",
|
|
"%_ptr_Output_v4float = OpTypePointer Output %v4float",
|
|
"%gl_FragColor = OpVariable %_ptr_Output_v4float Output",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> nonEntryFuncs = {
|
|
// clang-format off
|
|
"%foo_vf4_ = OpFunction %float None %14",
|
|
"%bar = OpFunctionParameter %_ptr_Function_v4float",
|
|
"%26 = OpLabel",
|
|
"%27 = OpAccessChain %_ptr_Function_float %bar %uint_0",
|
|
"%28 = OpLoad %float %27",
|
|
"%29 = OpAccessChain %_ptr_Function_float %bar %uint_1",
|
|
"%30 = OpLoad %float %29",
|
|
"%31 = OpFAdd %float %28 %30",
|
|
"OpReturnValue %31",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> before = {
|
|
// clang-format off
|
|
"%main = OpFunction %void None %10",
|
|
"%21 = OpLabel",
|
|
"%color = OpVariable %_ptr_Function_v4float Function",
|
|
"%param = OpVariable %_ptr_Function_v4float Function",
|
|
"%22 = OpLoad %v4float %BaseColor",
|
|
"OpStore %param %22",
|
|
"%23 = OpFunctionCall %float %foo_vf4_ %param",
|
|
"%24 = OpCompositeConstruct %v4float %23 %23 %23 %23",
|
|
"OpStore %color %24",
|
|
"%25 = OpLoad %v4float %color",
|
|
"OpStore %gl_FragColor %25",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> after = {
|
|
// clang-format off
|
|
"%main = OpFunction %void None %10",
|
|
"%21 = OpLabel",
|
|
"%32 = OpVariable %_ptr_Function_float Function",
|
|
"%color = OpVariable %_ptr_Function_v4float Function",
|
|
"%param = OpVariable %_ptr_Function_v4float Function",
|
|
"%22 = OpLoad %v4float %BaseColor",
|
|
"OpStore %param %22",
|
|
"%34 = OpAccessChain %_ptr_Function_float %param %uint_0",
|
|
"%35 = OpLoad %float %34",
|
|
"%36 = OpAccessChain %_ptr_Function_float %param %uint_1",
|
|
"%37 = OpLoad %float %36",
|
|
"%38 = OpFAdd %float %35 %37",
|
|
"OpStore %32 %38",
|
|
"%23 = OpLoad %float %32",
|
|
"%24 = OpCompositeConstruct %v4float %23 %23 %23 %23",
|
|
"OpStore %color %24",
|
|
"%25 = OpLoad %v4float %color",
|
|
"OpStore %gl_FragColor %25",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(
|
|
JoinAllInsts(Concat(Concat(predefs, before), nonEntryFuncs)),
|
|
JoinAllInsts(Concat(Concat(predefs, after), nonEntryFuncs)),
|
|
/* skip_nop = */ false, /* do_validate = */ true);
|
|
}
|
|
|
|
TEST_F(InlineTest, Nested) {
|
|
// #version 140
|
|
//
|
|
// in vec4 BaseColor;
|
|
//
|
|
// float foo2(float f, float f2)
|
|
// {
|
|
// return f * f2;
|
|
// }
|
|
//
|
|
// float foo(vec4 bar)
|
|
// {
|
|
// return foo2(bar.x + bar.y, bar.z);
|
|
// }
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 color = vec4(foo(BaseColor));
|
|
// gl_FragColor = color;
|
|
// }
|
|
const std::vector<const char*> predefs = {
|
|
// clang-format off
|
|
"OpCapability Shader",
|
|
"%1 = OpExtInstImport \"GLSL.std.450\"",
|
|
"OpMemoryModel Logical GLSL450",
|
|
"OpEntryPoint Fragment %main \"main\" %BaseColor %gl_FragColor",
|
|
"OpExecutionMode %main OriginUpperLeft",
|
|
"OpSource GLSL 140",
|
|
"OpName %main \"main\"",
|
|
"OpName %foo2_f1_f1_ \"foo2(f1;f1;\"",
|
|
"OpName %f \"f\"",
|
|
"OpName %f2 \"f2\"",
|
|
"OpName %foo_vf4_ \"foo(vf4;\"",
|
|
"OpName %bar \"bar\"",
|
|
"OpName %param \"param\"",
|
|
"OpName %param_0 \"param\"",
|
|
"OpName %color \"color\"",
|
|
"OpName %BaseColor \"BaseColor\"",
|
|
"OpName %param_1 \"param\"",
|
|
"OpName %gl_FragColor \"gl_FragColor\"",
|
|
"%void = OpTypeVoid",
|
|
"%15 = OpTypeFunction %void",
|
|
"%float = OpTypeFloat 32",
|
|
"%_ptr_Function_float = OpTypePointer Function %float",
|
|
"%18 = OpTypeFunction %float %_ptr_Function_float %_ptr_Function_float",
|
|
"%v4float = OpTypeVector %float 4",
|
|
"%_ptr_Function_v4float = OpTypePointer Function %v4float",
|
|
"%21 = OpTypeFunction %float %_ptr_Function_v4float",
|
|
"%uint = OpTypeInt 32 0",
|
|
"%uint_0 = OpConstant %uint 0",
|
|
"%uint_1 = OpConstant %uint 1",
|
|
"%uint_2 = OpConstant %uint 2",
|
|
"%_ptr_Input_v4float = OpTypePointer Input %v4float",
|
|
"%BaseColor = OpVariable %_ptr_Input_v4float Input",
|
|
"%_ptr_Output_v4float = OpTypePointer Output %v4float",
|
|
"%gl_FragColor = OpVariable %_ptr_Output_v4float Output",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> nonEntryFuncs = {
|
|
// clang-format off
|
|
"%foo2_f1_f1_ = OpFunction %float None %18",
|
|
"%f = OpFunctionParameter %_ptr_Function_float",
|
|
"%f2 = OpFunctionParameter %_ptr_Function_float",
|
|
"%33 = OpLabel",
|
|
"%34 = OpLoad %float %f",
|
|
"%35 = OpLoad %float %f2",
|
|
"%36 = OpFMul %float %34 %35",
|
|
"OpReturnValue %36",
|
|
"OpFunctionEnd",
|
|
"%foo_vf4_ = OpFunction %float None %21",
|
|
"%bar = OpFunctionParameter %_ptr_Function_v4float",
|
|
"%37 = OpLabel",
|
|
"%param = OpVariable %_ptr_Function_float Function",
|
|
"%param_0 = OpVariable %_ptr_Function_float Function",
|
|
"%38 = OpAccessChain %_ptr_Function_float %bar %uint_0",
|
|
"%39 = OpLoad %float %38",
|
|
"%40 = OpAccessChain %_ptr_Function_float %bar %uint_1",
|
|
"%41 = OpLoad %float %40",
|
|
"%42 = OpFAdd %float %39 %41",
|
|
"OpStore %param %42",
|
|
"%43 = OpAccessChain %_ptr_Function_float %bar %uint_2",
|
|
"%44 = OpLoad %float %43",
|
|
"OpStore %param_0 %44",
|
|
"%45 = OpFunctionCall %float %foo2_f1_f1_ %param %param_0",
|
|
"OpReturnValue %45",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> before = {
|
|
// clang-format off
|
|
"%main = OpFunction %void None %15",
|
|
"%28 = OpLabel",
|
|
"%color = OpVariable %_ptr_Function_v4float Function",
|
|
"%param_1 = OpVariable %_ptr_Function_v4float Function",
|
|
"%29 = OpLoad %v4float %BaseColor",
|
|
"OpStore %param_1 %29",
|
|
"%30 = OpFunctionCall %float %foo_vf4_ %param_1",
|
|
"%31 = OpCompositeConstruct %v4float %30 %30 %30 %30",
|
|
"OpStore %color %31",
|
|
"%32 = OpLoad %v4float %color",
|
|
"OpStore %gl_FragColor %32",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> after = {
|
|
// clang-format off
|
|
"%main = OpFunction %void None %15",
|
|
"%28 = OpLabel",
|
|
"%58 = OpVariable %_ptr_Function_float Function",
|
|
"%46 = OpVariable %_ptr_Function_float Function",
|
|
"%47 = OpVariable %_ptr_Function_float Function",
|
|
"%48 = OpVariable %_ptr_Function_float Function",
|
|
"%color = OpVariable %_ptr_Function_v4float Function",
|
|
"%param_1 = OpVariable %_ptr_Function_v4float Function",
|
|
"%29 = OpLoad %v4float %BaseColor",
|
|
"OpStore %param_1 %29",
|
|
"%50 = OpAccessChain %_ptr_Function_float %param_1 %uint_0",
|
|
"%51 = OpLoad %float %50",
|
|
"%52 = OpAccessChain %_ptr_Function_float %param_1 %uint_1",
|
|
"%53 = OpLoad %float %52",
|
|
"%54 = OpFAdd %float %51 %53",
|
|
"OpStore %46 %54",
|
|
"%55 = OpAccessChain %_ptr_Function_float %param_1 %uint_2",
|
|
"%56 = OpLoad %float %55",
|
|
"OpStore %47 %56",
|
|
"%60 = OpLoad %float %46",
|
|
"%61 = OpLoad %float %47",
|
|
"%62 = OpFMul %float %60 %61",
|
|
"OpStore %58 %62",
|
|
"%57 = OpLoad %float %58",
|
|
"OpStore %48 %57",
|
|
"%30 = OpLoad %float %48",
|
|
"%31 = OpCompositeConstruct %v4float %30 %30 %30 %30",
|
|
"OpStore %color %31",
|
|
"%32 = OpLoad %v4float %color",
|
|
"OpStore %gl_FragColor %32",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(
|
|
JoinAllInsts(Concat(Concat(predefs, before), nonEntryFuncs)),
|
|
JoinAllInsts(Concat(Concat(predefs, after), nonEntryFuncs)),
|
|
/* skip_nop = */ false, /* do_validate = */ true);
|
|
}
|
|
|
|
TEST_F(InlineTest, InOutParameter) {
|
|
// #version 400
|
|
//
|
|
// in vec4 Basecolor;
|
|
//
|
|
// void foo(inout vec4 bar)
|
|
// {
|
|
// bar.z = bar.x + bar.y;
|
|
// }
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 b = Basecolor;
|
|
// foo(b);
|
|
// vec4 color = vec4(b.z);
|
|
// gl_FragColor = color;
|
|
// }
|
|
const std::vector<const char*> predefs = {
|
|
// clang-format off
|
|
"OpCapability Shader",
|
|
"%1 = OpExtInstImport \"GLSL.std.450\"",
|
|
"OpMemoryModel Logical GLSL450",
|
|
"OpEntryPoint Fragment %main \"main\" %Basecolor %gl_FragColor",
|
|
"OpExecutionMode %main OriginUpperLeft",
|
|
"OpSource GLSL 400",
|
|
"OpName %main \"main\"",
|
|
"OpName %foo_vf4_ \"foo(vf4;\"",
|
|
"OpName %bar \"bar\"",
|
|
"OpName %b \"b\"",
|
|
"OpName %Basecolor \"Basecolor\"",
|
|
"OpName %param \"param\"",
|
|
"OpName %color \"color\"",
|
|
"OpName %gl_FragColor \"gl_FragColor\"",
|
|
"%void = OpTypeVoid",
|
|
"%11 = OpTypeFunction %void",
|
|
"%float = OpTypeFloat 32",
|
|
"%v4float = OpTypeVector %float 4",
|
|
"%_ptr_Function_v4float = OpTypePointer Function %v4float",
|
|
"%15 = OpTypeFunction %void %_ptr_Function_v4float",
|
|
"%uint = OpTypeInt 32 0",
|
|
"%uint_0 = OpConstant %uint 0",
|
|
"%_ptr_Function_float = OpTypePointer Function %float",
|
|
"%uint_1 = OpConstant %uint 1",
|
|
"%uint_2 = OpConstant %uint 2",
|
|
"%_ptr_Input_v4float = OpTypePointer Input %v4float",
|
|
"%Basecolor = OpVariable %_ptr_Input_v4float Input",
|
|
"%_ptr_Output_v4float = OpTypePointer Output %v4float",
|
|
"%gl_FragColor = OpVariable %_ptr_Output_v4float Output",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> nonEntryFuncs = {
|
|
// clang-format off
|
|
"%foo_vf4_ = OpFunction %void None %15",
|
|
"%bar = OpFunctionParameter %_ptr_Function_v4float",
|
|
"%32 = OpLabel",
|
|
"%33 = OpAccessChain %_ptr_Function_float %bar %uint_0",
|
|
"%34 = OpLoad %float %33",
|
|
"%35 = OpAccessChain %_ptr_Function_float %bar %uint_1",
|
|
"%36 = OpLoad %float %35",
|
|
"%37 = OpFAdd %float %34 %36",
|
|
"%38 = OpAccessChain %_ptr_Function_float %bar %uint_2",
|
|
"OpStore %38 %37",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> before = {
|
|
// clang-format off
|
|
"%main = OpFunction %void None %11",
|
|
"%23 = OpLabel",
|
|
"%b = OpVariable %_ptr_Function_v4float Function",
|
|
"%param = OpVariable %_ptr_Function_v4float Function",
|
|
"%color = OpVariable %_ptr_Function_v4float Function",
|
|
"%24 = OpLoad %v4float %Basecolor",
|
|
"OpStore %b %24",
|
|
"%25 = OpLoad %v4float %b",
|
|
"OpStore %param %25",
|
|
"%26 = OpFunctionCall %void %foo_vf4_ %param",
|
|
"%27 = OpLoad %v4float %param",
|
|
"OpStore %b %27",
|
|
"%28 = OpAccessChain %_ptr_Function_float %b %uint_2",
|
|
"%29 = OpLoad %float %28",
|
|
"%30 = OpCompositeConstruct %v4float %29 %29 %29 %29",
|
|
"OpStore %color %30",
|
|
"%31 = OpLoad %v4float %color",
|
|
"OpStore %gl_FragColor %31",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> after = {
|
|
// clang-format off
|
|
"%main = OpFunction %void None %11",
|
|
"%23 = OpLabel",
|
|
"%b = OpVariable %_ptr_Function_v4float Function",
|
|
"%param = OpVariable %_ptr_Function_v4float Function",
|
|
"%color = OpVariable %_ptr_Function_v4float Function",
|
|
"%24 = OpLoad %v4float %Basecolor",
|
|
"OpStore %b %24",
|
|
"%25 = OpLoad %v4float %b",
|
|
"OpStore %param %25",
|
|
"%40 = OpAccessChain %_ptr_Function_float %param %uint_0",
|
|
"%41 = OpLoad %float %40",
|
|
"%42 = OpAccessChain %_ptr_Function_float %param %uint_1",
|
|
"%43 = OpLoad %float %42",
|
|
"%44 = OpFAdd %float %41 %43",
|
|
"%45 = OpAccessChain %_ptr_Function_float %param %uint_2",
|
|
"OpStore %45 %44",
|
|
"%27 = OpLoad %v4float %param",
|
|
"OpStore %b %27",
|
|
"%28 = OpAccessChain %_ptr_Function_float %b %uint_2",
|
|
"%29 = OpLoad %float %28",
|
|
"%30 = OpCompositeConstruct %v4float %29 %29 %29 %29",
|
|
"OpStore %color %30",
|
|
"%31 = OpLoad %v4float %color",
|
|
"OpStore %gl_FragColor %31",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(
|
|
JoinAllInsts(Concat(Concat(predefs, before), nonEntryFuncs)),
|
|
JoinAllInsts(Concat(Concat(predefs, after), nonEntryFuncs)),
|
|
/* skip_nop = */ false, /* do_validate = */ true);
|
|
}
|
|
|
|
TEST_F(InlineTest, BranchInCallee) {
|
|
// #version 140
|
|
//
|
|
// in vec4 BaseColor;
|
|
//
|
|
// float foo(vec4 bar)
|
|
// {
|
|
// float r = bar.x;
|
|
// if (r < 0.0)
|
|
// r = -r;
|
|
// return r;
|
|
// }
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 color = vec4(foo(BaseColor));
|
|
//
|
|
// gl_FragColor = color;
|
|
// }
|
|
const std::vector<const char*> predefs = {
|
|
// clang-format off
|
|
"OpCapability Shader",
|
|
"%1 = OpExtInstImport \"GLSL.std.450\"",
|
|
"OpMemoryModel Logical GLSL450",
|
|
"OpEntryPoint Fragment %main \"main\" %BaseColor %gl_FragColor",
|
|
"OpExecutionMode %main OriginUpperLeft",
|
|
"OpSource GLSL 140",
|
|
"OpName %main \"main\"",
|
|
"OpName %foo_vf4_ \"foo(vf4;\"",
|
|
"OpName %bar \"bar\"",
|
|
"OpName %r \"r\"",
|
|
"OpName %color \"color\"",
|
|
"OpName %BaseColor \"BaseColor\"",
|
|
"OpName %param \"param\"",
|
|
"OpName %gl_FragColor \"gl_FragColor\"",
|
|
"%void = OpTypeVoid",
|
|
"%11 = OpTypeFunction %void",
|
|
"%float = OpTypeFloat 32",
|
|
"%v4float = OpTypeVector %float 4",
|
|
"%_ptr_Function_v4float = OpTypePointer Function %v4float",
|
|
"%15 = OpTypeFunction %float %_ptr_Function_v4float",
|
|
"%_ptr_Function_float = OpTypePointer Function %float",
|
|
"%uint = OpTypeInt 32 0",
|
|
"%uint_0 = OpConstant %uint 0",
|
|
"%float_0 = OpConstant %float 0",
|
|
"%bool = OpTypeBool",
|
|
"%_ptr_Input_v4float = OpTypePointer Input %v4float",
|
|
"%BaseColor = OpVariable %_ptr_Input_v4float Input",
|
|
"%_ptr_Output_v4float = OpTypePointer Output %v4float",
|
|
"%gl_FragColor = OpVariable %_ptr_Output_v4float Output",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> nonEntryFuncs = {
|
|
// clang-format off
|
|
"%foo_vf4_ = OpFunction %float None %15",
|
|
"%bar = OpFunctionParameter %_ptr_Function_v4float",
|
|
"%28 = OpLabel",
|
|
"%r = OpVariable %_ptr_Function_float Function",
|
|
"%29 = OpAccessChain %_ptr_Function_float %bar %uint_0",
|
|
"%30 = OpLoad %float %29",
|
|
"OpStore %r %30",
|
|
"%31 = OpLoad %float %r",
|
|
"%32 = OpFOrdLessThan %bool %31 %float_0",
|
|
"OpSelectionMerge %33 None",
|
|
"OpBranchConditional %32 %34 %33",
|
|
"%34 = OpLabel",
|
|
"%35 = OpLoad %float %r",
|
|
"%36 = OpFNegate %float %35",
|
|
"OpStore %r %36",
|
|
"OpBranch %33",
|
|
"%33 = OpLabel",
|
|
"%37 = OpLoad %float %r",
|
|
"OpReturnValue %37",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> before = {
|
|
// clang-format off
|
|
"%main = OpFunction %void None %11",
|
|
"%23 = OpLabel",
|
|
"%color = OpVariable %_ptr_Function_v4float Function",
|
|
"%param = OpVariable %_ptr_Function_v4float Function",
|
|
"%24 = OpLoad %v4float %BaseColor",
|
|
"OpStore %param %24",
|
|
"%25 = OpFunctionCall %float %foo_vf4_ %param",
|
|
"%26 = OpCompositeConstruct %v4float %25 %25 %25 %25",
|
|
"OpStore %color %26",
|
|
"%27 = OpLoad %v4float %color",
|
|
"OpStore %gl_FragColor %27",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> after = {
|
|
// clang-format off
|
|
"%main = OpFunction %void None %11",
|
|
"%23 = OpLabel",
|
|
"%38 = OpVariable %_ptr_Function_float Function",
|
|
"%39 = OpVariable %_ptr_Function_float Function",
|
|
"%color = OpVariable %_ptr_Function_v4float Function",
|
|
"%param = OpVariable %_ptr_Function_v4float Function",
|
|
"%24 = OpLoad %v4float %BaseColor",
|
|
"OpStore %param %24",
|
|
"%41 = OpAccessChain %_ptr_Function_float %param %uint_0",
|
|
"%42 = OpLoad %float %41",
|
|
"OpStore %38 %42",
|
|
"%43 = OpLoad %float %38",
|
|
"%44 = OpFOrdLessThan %bool %43 %float_0",
|
|
"OpSelectionMerge %48 None",
|
|
"OpBranchConditional %44 %45 %48",
|
|
"%45 = OpLabel",
|
|
"%46 = OpLoad %float %38",
|
|
"%47 = OpFNegate %float %46",
|
|
"OpStore %38 %47",
|
|
"OpBranch %48",
|
|
"%48 = OpLabel",
|
|
"%49 = OpLoad %float %38",
|
|
"OpStore %39 %49",
|
|
"%25 = OpLoad %float %39",
|
|
"%26 = OpCompositeConstruct %v4float %25 %25 %25 %25",
|
|
"OpStore %color %26",
|
|
"%27 = OpLoad %v4float %color",
|
|
"OpStore %gl_FragColor %27",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(
|
|
JoinAllInsts(Concat(Concat(predefs, before), nonEntryFuncs)),
|
|
JoinAllInsts(Concat(Concat(predefs, after), nonEntryFuncs)),
|
|
/* skip_nop = */ false, /* do_validate = */ true);
|
|
}
|
|
|
|
TEST_F(InlineTest, PhiAfterCall) {
|
|
// #version 140
|
|
//
|
|
// in vec4 BaseColor;
|
|
//
|
|
// float foo(float bar)
|
|
// {
|
|
// float r = bar;
|
|
// if (r < 0.0)
|
|
// r = -r;
|
|
// return r;
|
|
// }
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 color = BaseColor;
|
|
// if (foo(color.x) > 2.0 && foo(color.y) > 2.0)
|
|
// color = vec4(0.0);
|
|
// gl_FragColor = color;
|
|
// }
|
|
const std::vector<const char*> predefs = {
|
|
// clang-format off
|
|
"OpCapability Shader",
|
|
"%1 = OpExtInstImport \"GLSL.std.450\"",
|
|
"OpMemoryModel Logical GLSL450",
|
|
"OpEntryPoint Fragment %main \"main\" %BaseColor %gl_FragColor",
|
|
"OpExecutionMode %main OriginUpperLeft",
|
|
"OpSource GLSL 140",
|
|
"OpName %main \"main\"",
|
|
"OpName %foo_f1_ \"foo(f1;\"",
|
|
"OpName %bar \"bar\"",
|
|
"OpName %r \"r\"",
|
|
"OpName %color \"color\"",
|
|
"OpName %BaseColor \"BaseColor\"",
|
|
"OpName %param \"param\"",
|
|
"OpName %param_0 \"param\"",
|
|
"OpName %gl_FragColor \"gl_FragColor\"",
|
|
"%void = OpTypeVoid",
|
|
"%12 = OpTypeFunction %void",
|
|
"%float = OpTypeFloat 32",
|
|
"%_ptr_Function_float = OpTypePointer Function %float",
|
|
"%15 = OpTypeFunction %float %_ptr_Function_float",
|
|
"%float_0 = OpConstant %float 0",
|
|
"%bool = OpTypeBool",
|
|
"%v4float = OpTypeVector %float 4",
|
|
"%_ptr_Function_v4float = OpTypePointer Function %v4float",
|
|
"%_ptr_Input_v4float = OpTypePointer Input %v4float",
|
|
"%BaseColor = OpVariable %_ptr_Input_v4float Input",
|
|
"%uint = OpTypeInt 32 0",
|
|
"%uint_0 = OpConstant %uint 0",
|
|
"%float_2 = OpConstant %float 2",
|
|
"%uint_1 = OpConstant %uint 1",
|
|
"%25 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0",
|
|
"%_ptr_Output_v4float = OpTypePointer Output %v4float",
|
|
"%gl_FragColor = OpVariable %_ptr_Output_v4float Output",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> nonEntryFuncs = {
|
|
// clang-format off
|
|
"%foo_f1_ = OpFunction %float None %15",
|
|
"%bar = OpFunctionParameter %_ptr_Function_float",
|
|
"%43 = OpLabel",
|
|
"%r = OpVariable %_ptr_Function_float Function",
|
|
"%44 = OpLoad %float %bar",
|
|
"OpStore %r %44",
|
|
"%45 = OpLoad %float %r",
|
|
"%46 = OpFOrdLessThan %bool %45 %float_0",
|
|
"OpSelectionMerge %47 None",
|
|
"OpBranchConditional %46 %48 %47",
|
|
"%48 = OpLabel",
|
|
"%49 = OpLoad %float %r",
|
|
"%50 = OpFNegate %float %49",
|
|
"OpStore %r %50",
|
|
"OpBranch %47",
|
|
"%47 = OpLabel",
|
|
"%51 = OpLoad %float %r",
|
|
"OpReturnValue %51",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> before = {
|
|
// clang-format off
|
|
"%main = OpFunction %void None %12",
|
|
"%27 = OpLabel",
|
|
"%color = OpVariable %_ptr_Function_v4float Function",
|
|
"%param = OpVariable %_ptr_Function_float Function",
|
|
"%param_0 = OpVariable %_ptr_Function_float Function",
|
|
"%28 = OpLoad %v4float %BaseColor",
|
|
"OpStore %color %28",
|
|
"%29 = OpAccessChain %_ptr_Function_float %color %uint_0",
|
|
"%30 = OpLoad %float %29",
|
|
"OpStore %param %30",
|
|
"%31 = OpFunctionCall %float %foo_f1_ %param",
|
|
"%32 = OpFOrdGreaterThan %bool %31 %float_2",
|
|
"OpSelectionMerge %33 None",
|
|
"OpBranchConditional %32 %34 %33",
|
|
"%34 = OpLabel",
|
|
"%35 = OpAccessChain %_ptr_Function_float %color %uint_1",
|
|
"%36 = OpLoad %float %35",
|
|
"OpStore %param_0 %36",
|
|
"%37 = OpFunctionCall %float %foo_f1_ %param_0",
|
|
"%38 = OpFOrdGreaterThan %bool %37 %float_2",
|
|
"OpBranch %33",
|
|
"%33 = OpLabel",
|
|
"%39 = OpPhi %bool %32 %27 %38 %34",
|
|
"OpSelectionMerge %40 None",
|
|
"OpBranchConditional %39 %41 %40",
|
|
"%41 = OpLabel",
|
|
"OpStore %color %25",
|
|
"OpBranch %40",
|
|
"%40 = OpLabel",
|
|
"%42 = OpLoad %v4float %color",
|
|
"OpStore %gl_FragColor %42",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> after = {
|
|
// clang-format off
|
|
"%main = OpFunction %void None %12",
|
|
"%27 = OpLabel",
|
|
"%63 = OpVariable %_ptr_Function_float Function",
|
|
"%64 = OpVariable %_ptr_Function_float Function",
|
|
"%52 = OpVariable %_ptr_Function_float Function",
|
|
"%53 = OpVariable %_ptr_Function_float Function",
|
|
"%color = OpVariable %_ptr_Function_v4float Function",
|
|
"%param = OpVariable %_ptr_Function_float Function",
|
|
"%param_0 = OpVariable %_ptr_Function_float Function",
|
|
"%28 = OpLoad %v4float %BaseColor",
|
|
"OpStore %color %28",
|
|
"%29 = OpAccessChain %_ptr_Function_float %color %uint_0",
|
|
"%30 = OpLoad %float %29",
|
|
"OpStore %param %30",
|
|
"%55 = OpLoad %float %param",
|
|
"OpStore %52 %55",
|
|
"%56 = OpLoad %float %52",
|
|
"%57 = OpFOrdLessThan %bool %56 %float_0",
|
|
"OpSelectionMerge %61 None",
|
|
"OpBranchConditional %57 %58 %61",
|
|
"%58 = OpLabel",
|
|
"%59 = OpLoad %float %52",
|
|
"%60 = OpFNegate %float %59",
|
|
"OpStore %52 %60",
|
|
"OpBranch %61",
|
|
"%61 = OpLabel",
|
|
"%62 = OpLoad %float %52",
|
|
"OpStore %53 %62",
|
|
"%31 = OpLoad %float %53",
|
|
"%32 = OpFOrdGreaterThan %bool %31 %float_2",
|
|
"OpSelectionMerge %33 None",
|
|
"OpBranchConditional %32 %34 %33",
|
|
"%34 = OpLabel",
|
|
"%35 = OpAccessChain %_ptr_Function_float %color %uint_1",
|
|
"%36 = OpLoad %float %35",
|
|
"OpStore %param_0 %36",
|
|
"%66 = OpLoad %float %param_0",
|
|
"OpStore %63 %66",
|
|
"%67 = OpLoad %float %63",
|
|
"%68 = OpFOrdLessThan %bool %67 %float_0",
|
|
"OpSelectionMerge %72 None",
|
|
"OpBranchConditional %68 %69 %72",
|
|
"%69 = OpLabel",
|
|
"%70 = OpLoad %float %63",
|
|
"%71 = OpFNegate %float %70",
|
|
"OpStore %63 %71",
|
|
"OpBranch %72",
|
|
"%72 = OpLabel",
|
|
"%73 = OpLoad %float %63",
|
|
"OpStore %64 %73",
|
|
"%37 = OpLoad %float %64",
|
|
"%38 = OpFOrdGreaterThan %bool %37 %float_2",
|
|
"OpBranch %33",
|
|
"%33 = OpLabel",
|
|
"%39 = OpPhi %bool %32 %61 %38 %72",
|
|
"OpSelectionMerge %40 None",
|
|
"OpBranchConditional %39 %41 %40",
|
|
"%41 = OpLabel",
|
|
"OpStore %color %25",
|
|
"OpBranch %40",
|
|
"%40 = OpLabel",
|
|
"%42 = OpLoad %v4float %color",
|
|
"OpStore %gl_FragColor %42",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(
|
|
JoinAllInsts(Concat(Concat(predefs, before), nonEntryFuncs)),
|
|
JoinAllInsts(Concat(Concat(predefs, after), nonEntryFuncs)),
|
|
/* skip_nop = */ false, /* do_validate = */ true);
|
|
}
|
|
|
|
TEST_F(InlineTest, OpSampledImageOutOfBlock) {
|
|
// #version 450
|
|
//
|
|
// uniform texture2D t2D;
|
|
// uniform sampler samp;
|
|
// out vec4 FragColor;
|
|
// in vec4 BaseColor;
|
|
//
|
|
// float foo(vec4 bar)
|
|
// {
|
|
// float r = bar.x;
|
|
// if (r < 0.0)
|
|
// r = -r;
|
|
// return r;
|
|
// }
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 color1 = texture(sampler2D(t2D, samp), vec2(1.0));
|
|
// vec4 color2 = vec4(foo(BaseColor));
|
|
// vec4 color3 = texture(sampler2D(t2D, samp), vec2(0.5));
|
|
// FragColor = (color1 + color2 + color3)/3;
|
|
// }
|
|
//
|
|
// Note: the before SPIR-V will need to be edited to create a use of
|
|
// the OpSampledImage across the function call.
|
|
const std::vector<const char*> predefs = {
|
|
// clang-format off
|
|
"OpCapability Shader",
|
|
"%1 = OpExtInstImport \"GLSL.std.450\"",
|
|
"OpMemoryModel Logical GLSL450",
|
|
"OpEntryPoint Fragment %main \"main\" %BaseColor %FragColor",
|
|
"OpExecutionMode %main OriginUpperLeft",
|
|
"OpSource GLSL 450",
|
|
"OpName %main \"main\"",
|
|
"OpName %foo_vf4_ \"foo(vf4;\"",
|
|
"OpName %bar \"bar\"",
|
|
"OpName %r \"r\"",
|
|
"OpName %color1 \"color1\"",
|
|
"OpName %t2D \"t2D\"",
|
|
"OpName %samp \"samp\"",
|
|
"OpName %color2 \"color2\"",
|
|
"OpName %BaseColor \"BaseColor\"",
|
|
"OpName %param \"param\"",
|
|
"OpName %color3 \"color3\"",
|
|
"OpName %FragColor \"FragColor\"",
|
|
"OpDecorate %t2D DescriptorSet 0",
|
|
"OpDecorate %samp DescriptorSet 0",
|
|
"%void = OpTypeVoid",
|
|
"%15 = OpTypeFunction %void",
|
|
"%float = OpTypeFloat 32",
|
|
"%v4float = OpTypeVector %float 4",
|
|
"%_ptr_Function_v4float = OpTypePointer Function %v4float",
|
|
"%19 = OpTypeFunction %float %_ptr_Function_v4float",
|
|
"%_ptr_Function_float = OpTypePointer Function %float",
|
|
"%uint = OpTypeInt 32 0",
|
|
"%uint_0 = OpConstant %uint 0",
|
|
"%float_0 = OpConstant %float 0",
|
|
"%bool = OpTypeBool",
|
|
"%25 = OpTypeImage %float 2D 0 0 0 1 Unknown",
|
|
"%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25",
|
|
"%t2D = OpVariable %_ptr_UniformConstant_25 UniformConstant",
|
|
"%27 = OpTypeSampler",
|
|
"%_ptr_UniformConstant_27 = OpTypePointer UniformConstant %27",
|
|
"%samp = OpVariable %_ptr_UniformConstant_27 UniformConstant",
|
|
"%29 = OpTypeSampledImage %25",
|
|
"%v2float = OpTypeVector %float 2",
|
|
"%float_1 = OpConstant %float 1",
|
|
"%32 = OpConstantComposite %v2float %float_1 %float_1",
|
|
"%_ptr_Input_v4float = OpTypePointer Input %v4float",
|
|
"%BaseColor = OpVariable %_ptr_Input_v4float Input",
|
|
"%float_0_5 = OpConstant %float 0.5",
|
|
"%35 = OpConstantComposite %v2float %float_0_5 %float_0_5",
|
|
"%_ptr_Output_v4float = OpTypePointer Output %v4float",
|
|
"%FragColor = OpVariable %_ptr_Output_v4float Output",
|
|
"%float_3 = OpConstant %float 3",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> nonEntryFuncs = {
|
|
// clang-format off
|
|
"%foo_vf4_ = OpFunction %float None %19",
|
|
"%bar = OpFunctionParameter %_ptr_Function_v4float",
|
|
"%56 = OpLabel",
|
|
"%r = OpVariable %_ptr_Function_float Function",
|
|
"%57 = OpAccessChain %_ptr_Function_float %bar %uint_0",
|
|
"%58 = OpLoad %float %57",
|
|
"OpStore %r %58",
|
|
"%59 = OpLoad %float %r",
|
|
"%60 = OpFOrdLessThan %bool %59 %float_0",
|
|
"OpSelectionMerge %61 None",
|
|
"OpBranchConditional %60 %62 %61",
|
|
"%62 = OpLabel",
|
|
"%63 = OpLoad %float %r",
|
|
"%64 = OpFNegate %float %63",
|
|
"OpStore %r %64",
|
|
"OpBranch %61",
|
|
"%61 = OpLabel",
|
|
"%65 = OpLoad %float %r",
|
|
"OpReturnValue %65",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> before = {
|
|
// clang-format off
|
|
"%main = OpFunction %void None %15",
|
|
"%38 = OpLabel",
|
|
"%color1 = OpVariable %_ptr_Function_v4float Function",
|
|
"%color2 = OpVariable %_ptr_Function_v4float Function",
|
|
"%param = OpVariable %_ptr_Function_v4float Function",
|
|
"%color3 = OpVariable %_ptr_Function_v4float Function",
|
|
"%39 = OpLoad %25 %t2D",
|
|
"%40 = OpLoad %27 %samp",
|
|
"%41 = OpSampledImage %29 %39 %40",
|
|
"%42 = OpImageSampleImplicitLod %v4float %41 %32",
|
|
"OpStore %color1 %42",
|
|
"%43 = OpLoad %v4float %BaseColor",
|
|
"OpStore %param %43",
|
|
"%44 = OpFunctionCall %float %foo_vf4_ %param",
|
|
"%45 = OpCompositeConstruct %v4float %44 %44 %44 %44",
|
|
"OpStore %color2 %45",
|
|
"%46 = OpLoad %25 %t2D",
|
|
"%47 = OpLoad %27 %samp",
|
|
"%48 = OpImageSampleImplicitLod %v4float %41 %35",
|
|
"OpStore %color3 %48",
|
|
"%49 = OpLoad %v4float %color1",
|
|
"%50 = OpLoad %v4float %color2",
|
|
"%51 = OpFAdd %v4float %49 %50",
|
|
"%52 = OpLoad %v4float %color3",
|
|
"%53 = OpFAdd %v4float %51 %52",
|
|
"%54 = OpCompositeConstruct %v4float %float_3 %float_3 %float_3 %float_3",
|
|
"%55 = OpFDiv %v4float %53 %54",
|
|
"OpStore %FragColor %55",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> after = {
|
|
// clang-format off
|
|
"%main = OpFunction %void None %15",
|
|
"%38 = OpLabel",
|
|
"%66 = OpVariable %_ptr_Function_float Function",
|
|
"%67 = OpVariable %_ptr_Function_float Function",
|
|
"%color1 = OpVariable %_ptr_Function_v4float Function",
|
|
"%color2 = OpVariable %_ptr_Function_v4float Function",
|
|
"%param = OpVariable %_ptr_Function_v4float Function",
|
|
"%color3 = OpVariable %_ptr_Function_v4float Function",
|
|
"%39 = OpLoad %25 %t2D",
|
|
"%40 = OpLoad %27 %samp",
|
|
"%41 = OpSampledImage %29 %39 %40",
|
|
"%42 = OpImageSampleImplicitLod %v4float %41 %32",
|
|
"OpStore %color1 %42",
|
|
"%43 = OpLoad %v4float %BaseColor",
|
|
"OpStore %param %43",
|
|
"%69 = OpAccessChain %_ptr_Function_float %param %uint_0",
|
|
"%70 = OpLoad %float %69",
|
|
"OpStore %66 %70",
|
|
"%71 = OpLoad %float %66",
|
|
"%72 = OpFOrdLessThan %bool %71 %float_0",
|
|
"OpSelectionMerge %76 None",
|
|
"OpBranchConditional %72 %73 %76",
|
|
"%73 = OpLabel",
|
|
"%74 = OpLoad %float %66",
|
|
"%75 = OpFNegate %float %74",
|
|
"OpStore %66 %75",
|
|
"OpBranch %76",
|
|
"%76 = OpLabel",
|
|
"%77 = OpLoad %float %66",
|
|
"OpStore %67 %77",
|
|
"%44 = OpLoad %float %67",
|
|
"%45 = OpCompositeConstruct %v4float %44 %44 %44 %44",
|
|
"OpStore %color2 %45",
|
|
"%46 = OpLoad %25 %t2D",
|
|
"%47 = OpLoad %27 %samp",
|
|
"%78 = OpSampledImage %29 %39 %40",
|
|
"%48 = OpImageSampleImplicitLod %v4float %78 %35",
|
|
"OpStore %color3 %48",
|
|
"%49 = OpLoad %v4float %color1",
|
|
"%50 = OpLoad %v4float %color2",
|
|
"%51 = OpFAdd %v4float %49 %50",
|
|
"%52 = OpLoad %v4float %color3",
|
|
"%53 = OpFAdd %v4float %51 %52",
|
|
"%54 = OpCompositeConstruct %v4float %float_3 %float_3 %float_3 %float_3",
|
|
"%55 = OpFDiv %v4float %53 %54",
|
|
"OpStore %FragColor %55",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(
|
|
JoinAllInsts(Concat(Concat(predefs, before), nonEntryFuncs)),
|
|
JoinAllInsts(Concat(Concat(predefs, after), nonEntryFuncs)),
|
|
/* skip_nop = */ false, /* do_validate = */ true);
|
|
}
|
|
|
|
TEST_F(InlineTest, OpImageOutOfBlock) {
|
|
// #version 450
|
|
//
|
|
// uniform texture2D t2D;
|
|
// uniform sampler samp;
|
|
// uniform sampler samp2;
|
|
//
|
|
// out vec4 FragColor;
|
|
//
|
|
// in vec4 BaseColor;
|
|
//
|
|
// float foo(vec4 bar)
|
|
// {
|
|
// float r = bar.x;
|
|
// if (r < 0.0)
|
|
// r = -r;
|
|
// return r;
|
|
// }
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 color1 = texture(sampler2D(t2D, samp), vec2(1.0));
|
|
// vec4 color2 = vec4(foo(BaseColor));
|
|
// vec4 color3 = texture(sampler2D(t2D, samp2), vec2(0.5));
|
|
// FragColor = (color1 + color2 + color3)/3;
|
|
// }
|
|
// Note: the before SPIR-V will need to be edited to create an OpImage
|
|
// from the first OpSampledImage, place it before the call and use it
|
|
// in the second OpSampledImage following the call.
|
|
const std::vector<const char*> predefs = {
|
|
// clang-format off
|
|
"OpCapability Shader",
|
|
"%1 = OpExtInstImport \"GLSL.std.450\"",
|
|
"OpMemoryModel Logical GLSL450",
|
|
"OpEntryPoint Fragment %main \"main\" %BaseColor %FragColor",
|
|
"OpExecutionMode %main OriginUpperLeft",
|
|
"OpSource GLSL 450",
|
|
"OpName %main \"main\"",
|
|
"OpName %foo_vf4_ \"foo(vf4;\"",
|
|
"OpName %bar \"bar\"",
|
|
"OpName %r \"r\"",
|
|
"OpName %color1 \"color1\"",
|
|
"OpName %t2D \"t2D\"",
|
|
"OpName %samp \"samp\"",
|
|
"OpName %color2 \"color2\"",
|
|
"OpName %BaseColor \"BaseColor\"",
|
|
"OpName %param \"param\"",
|
|
"OpName %color3 \"color3\"",
|
|
"OpName %samp2 \"samp2\"",
|
|
"OpName %FragColor \"FragColor\"",
|
|
"OpDecorate %t2D DescriptorSet 0",
|
|
"OpDecorate %samp DescriptorSet 0",
|
|
"OpDecorate %samp2 DescriptorSet 0",
|
|
"%void = OpTypeVoid",
|
|
"%16 = OpTypeFunction %void",
|
|
"%float = OpTypeFloat 32",
|
|
"%v4float = OpTypeVector %float 4",
|
|
"%_ptr_Function_v4float = OpTypePointer Function %v4float",
|
|
"%20 = OpTypeFunction %float %_ptr_Function_v4float",
|
|
"%_ptr_Function_float = OpTypePointer Function %float",
|
|
"%uint = OpTypeInt 32 0",
|
|
"%uint_0 = OpConstant %uint 0",
|
|
"%float_0 = OpConstant %float 0",
|
|
"%bool = OpTypeBool",
|
|
"%26 = OpTypeImage %float 2D 0 0 0 1 Unknown",
|
|
"%_ptr_UniformConstant_26 = OpTypePointer UniformConstant %26",
|
|
"%t2D = OpVariable %_ptr_UniformConstant_26 UniformConstant",
|
|
"%28 = OpTypeSampler",
|
|
"%_ptr_UniformConstant_28 = OpTypePointer UniformConstant %28",
|
|
"%samp = OpVariable %_ptr_UniformConstant_28 UniformConstant",
|
|
"%30 = OpTypeSampledImage %26",
|
|
"%v2float = OpTypeVector %float 2",
|
|
"%float_1 = OpConstant %float 1",
|
|
"%33 = OpConstantComposite %v2float %float_1 %float_1",
|
|
"%_ptr_Input_v4float = OpTypePointer Input %v4float",
|
|
"%BaseColor = OpVariable %_ptr_Input_v4float Input",
|
|
"%samp2 = OpVariable %_ptr_UniformConstant_28 UniformConstant",
|
|
"%float_0_5 = OpConstant %float 0.5",
|
|
"%36 = OpConstantComposite %v2float %float_0_5 %float_0_5",
|
|
"%_ptr_Output_v4float = OpTypePointer Output %v4float",
|
|
"%FragColor = OpVariable %_ptr_Output_v4float Output",
|
|
"%float_3 = OpConstant %float 3",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> nonEntryFuncs = {
|
|
// clang-format off
|
|
"%foo_vf4_ = OpFunction %float None %20",
|
|
"%bar = OpFunctionParameter %_ptr_Function_v4float",
|
|
"%58 = OpLabel",
|
|
"%r = OpVariable %_ptr_Function_float Function",
|
|
"%59 = OpAccessChain %_ptr_Function_float %bar %uint_0",
|
|
"%60 = OpLoad %float %59",
|
|
"OpStore %r %60",
|
|
"%61 = OpLoad %float %r",
|
|
"%62 = OpFOrdLessThan %bool %61 %float_0",
|
|
"OpSelectionMerge %63 None",
|
|
"OpBranchConditional %62 %64 %63",
|
|
"%64 = OpLabel",
|
|
"%65 = OpLoad %float %r",
|
|
"%66 = OpFNegate %float %65",
|
|
"OpStore %r %66",
|
|
"OpBranch %63",
|
|
"%63 = OpLabel",
|
|
"%67 = OpLoad %float %r",
|
|
"OpReturnValue %67",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> before = {
|
|
// clang-format off
|
|
"%main = OpFunction %void None %16",
|
|
"%39 = OpLabel",
|
|
"%color1 = OpVariable %_ptr_Function_v4float Function",
|
|
"%color2 = OpVariable %_ptr_Function_v4float Function",
|
|
"%param = OpVariable %_ptr_Function_v4float Function",
|
|
"%color3 = OpVariable %_ptr_Function_v4float Function",
|
|
"%40 = OpLoad %26 %t2D",
|
|
"%41 = OpLoad %28 %samp",
|
|
"%42 = OpSampledImage %30 %40 %41",
|
|
"%43 = OpImageSampleImplicitLod %v4float %42 %33",
|
|
"%44 = OpImage %26 %42",
|
|
"%45 = OpLoad %28 %samp2",
|
|
"OpStore %color1 %43",
|
|
"%46 = OpLoad %v4float %BaseColor",
|
|
"OpStore %param %46",
|
|
"%47 = OpFunctionCall %float %foo_vf4_ %param",
|
|
"%48 = OpCompositeConstruct %v4float %47 %47 %47 %47",
|
|
"OpStore %color2 %48",
|
|
"%49 = OpSampledImage %30 %44 %45",
|
|
"%50 = OpImageSampleImplicitLod %v4float %49 %36",
|
|
"OpStore %color3 %50",
|
|
"%51 = OpLoad %v4float %color1",
|
|
"%52 = OpLoad %v4float %color2",
|
|
"%53 = OpFAdd %v4float %51 %52",
|
|
"%54 = OpLoad %v4float %color3",
|
|
"%55 = OpFAdd %v4float %53 %54",
|
|
"%56 = OpCompositeConstruct %v4float %float_3 %float_3 %float_3 %float_3",
|
|
"%57 = OpFDiv %v4float %55 %56",
|
|
"OpStore %FragColor %57",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> after = {
|
|
// clang-format off
|
|
"%main = OpFunction %void None %16",
|
|
"%39 = OpLabel",
|
|
"%68 = OpVariable %_ptr_Function_float Function",
|
|
"%69 = OpVariable %_ptr_Function_float Function",
|
|
"%color1 = OpVariable %_ptr_Function_v4float Function",
|
|
"%color2 = OpVariable %_ptr_Function_v4float Function",
|
|
"%param = OpVariable %_ptr_Function_v4float Function",
|
|
"%color3 = OpVariable %_ptr_Function_v4float Function",
|
|
"%40 = OpLoad %26 %t2D",
|
|
"%41 = OpLoad %28 %samp",
|
|
"%42 = OpSampledImage %30 %40 %41",
|
|
"%43 = OpImageSampleImplicitLod %v4float %42 %33",
|
|
"%44 = OpImage %26 %42",
|
|
"%45 = OpLoad %28 %samp2",
|
|
"OpStore %color1 %43",
|
|
"%46 = OpLoad %v4float %BaseColor",
|
|
"OpStore %param %46",
|
|
"%71 = OpAccessChain %_ptr_Function_float %param %uint_0",
|
|
"%72 = OpLoad %float %71",
|
|
"OpStore %68 %72",
|
|
"%73 = OpLoad %float %68",
|
|
"%74 = OpFOrdLessThan %bool %73 %float_0",
|
|
"OpSelectionMerge %78 None",
|
|
"OpBranchConditional %74 %75 %78",
|
|
"%75 = OpLabel",
|
|
"%76 = OpLoad %float %68",
|
|
"%77 = OpFNegate %float %76",
|
|
"OpStore %68 %77",
|
|
"OpBranch %78",
|
|
"%78 = OpLabel",
|
|
"%79 = OpLoad %float %68",
|
|
"OpStore %69 %79",
|
|
"%47 = OpLoad %float %69",
|
|
"%48 = OpCompositeConstruct %v4float %47 %47 %47 %47",
|
|
"OpStore %color2 %48",
|
|
"%80 = OpSampledImage %30 %40 %41",
|
|
"%81 = OpImage %26 %80",
|
|
"%49 = OpSampledImage %30 %81 %45",
|
|
"%50 = OpImageSampleImplicitLod %v4float %49 %36",
|
|
"OpStore %color3 %50",
|
|
"%51 = OpLoad %v4float %color1",
|
|
"%52 = OpLoad %v4float %color2",
|
|
"%53 = OpFAdd %v4float %51 %52",
|
|
"%54 = OpLoad %v4float %color3",
|
|
"%55 = OpFAdd %v4float %53 %54",
|
|
"%56 = OpCompositeConstruct %v4float %float_3 %float_3 %float_3 %float_3",
|
|
"%57 = OpFDiv %v4float %55 %56",
|
|
"OpStore %FragColor %57",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(
|
|
JoinAllInsts(Concat(Concat(predefs, before), nonEntryFuncs)),
|
|
JoinAllInsts(Concat(Concat(predefs, after), nonEntryFuncs)),
|
|
/* skip_nop = */ false, /* do_validate = */ true);
|
|
}
|
|
|
|
TEST_F(InlineTest, OpImageAndOpSampledImageOutOfBlock) {
|
|
// #version 450
|
|
//
|
|
// uniform texture2D t2D;
|
|
// uniform sampler samp;
|
|
// uniform sampler samp2;
|
|
//
|
|
// out vec4 FragColor;
|
|
//
|
|
// in vec4 BaseColor;
|
|
//
|
|
// float foo(vec4 bar)
|
|
// {
|
|
// float r = bar.x;
|
|
// if (r < 0.0)
|
|
// r = -r;
|
|
// return r;
|
|
// }
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 color1 = texture(sampler2D(t2D, samp), vec2(1.0));
|
|
// vec4 color2 = vec4(foo(BaseColor));
|
|
// vec4 color3 = texture(sampler2D(t2D, samp2), vec2(0.5));
|
|
// FragColor = (color1 + color2 + color3)/3;
|
|
// }
|
|
// Note: the before SPIR-V will need to be edited to create an OpImage
|
|
// and subsequent OpSampledImage that is used across the function call.
|
|
const std::vector<const char*> predefs = {
|
|
// clang-format off
|
|
"OpCapability Shader",
|
|
"%1 = OpExtInstImport \"GLSL.std.450\"",
|
|
"OpMemoryModel Logical GLSL450",
|
|
"OpEntryPoint Fragment %main \"main\" %BaseColor %FragColor",
|
|
"OpExecutionMode %main OriginUpperLeft",
|
|
"OpSource GLSL 450",
|
|
"OpName %main \"main\"",
|
|
"OpName %foo_vf4_ \"foo(vf4;\"",
|
|
"OpName %bar \"bar\"",
|
|
"OpName %r \"r\"",
|
|
"OpName %color1 \"color1\"",
|
|
"OpName %t2D \"t2D\"",
|
|
"OpName %samp \"samp\"",
|
|
"OpName %color2 \"color2\"",
|
|
"OpName %BaseColor \"BaseColor\"",
|
|
"OpName %param \"param\"",
|
|
"OpName %color3 \"color3\"",
|
|
"OpName %samp2 \"samp2\"",
|
|
"OpName %FragColor \"FragColor\"",
|
|
"OpDecorate %t2D DescriptorSet 0",
|
|
"OpDecorate %samp DescriptorSet 0",
|
|
"OpDecorate %samp2 DescriptorSet 0",
|
|
"%void = OpTypeVoid",
|
|
"%16 = OpTypeFunction %void",
|
|
"%float = OpTypeFloat 32",
|
|
"%v4float = OpTypeVector %float 4",
|
|
"%_ptr_Function_v4float = OpTypePointer Function %v4float",
|
|
"%20 = OpTypeFunction %float %_ptr_Function_v4float",
|
|
"%_ptr_Function_float = OpTypePointer Function %float",
|
|
"%uint = OpTypeInt 32 0",
|
|
"%uint_0 = OpConstant %uint 0",
|
|
"%float_0 = OpConstant %float 0",
|
|
"%bool = OpTypeBool",
|
|
"%26 = OpTypeImage %float 2D 0 0 0 1 Unknown",
|
|
"%_ptr_UniformConstant_26 = OpTypePointer UniformConstant %26",
|
|
"%t2D = OpVariable %_ptr_UniformConstant_26 UniformConstant",
|
|
"%28 = OpTypeSampler",
|
|
"%_ptr_UniformConstant_28 = OpTypePointer UniformConstant %28",
|
|
"%samp = OpVariable %_ptr_UniformConstant_28 UniformConstant",
|
|
"%30 = OpTypeSampledImage %26",
|
|
"%v2float = OpTypeVector %float 2",
|
|
"%float_1 = OpConstant %float 1",
|
|
"%33 = OpConstantComposite %v2float %float_1 %float_1",
|
|
"%_ptr_Input_v4float = OpTypePointer Input %v4float",
|
|
"%BaseColor = OpVariable %_ptr_Input_v4float Input",
|
|
"%samp2 = OpVariable %_ptr_UniformConstant_28 UniformConstant",
|
|
"%float_0_5 = OpConstant %float 0.5",
|
|
"%36 = OpConstantComposite %v2float %float_0_5 %float_0_5",
|
|
"%_ptr_Output_v4float = OpTypePointer Output %v4float",
|
|
"%FragColor = OpVariable %_ptr_Output_v4float Output",
|
|
"%float_3 = OpConstant %float 3",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> nonEntryFuncs = {
|
|
// clang-format off
|
|
"%foo_vf4_ = OpFunction %float None %20",
|
|
"%bar = OpFunctionParameter %_ptr_Function_v4float",
|
|
"%58 = OpLabel",
|
|
"%r = OpVariable %_ptr_Function_float Function",
|
|
"%59 = OpAccessChain %_ptr_Function_float %bar %uint_0",
|
|
"%60 = OpLoad %float %59",
|
|
"OpStore %r %60",
|
|
"%61 = OpLoad %float %r",
|
|
"%62 = OpFOrdLessThan %bool %61 %float_0",
|
|
"OpSelectionMerge %63 None",
|
|
"OpBranchConditional %62 %64 %63",
|
|
"%64 = OpLabel",
|
|
"%65 = OpLoad %float %r",
|
|
"%66 = OpFNegate %float %65",
|
|
"OpStore %r %66",
|
|
"OpBranch %63",
|
|
"%63 = OpLabel",
|
|
"%67 = OpLoad %float %r",
|
|
"OpReturnValue %67",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> before = {
|
|
// clang-format off
|
|
"%main = OpFunction %void None %16",
|
|
"%39 = OpLabel",
|
|
"%color1 = OpVariable %_ptr_Function_v4float Function",
|
|
"%color2 = OpVariable %_ptr_Function_v4float Function",
|
|
"%param = OpVariable %_ptr_Function_v4float Function",
|
|
"%color3 = OpVariable %_ptr_Function_v4float Function",
|
|
"%40 = OpLoad %26 %t2D",
|
|
"%41 = OpLoad %28 %samp",
|
|
"%42 = OpSampledImage %30 %40 %41",
|
|
"%43 = OpImageSampleImplicitLod %v4float %42 %33",
|
|
"%44 = OpImage %26 %42",
|
|
"%45 = OpLoad %28 %samp2",
|
|
"%46 = OpSampledImage %30 %44 %45",
|
|
"OpStore %color1 %43",
|
|
"%47 = OpLoad %v4float %BaseColor",
|
|
"OpStore %param %47",
|
|
"%48 = OpFunctionCall %float %foo_vf4_ %param",
|
|
"%49 = OpCompositeConstruct %v4float %48 %48 %48 %48",
|
|
"OpStore %color2 %49",
|
|
"%50 = OpImageSampleImplicitLod %v4float %46 %36",
|
|
"OpStore %color3 %50",
|
|
"%51 = OpLoad %v4float %color1",
|
|
"%52 = OpLoad %v4float %color2",
|
|
"%53 = OpFAdd %v4float %51 %52",
|
|
"%54 = OpLoad %v4float %color3",
|
|
"%55 = OpFAdd %v4float %53 %54",
|
|
"%56 = OpCompositeConstruct %v4float %float_3 %float_3 %float_3 %float_3",
|
|
"%57 = OpFDiv %v4float %55 %56",
|
|
"OpStore %FragColor %57",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
|
|
const std::vector<const char*> after = {
|
|
// clang-format off
|
|
"%main = OpFunction %void None %16",
|
|
"%39 = OpLabel",
|
|
"%68 = OpVariable %_ptr_Function_float Function",
|
|
"%69 = OpVariable %_ptr_Function_float Function",
|
|
"%color1 = OpVariable %_ptr_Function_v4float Function",
|
|
"%color2 = OpVariable %_ptr_Function_v4float Function",
|
|
"%param = OpVariable %_ptr_Function_v4float Function",
|
|
"%color3 = OpVariable %_ptr_Function_v4float Function",
|
|
"%40 = OpLoad %26 %t2D",
|
|
"%41 = OpLoad %28 %samp",
|
|
"%42 = OpSampledImage %30 %40 %41",
|
|
"%43 = OpImageSampleImplicitLod %v4float %42 %33",
|
|
"%44 = OpImage %26 %42",
|
|
"%45 = OpLoad %28 %samp2",
|
|
"%46 = OpSampledImage %30 %44 %45",
|
|
"OpStore %color1 %43",
|
|
"%47 = OpLoad %v4float %BaseColor",
|
|
"OpStore %param %47",
|
|
"%71 = OpAccessChain %_ptr_Function_float %param %uint_0",
|
|
"%72 = OpLoad %float %71",
|
|
"OpStore %68 %72",
|
|
"%73 = OpLoad %float %68",
|
|
"%74 = OpFOrdLessThan %bool %73 %float_0",
|
|
"OpSelectionMerge %78 None",
|
|
"OpBranchConditional %74 %75 %78",
|
|
"%75 = OpLabel",
|
|
"%76 = OpLoad %float %68",
|
|
"%77 = OpFNegate %float %76",
|
|
"OpStore %68 %77",
|
|
"OpBranch %78",
|
|
"%78 = OpLabel",
|
|
"%79 = OpLoad %float %68",
|
|
"OpStore %69 %79",
|
|
"%48 = OpLoad %float %69",
|
|
"%49 = OpCompositeConstruct %v4float %48 %48 %48 %48",
|
|
"OpStore %color2 %49",
|
|
"%80 = OpSampledImage %30 %40 %41",
|
|
"%81 = OpImage %26 %80",
|
|
"%82 = OpSampledImage %30 %81 %45",
|
|
"%50 = OpImageSampleImplicitLod %v4float %82 %36",
|
|
"OpStore %color3 %50",
|
|
"%51 = OpLoad %v4float %color1",
|
|
"%52 = OpLoad %v4float %color2",
|
|
"%53 = OpFAdd %v4float %51 %52",
|
|
"%54 = OpLoad %v4float %color3",
|
|
"%55 = OpFAdd %v4float %53 %54",
|
|
"%56 = OpCompositeConstruct %v4float %float_3 %float_3 %float_3 %float_3",
|
|
"%57 = OpFDiv %v4float %55 %56",
|
|
"OpStore %FragColor %57",
|
|
"OpReturn",
|
|
"OpFunctionEnd",
|
|
// clang-format on
|
|
};
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(
|
|
JoinAllInsts(Concat(Concat(predefs, before), nonEntryFuncs)),
|
|
JoinAllInsts(Concat(Concat(predefs, after), nonEntryFuncs)),
|
|
/* skip_nop = */ false, /* do_validate = */ true);
|
|
}
|
|
|
|
TEST_F(InlineTest, EarlyReturnInLoopIsNotInlined) {
|
|
// #version 140
|
|
//
|
|
// in vec4 BaseColor;
|
|
//
|
|
// float foo(vec4 bar)
|
|
// {
|
|
// while (true) {
|
|
// if (bar.x < 0.0)
|
|
// return 0.0;
|
|
// return bar.x;
|
|
// }
|
|
// }
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 color = vec4(foo(BaseColor));
|
|
// gl_FragColor = color;
|
|
// }
|
|
|
|
const std::string assembly =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
OpName %main "main"
|
|
OpName %foo_vf4_ "foo(vf4;"
|
|
OpName %bar "bar"
|
|
OpName %color "color"
|
|
OpName %BaseColor "BaseColor"
|
|
OpName %param "param"
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
%void = OpTypeVoid
|
|
%10 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%14 = OpTypeFunction %float %_ptr_Function_v4float
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%uint = OpTypeInt 32 0
|
|
%uint_0 = OpConstant %uint 0
|
|
%_ptr_Function_float = OpTypePointer Function %float
|
|
%float_0 = OpConstant %float 0
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%BaseColor = OpVariable %_ptr_Input_v4float Input
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
|
%main = OpFunction %void None %10
|
|
%23 = OpLabel
|
|
%color = OpVariable %_ptr_Function_v4float Function
|
|
%param = OpVariable %_ptr_Function_v4float Function
|
|
%24 = OpLoad %v4float %BaseColor
|
|
OpStore %param %24
|
|
%25 = OpFunctionCall %float %foo_vf4_ %param
|
|
%26 = OpCompositeConstruct %v4float %25 %25 %25 %25
|
|
OpStore %color %26
|
|
%27 = OpLoad %v4float %color
|
|
OpStore %gl_FragColor %27
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%foo_vf4_ = OpFunction %float None %14
|
|
%bar = OpFunctionParameter %_ptr_Function_v4float
|
|
%28 = OpLabel
|
|
OpBranch %29
|
|
%29 = OpLabel
|
|
OpLoopMerge %30 %31 None
|
|
OpBranch %32
|
|
%32 = OpLabel
|
|
OpBranchConditional %true %33 %30
|
|
%33 = OpLabel
|
|
%34 = OpAccessChain %_ptr_Function_float %bar %uint_0
|
|
%35 = OpLoad %float %34
|
|
%36 = OpFOrdLessThan %bool %35 %float_0
|
|
OpSelectionMerge %37 None
|
|
OpBranchConditional %36 %38 %37
|
|
%38 = OpLabel
|
|
OpReturnValue %float_0
|
|
%37 = OpLabel
|
|
%39 = OpAccessChain %_ptr_Function_float %bar %uint_0
|
|
%40 = OpLoad %float %39
|
|
OpReturnValue %40
|
|
%31 = OpLabel
|
|
OpBranch %29
|
|
%30 = OpLabel
|
|
%41 = OpUndef %float
|
|
OpReturnValue %41
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(assembly, assembly, false, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, ExternalFunctionIsNotInlined) {
|
|
// In particular, don't crash.
|
|
// See report https://github.com/KhronosGroup/SPIRV-Tools/issues/605
|
|
const std::string assembly =
|
|
R"(OpCapability Addresses
|
|
OpCapability Kernel
|
|
OpCapability Linkage
|
|
OpMemoryModel Physical32 OpenCL
|
|
OpEntryPoint Kernel %1 "entry_pt"
|
|
OpDecorate %2 LinkageAttributes "external" Import
|
|
%void = OpTypeVoid
|
|
%4 = OpTypeFunction %void
|
|
%2 = OpFunction %void None %4
|
|
OpFunctionEnd
|
|
%1 = OpFunction %void None %4
|
|
%5 = OpLabel
|
|
%6 = OpFunctionCall %void %2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(assembly, assembly, false, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, SingleBlockLoopCallsMultiBlockCallee) {
|
|
// Example from https://github.com/KhronosGroup/SPIRV-Tools/issues/787
|
|
//
|
|
// CFG structure is:
|
|
// foo:
|
|
// fooentry -> fooexit
|
|
//
|
|
// main:
|
|
// entry -> loop
|
|
// loop -> loop, merge
|
|
// loop calls foo()
|
|
// merge
|
|
//
|
|
// Since the callee has multiple blocks, it will split the calling block
|
|
// into at least two, resulting in a new "back-half" block that contains
|
|
// the instructions after the inlined function call. If the calling block
|
|
// has an OpLoopMerge that points back to the calling block itself, then
|
|
// the OpLoopMerge can't remain in the back-half block, but must be
|
|
// moved to the end of the original calling block, and it continue target
|
|
// operand updated to point to the back-half block.
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %1 "main"
|
|
OpSource OpenCL_C 120
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%void = OpTypeVoid
|
|
)";
|
|
|
|
const std::string nonEntryFuncs =
|
|
R"(%5 = OpTypeFunction %void
|
|
%6 = OpFunction %void None %5
|
|
%7 = OpLabel
|
|
OpBranch %8
|
|
%8 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%1 = OpFunction %void None %5
|
|
%9 = OpLabel
|
|
OpBranch %10
|
|
%10 = OpLabel
|
|
%11 = OpFunctionCall %void %6
|
|
OpLoopMerge %12 %10 None
|
|
OpBranchConditional %true %10 %12
|
|
%12 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%1 = OpFunction %void None %5
|
|
%9 = OpLabel
|
|
OpBranch %10
|
|
%10 = OpLabel
|
|
OpLoopMerge %12 %10 None
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
OpBranchConditional %true %10 %12
|
|
%12 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
|
|
predefs + nonEntryFuncs + after,
|
|
false, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, MultiBlockLoopHeaderCallsMultiBlockCallee) {
|
|
// Like SingleBlockLoopCallsMultiBlockCallee but the loop has several
|
|
// blocks, but the function call still occurs in the loop header.
|
|
// Example from https://github.com/KhronosGroup/SPIRV-Tools/issues/800
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %1 "main"
|
|
OpSource OpenCL_C 120
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%int = OpTypeInt 32 1
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%int_3 = OpConstant %int 3
|
|
%int_4 = OpConstant %int 4
|
|
%int_5 = OpConstant %int 5
|
|
%void = OpTypeVoid
|
|
%11 = OpTypeFunction %void
|
|
)";
|
|
|
|
const std::string nonEntryFuncs =
|
|
R"(%12 = OpFunction %void None %11
|
|
%13 = OpLabel
|
|
%14 = OpCopyObject %int %int_1
|
|
OpBranch %15
|
|
%15 = OpLabel
|
|
%16 = OpCopyObject %int %int_2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%1 = OpFunction %void None %11
|
|
%17 = OpLabel
|
|
OpBranch %18
|
|
%18 = OpLabel
|
|
%19 = OpCopyObject %int %int_3
|
|
%20 = OpFunctionCall %void %12
|
|
%21 = OpCopyObject %int %int_4
|
|
OpLoopMerge %22 %23 None
|
|
OpBranchConditional %true %23 %22
|
|
%23 = OpLabel
|
|
%24 = OpCopyObject %int %int_5
|
|
OpBranchConditional %true %18 %22
|
|
%22 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%1 = OpFunction %void None %11
|
|
%17 = OpLabel
|
|
OpBranch %18
|
|
%18 = OpLabel
|
|
%19 = OpCopyObject %int %int_3
|
|
%26 = OpCopyObject %int %int_1
|
|
OpLoopMerge %22 %23 None
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
%28 = OpCopyObject %int %int_2
|
|
%21 = OpCopyObject %int %int_4
|
|
OpBranchConditional %true %23 %22
|
|
%23 = OpLabel
|
|
%24 = OpCopyObject %int %int_5
|
|
OpBranchConditional %true %18 %22
|
|
%22 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
|
|
predefs + nonEntryFuncs + after,
|
|
false, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, SingleBlockLoopCallsMultiBlockCalleeHavingSelectionMerge) {
|
|
// This is similar to SingleBlockLoopCallsMultiBlockCallee except
|
|
// that calleee block also has a merge instruction in its first block.
|
|
// That merge instruction must be an OpSelectionMerge (because the entry
|
|
// block of a function can't be the header of a loop since the entry
|
|
// block can't be the target of a branch).
|
|
//
|
|
// In this case the OpLoopMerge can't be placed in the same block as
|
|
// the OpSelectionMerge, so inlining must create a new block to contain
|
|
// the callee contents.
|
|
//
|
|
// Additionally, we have two dummy OpCopyObject instructions to prove that
|
|
// the OpLoopMerge is moved to the right location.
|
|
//
|
|
// Also ensure that OpPhis within the cloned callee code are valid.
|
|
// We need to test that the predecessor blocks are remapped correctly so that
|
|
// dominance rules are satisfied
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %1 "main"
|
|
OpSource OpenCL_C 120
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%false = OpConstantFalse %bool
|
|
%void = OpTypeVoid
|
|
%6 = OpTypeFunction %void
|
|
)";
|
|
|
|
// This callee has multiple blocks, and an OpPhi in the last block
|
|
// that references a value from the first block. This tests that
|
|
// cloned block IDs are remapped appropriately. The OpPhi dominance
|
|
// requires that the remapped %9 must be in a block that dominates
|
|
// the remapped %8.
|
|
const std::string nonEntryFuncs =
|
|
R"(%7 = OpFunction %void None %6
|
|
%8 = OpLabel
|
|
%9 = OpCopyObject %bool %true
|
|
OpSelectionMerge %10 None
|
|
OpBranchConditional %true %10 %10
|
|
%10 = OpLabel
|
|
%11 = OpPhi %bool %9 %8
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%1 = OpFunction %void None %6
|
|
%12 = OpLabel
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
%14 = OpCopyObject %bool %false
|
|
%15 = OpFunctionCall %void %7
|
|
OpLoopMerge %16 %13 None
|
|
OpBranchConditional %true %13 %16
|
|
%16 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
// Note the remapped Phi uses %17 as the parent instead
|
|
// of %13, demonstrating that the parent block has been remapped
|
|
// correctly.
|
|
const std::string after =
|
|
R"(%1 = OpFunction %void None %6
|
|
%12 = OpLabel
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
%14 = OpCopyObject %bool %false
|
|
OpLoopMerge %16 %13 None
|
|
OpBranch %17
|
|
%17 = OpLabel
|
|
%19 = OpCopyObject %bool %true
|
|
OpSelectionMerge %20 None
|
|
OpBranchConditional %true %20 %20
|
|
%20 = OpLabel
|
|
%21 = OpPhi %bool %19 %17
|
|
OpBranchConditional %true %13 %16
|
|
%16 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
|
|
predefs + nonEntryFuncs + after,
|
|
false, true);
|
|
}
|
|
|
|
TEST_F(InlineTest,
|
|
MultiBlockLoopHeaderCallsFromToMultiBlockCalleeHavingSelectionMerge) {
|
|
// This is similar to SingleBlockLoopCallsMultiBlockCalleeHavingSelectionMerge
|
|
// but the call is in the header block of a multi block loop.
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint GLCompute %1 "main"
|
|
OpSource OpenCL_C 120
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%int = OpTypeInt 32 1
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%int_3 = OpConstant %int 3
|
|
%int_4 = OpConstant %int 4
|
|
%int_5 = OpConstant %int 5
|
|
%void = OpTypeVoid
|
|
%11 = OpTypeFunction %void
|
|
)";
|
|
|
|
const std::string nonEntryFuncs =
|
|
R"(%12 = OpFunction %void None %11
|
|
%13 = OpLabel
|
|
%14 = OpCopyObject %int %int_1
|
|
OpSelectionMerge %15 None
|
|
OpBranchConditional %true %15 %15
|
|
%15 = OpLabel
|
|
%16 = OpCopyObject %int %int_2
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%1 = OpFunction %void None %11
|
|
%17 = OpLabel
|
|
OpBranch %18
|
|
%18 = OpLabel
|
|
%19 = OpCopyObject %int %int_3
|
|
%20 = OpFunctionCall %void %12
|
|
%21 = OpCopyObject %int %int_4
|
|
OpLoopMerge %22 %23 None
|
|
OpBranchConditional %true %23 %22
|
|
%23 = OpLabel
|
|
%24 = OpCopyObject %int %int_5
|
|
OpBranchConditional %true %18 %22
|
|
%22 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%1 = OpFunction %void None %11
|
|
%17 = OpLabel
|
|
OpBranch %18
|
|
%18 = OpLabel
|
|
%19 = OpCopyObject %int %int_3
|
|
OpLoopMerge %22 %23 None
|
|
OpBranch %25
|
|
%25 = OpLabel
|
|
%27 = OpCopyObject %int %int_1
|
|
OpSelectionMerge %28 None
|
|
OpBranchConditional %true %28 %28
|
|
%28 = OpLabel
|
|
%29 = OpCopyObject %int %int_2
|
|
%21 = OpCopyObject %int %int_4
|
|
OpBranchConditional %true %23 %22
|
|
%23 = OpLabel
|
|
%24 = OpCopyObject %int %int_5
|
|
OpBranchConditional %true %18 %22
|
|
%22 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(predefs + nonEntryFuncs + before,
|
|
predefs + nonEntryFuncs + after,
|
|
false, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, NonInlinableCalleeWithSingleReturn) {
|
|
// The case from https://github.com/KhronosGroup/SPIRV-Tools/issues/2018
|
|
//
|
|
// The callee has a single return, but cannot be inlined because the
|
|
// return is inside a loop.
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %_GLF_color
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource ESSL 310
|
|
OpName %main "main"
|
|
OpName %f_ "f("
|
|
OpName %i "i"
|
|
OpName %_GLF_color "_GLF_color"
|
|
OpDecorate %_GLF_color Location 0
|
|
%void = OpTypeVoid
|
|
%7 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%9 = OpTypeFunction %float
|
|
%float_1 = OpConstant %float 1
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%int = OpTypeInt 32 1
|
|
%_ptr_Function_int = OpTypePointer Function %int
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%_GLF_color = OpVariable %_ptr_Output_v4float Output
|
|
%float_0 = OpConstant %float 0
|
|
%20 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
|
%21 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1
|
|
)";
|
|
|
|
const std::string caller =
|
|
R"(%main = OpFunction %void None %7
|
|
%22 = OpLabel
|
|
%i = OpVariable %_ptr_Function_int Function
|
|
OpStore %i %int_0
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
OpLoopMerge %24 %25 None
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%27 = OpLoad %int %i
|
|
%28 = OpSLessThan %bool %27 %int_1
|
|
OpBranchConditional %28 %29 %24
|
|
%29 = OpLabel
|
|
OpStore %_GLF_color %20
|
|
%30 = OpFunctionCall %float %f_
|
|
OpBranch %25
|
|
%25 = OpLabel
|
|
%31 = OpLoad %int %i
|
|
%32 = OpIAdd %int %31 %int_1
|
|
OpStore %i %32
|
|
OpBranch %23
|
|
%24 = OpLabel
|
|
OpStore %_GLF_color %21
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string callee =
|
|
R"(%f_ = OpFunction %float None %9
|
|
%33 = OpLabel
|
|
OpBranch %34
|
|
%34 = OpLabel
|
|
OpLoopMerge %35 %36 None
|
|
OpBranch %37
|
|
%37 = OpLabel
|
|
OpReturnValue %float_1
|
|
%36 = OpLabel
|
|
OpBranch %34
|
|
%35 = OpLabel
|
|
OpUnreachable
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(
|
|
predefs + caller + callee, predefs + caller + callee, false, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, Decorated1) {
|
|
// Same test as Simple with the difference
|
|
// that OpFAdd in the outlined function is
|
|
// decorated with RelaxedPrecision
|
|
// Expected result is an equal decoration
|
|
// of the corresponding inlined instruction
|
|
//
|
|
// #version 140
|
|
//
|
|
// in vec4 BaseColor;
|
|
//
|
|
// float foo(vec4 bar)
|
|
// {
|
|
// return bar.x + bar.y;
|
|
// }
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 color = vec4(foo(BaseColor));
|
|
// gl_FragColor = color;
|
|
// }
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
OpName %main "main"
|
|
OpName %foo_vf4_ "foo(vf4;"
|
|
OpName %bar "bar"
|
|
OpName %color "color"
|
|
OpName %BaseColor "BaseColor"
|
|
OpName %param "param"
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
OpDecorate %9 RelaxedPrecision
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%void = OpTypeVoid
|
|
%11 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%15 = OpTypeFunction %float %_ptr_Function_v4float
|
|
%uint = OpTypeInt 32 0
|
|
%uint_0 = OpConstant %uint 0
|
|
%_ptr_Function_float = OpTypePointer Function %float
|
|
%uint_1 = OpConstant %uint 1
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%BaseColor = OpVariable %_ptr_Input_v4float Input
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
|
%main = OpFunction %void None %11
|
|
%22 = OpLabel
|
|
%color = OpVariable %_ptr_Function_v4float Function
|
|
%param = OpVariable %_ptr_Function_v4float Function
|
|
%23 = OpLoad %v4float %BaseColor
|
|
OpStore %param %23
|
|
%24 = OpFunctionCall %float %foo_vf4_ %param
|
|
%25 = OpCompositeConstruct %v4float %24 %24 %24 %24
|
|
OpStore %color %25
|
|
%26 = OpLoad %v4float %color
|
|
OpStore %gl_FragColor %26
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(OpDecorate %38 RelaxedPrecision
|
|
%void = OpTypeVoid
|
|
%11 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%15 = OpTypeFunction %float %_ptr_Function_v4float
|
|
%uint = OpTypeInt 32 0
|
|
%uint_0 = OpConstant %uint 0
|
|
%_ptr_Function_float = OpTypePointer Function %float
|
|
%uint_1 = OpConstant %uint 1
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%BaseColor = OpVariable %_ptr_Input_v4float Input
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
|
%main = OpFunction %void None %11
|
|
%22 = OpLabel
|
|
%32 = OpVariable %_ptr_Function_float Function
|
|
%color = OpVariable %_ptr_Function_v4float Function
|
|
%param = OpVariable %_ptr_Function_v4float Function
|
|
%23 = OpLoad %v4float %BaseColor
|
|
OpStore %param %23
|
|
%34 = OpAccessChain %_ptr_Function_float %param %uint_0
|
|
%35 = OpLoad %float %34
|
|
%36 = OpAccessChain %_ptr_Function_float %param %uint_1
|
|
%37 = OpLoad %float %36
|
|
%38 = OpFAdd %float %35 %37
|
|
OpStore %32 %38
|
|
%24 = OpLoad %float %32
|
|
%25 = OpCompositeConstruct %v4float %24 %24 %24 %24
|
|
OpStore %color %25
|
|
%26 = OpLoad %v4float %color
|
|
OpStore %gl_FragColor %26
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string nonEntryFuncs =
|
|
R"(%foo_vf4_ = OpFunction %float None %15
|
|
%bar = OpFunctionParameter %_ptr_Function_v4float
|
|
%27 = OpLabel
|
|
%28 = OpAccessChain %_ptr_Function_float %bar %uint_0
|
|
%29 = OpLoad %float %28
|
|
%30 = OpAccessChain %_ptr_Function_float %bar %uint_1
|
|
%31 = OpLoad %float %30
|
|
%9 = OpFAdd %float %29 %31
|
|
OpReturnValue %9
|
|
OpFunctionEnd
|
|
)";
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(predefs + before + nonEntryFuncs,
|
|
predefs + after + nonEntryFuncs,
|
|
false, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, Decorated2) {
|
|
// Same test as Simple with the difference
|
|
// that the Result <id> of the outlined OpFunction
|
|
// is decorated with RelaxedPrecision
|
|
// Expected result is an equal decoration
|
|
// of the created return variable
|
|
//
|
|
// #version 140
|
|
//
|
|
// in vec4 BaseColor;
|
|
//
|
|
// float foo(vec4 bar)
|
|
// {
|
|
// return bar.x + bar.y;
|
|
// }
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 color = vec4(foo(BaseColor));
|
|
// gl_FragColor = color;
|
|
// }
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
OpName %main "main"
|
|
OpName %foo_vf4_ "foo(vf4;"
|
|
OpName %bar "bar"
|
|
OpName %color "color"
|
|
OpName %BaseColor "BaseColor"
|
|
OpName %param "param"
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
OpDecorate %foo_vf4_ RelaxedPrecision
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%void = OpTypeVoid
|
|
%10 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%14 = OpTypeFunction %float %_ptr_Function_v4float
|
|
%uint = OpTypeInt 32 0
|
|
%uint_0 = OpConstant %uint 0
|
|
%_ptr_Function_float = OpTypePointer Function %float
|
|
%uint_1 = OpConstant %uint 1
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%BaseColor = OpVariable %_ptr_Input_v4float Input
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
|
%main = OpFunction %void None %10
|
|
%21 = OpLabel
|
|
%color = OpVariable %_ptr_Function_v4float Function
|
|
%param = OpVariable %_ptr_Function_v4float Function
|
|
%22 = OpLoad %v4float %BaseColor
|
|
OpStore %param %22
|
|
%23 = OpFunctionCall %float %foo_vf4_ %param
|
|
%24 = OpCompositeConstruct %v4float %23 %23 %23 %23
|
|
OpStore %color %24
|
|
%25 = OpLoad %v4float %color
|
|
OpStore %gl_FragColor %25
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(OpDecorate %32 RelaxedPrecision
|
|
%void = OpTypeVoid
|
|
%10 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%14 = OpTypeFunction %float %_ptr_Function_v4float
|
|
%uint = OpTypeInt 32 0
|
|
%uint_0 = OpConstant %uint 0
|
|
%_ptr_Function_float = OpTypePointer Function %float
|
|
%uint_1 = OpConstant %uint 1
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%BaseColor = OpVariable %_ptr_Input_v4float Input
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
|
%main = OpFunction %void None %10
|
|
%21 = OpLabel
|
|
%32 = OpVariable %_ptr_Function_float Function
|
|
%color = OpVariable %_ptr_Function_v4float Function
|
|
%param = OpVariable %_ptr_Function_v4float Function
|
|
%22 = OpLoad %v4float %BaseColor
|
|
OpStore %param %22
|
|
%34 = OpAccessChain %_ptr_Function_float %param %uint_0
|
|
%35 = OpLoad %float %34
|
|
%36 = OpAccessChain %_ptr_Function_float %param %uint_1
|
|
%37 = OpLoad %float %36
|
|
%38 = OpFAdd %float %35 %37
|
|
OpStore %32 %38
|
|
%23 = OpLoad %float %32
|
|
%24 = OpCompositeConstruct %v4float %23 %23 %23 %23
|
|
OpStore %color %24
|
|
%25 = OpLoad %v4float %color
|
|
OpStore %gl_FragColor %25
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string nonEntryFuncs =
|
|
R"(%foo_vf4_ = OpFunction %float None %14
|
|
%bar = OpFunctionParameter %_ptr_Function_v4float
|
|
%26 = OpLabel
|
|
%27 = OpAccessChain %_ptr_Function_float %bar %uint_0
|
|
%28 = OpLoad %float %27
|
|
%29 = OpAccessChain %_ptr_Function_float %bar %uint_1
|
|
%30 = OpLoad %float %29
|
|
%31 = OpFAdd %float %28 %30
|
|
OpReturnValue %31
|
|
OpFunctionEnd
|
|
)";
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(predefs + before + nonEntryFuncs,
|
|
predefs + after + nonEntryFuncs,
|
|
false, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, DeleteName) {
|
|
// Test that the name of the result id of the call is deleted.
|
|
const std::string before =
|
|
R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpName %main "main"
|
|
OpName %main_entry "main_entry"
|
|
OpName %foo_result "foo_result"
|
|
OpName %void_fn "void_fn"
|
|
OpName %foo "foo"
|
|
OpName %foo_entry "foo_entry"
|
|
%void = OpTypeVoid
|
|
%void_fn = OpTypeFunction %void
|
|
%foo = OpFunction %void None %void_fn
|
|
%foo_entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%main = OpFunction %void None %void_fn
|
|
%main_entry = OpLabel
|
|
%foo_result = OpFunctionCall %void %foo
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpName %main "main"
|
|
OpName %main_entry "main_entry"
|
|
OpName %void_fn "void_fn"
|
|
OpName %foo "foo"
|
|
OpName %foo_entry "foo_entry"
|
|
%void = OpTypeVoid
|
|
%void_fn = OpTypeFunction %void
|
|
%foo = OpFunction %void None %void_fn
|
|
%foo_entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%main = OpFunction %void None %void_fn
|
|
%main_entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(before, after, false, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, SetParent) {
|
|
// Test that after inlining all basic blocks have the correct parent.
|
|
const std::string text =
|
|
R"(
|
|
OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpName %main "main"
|
|
OpName %main_entry "main_entry"
|
|
OpName %foo_result "foo_result"
|
|
OpName %void_fn "void_fn"
|
|
OpName %foo "foo"
|
|
OpName %foo_entry "foo_entry"
|
|
%void = OpTypeVoid
|
|
%void_fn = OpTypeFunction %void
|
|
%foo = OpFunction %void None %void_fn
|
|
%foo_entry = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%main = OpFunction %void None %void_fn
|
|
%main_entry = OpLabel
|
|
%foo_result = OpFunctionCall %void %foo
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
|
|
InlineExhaustivePass pass;
|
|
pass.Run(context.get());
|
|
|
|
for (Function& func : *context->module()) {
|
|
for (BasicBlock& bb : func) {
|
|
EXPECT_TRUE(bb.GetParent() == &func);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(InlineTest, OpVariableWithInit) {
|
|
// Check that there is a store that corresponds to the initializer. This
|
|
// test makes sure that is a store to the variable in the loop and before any
|
|
// load.
|
|
const std::string text = R"(
|
|
; CHECK: OpFunction
|
|
; CHECK-NOT: OpFunctionEnd
|
|
; CHECK: [[var:%\w+]] = OpVariable %_ptr_Function_float Function %float_0
|
|
; CHECK: OpLoopMerge [[outer_merge:%\w+]]
|
|
; CHECK-NOT: OpLoad %float [[var]]
|
|
; CHECK: OpStore [[var]] %float_0
|
|
; CHECK: OpFunctionEnd
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %o
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 450
|
|
OpDecorate %o Location 0
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%7 = OpTypeFunction %float
|
|
%_ptr_Function_float = OpTypePointer Function %float
|
|
%float_0 = OpConstant %float 0
|
|
%bool = OpTypeBool
|
|
%float_1 = OpConstant %float 1
|
|
%_ptr_Output_float = OpTypePointer Output %float
|
|
%o = OpVariable %_ptr_Output_float Output
|
|
%int = OpTypeInt 32 1
|
|
%_ptr_Function_int = OpTypePointer Function %int
|
|
%_ptr_Input_int = OpTypePointer Input %int
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%int_2 = OpConstant %int 2
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpStore %o %float_0
|
|
OpBranch %34
|
|
%34 = OpLabel
|
|
%39 = OpPhi %int %int_0 %5 %47 %37
|
|
OpLoopMerge %36 %37 None
|
|
OpBranch %38
|
|
%38 = OpLabel
|
|
%41 = OpSLessThan %bool %39 %int_2
|
|
OpBranchConditional %41 %35 %36
|
|
%35 = OpLabel
|
|
%42 = OpFunctionCall %float %foo_
|
|
%43 = OpLoad %float %o
|
|
%44 = OpFAdd %float %43 %42
|
|
OpStore %o %44
|
|
OpBranch %37
|
|
%37 = OpLabel
|
|
%47 = OpIAdd %int %39 %int_1
|
|
OpBranch %34
|
|
%36 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%foo_ = OpFunction %float None %7
|
|
%9 = OpLabel
|
|
%n = OpVariable %_ptr_Function_float Function %float_0
|
|
%13 = OpLoad %float %n
|
|
%15 = OpFOrdEqual %bool %13 %float_0
|
|
OpSelectionMerge %17 None
|
|
OpBranchConditional %15 %16 %17
|
|
%16 = OpLabel
|
|
%19 = OpLoad %float %n
|
|
%20 = OpFAdd %float %19 %float_1
|
|
OpStore %n %20
|
|
OpBranch %17
|
|
%17 = OpLabel
|
|
%21 = OpLoad %float %n
|
|
OpReturnValue %21
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, DontInlineDirectlyRecursiveFunc) {
|
|
// Test that the name of the result id of the call is deleted.
|
|
const std::string test =
|
|
R"(OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
OpDecorate %2 DescriptorSet 439418829
|
|
%void = OpTypeVoid
|
|
%4 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%_struct_6 = OpTypeStruct %float %float
|
|
%15 = OpConstantNull %_struct_6
|
|
%7 = OpTypeFunction %_struct_6
|
|
%1 = OpFunction %void Pure|Const %4
|
|
%8 = OpLabel
|
|
%2 = OpFunctionCall %_struct_6 %9
|
|
OpKill
|
|
OpFunctionEnd
|
|
%9 = OpFunction %_struct_6 None %7
|
|
%10 = OpLabel
|
|
%11 = OpFunctionCall %_struct_6 %9
|
|
OpReturnValue %15
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(test, test, false, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, DontInlineInDirectlyRecursiveFunc) {
|
|
// Test that the name of the result id of the call is deleted.
|
|
const std::string test =
|
|
R"(OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %1 "main"
|
|
OpExecutionMode %1 OriginUpperLeft
|
|
OpDecorate %2 DescriptorSet 439418829
|
|
%void = OpTypeVoid
|
|
%4 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%_struct_6 = OpTypeStruct %float %float
|
|
%15 = OpConstantNull %_struct_6
|
|
%7 = OpTypeFunction %_struct_6
|
|
%1 = OpFunction %void Pure|Const %4
|
|
%8 = OpLabel
|
|
%2 = OpFunctionCall %_struct_6 %9
|
|
OpKill
|
|
OpFunctionEnd
|
|
%9 = OpFunction %_struct_6 None %7
|
|
%10 = OpLabel
|
|
%11 = OpFunctionCall %_struct_6 %12
|
|
OpReturnValue %15
|
|
OpFunctionEnd
|
|
%12 = OpFunction %_struct_6 None %7
|
|
%13 = OpLabel
|
|
%14 = OpFunctionCall %_struct_6 %9
|
|
OpReturnValue %15
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(test, test, false, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, DontInlineFuncWithOpKillInContinue) {
|
|
const std::string test =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 330
|
|
OpName %main "main"
|
|
OpName %kill_ "kill("
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpBranch %9
|
|
%9 = OpLabel
|
|
OpLoopMerge %11 %12 None
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
OpBranchConditional %true %10 %11
|
|
%10 = OpLabel
|
|
OpBranch %12
|
|
%12 = OpLabel
|
|
%16 = OpFunctionCall %void %kill_
|
|
OpBranch %9
|
|
%11 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%kill_ = OpFunction %void None %3
|
|
%7 = OpLabel
|
|
OpKill
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(test, test, false, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, InlineFuncWithOpKillNotInContinue) {
|
|
const std::string before =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 330
|
|
OpName %main "main"
|
|
OpName %kill_ "kill("
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
%16 = OpFunctionCall %void %kill_
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%kill_ = OpFunction %void None %3
|
|
%7 = OpLabel
|
|
OpKill
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main"
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 330
|
|
OpName %main "main"
|
|
OpName %kill_ "kill("
|
|
%void = OpTypeVoid
|
|
%3 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%main = OpFunction %void None %3
|
|
%5 = OpLabel
|
|
OpKill
|
|
%18 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%kill_ = OpFunction %void None %3
|
|
%7 = OpLabel
|
|
OpKill
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
SinglePassRunAndCheck<InlineExhaustivePass>(before, after, false, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, EarlyReturnFunctionInlined) {
|
|
// #version 140
|
|
//
|
|
// in vec4 BaseColor;
|
|
//
|
|
// float foo(vec4 bar)
|
|
// {
|
|
// if (bar.x < 0.0)
|
|
// return 0.0;
|
|
// return bar.x;
|
|
// }
|
|
//
|
|
// void main()
|
|
// {
|
|
// vec4 color = vec4(foo(BaseColor));
|
|
// gl_FragColor = color;
|
|
// }
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource GLSL 140
|
|
OpName %main "main"
|
|
OpName %foo_vf4_ "foo(vf4;"
|
|
OpName %bar "bar"
|
|
OpName %color "color"
|
|
OpName %BaseColor "BaseColor"
|
|
OpName %param "param"
|
|
OpName %gl_FragColor "gl_FragColor"
|
|
%void = OpTypeVoid
|
|
%10 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%14 = OpTypeFunction %float %_ptr_Function_v4float
|
|
%uint = OpTypeInt 32 0
|
|
%uint_0 = OpConstant %uint 0
|
|
%_ptr_Function_float = OpTypePointer Function %float
|
|
%float_0 = OpConstant %float 0
|
|
%bool = OpTypeBool
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%BaseColor = OpVariable %_ptr_Input_v4float Input
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
|
)";
|
|
|
|
const std::string foo =
|
|
R"(%foo_vf4_ = OpFunction %float None %14
|
|
%bar = OpFunctionParameter %_ptr_Function_v4float
|
|
%27 = OpLabel
|
|
%28 = OpAccessChain %_ptr_Function_float %bar %uint_0
|
|
%29 = OpLoad %float %28
|
|
%30 = OpFOrdLessThan %bool %29 %float_0
|
|
OpSelectionMerge %31 None
|
|
OpBranchConditional %30 %32 %31
|
|
%32 = OpLabel
|
|
OpReturnValue %float_0
|
|
%31 = OpLabel
|
|
%33 = OpAccessChain %_ptr_Function_float %bar %uint_0
|
|
%34 = OpLoad %float %33
|
|
OpReturnValue %34
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string fooMergeReturn =
|
|
R"(%foo_vf4_ = OpFunction %float None %14
|
|
%bar = OpFunctionParameter %_ptr_Function_v4float
|
|
%27 = OpLabel
|
|
%41 = OpVariable %_ptr_Function_bool Function %false
|
|
%36 = OpVariable %_ptr_Function_float Function
|
|
OpSelectionMerge %35 None
|
|
OpSwitch %uint_0 %38
|
|
%38 = OpLabel
|
|
%28 = OpAccessChain %_ptr_Function_float %bar %uint_0
|
|
%29 = OpLoad %float %28
|
|
%30 = OpFOrdLessThan %bool %29 %float_0
|
|
OpSelectionMerge %31 None
|
|
OpBranchConditional %30 %32 %31
|
|
%32 = OpLabel
|
|
OpStore %41 %true
|
|
OpStore %36 %float_0
|
|
OpBranch %35
|
|
%31 = OpLabel
|
|
%33 = OpAccessChain %_ptr_Function_float %bar %uint_0
|
|
%34 = OpLoad %float %33
|
|
OpStore %41 %true
|
|
OpStore %36 %34
|
|
OpBranch %35
|
|
%35 = OpLabel
|
|
%37 = OpLoad %float %36
|
|
OpReturnValue %37
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%main = OpFunction %void None %10
|
|
%22 = OpLabel
|
|
%color = OpVariable %_ptr_Function_v4float Function
|
|
%param = OpVariable %_ptr_Function_v4float Function
|
|
%23 = OpLoad %v4float %BaseColor
|
|
OpStore %param %23
|
|
%24 = OpFunctionCall %float %foo_vf4_ %param
|
|
%25 = OpCompositeConstruct %v4float %24 %24 %24 %24
|
|
OpStore %color %25
|
|
%26 = OpLoad %v4float %color
|
|
OpStore %gl_FragColor %26
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%false = OpConstantFalse %bool
|
|
%_ptr_Function_bool = OpTypePointer Function %bool
|
|
%true = OpConstantTrue %bool
|
|
%main = OpFunction %void None %10
|
|
%22 = OpLabel
|
|
%43 = OpVariable %_ptr_Function_bool Function %false
|
|
%44 = OpVariable %_ptr_Function_float Function
|
|
%45 = OpVariable %_ptr_Function_float Function
|
|
%color = OpVariable %_ptr_Function_v4float Function
|
|
%param = OpVariable %_ptr_Function_v4float Function
|
|
%23 = OpLoad %v4float %BaseColor
|
|
OpStore %param %23
|
|
OpStore %43 %false
|
|
OpSelectionMerge %55 None
|
|
OpSwitch %uint_0 %47
|
|
%47 = OpLabel
|
|
%48 = OpAccessChain %_ptr_Function_float %param %uint_0
|
|
%49 = OpLoad %float %48
|
|
%50 = OpFOrdLessThan %bool %49 %float_0
|
|
OpSelectionMerge %52 None
|
|
OpBranchConditional %50 %51 %52
|
|
%51 = OpLabel
|
|
OpStore %43 %true
|
|
OpStore %44 %float_0
|
|
OpBranch %55
|
|
%52 = OpLabel
|
|
%53 = OpAccessChain %_ptr_Function_float %param %uint_0
|
|
%54 = OpLoad %float %53
|
|
OpStore %43 %true
|
|
OpStore %44 %54
|
|
OpBranch %55
|
|
%55 = OpLabel
|
|
%56 = OpLoad %float %44
|
|
OpStore %45 %56
|
|
%24 = OpLoad %float %45
|
|
%25 = OpCompositeConstruct %v4float %24 %24 %24 %24
|
|
OpStore %color %25
|
|
%26 = OpLoad %v4float %color
|
|
OpStore %gl_FragColor %26
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
// The early return case must be handled by merge-return first.
|
|
AddPass<MergeReturnPass>();
|
|
AddPass<InlineExhaustivePass>();
|
|
RunAndCheck(predefs + before + foo, predefs + after + fooMergeReturn);
|
|
}
|
|
|
|
TEST_F(InlineTest, EarlyReturnNotAppearingLastInFunctionInlined) {
|
|
// Example from https://github.com/KhronosGroup/SPIRV-Tools/issues/755
|
|
//
|
|
// Original example is derived from:
|
|
//
|
|
// #version 450
|
|
//
|
|
// float foo() {
|
|
// if (true) {
|
|
// }
|
|
// }
|
|
//
|
|
// void main() { foo(); }
|
|
//
|
|
// But the order of basic blocks in foo is changed so that the return
|
|
// block is listed second-last. There is only one return in the callee
|
|
// but it does not appear last.
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource GLSL 450
|
|
OpName %main "main"
|
|
OpName %foo_ "foo("
|
|
%void = OpTypeVoid
|
|
%4 = OpTypeFunction %void
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
)";
|
|
|
|
const std::string foo =
|
|
R"(%foo_ = OpFunction %void None %4
|
|
%7 = OpLabel
|
|
OpSelectionMerge %8 None
|
|
OpBranchConditional %true %9 %8
|
|
%8 = OpLabel
|
|
OpReturn
|
|
%9 = OpLabel
|
|
OpBranch %8
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string fooMergeReturn =
|
|
R"(%uint = OpTypeInt 32 0
|
|
%uint_0 = OpConstant %uint 0
|
|
%false = OpConstantFalse %bool
|
|
%_ptr_Function_bool = OpTypePointer Function %bool
|
|
%foo_ = OpFunction %void None %4
|
|
%7 = OpLabel
|
|
%18 = OpVariable %_ptr_Function_bool Function %false
|
|
OpSelectionMerge %12 None
|
|
OpSwitch %uint_0 %13
|
|
%13 = OpLabel
|
|
OpSelectionMerge %8 None
|
|
OpBranchConditional %true %9 %8
|
|
%8 = OpLabel
|
|
OpStore %18 %true
|
|
OpBranch %12
|
|
%9 = OpLabel
|
|
OpBranch %8
|
|
%12 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%main = OpFunction %void None %4
|
|
%10 = OpLabel
|
|
%11 = OpFunctionCall %void %foo_
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %4
|
|
%10 = OpLabel
|
|
%19 = OpVariable %_ptr_Function_bool Function %false
|
|
OpStore %19 %false
|
|
OpSelectionMerge %24 None
|
|
OpSwitch %uint_0 %21
|
|
%21 = OpLabel
|
|
OpSelectionMerge %22 None
|
|
OpBranchConditional %true %23 %22
|
|
%22 = OpLabel
|
|
OpStore %19 %true
|
|
OpBranch %24
|
|
%23 = OpLabel
|
|
OpBranch %22
|
|
%24 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
// The early return case must be handled by merge-return first.
|
|
AddPass<MergeReturnPass>();
|
|
AddPass<InlineExhaustivePass>();
|
|
RunAndCheck(predefs + foo + before, predefs + fooMergeReturn + after);
|
|
}
|
|
|
|
TEST_F(InlineTest, CalleeWithSingleReturnNeedsSingleTripLoopWrapper) {
|
|
// The case from https://github.com/KhronosGroup/SPIRV-Tools/issues/2018
|
|
//
|
|
// The callee has a single return, but needs single-trip loop wrapper
|
|
// to be inlined because the return is in a selection structure.
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %_GLF_color
|
|
OpExecutionMode %main OriginUpperLeft
|
|
OpSource ESSL 310
|
|
OpName %main "main"
|
|
OpName %f_ "f("
|
|
OpName %i "i"
|
|
OpName %_GLF_color "_GLF_color"
|
|
OpDecorate %_GLF_color Location 0
|
|
%void = OpTypeVoid
|
|
%7 = OpTypeFunction %void
|
|
%float = OpTypeFloat 32
|
|
%9 = OpTypeFunction %float
|
|
%float_1 = OpConstant %float 1
|
|
%bool = OpTypeBool
|
|
%false = OpConstantFalse %bool
|
|
%true = OpConstantTrue %bool
|
|
%int = OpTypeInt 32 1
|
|
%_ptr_Function_int = OpTypePointer Function %int
|
|
%int_0 = OpConstant %int 0
|
|
%int_1 = OpConstant %int 1
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%_GLF_color = OpVariable %_ptr_Output_v4float Output
|
|
%float_0 = OpConstant %float 0
|
|
%21 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
|
%22 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1
|
|
)";
|
|
|
|
const std::string new_predefs =
|
|
R"(%_ptr_Function_float = OpTypePointer Function %float
|
|
%uint = OpTypeInt 32 0
|
|
%uint_0 = OpConstant %uint 0
|
|
%_ptr_Function_bool = OpTypePointer Function %bool
|
|
)";
|
|
|
|
const std::string main_before =
|
|
R"(%main = OpFunction %void None %7
|
|
%23 = OpLabel
|
|
%i = OpVariable %_ptr_Function_int Function
|
|
OpStore %i %int_0
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
OpLoopMerge %25 %26 None
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
%28 = OpLoad %int %i
|
|
%29 = OpSLessThan %bool %28 %int_1
|
|
OpBranchConditional %29 %30 %25
|
|
%30 = OpLabel
|
|
OpStore %_GLF_color %21
|
|
%31 = OpFunctionCall %float %f_
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%32 = OpLoad %int %i
|
|
%33 = OpIAdd %int %32 %int_1
|
|
OpStore %i %33
|
|
OpBranch %24
|
|
%25 = OpLabel
|
|
OpStore %_GLF_color %22
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string main_after =
|
|
R"(%main = OpFunction %void None %7
|
|
%23 = OpLabel
|
|
%46 = OpVariable %_ptr_Function_bool Function %false
|
|
%47 = OpVariable %_ptr_Function_float Function
|
|
%48 = OpVariable %_ptr_Function_float Function
|
|
%i = OpVariable %_ptr_Function_int Function
|
|
OpStore %i %int_0
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
OpLoopMerge %25 %26 None
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
%28 = OpLoad %int %i
|
|
%29 = OpSLessThan %bool %28 %int_1
|
|
OpBranchConditional %29 %30 %25
|
|
%30 = OpLabel
|
|
OpStore %_GLF_color %21
|
|
OpStore %46 %false
|
|
OpSelectionMerge %53 None
|
|
OpSwitch %uint_0 %50
|
|
%50 = OpLabel
|
|
OpSelectionMerge %52 None
|
|
OpBranchConditional %true %51 %52
|
|
%51 = OpLabel
|
|
OpStore %46 %true
|
|
OpStore %47 %float_1
|
|
OpBranch %53
|
|
%52 = OpLabel
|
|
OpStore %46 %true
|
|
OpStore %47 %float_1
|
|
OpBranch %53
|
|
%53 = OpLabel
|
|
%54 = OpLoad %float %47
|
|
OpStore %48 %54
|
|
%31 = OpLoad %float %48
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%32 = OpLoad %int %i
|
|
%33 = OpIAdd %int %32 %int_1
|
|
OpStore %i %33
|
|
OpBranch %24
|
|
%25 = OpLabel
|
|
OpStore %_GLF_color %22
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string callee =
|
|
R"(%f_ = OpFunction %float None %9
|
|
%34 = OpLabel
|
|
OpSelectionMerge %35 None
|
|
OpBranchConditional %true %36 %35
|
|
%36 = OpLabel
|
|
OpReturnValue %float_1
|
|
%35 = OpLabel
|
|
OpReturnValue %float_1
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string calleeMergeReturn =
|
|
R"(%f_ = OpFunction %float None %9
|
|
%34 = OpLabel
|
|
%45 = OpVariable %_ptr_Function_bool Function %false
|
|
%39 = OpVariable %_ptr_Function_float Function
|
|
OpSelectionMerge %37 None
|
|
OpSwitch %uint_0 %41
|
|
%41 = OpLabel
|
|
OpSelectionMerge %35 None
|
|
OpBranchConditional %true %36 %35
|
|
%36 = OpLabel
|
|
OpStore %45 %true
|
|
OpStore %39 %float_1
|
|
OpBranch %37
|
|
%35 = OpLabel
|
|
OpStore %45 %true
|
|
OpStore %39 %float_1
|
|
OpBranch %37
|
|
%37 = OpLabel
|
|
%40 = OpLoad %float %39
|
|
OpReturnValue %40
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
// The early return case must be handled by merge-return first.
|
|
AddPass<MergeReturnPass>();
|
|
AddPass<InlineExhaustivePass>();
|
|
RunAndCheck(predefs + main_before + callee,
|
|
predefs + new_predefs + main_after + calleeMergeReturn);
|
|
}
|
|
|
|
TEST_F(InlineTest, ForwardReferencesInPhiInlined) {
|
|
// The basic structure of the test case is like this:
|
|
//
|
|
// int foo() {
|
|
// int result = 1;
|
|
// if (true) {
|
|
// result = 1;
|
|
// }
|
|
// return result;
|
|
// }
|
|
//
|
|
// void main() {
|
|
// int x = foo();
|
|
// }
|
|
//
|
|
// but with modifications: Using Phi instead of load/store, and the
|
|
// return block in foo appears before the "then" block.
|
|
|
|
const std::string predefs =
|
|
R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Vertex %main "main"
|
|
OpSource GLSL 450
|
|
OpName %main "main"
|
|
OpName %foo_ "foo("
|
|
OpName %x "x"
|
|
%void = OpTypeVoid
|
|
%6 = OpTypeFunction %void
|
|
%int = OpTypeInt 32 1
|
|
%8 = OpTypeFunction %int
|
|
%bool = OpTypeBool
|
|
%true = OpConstantTrue %bool
|
|
%int_0 = OpConstant %int 0
|
|
%_ptr_Function_int = OpTypePointer Function %int
|
|
)";
|
|
|
|
const std::string callee =
|
|
R"(%foo_ = OpFunction %int None %8
|
|
%13 = OpLabel
|
|
%14 = OpCopyObject %int %int_0
|
|
OpSelectionMerge %15 None
|
|
OpBranchConditional %true %16 %15
|
|
%15 = OpLabel
|
|
%17 = OpPhi %int %14 %13 %18 %16
|
|
OpReturnValue %17
|
|
%16 = OpLabel
|
|
%18 = OpCopyObject %int %int_0
|
|
OpBranch %15
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string calleeMergeReturn =
|
|
R"(%uint = OpTypeInt 32 0
|
|
%uint_0 = OpConstant %uint 0
|
|
%false = OpConstantFalse %bool
|
|
%_ptr_Function_bool = OpTypePointer Function %bool
|
|
%foo_ = OpFunction %int None %8
|
|
%13 = OpLabel
|
|
%29 = OpVariable %_ptr_Function_bool Function %false
|
|
%22 = OpVariable %_ptr_Function_int Function
|
|
OpSelectionMerge %21 None
|
|
OpSwitch %uint_0 %24
|
|
%24 = OpLabel
|
|
%14 = OpCopyObject %int %int_0
|
|
OpSelectionMerge %15 None
|
|
OpBranchConditional %true %16 %15
|
|
%15 = OpLabel
|
|
%17 = OpPhi %int %14 %24 %18 %16
|
|
OpStore %29 %true
|
|
OpStore %22 %17
|
|
OpBranch %21
|
|
%16 = OpLabel
|
|
%18 = OpCopyObject %int %int_0
|
|
OpBranch %15
|
|
%21 = OpLabel
|
|
%23 = OpLoad %int %22
|
|
OpReturnValue %23
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string before =
|
|
R"(%main = OpFunction %void None %6
|
|
%19 = OpLabel
|
|
%x = OpVariable %_ptr_Function_int Function
|
|
%20 = OpFunctionCall %int %foo_
|
|
OpStore %x %20
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string after =
|
|
R"(%main = OpFunction %void None %6
|
|
%19 = OpLabel
|
|
%30 = OpVariable %_ptr_Function_bool Function %false
|
|
%31 = OpVariable %_ptr_Function_int Function
|
|
%32 = OpVariable %_ptr_Function_int Function
|
|
%x = OpVariable %_ptr_Function_int Function
|
|
OpStore %30 %false
|
|
OpSelectionMerge %40 None
|
|
OpSwitch %uint_0 %34
|
|
%34 = OpLabel
|
|
%35 = OpCopyObject %int %int_0
|
|
OpSelectionMerge %36 None
|
|
OpBranchConditional %true %38 %36
|
|
%36 = OpLabel
|
|
%37 = OpPhi %int %35 %34 %39 %38
|
|
OpStore %30 %true
|
|
OpStore %31 %37
|
|
OpBranch %40
|
|
%38 = OpLabel
|
|
%39 = OpCopyObject %int %int_0
|
|
OpBranch %36
|
|
%40 = OpLabel
|
|
%41 = OpLoad %int %31
|
|
OpStore %32 %41
|
|
%20 = OpLoad %int %32
|
|
OpStore %x %20
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
AddPass<MergeReturnPass>();
|
|
AddPass<InlineExhaustivePass>();
|
|
RunAndCheck(predefs + callee + before, predefs + calleeMergeReturn + after);
|
|
}
|
|
|
|
TEST_F(InlineTest, DebugSimple) {
|
|
// Check that it correctly generates DebugInlinedAt and maps it to DebugScope
|
|
// for the inlined function foo().
|
|
const std::string text = R"(
|
|
; CHECK: [[main_name:%\d+]] = OpString "main"
|
|
; CHECK: [[foo_name:%\d+]] = OpString "foo"
|
|
; CHECK: [[dbg_main:%\d+]] = OpExtInst %void {{%\d+}} DebugFunction [[main_name]] {{%\d+}} {{%\d+}} 4 1 {{%\d+}} [[main_name]] FlagIsProtected|FlagIsPrivate 4 [[main:%\d+]]
|
|
; CHECK: [[dbg_foo:%\d+]] = OpExtInst %void {{%\d+}} DebugFunction [[foo_name]] {{%\d+}} {{%\d+}} 1 1 {{%\d+}} [[foo_name]] FlagIsProtected|FlagIsPrivate 1 [[foo:%\d+]]
|
|
; CHECK: [[foo_bb:%\d+]] = OpExtInst %void {{%\d+}} DebugLexicalBlock {{%\d+}} 1 14 [[dbg_foo]]
|
|
; CHECK: [[inlined_at:%\d+]] = OpExtInst %void {{%\d+}} DebugInlinedAt 4 [[dbg_main]]
|
|
; CHECK: [[main]] = OpFunction %void None
|
|
; CHECK: {{%\d+}} = OpExtInst %void {{%\d+}} DebugScope [[foo_bb]] [[inlined_at]]
|
|
; CHECK: [[foo]] = OpFunction %v4float None
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "OpenCL.DebugInfo.100"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %3 %4
|
|
OpExecutionMode %main OriginUpperLeft
|
|
%5 = OpString "ps.hlsl"
|
|
OpSource HLSL 600 %5
|
|
%6 = OpString "float"
|
|
%main_name = OpString "main"
|
|
%foo_name = OpString "foo"
|
|
OpDecorate %3 Location 0
|
|
OpDecorate %4 Location 0
|
|
%uint = OpTypeInt 32 0
|
|
%uint_32 = OpConstant %uint 32
|
|
%float = OpTypeFloat 32
|
|
%float_1 = OpConstant %float 1
|
|
%v4float = OpTypeVector %float 4
|
|
%14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%void = OpTypeVoid
|
|
%18 = OpTypeFunction %void
|
|
%19 = OpTypeFunction %v4float
|
|
%3 = OpVariable %_ptr_Input_v4float Input
|
|
%4 = OpVariable %_ptr_Output_v4float Output
|
|
%20 = OpExtInst %void %1 DebugSource %5
|
|
%21 = OpExtInst %void %1 DebugCompilationUnit 1 4 %20 HLSL
|
|
%22 = OpExtInst %void %1 DebugTypeBasic %6 %uint_32 Float
|
|
%23 = OpExtInst %void %1 DebugTypeVector %22 4
|
|
%24 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %23 %23
|
|
%25 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %23
|
|
%dbg_main = OpExtInst %void %1 DebugFunction %main_name %24 %20 4 1 %21 %main_name FlagIsProtected|FlagIsPrivate 4 %main
|
|
%dbg_foo = OpExtInst %void %1 DebugFunction %foo_name %25 %20 1 1 %21 %foo_name FlagIsProtected|FlagIsPrivate 1 %foo
|
|
%29 = OpExtInst %void %1 DebugLexicalBlock %20 1 14 %dbg_foo
|
|
%main = OpFunction %void None %18
|
|
%30 = OpLabel
|
|
%31 = OpExtInst %void %1 DebugScope %dbg_main
|
|
%32 = OpFunctionCall %v4float %foo
|
|
%33 = OpLoad %v4float %3
|
|
%34 = OpFAdd %v4float %32 %33
|
|
OpStore %4 %34
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%foo = OpFunction %v4float None %19
|
|
%35 = OpExtInst %void %1 DebugScope %dbg_foo
|
|
%36 = OpLabel
|
|
%37 = OpExtInst %void %1 DebugScope %29
|
|
OpReturnValue %14
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, DebugNested) {
|
|
// When function main() calls function zoo() and function zoo() calls
|
|
// function bar() and function bar() calls function foo(), check that
|
|
// the inline pass correctly generates DebugInlinedAt instructions
|
|
// for the nested function calls.
|
|
const std::string text = R"(
|
|
; CHECK: [[v4f1:%\d+]] = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
; CHECK: [[v4f2:%\d+]] = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
|
|
; CHECK: [[v4f3:%\d+]] = OpConstantComposite %v4float %float_3 %float_3 %float_3 %float_3
|
|
; CHECK: [[color:%\d+]] = OpVariable %_ptr_Input_v4float Input
|
|
; CHECK: [[dbg_main:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction {{%\d+}} {{%\d+}} {{%\d+}} 10 1 {{%\d+}} {{%\d+}} FlagIsProtected|FlagIsPrivate 10 [[main:%\d+]]
|
|
; CHECK: [[dbg_foo:%\d+]] = OpExtInst %void [[ext]] DebugFunction {{%\d+}} {{%\d+}} {{%\d+}} 1 1 {{%\d+}} {{%\d+}} FlagIsProtected|FlagIsPrivate 1 [[foo:%\d+]]
|
|
; CHECK: [[dbg_bar:%\d+]] = OpExtInst %void [[ext]] DebugFunction {{%\d+}} {{%\d+}} {{%\d+}} 4 1 {{%\d+}} {{%\d+}} FlagIsProtected|FlagIsPrivate 4 [[bar:%\d+]]
|
|
; CHECK: [[dbg_zoo:%\d+]] = OpExtInst %void [[ext]] DebugFunction {{%\d+}} {{%\d+}} {{%\d+}} 7 1 {{%\d+}} {{%\d+}} FlagIsProtected|FlagIsPrivate 7 [[zoo:%\d+]]
|
|
; CHECK: [[inlined_to_main:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 600 [[dbg_main]]
|
|
; CHECK: [[inlined_to_zoo:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 700 [[dbg_zoo]] [[inlined_to_main]]
|
|
; CHECK: [[inlined_to_bar:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 300 [[dbg_bar]] [[inlined_to_zoo]]
|
|
; CHECK: [[main]] = OpFunction %void None
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_foo]] [[inlined_to_bar]]
|
|
; CHECK-NEXT: OpLine {{%\d+}} 100 0
|
|
; CHECK-NEXT: OpStore {{%\d+}} [[v4f1]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_bar]] [[inlined_to_zoo]]
|
|
; CHECK-NEXT: OpLine {{%\d+}} 300 0
|
|
; CHECK-NEXT: [[foo_ret:%\d+]] = OpLoad %v4float
|
|
; CHECK-NEXT: OpLine {{%\d+}} 400 0
|
|
; CHECK-NEXT: {{%\d+}} = OpFAdd %v4float [[foo_ret]] [[v4f2]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_zoo]] [[inlined_to_main]]
|
|
; CHECK-NEXT: OpLine {{%\d+}} 700 0
|
|
; CHECK-NEXT: [[bar_ret:%\d+]] = OpLoad %v4float
|
|
; CHECK-NEXT: {{%\d+}} = OpFAdd %v4float [[bar_ret]] [[v4f3]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_main]]
|
|
; CHECK-NEXT: OpLine {{%\d+}} 600 0
|
|
; CHECK-NEXT: [[zoo_ret:%\d+]] = OpLoad %v4float
|
|
; CHECK-NEXT: [[color_val:%\d+]] = OpLoad %v4float [[color]]
|
|
; CHECK-NEXT: {{%\d+}} = OpFAdd %v4float [[zoo_ret]] [[color_val]]
|
|
; CHECK: [[foo]] = OpFunction %v4float None
|
|
; CHECK: [[bar]] = OpFunction %v4float None
|
|
; CHECK: [[zoo]] = OpFunction %v4float None
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "OpenCL.DebugInfo.100"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %3 %4
|
|
OpExecutionMode %main OriginUpperLeft
|
|
%5 = OpString "ps.hlsl"
|
|
OpSource HLSL 600 %5
|
|
%6 = OpString "float"
|
|
%7 = OpString "main"
|
|
%8 = OpString "foo"
|
|
%9 = OpString "bar"
|
|
%10 = OpString "zoo"
|
|
OpDecorate %3 Location 0
|
|
OpDecorate %4 Location 0
|
|
%uint = OpTypeInt 32 0
|
|
%uint_32 = OpConstant %uint 32
|
|
%float = OpTypeFloat 32
|
|
%float_1 = OpConstant %float 1
|
|
%float_2 = OpConstant %float 2
|
|
%float_3 = OpConstant %float 3
|
|
%v4float = OpTypeVector %float 4
|
|
%18 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%19 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
|
|
%20 = OpConstantComposite %v4float %float_3 %float_3 %float_3 %float_3
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%void = OpTypeVoid
|
|
%24 = OpTypeFunction %void
|
|
%25 = OpTypeFunction %v4float
|
|
%3 = OpVariable %_ptr_Input_v4float Input
|
|
%4 = OpVariable %_ptr_Output_v4float Output
|
|
%26 = OpExtInst %void %1 DebugSource %5
|
|
%27 = OpExtInst %void %1 DebugCompilationUnit 1 4 %26 HLSL
|
|
%28 = OpExtInst %void %1 DebugTypeBasic %6 %uint_32 Float
|
|
%29 = OpExtInst %void %1 DebugTypeVector %28 4
|
|
%30 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %29 %29
|
|
%31 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %29
|
|
%32 = OpExtInst %void %1 DebugFunction %7 %30 %26 10 1 %27 %7 FlagIsProtected|FlagIsPrivate 10 %main
|
|
%33 = OpExtInst %void %1 DebugFunction %8 %31 %26 1 1 %27 %8 FlagIsProtected|FlagIsPrivate 1 %foo
|
|
%35 = OpExtInst %void %1 DebugFunction %9 %31 %26 4 1 %27 %9 FlagIsProtected|FlagIsPrivate 4 %bar
|
|
%37 = OpExtInst %void %1 DebugFunction %10 %31 %26 7 1 %27 %10 FlagIsProtected|FlagIsPrivate 7 %zoo
|
|
%main = OpFunction %void None %24
|
|
%39 = OpLabel
|
|
%40 = OpExtInst %void %1 DebugScope %32
|
|
OpLine %5 600 0
|
|
%41 = OpFunctionCall %v4float %zoo
|
|
%42 = OpLoad %v4float %3
|
|
%43 = OpFAdd %v4float %41 %42
|
|
OpStore %4 %43
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%foo = OpFunction %v4float None %25
|
|
%44 = OpExtInst %void %1 DebugScope %33
|
|
%45 = OpLabel
|
|
OpLine %5 100 0
|
|
OpReturnValue %18
|
|
OpFunctionEnd
|
|
OpLine %5 200 0
|
|
%bar = OpFunction %v4float None %25
|
|
%46 = OpExtInst %void %1 DebugScope %35
|
|
%47 = OpLabel
|
|
OpLine %5 300 0
|
|
%48 = OpFunctionCall %v4float %foo
|
|
OpLine %5 400 0
|
|
%49 = OpFAdd %v4float %48 %19
|
|
OpLine %5 500 0
|
|
OpReturnValue %49
|
|
OpFunctionEnd
|
|
%zoo = OpFunction %v4float None %25
|
|
%50 = OpExtInst %void %1 DebugScope %37
|
|
%51 = OpLabel
|
|
OpLine %5 700 0
|
|
%52 = OpFunctionCall %v4float %bar
|
|
%53 = OpFAdd %v4float %52 %20
|
|
OpReturnValue %53
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, DebugSimpleHLSLPixelShader) {
|
|
const std::string text = R"(
|
|
; CHECK: [[dbg_main:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction {{%\d+}} {{%\d+}} {{%\d+}} 1 1 {{%\d+}} {{%\d+}} FlagIsProtected|FlagIsPrivate 1 %src_main
|
|
; CHECK: [[lex_blk:%\d+]] = OpExtInst %void [[ext]] DebugLexicalBlock {{%\d+}} 1 47 [[dbg_main]]
|
|
; CHECK: %main = OpFunction %void None
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_main]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugDeclare {{%\d+}} %param_var_color
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[lex_blk]]
|
|
; CHECK: OpLine {{%\d+}} 2 10
|
|
; CHECK: {{%\d+}} = OpLoad %v4float %param_var_color
|
|
; CHECK: OpLine {{%\d+}} 2 3
|
|
; CHECK: OpFunctionEnd
|
|
; CHECK: %src_main = OpFunction %v4float None
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "OpenCL.DebugInfo.100"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %in_var_COLOR %out_var_SV_TARGET
|
|
OpExecutionMode %main OriginUpperLeft
|
|
%5 = OpString "ps.hlsl"
|
|
OpSource HLSL 600 %5
|
|
%14 = OpString "#line 1 \"ps.hlsl\"
|
|
float4 main(float4 color : COLOR) : SV_TARGET {
|
|
return color;
|
|
}
|
|
"
|
|
%17 = OpString "float"
|
|
%21 = OpString "src.main"
|
|
%24 = OpString "color"
|
|
OpName %in_var_COLOR "in.var.COLOR"
|
|
OpName %out_var_SV_TARGET "out.var.SV_TARGET"
|
|
OpName %main "main"
|
|
OpName %param_var_color "param.var.color"
|
|
OpName %src_main "src.main"
|
|
OpName %color "color"
|
|
OpName %bb_entry "bb.entry"
|
|
OpDecorate %in_var_COLOR Location 0
|
|
OpDecorate %out_var_SV_TARGET Location 0
|
|
%uint = OpTypeInt 32 0
|
|
%uint_32 = OpConstant %uint 32
|
|
%float = OpTypeFloat 32
|
|
%v4float = OpTypeVector %float 4
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%void = OpTypeVoid
|
|
%27 = OpTypeFunction %void
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%33 = OpTypeFunction %v4float %_ptr_Function_v4float
|
|
%in_var_COLOR = OpVariable %_ptr_Input_v4float Input
|
|
%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
|
|
%13 = OpExtInst %void %1 DebugExpression
|
|
%15 = OpExtInst %void %1 DebugSource %5 %14
|
|
%16 = OpExtInst %void %1 DebugCompilationUnit 1 4 %15 HLSL
|
|
%18 = OpExtInst %void %1 DebugTypeBasic %17 %uint_32 Float
|
|
%19 = OpExtInst %void %1 DebugTypeVector %18 4
|
|
%20 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %19 %19
|
|
%22 = OpExtInst %void %1 DebugFunction %21 %20 %15 1 1 %16 %21 FlagIsProtected|FlagIsPrivate 1 %src_main
|
|
%25 = OpExtInst %void %1 DebugLocalVariable %24 %19 %15 1 20 %22 FlagIsLocal 0
|
|
%26 = OpExtInst %void %1 DebugLexicalBlock %15 1 47 %22
|
|
%main = OpFunction %void None %27
|
|
%28 = OpLabel
|
|
%param_var_color = OpVariable %_ptr_Function_v4float Function
|
|
%31 = OpLoad %v4float %in_var_COLOR
|
|
OpStore %param_var_color %31
|
|
%32 = OpFunctionCall %v4float %src_main %param_var_color
|
|
OpStore %out_var_SV_TARGET %32
|
|
OpReturn
|
|
OpFunctionEnd
|
|
OpLine %5 1 1
|
|
%src_main = OpFunction %v4float None %33
|
|
%34 = OpExtInst %void %1 DebugScope %22
|
|
%color = OpFunctionParameter %_ptr_Function_v4float
|
|
%36 = OpExtInst %void %1 DebugDeclare %25 %color %13
|
|
%bb_entry = OpLabel
|
|
%38 = OpExtInst %void %1 DebugScope %26
|
|
OpLine %5 2 10
|
|
%39 = OpLoad %v4float %color
|
|
OpLine %5 2 3
|
|
OpReturnValue %39
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, DebugDeclareForCalleeFunctionParam) {
|
|
// Check that InlinePass correctly generates DebugDeclare instructions
|
|
// for callee function's parameters and maps them to corresponding
|
|
// local variables of caller function.
|
|
const std::string text = R"(
|
|
; CHECK: [[add:%\d+]] = OpString "add"
|
|
; CHECK: [[a:%\d+]] = OpString "a"
|
|
; CHECK: [[b:%\d+]] = OpString "b"
|
|
; CHECK: [[dbg_add:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction [[add]]
|
|
; CHECK: [[dbg_a:%\d+]] = OpExtInst %void [[ext]] DebugLocalVariable [[a]]
|
|
; CHECK: [[dbg_b:%\d+]] = OpExtInst %void [[ext]] DebugLocalVariable [[b]]
|
|
; CHECK: [[inlinedat:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 5
|
|
; CHECK: OpStore [[param_a:%\d+]]
|
|
; CHECK: OpStore [[param_b:%\d+]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_add]] [[inlinedat]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugDeclare [[dbg_a]] [[param_a]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugDeclare [[dbg_b]] [[param_b]]
|
|
|
|
OpCapability Shader
|
|
%ext = OpExtInstImport "OpenCL.DebugInfo.100"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %in_var_COLOR %out_var_SV_TARGET
|
|
OpExecutionMode %main OriginUpperLeft
|
|
%file_name = OpString "ps.hlsl"
|
|
OpSource HLSL 600 %file_name
|
|
%float_name = OpString "float"
|
|
%main_name = OpString "main"
|
|
%add_name = OpString "add"
|
|
%a_name = OpString "a"
|
|
%b_name = OpString "b"
|
|
OpDecorate %in_var_COLOR Location 0
|
|
OpDecorate %out_var_SV_TARGET Location 0
|
|
%uint = OpTypeInt 32 0
|
|
%uint_32 = OpConstant %uint 32
|
|
%float = OpTypeFloat 32
|
|
%float_1 = OpConstant %float 1
|
|
%float_2 = OpConstant %float 2
|
|
%v4float = OpTypeVector %float 4
|
|
%v4f1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%v4f2 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%add_fn_type = OpTypeFunction %v4float %_ptr_Function_v4float %_ptr_Function_v4float
|
|
%void = OpTypeVoid
|
|
%void_fn_type = OpTypeFunction %void
|
|
%v4f_fn_type = OpTypeFunction %v4float
|
|
%in_var_COLOR = OpVariable %_ptr_Input_v4float Input
|
|
%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
|
|
%null_expr = OpExtInst %void %ext DebugExpression
|
|
%src = OpExtInst %void %ext DebugSource %file_name
|
|
%cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
|
|
%dbg_f = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
|
|
%dbg_v4f = OpExtInst %void %ext DebugTypeVector %dbg_f 4
|
|
%main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f
|
|
%add_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f %dbg_v4f
|
|
%dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 5 1 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
|
|
%dbg_add = OpExtInst %void %ext DebugFunction %add_name %add_ty %src 1 1 %cu %add_name FlagIsProtected|FlagIsPrivate 1 %add
|
|
%dbg_a = OpExtInst %void %ext DebugLocalVariable %a_name %dbg_v4f %src 1 13 %dbg_add FlagIsLocal 0
|
|
%dbg_b = OpExtInst %void %ext DebugLocalVariable %b_name %dbg_v4f %src 1 20 %dbg_add FlagIsLocal 1
|
|
%add_lb = OpExtInst %void %ext DebugLexicalBlock %src 1 23 %dbg_add
|
|
%main = OpFunction %void None %void_fn_type
|
|
%main_bb = OpLabel
|
|
%param_a = OpVariable %_ptr_Function_v4float Function
|
|
%param_b = OpVariable %_ptr_Function_v4float Function
|
|
%scope0 = OpExtInst %void %ext DebugScope %dbg_main
|
|
OpStore %param_a %v4f1
|
|
OpStore %param_b %v4f2
|
|
%result = OpFunctionCall %v4float %add %param_a %param_b
|
|
OpStore %out_var_SV_TARGET %result
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%add = OpFunction %v4float None %add_fn_type
|
|
%scope1 = OpExtInst %void %ext DebugScope %dbg_add
|
|
%a = OpFunctionParameter %_ptr_Function_v4float
|
|
%b = OpFunctionParameter %_ptr_Function_v4float
|
|
%decl0 = OpExtInst %void %ext DebugDeclare %dbg_a %a %null_expr
|
|
%decl1 = OpExtInst %void %ext DebugDeclare %dbg_b %b %null_expr
|
|
%add_bb = OpLabel
|
|
%scope2 = OpExtInst %void %ext DebugScope %add_lb
|
|
%a_val = OpLoad %v4float %a
|
|
%b_val = OpLoad %v4float %b
|
|
%res = OpFAdd %v4float %a_val %b_val
|
|
OpReturnValue %res
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, DebugDeclareForCalleeLocalVar) {
|
|
// Check that InlinePass correctly generates DebugDeclare instructions
|
|
// for callee function's local variables and maps them to corresponding
|
|
// local variables of caller function.
|
|
const std::string text = R"(
|
|
; CHECK: [[add:%\d+]] = OpString "add"
|
|
; CHECK: [[foo:%\d+]] = OpString "foo"
|
|
; CHECK: [[dbg_add:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction [[add]]
|
|
; CHECK: [[dbg_foo:%\d+]] = OpExtInst %void [[ext]] DebugLocalVariable [[foo]] {{%\d+}} {{%\d+}} 2 2 [[dbg_add]]
|
|
; CHECK: [[inlinedat:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 5
|
|
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_add]] [[inlinedat]]
|
|
; CHECK: [[new_foo:%\d+]] = OpVariable %_ptr_Function_v4float Function
|
|
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_add]] [[inlinedat]]
|
|
; CHECK: [[a_val:%\d+]] = OpLoad %v4float
|
|
; CHECK: [[b_val:%\d+]] = OpLoad %v4float
|
|
; CHECK: [[res:%\d+]] = OpFAdd %v4float [[a_val]] [[b_val]]
|
|
; CHECK: OpStore [[new_foo]] [[res]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugDeclare [[dbg_foo]] [[new_foo]]
|
|
|
|
OpCapability Shader
|
|
%ext = OpExtInstImport "OpenCL.DebugInfo.100"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %in_var_COLOR %out_var_SV_TARGET
|
|
OpExecutionMode %main OriginUpperLeft
|
|
%file_name = OpString "ps.hlsl"
|
|
OpSource HLSL 600 %file_name
|
|
%float_name = OpString "float"
|
|
%main_name = OpString "main"
|
|
%add_name = OpString "add"
|
|
%foo_name = OpString "foo"
|
|
OpDecorate %in_var_COLOR Location 0
|
|
OpDecorate %out_var_SV_TARGET Location 0
|
|
%uint = OpTypeInt 32 0
|
|
%uint_32 = OpConstant %uint 32
|
|
%float = OpTypeFloat 32
|
|
%float_1 = OpConstant %float 1
|
|
%float_2 = OpConstant %float 2
|
|
%v4float = OpTypeVector %float 4
|
|
%v4f1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%v4f2 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%add_fn_type = OpTypeFunction %v4float %_ptr_Function_v4float %_ptr_Function_v4float
|
|
%void = OpTypeVoid
|
|
%void_fn_type = OpTypeFunction %void
|
|
%v4f_fn_type = OpTypeFunction %v4float
|
|
%in_var_COLOR = OpVariable %_ptr_Input_v4float Input
|
|
%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
|
|
%null_expr = OpExtInst %void %ext DebugExpression
|
|
%src = OpExtInst %void %ext DebugSource %file_name
|
|
%cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
|
|
%dbg_f = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
|
|
%dbg_v4f = OpExtInst %void %ext DebugTypeVector %dbg_f 4
|
|
%main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f
|
|
%add_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f %dbg_v4f
|
|
%dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 5 1 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
|
|
%dbg_add = OpExtInst %void %ext DebugFunction %add_name %add_ty %src 1 1 %cu %add_name FlagIsProtected|FlagIsPrivate 1 %add
|
|
%dbg_foo = OpExtInst %void %ext DebugLocalVariable %foo_name %dbg_v4f %src 2 2 %dbg_add FlagIsLocal
|
|
%main = OpFunction %void None %void_fn_type
|
|
%main_bb = OpLabel
|
|
%param_a = OpVariable %_ptr_Function_v4float Function
|
|
%param_b = OpVariable %_ptr_Function_v4float Function
|
|
%scope0 = OpExtInst %void %ext DebugScope %dbg_main
|
|
OpStore %param_a %v4f1
|
|
OpStore %param_b %v4f2
|
|
%result = OpFunctionCall %v4float %add %param_a %param_b
|
|
OpStore %out_var_SV_TARGET %result
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%add = OpFunction %v4float None %add_fn_type
|
|
%scope1 = OpExtInst %void %ext DebugScope %dbg_add
|
|
%a = OpFunctionParameter %_ptr_Function_v4float
|
|
%b = OpFunctionParameter %_ptr_Function_v4float
|
|
%add_bb = OpLabel
|
|
%foo = OpVariable %_ptr_Function_v4float Function
|
|
%a_val = OpLoad %v4float %a
|
|
%b_val = OpLoad %v4float %b
|
|
%res = OpFAdd %v4float %a_val %b_val
|
|
OpStore %foo %res
|
|
%decl = OpExtInst %void %ext DebugDeclare %dbg_foo %foo %null_expr
|
|
%foo_val = OpLoad %v4float %foo
|
|
OpReturnValue %foo_val
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, DebugDeclareMultiple) {
|
|
// Check that InlinePass correctly generates DebugDeclare instructions
|
|
// for callee function's parameters and maps them to corresponding
|
|
// local variables of caller function.
|
|
const std::string text = R"(
|
|
; CHECK: [[add:%\d+]] = OpString "add"
|
|
; CHECK: [[a:%\d+]] = OpString "a"
|
|
; CHECK: [[b:%\d+]] = OpString "b"
|
|
; CHECK: [[dbg_add:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction [[add]]
|
|
; CHECK: [[dbg_a:%\d+]] = OpExtInst %void [[ext]] DebugLocalVariable [[a]]
|
|
; CHECK: [[dbg_b:%\d+]] = OpExtInst %void [[ext]] DebugLocalVariable [[b]]
|
|
; CHECK: OpFunction
|
|
; CHECK-NOT: OpFunctionEnd
|
|
; CHECK: OpStore [[param_a:%\d+]]
|
|
; CHECK: OpStore [[param_b:%\d+]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_add]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugDeclare [[dbg_a]] [[param_a]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugDeclare [[dbg_b]] [[param_b]]
|
|
; CHECK: [[a_val:%\d+]] = OpLoad %v4float [[param_a]]
|
|
; CHECK: OpStore [[foo:%\d+]] [[a_val]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugValue [[dbg_a]] [[foo]]
|
|
|
|
OpCapability Shader
|
|
%ext = OpExtInstImport "OpenCL.DebugInfo.100"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %in_var_COLOR %out_var_SV_TARGET
|
|
OpExecutionMode %main OriginUpperLeft
|
|
%file_name = OpString "ps.hlsl"
|
|
OpSource HLSL 600 %file_name
|
|
%float_name = OpString "float"
|
|
%main_name = OpString "main"
|
|
%add_name = OpString "add"
|
|
%a_name = OpString "a"
|
|
%b_name = OpString "b"
|
|
OpDecorate %in_var_COLOR Location 0
|
|
OpDecorate %out_var_SV_TARGET Location 0
|
|
%uint = OpTypeInt 32 0
|
|
%uint_32 = OpConstant %uint 32
|
|
%float = OpTypeFloat 32
|
|
%float_1 = OpConstant %float 1
|
|
%float_2 = OpConstant %float 2
|
|
%v4float = OpTypeVector %float 4
|
|
%v4f1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%v4f2 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%add_fn_type = OpTypeFunction %v4float %_ptr_Function_v4float %_ptr_Function_v4float
|
|
%void = OpTypeVoid
|
|
%void_fn_type = OpTypeFunction %void
|
|
%v4f_fn_type = OpTypeFunction %v4float
|
|
%in_var_COLOR = OpVariable %_ptr_Input_v4float Input
|
|
%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
|
|
%null_expr = OpExtInst %void %ext DebugExpression
|
|
%src = OpExtInst %void %ext DebugSource %file_name
|
|
%cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
|
|
%dbg_f = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
|
|
%dbg_v4f = OpExtInst %void %ext DebugTypeVector %dbg_f 4
|
|
%main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f
|
|
%add_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f %dbg_v4f
|
|
%dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 5 1 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
|
|
%dbg_add = OpExtInst %void %ext DebugFunction %add_name %add_ty %src 1 1 %cu %add_name FlagIsProtected|FlagIsPrivate 1 %add
|
|
%dbg_a = OpExtInst %void %ext DebugLocalVariable %a_name %dbg_v4f %src 1 13 %dbg_add FlagIsLocal 0
|
|
%dbg_b = OpExtInst %void %ext DebugLocalVariable %b_name %dbg_v4f %src 1 20 %dbg_add FlagIsLocal 1
|
|
%main = OpFunction %void None %void_fn_type
|
|
%main_bb = OpLabel
|
|
%param_a = OpVariable %_ptr_Function_v4float Function
|
|
%param_b = OpVariable %_ptr_Function_v4float Function
|
|
%scope0 = OpExtInst %void %ext DebugScope %dbg_main
|
|
OpStore %param_a %v4f1
|
|
OpStore %param_b %v4f2
|
|
%result = OpFunctionCall %v4float %add %param_a %param_b
|
|
OpStore %out_var_SV_TARGET %result
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%add = OpFunction %v4float None %add_fn_type
|
|
%scope1 = OpExtInst %void %ext DebugScope %dbg_add
|
|
%a = OpFunctionParameter %_ptr_Function_v4float
|
|
%b = OpFunctionParameter %_ptr_Function_v4float
|
|
%decl0 = OpExtInst %void %ext DebugDeclare %dbg_a %a %null_expr
|
|
%add_bb = OpLabel
|
|
%decl1 = OpExtInst %void %ext DebugDeclare %dbg_b %b %null_expr
|
|
%foo = OpVariable %_ptr_Function_v4float Function
|
|
%a_val = OpLoad %v4float %a
|
|
OpStore %foo %a_val
|
|
%dbg_val = OpExtInst %void %ext DebugValue %dbg_a %foo %null_expr
|
|
%b_val = OpLoad %v4float %b
|
|
%res = OpFAdd %v4float %a_val %b_val
|
|
OpReturnValue %res
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, DebugValueForFunctionCallReturn) {
|
|
// Check that InlinePass correctly generates DebugValue instruction
|
|
// for function call's return value and maps it to a corresponding
|
|
// value in the caller function.
|
|
const std::string text = R"(
|
|
; CHECK: [[main:%\d+]] = OpString "main"
|
|
; CHECK: [[add:%\d+]] = OpString "add"
|
|
; CHECK: [[result:%\d+]] = OpString "result"
|
|
; CHECK: [[dbg_main:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction [[main]]
|
|
; CHECK: [[dbg_add:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction [[add]]
|
|
; CHECK: [[dbg_result:%\d+]] = OpExtInst %void [[ext]] DebugLocalVariable [[result]] {{%\d+}} {{%\d+}} 6 2 [[dbg_main]]
|
|
; CHECK: [[inlinedat:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 5
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_add]] [[inlinedat]]
|
|
; CHECK: [[a_val:%\d+]] = OpLoad %v4float
|
|
; CHECK: [[b_val:%\d+]] = OpLoad %v4float
|
|
; CHECK: [[res:%\d+]] = OpFAdd %v4float [[a_val]] [[b_val]]
|
|
; CHECK: OpStore [[new_result:%\d+]] [[res]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_main]]
|
|
; CHECK: [[result_val:%\d+]] = OpLoad %v4float [[new_result]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugValue [[dbg_result]] [[result_val]]
|
|
|
|
OpCapability Shader
|
|
%ext = OpExtInstImport "OpenCL.DebugInfo.100"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %in_var_COLOR %out_var_SV_TARGET
|
|
OpExecutionMode %main OriginUpperLeft
|
|
%file_name = OpString "ps.hlsl"
|
|
OpSource HLSL 600 %file_name
|
|
%float_name = OpString "float"
|
|
%main_name = OpString "main"
|
|
%add_name = OpString "add"
|
|
%result_name = OpString "result"
|
|
OpDecorate %in_var_COLOR Location 0
|
|
OpDecorate %out_var_SV_TARGET Location 0
|
|
%uint = OpTypeInt 32 0
|
|
%uint_32 = OpConstant %uint 32
|
|
%float = OpTypeFloat 32
|
|
%float_1 = OpConstant %float 1
|
|
%float_2 = OpConstant %float 2
|
|
%v4float = OpTypeVector %float 4
|
|
%v4f1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%v4f2 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
|
%add_fn_type = OpTypeFunction %v4float %_ptr_Function_v4float %_ptr_Function_v4float
|
|
%void = OpTypeVoid
|
|
%void_fn_type = OpTypeFunction %void
|
|
%v4f_fn_type = OpTypeFunction %v4float
|
|
%in_var_COLOR = OpVariable %_ptr_Input_v4float Input
|
|
%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
|
|
%null_expr = OpExtInst %void %ext DebugExpression
|
|
%src = OpExtInst %void %ext DebugSource %file_name
|
|
%cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
|
|
%dbg_f = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
|
|
%dbg_v4f = OpExtInst %void %ext DebugTypeVector %dbg_f 4
|
|
%main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f
|
|
%add_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f %dbg_v4f
|
|
%dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 5 1 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
|
|
%dbg_add = OpExtInst %void %ext DebugFunction %add_name %add_ty %src 1 1 %cu %add_name FlagIsProtected|FlagIsPrivate 1 %add
|
|
%dbg_result = OpExtInst %void %ext DebugLocalVariable %result_name %dbg_v4f %src 6 2 %dbg_main FlagIsLocal
|
|
%main = OpFunction %void None %void_fn_type
|
|
%main_bb = OpLabel
|
|
%param_a = OpVariable %_ptr_Function_v4float Function
|
|
%param_b = OpVariable %_ptr_Function_v4float Function
|
|
%scope0 = OpExtInst %void %ext DebugScope %dbg_main
|
|
OpStore %param_a %v4f1
|
|
OpStore %param_b %v4f2
|
|
%result = OpFunctionCall %v4float %add %param_a %param_b
|
|
%value = OpExtInst %void %ext DebugValue %dbg_result %result %null_expr
|
|
OpStore %out_var_SV_TARGET %result
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%add = OpFunction %v4float None %add_fn_type
|
|
%scope1 = OpExtInst %void %ext DebugScope %dbg_add
|
|
%a = OpFunctionParameter %_ptr_Function_v4float
|
|
%b = OpFunctionParameter %_ptr_Function_v4float
|
|
%add_bb = OpLabel
|
|
%a_val = OpLoad %v4float %a
|
|
%b_val = OpLoad %v4float %b
|
|
%res = OpFAdd %v4float %a_val %b_val
|
|
OpReturnValue %res
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
|
|
}
|
|
|
|
TEST_F(InlineTest, NestedWithAnExistingDebugInlinedAt) {
|
|
// When a DebugScope instruction in a callee function already has a
|
|
// DebugInlinedAt information, we have to create a recursive
|
|
// DebugInlinedAt chain. See inlined_to_zoo and inlined_to_bar in
|
|
// the following code.
|
|
const std::string text = R"(
|
|
; CHECK: [[main:%\d+]] = OpString "main"
|
|
; CHECK: [[foo:%\d+]] = OpString "foo"
|
|
; CHECK: [[bar:%\d+]] = OpString "bar"
|
|
; CHECK: [[zoo:%\d+]] = OpString "zoo"
|
|
; CHECK: [[v4f1:%\d+]] = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
; CHECK: [[v4f2:%\d+]] = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
|
|
; CHECK: [[v4f3:%\d+]] = OpConstantComposite %v4float %float_3 %float_3 %float_3 %float_3
|
|
; CHECK: [[dbg_main:%\d+]] = OpExtInst %void [[ext:%\d+]] DebugFunction [[main]]
|
|
; CHECK: [[dbg_foo:%\d+]] = OpExtInst %void [[ext]] DebugFunction [[foo]]
|
|
; CHECK: [[dbg_bar:%\d+]] = OpExtInst %void [[ext]] DebugFunction [[bar]]
|
|
; CHECK: [[dbg_zoo:%\d+]] = OpExtInst %void [[ext]] DebugFunction [[zoo]]
|
|
; CHECK: [[inlined_to_main:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 10 [[dbg_main]]
|
|
; CHECK: [[inlined_to_zoo:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 7 [[dbg_zoo]] [[inlined_to_main]]
|
|
; CHECK: [[inlined_to_main:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 10 [[dbg_main]]
|
|
; CHECK: [[inlined_to_bar:%\d+]] = OpExtInst %void [[ext]] DebugInlinedAt 4 [[dbg_bar]] [[inlined_to_zoo]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_foo]] [[inlined_to_bar]]
|
|
; CHECK: OpStore [[foo_ret:%\d+]] [[v4f1]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_bar]] [[inlined_to_zoo]]
|
|
; CHECK: [[foo_ret_val:%\d+]] = OpLoad %v4float [[foo_ret]]
|
|
; CHECK: [[bar_ret:%\d+]] = OpFAdd %v4float [[foo_ret_val]] [[v4f2]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_zoo]] [[inlined_to_main]]
|
|
; CHECK: [[zoo_result:%\d+]] = OpFAdd %v4float [[bar_ret]] [[v4f3]]
|
|
; CHECK: OpStore [[zoo_ret:%\d+]] [[zoo_result]]
|
|
; CHECK: {{%\d+}} = OpExtInst %void [[ext]] DebugScope [[dbg_main]]
|
|
; CHECK: [[zoo_ret_val:%\d+]] = OpLoad %v4float [[zoo_ret]]
|
|
; CHECK: {{%\d+}} = OpFAdd %v4float [[zoo_ret_val]] {{%\d+}}
|
|
|
|
OpCapability Shader
|
|
%ext = OpExtInstImport "OpenCL.DebugInfo.100"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %main "main" %in_var_COLOR %out_var_SV_TARGET
|
|
OpExecutionMode %main OriginUpperLeft
|
|
%file_name = OpString "ps.hlsl"
|
|
OpSource HLSL 600 %file_name
|
|
%float_name = OpString "float"
|
|
%main_name = OpString "main"
|
|
%foo_name = OpString "foo"
|
|
%bar_name = OpString "bar"
|
|
%zoo_name = OpString "zoo"
|
|
OpDecorate %in_var_COLOR Location 0
|
|
OpDecorate %out_var_SV_TARGET Location 0
|
|
%uint = OpTypeInt 32 0
|
|
%uint_32 = OpConstant %uint 32
|
|
%float = OpTypeFloat 32
|
|
%float_1 = OpConstant %float 1
|
|
%float_2 = OpConstant %float 2
|
|
%float_3 = OpConstant %float 3
|
|
%v4float = OpTypeVector %float 4
|
|
%v4f1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
|
|
%v4f2 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
|
|
%v4f3 = OpConstantComposite %v4float %float_3 %float_3 %float_3 %float_3
|
|
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
|
%void = OpTypeVoid
|
|
%void_fn_type = OpTypeFunction %void
|
|
%v4f_fn_type = OpTypeFunction %v4float
|
|
%in_var_COLOR = OpVariable %_ptr_Input_v4float Input
|
|
%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
|
|
%src = OpExtInst %void %ext DebugSource %file_name
|
|
%cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
|
|
%dbg_f = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
|
|
%dbg_v4f = OpExtInst %void %ext DebugTypeVector %dbg_f 4
|
|
%main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f %dbg_v4f
|
|
%foo_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_v4f
|
|
%dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 10 1 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
|
|
%dbg_foo = OpExtInst %void %ext DebugFunction %foo_name %foo_ty %src 1 1 %cu %foo_name FlagIsProtected|FlagIsPrivate 1 %foo
|
|
%dbg_bar = OpExtInst %void %ext DebugFunction %bar_name %foo_ty %src 4 1 %cu %bar_name FlagIsProtected|FlagIsPrivate 4 %bar
|
|
%dbg_zoo = OpExtInst %void %ext DebugFunction %zoo_name %foo_ty %src 7 1 %cu %zoo_name FlagIsProtected|FlagIsPrivate 7 %zoo
|
|
%inlined_to_zoo = OpExtInst %void %ext DebugInlinedAt 7 %dbg_zoo
|
|
%main = OpFunction %void None %void_fn_type
|
|
%main_bb = OpLabel
|
|
%scope0 = OpExtInst %void %ext DebugScope %dbg_main
|
|
%zoo_val = OpFunctionCall %v4float %zoo
|
|
%color = OpLoad %v4float %in_var_COLOR
|
|
%result = OpFAdd %v4float %zoo_val %color
|
|
OpStore %out_var_SV_TARGET %result
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%foo = OpFunction %v4float None %v4f_fn_type
|
|
%scope1 = OpExtInst %void %ext DebugScope %dbg_foo
|
|
%foo_bb = OpLabel
|
|
OpReturnValue %v4f1
|
|
OpFunctionEnd
|
|
%zoo = OpFunction %v4float None %v4f_fn_type
|
|
%scope3 = OpExtInst %void %ext DebugScope %dbg_zoo
|
|
%zoo_bb = OpLabel
|
|
%scope2 = OpExtInst %void %ext DebugScope %dbg_bar %inlined_to_zoo
|
|
%foo_val = OpFunctionCall %v4float %foo
|
|
%bar_val = OpFAdd %v4float %foo_val %v4f2
|
|
%scope4 = OpExtInst %void %ext DebugScope %dbg_zoo
|
|
%zoo_ret = OpFAdd %v4float %bar_val %v4f3
|
|
OpReturnValue %zoo_ret
|
|
OpFunctionEnd
|
|
%bar = OpFunction %v4float None %v4f_fn_type
|
|
%scope5 = OpExtInst %void %ext DebugScope %dbg_bar
|
|
%bar_bb = OpLabel
|
|
%foo_val0 = OpFunctionCall %v4float %foo
|
|
%bar_ret = OpFAdd %v4float %foo_val0 %v4f2
|
|
OpReturnValue %bar_ret
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
SinglePassRunAndMatch<InlineExhaustivePass>(text, true);
|
|
}
|
|
|
|
// TODO(greg-lunarg): Add tests to verify handling of these cases:
|
|
//
|
|
// Empty modules
|
|
// Modules without function definitions
|
|
// Modules in which all functions do not call other functions
|
|
// Caller and callee both accessing the same global variable
|
|
// Functions with OpLine & OpNoLine
|
|
// Others?
|
|
|
|
// TODO(dneto): Test suggestions from code review
|
|
// https://github.com/KhronosGroup/SPIRV-Tools/pull/534
|
|
//
|
|
// Callee function returns a value generated outside the callee,
|
|
// e.g. a constant value. This might exercise some logic not yet
|
|
// exercised by the current tests: the false branch in the "if"
|
|
// inside the SpvOpReturnValue case in InlinePass::GenInlineCode?
|
|
// SampledImage before function call, but callee is only single block.
|
|
// Then the SampledImage instruction is not cloned. Documents existing
|
|
// behaviour.
|
|
// SampledImage after function call. It is not cloned or changed.
|
|
|
|
} // namespace
|
|
} // namespace opt
|
|
} // namespace spvtools
|