SPIRV-Tools/test/opt/inline_test.cpp

1628 lines
59 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 "pass_fixture.h"
#include "pass_utils.h"
template <typename T> std::vector<T> concat(const std::vector<T> &a, const std::vector<T> &b) {
std::vector<T> ret = std::vector<T>();
std::copy(a.begin(), a.end(), back_inserter(ret));
std::copy(b.begin(), b.end(), back_inserter(ret));
return ret;
}
namespace {
using namespace spvtools;
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",
"%33 = OpAccessChain %_ptr_Function_float %param %uint_0",
"%34 = OpLoad %float %33",
"%35 = OpAccessChain %_ptr_Function_float %param %uint_1",
"%36 = OpLoad %float %35",
"%37 = OpFAdd %float %34 %36",
"OpStore %32 %37",
"%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<opt::InlinePass>(
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",
"%57 = 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",
"%49 = OpAccessChain %_ptr_Function_float %param_1 %uint_0",
"%50 = OpLoad %float %49",
"%51 = OpAccessChain %_ptr_Function_float %param_1 %uint_1",
"%52 = OpLoad %float %51",
"%53 = OpFAdd %float %50 %52",
"OpStore %46 %53",
"%54 = OpAccessChain %_ptr_Function_float %param_1 %uint_2",
"%55 = OpLoad %float %54",
"OpStore %47 %55",
"%58 = OpLoad %float %46",
"%59 = OpLoad %float %47",
"%60 = OpFMul %float %58 %59",
"OpStore %57 %60",
"%56 = OpLoad %float %57",
"OpStore %48 %56",
"%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<opt::InlinePass>(
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",
"%39 = OpAccessChain %_ptr_Function_float %param %uint_0",
"%40 = OpLoad %float %39",
"%41 = OpAccessChain %_ptr_Function_float %param %uint_1",
"%42 = OpLoad %float %41",
"%43 = OpFAdd %float %40 %42",
"%44 = OpAccessChain %_ptr_Function_float %param %uint_2",
"OpStore %44 %43",
"%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<opt::InlinePass>(
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",
"%40 = OpAccessChain %_ptr_Function_float %param %uint_0",
"%41 = OpLoad %float %40",
"OpStore %38 %41",
"%42 = OpLoad %float %38",
"%43 = OpFOrdLessThan %bool %42 %float_0",
"OpSelectionMerge %44 None",
"OpBranchConditional %43 %45 %44",
"%45 = OpLabel",
"%46 = OpLoad %float %38",
"%47 = OpFNegate %float %46",
"OpStore %38 %47",
"OpBranch %44",
"%44 = OpLabel",
"%48 = OpLoad %float %38",
"OpStore %39 %48",
"%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<opt::InlinePass>(
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",
"%62 = OpVariable %_ptr_Function_float Function",
"%63 = 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",
"%54 = OpLoad %float %param",
"OpStore %52 %54",
"%55 = OpLoad %float %52",
"%56 = OpFOrdLessThan %bool %55 %float_0",
"OpSelectionMerge %57 None",
"OpBranchConditional %56 %58 %57",
"%58 = OpLabel",
"%59 = OpLoad %float %52",
"%60 = OpFNegate %float %59",
"OpStore %52 %60",
"OpBranch %57",
"%57 = OpLabel",
"%61 = OpLoad %float %52",
"OpStore %53 %61",
"%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",
"%64 = OpLoad %float %param_0",
"OpStore %62 %64",
"%65 = OpLoad %float %62",
"%66 = OpFOrdLessThan %bool %65 %float_0",
"OpSelectionMerge %67 None",
"OpBranchConditional %66 %68 %67",
"%68 = OpLabel",
"%69 = OpLoad %float %62",
"%70 = OpFNegate %float %69",
"OpStore %62 %70",
"OpBranch %67",
"%67 = OpLabel",
"%71 = OpLoad %float %62",
"OpStore %63 %71",
"%37 = OpLoad %float %63",
"%38 = OpFOrdGreaterThan %bool %37 %float_2",
"OpBranch %33",
"%33 = OpLabel",
"%39 = OpPhi %bool %32 %57 %38 %67",
"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<opt::InlinePass>(
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",
"%68 = OpAccessChain %_ptr_Function_float %param %uint_0",
"%69 = OpLoad %float %68",
"OpStore %66 %69",
"%70 = OpLoad %float %66",
"%71 = OpFOrdLessThan %bool %70 %float_0",
"OpSelectionMerge %72 None",
"OpBranchConditional %71 %73 %72",
"%73 = OpLabel",
"%74 = OpLoad %float %66",
"%75 = OpFNegate %float %74",
"OpStore %66 %75",
"OpBranch %72",
"%72 = OpLabel",
"%76 = OpLoad %float %66",
"OpStore %67 %76",
"%44 = OpLoad %float %67",
"%45 = OpCompositeConstruct %v4float %44 %44 %44 %44",
"OpStore %color2 %45",
"%46 = OpLoad %25 %t2D",
"%47 = OpLoad %27 %samp",
"%77 = OpSampledImage %29 %39 %40",
"%48 = OpImageSampleImplicitLod %v4float %77 %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<opt::InlinePass>(
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",
"%70 = OpAccessChain %_ptr_Function_float %param %uint_0",
"%71 = OpLoad %float %70",
"OpStore %68 %71",
"%72 = OpLoad %float %68",
"%73 = OpFOrdLessThan %bool %72 %float_0",
"OpSelectionMerge %74 None",
"OpBranchConditional %73 %75 %74",
"%75 = OpLabel",
"%76 = OpLoad %float %68",
"%77 = OpFNegate %float %76",
"OpStore %68 %77",
"OpBranch %74",
"%74 = OpLabel",
"%78 = OpLoad %float %68",
"OpStore %69 %78",
"%47 = OpLoad %float %69",
"%48 = OpCompositeConstruct %v4float %47 %47 %47 %47",
"OpStore %color2 %48",
"%79 = OpSampledImage %30 %40 %41",
"%80 = OpImage %26 %79",
"%49 = OpSampledImage %30 %80 %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<opt::InlinePass>(
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",
"%70 = OpAccessChain %_ptr_Function_float %param %uint_0",
"%71 = OpLoad %float %70",
"OpStore %68 %71",
"%72 = OpLoad %float %68",
"%73 = OpFOrdLessThan %bool %72 %float_0",
"OpSelectionMerge %74 None",
"OpBranchConditional %73 %75 %74",
"%75 = OpLabel",
"%76 = OpLoad %float %68",
"%77 = OpFNegate %float %76",
"OpStore %68 %77",
"OpBranch %74",
"%74 = OpLabel",
"%78 = OpLoad %float %68",
"OpStore %69 %78",
"%48 = OpLoad %float %69",
"%49 = OpCompositeConstruct %v4float %48 %48 %48 %48",
"OpStore %color2 %49",
"%79 = OpSampledImage %30 %40 %41",
"%80 = OpImage %26 %79",
"%81 = OpSampledImage %30 %80 %45",
"%50 = OpImageSampleImplicitLod %v4float %81 %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<opt::InlinePass>(
JoinAllInsts(concat(concat(predefs, before), nonEntryFuncs)),
JoinAllInsts(concat(concat(predefs, after), nonEntryFuncs)),
/* skip_nop = */ false, /* do_validate = */ 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 nonEntryFuncs =
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 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
%main = OpFunction %void None %10
%22 = OpLabel
%35 = OpVariable %_ptr_Function_float Function
%color = OpVariable %_ptr_Function_v4float Function
%param = OpVariable %_ptr_Function_v4float Function
%23 = OpLoad %v4float %BaseColor
OpStore %param %23
OpBranch %36
%36 = OpLabel
OpLoopMerge %37 %38 None
OpBranch %39
%39 = OpLabel
%40 = OpAccessChain %_ptr_Function_float %param %uint_0
%41 = OpLoad %float %40
%42 = OpFOrdLessThan %bool %41 %float_0
OpSelectionMerge %43 None
OpBranchConditional %42 %44 %43
%44 = OpLabel
OpStore %35 %float_0
OpBranch %37
%43 = OpLabel
%45 = OpAccessChain %_ptr_Function_float %param %uint_0
%46 = OpLoad %float %45
OpStore %35 %46
OpBranch %37
%38 = OpLabel
OpBranchConditional %false %36 %37
%37 = OpLabel
%24 = OpLoad %float %35
%25 = OpCompositeConstruct %v4float %24 %24 %24 %24
OpStore %color %25
%26 = OpLoad %v4float %color
OpStore %gl_FragColor %26
OpReturn
OpFunctionEnd
)";
SinglePassRunAndCheck<opt::InlinePass>(predefs + before + nonEntryFuncs,
predefs + after + nonEntryFuncs, false, 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<opt::InlinePass>(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<opt::InlinePass>(assembly, assembly, false, 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
// Recursive functions (calling self & calling each other)
// 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.
} // anonymous namespace