// 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 #include #include #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 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 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 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 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( 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 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 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 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 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( 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 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 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 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 after = { // clang-format off "%26 = OpUndef %void", "%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( 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 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 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 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 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( 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 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 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 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 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( 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 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 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 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 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( 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 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 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 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 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( 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 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 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 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 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( 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(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(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 %5 = OpTypeFunction %void )"; const std::string nonEntryFuncs = R"(%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 )"; const std::string undef = "%11 = OpUndef %void\n"; SinglePassRunAndCheck( predefs + nonEntryFuncs + before, predefs + undef + 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 )"; const std::string undef = "%20 = OpUndef %void\n"; SinglePassRunAndCheck( predefs + nonEntryFuncs + before, predefs + undef + 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 extra 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 )"; const std::string undef = "%15 = OpUndef %void\n"; SinglePassRunAndCheck( predefs + nonEntryFuncs + before, predefs + undef + 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 )"; const std::string undef = "%20 = OpUndef %void\n"; SinglePassRunAndCheck( predefs + nonEntryFuncs + before, predefs + undef + 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( 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(predefs + before + nonEntryFuncs, predefs + after + nonEntryFuncs, false, true); } TEST_F(InlineTest, Decorated2) { // Same test as Simple with the difference // that the Result 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(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 %3 = OpUndef %void %foo = OpFunction %void None %void_fn %foo_entry = OpLabel OpReturn OpFunctionEnd %main = OpFunction %void None %void_fn %main_entry = OpLabel OpReturn OpFunctionEnd )"; SinglePassRunAndCheck(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 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(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(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(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(test, test, false, true); } TEST_F(InlineTest, DontInlineFuncWithDontInline) { // Check that the function with DontInline flag is not inlined. const std::string text = R"( ; CHECK: %foo = OpFunction %int DontInline ; CHECK: OpReturnValue %int_0 OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" OpExecutionMode %main OriginUpperLeft OpSource HLSL 600 OpName %main "main" OpName %foo "foo" %int = OpTypeInt 32 1 %int_0 = OpConstant %int 0 %void = OpTypeVoid %6 = OpTypeFunction %void %7 = OpTypeFunction %int %main = OpFunction %void None %6 %8 = OpLabel %9 = OpFunctionCall %int %foo OpReturn OpFunctionEnd %foo = OpFunction %int DontInline %7 %10 = OpLabel OpReturnValue %int_0 OpFunctionEnd )"; SinglePassRunAndMatch(text, 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 %16 = OpUndef %void %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(before, after, false, true); } TEST_F(InlineTest, DontInlineFuncWithOpTerminateInvocationInContinue) { const std::string test = R"(OpCapability Shader OpExtension "SPV_KHR_terminate_invocation" %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 OpTerminateInvocation OpFunctionEnd )"; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndCheck(test, test, false, true); } TEST_F(InlineTest, InlineFuncWithOpTerminateInvocationNotInContinue) { const std::string before = R"(OpCapability Shader OpExtension "SPV_KHR_terminate_invocation" %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 OpTerminateInvocation OpFunctionEnd )"; const std::string after = R"(OpCapability Shader OpExtension "SPV_KHR_terminate_invocation" %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 %16 = OpUndef %void %main = OpFunction %void None %3 %5 = OpLabel OpTerminateInvocation %18 = OpLabel OpReturn OpFunctionEnd %kill_ = OpFunction %void None %3 %7 = OpLabel OpTerminateInvocation OpFunctionEnd )"; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndCheck(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(); AddPass(); 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 %11 = OpUndef %void %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(); AddPass(); 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(); AddPass(); 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(); AddPass(); 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(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(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(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(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(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(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(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(text, true); } TEST_F(InlineTest, UsingVoidFunctionResult) { const std::string text = R"( ; CHECK: [[undef:%\w+]] = OpUndef %void ; CHECK: OpFunction ; CHECK: OpCopyObject %void [[undef]] ; CHECK: OpFunctionEnd OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" OpExecutionMode %4 OriginUpperLeft OpSource ESSL 320 %2 = OpTypeVoid %3 = OpTypeFunction %2 %4 = OpFunction %2 None %3 %5 = OpLabel %8 = OpFunctionCall %2 %6 %9 = OpCopyObject %2 %8 OpReturn OpFunctionEnd %6 = OpFunction %2 None %3 %7 = OpLabel OpReturn OpFunctionEnd )"; SinglePassRunAndMatch(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