aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Perron <stevenperron@google.com>2022-03-07 17:45:17 +0000
committerGitHub <noreply@github.com>2022-03-07 12:45:17 -0500
commit920156cf183baa11f6b65d159da6fba9fdab684e (patch)
tree712531eb825661f1eae11741e098fe7066120278
parent273d2a45adda86c0a4299032dc9e71b270373739 (diff)
downloadspirv-tools-920156cf183baa11f6b65d159da6fba9fdab684e.tar.gz
Add pass to remove DontInline function control (#4747)
Swift shader needs a way to inline all functions, even those marked as DontInline. See https://github.com/KhronosGroup/SPIRV-Tools/pull/4471. This implements the suggestion I made in the PR. We add a pass that will remove the DontInline function control, so that the inlining passes will inline them. SwiftShader will still have to modify their code to add this pass before the other passes are run.
-rw-r--r--Android.mk1
-rw-r--r--BUILD.gn2
-rw-r--r--include/spirv-tools/optimizer.hpp4
-rw-r--r--source/opt/CMakeLists.txt2
-rw-r--r--source/opt/optimizer.cpp6
-rw-r--r--source/opt/passes.h1
-rw-r--r--source/opt/remove_dontinline_pass.cpp49
-rw-r--r--source/opt/remove_dontinline_pass.h42
-rw-r--r--test/opt/CMakeLists.txt1
-rw-r--r--test/opt/remove_dontinline_test.cpp127
10 files changed, 235 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
index 2aee9288..3e836c50 100644
--- a/Android.mk
+++ b/Android.mk
@@ -156,6 +156,7 @@ SPVTOOLS_OPT_SRC_FILES := \
source/opt/redundancy_elimination.cpp \
source/opt/register_pressure.cpp \
source/opt/relax_float_ops_pass.cpp \
+ source/opt/remove_dontinline_pass.cpp \
source/opt/remove_duplicates_pass.cpp \
source/opt/remove_unused_interface_variables_pass.cpp \
source/opt/replace_desc_array_access_using_var_index.cpp \
diff --git a/BUILD.gn b/BUILD.gn
index b2cc934c..0f588842 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -716,6 +716,8 @@ static_library("spvtools_opt") {
"source/opt/register_pressure.h",
"source/opt/relax_float_ops_pass.cpp",
"source/opt/relax_float_ops_pass.h",
+ "source/opt/remove_dontinline_pass.cpp",
+ "source/opt/remove_dontinline_pass.h",
"source/opt/remove_duplicates_pass.cpp",
"source/opt/remove_duplicates_pass.h",
"source/opt/remove_unused_interface_variables_pass.cpp",
diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp
index fdb2e648..2273e85d 100644
--- a/include/spirv-tools/optimizer.hpp
+++ b/include/spirv-tools/optimizer.hpp
@@ -896,6 +896,10 @@ Optimizer::PassToken CreateConvertToSampledImagePass(
const std::vector<opt::DescriptorSetAndBinding>&
descriptor_set_binding_pairs);
+// Creates a remove-dont-inline pass to remove the |DontInline| function control
+// from every function in the module. This is useful if you want the inliner to
+// inline these functions some reason.
+Optimizer::PassToken CreateRemoveDontInlinePass();
} // namespace spvtools
#endif // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_
diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt
index 7508dc02..05c02fcd 100644
--- a/source/opt/CMakeLists.txt
+++ b/source/opt/CMakeLists.txt
@@ -99,6 +99,7 @@ set(SPIRV_TOOLS_OPT_SOURCES
reflect.h
register_pressure.h
relax_float_ops_pass.h
+ remove_dontinline_pass.h
remove_duplicates_pass.h
remove_unused_interface_variables_pass.h
replace_desc_array_access_using_var_index.h
@@ -207,6 +208,7 @@ set(SPIRV_TOOLS_OPT_SOURCES
redundancy_elimination.cpp
register_pressure.cpp
relax_float_ops_pass.cpp
+ remove_dontinline_pass.cpp
remove_duplicates_pass.cpp
remove_unused_interface_variables_pass.cpp
replace_desc_array_access_using_var_index.cpp
diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp
index 330093e4..ec2c8ea2 100644
--- a/source/opt/optimizer.cpp
+++ b/source/opt/optimizer.cpp
@@ -521,6 +521,8 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
RegisterPass(CreateAmdExtToKhrPass());
} else if (pass_name == "interpolate-fixup") {
RegisterPass(CreateInterpolateFixupPass());
+ } else if (pass_name == "remove-dont-inline") {
+ RegisterPass(CreateRemoveDontInlinePass());
} else if (pass_name == "convert-to-sampled-image") {
if (pass_args.size() > 0) {
auto descriptor_set_binding_pairs =
@@ -1009,4 +1011,8 @@ Optimizer::PassToken CreateConvertToSampledImagePass(
MakeUnique<opt::ConvertToSampledImagePass>(descriptor_set_binding_pairs));
}
+Optimizer::PassToken CreateRemoveDontInlinePass() {
+ return MakeUnique<Optimizer::PassToken::Impl>(
+ MakeUnique<opt::RemoveDontInline>());
+}
} // namespace spvtools
diff --git a/source/opt/passes.h b/source/opt/passes.h
index d51c306e..26739cdc 100644
--- a/source/opt/passes.h
+++ b/source/opt/passes.h
@@ -64,6 +64,7 @@
#include "source/opt/reduce_load_size.h"
#include "source/opt/redundancy_elimination.h"
#include "source/opt/relax_float_ops_pass.h"
+#include "source/opt/remove_dontinline_pass.h"
#include "source/opt/remove_duplicates_pass.h"
#include "source/opt/remove_unused_interface_variables_pass.h"
#include "source/opt/replace_desc_array_access_using_var_index.h"
diff --git a/source/opt/remove_dontinline_pass.cpp b/source/opt/remove_dontinline_pass.cpp
new file mode 100644
index 00000000..4dd1cd4f
--- /dev/null
+++ b/source/opt/remove_dontinline_pass.cpp
@@ -0,0 +1,49 @@
+// Copyright (c) 2022 Google LLC
+//
+// 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 "source/opt/remove_dontinline_pass.h"
+
+namespace spvtools {
+namespace opt {
+
+Pass::Status RemoveDontInline::Process() {
+ bool modified = false;
+ modified = ClearDontInlineFunctionControl();
+ return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange);
+}
+
+bool RemoveDontInline::ClearDontInlineFunctionControl() {
+ bool modified = false;
+ for (auto& func : *get_module()) {
+ ClearDontInlineFunctionControl(&func);
+ }
+ return modified;
+}
+
+bool RemoveDontInline::ClearDontInlineFunctionControl(Function* function) {
+ constexpr uint32_t kFunctionControlInOperandIdx = 0;
+ Instruction* function_inst = &function->DefInst();
+ uint32_t function_control =
+ function_inst->GetSingleWordInOperand(kFunctionControlInOperandIdx);
+
+ if ((function_control & SpvFunctionControlDontInlineMask) == 0) {
+ return false;
+ }
+ function_control &= ~SpvFunctionControlDontInlineMask;
+ function_inst->SetInOperand(kFunctionControlInOperandIdx, {function_control});
+ return true;
+}
+
+} // namespace opt
+} // namespace spvtools
diff --git a/source/opt/remove_dontinline_pass.h b/source/opt/remove_dontinline_pass.h
new file mode 100644
index 00000000..16243199
--- /dev/null
+++ b/source/opt/remove_dontinline_pass.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2022 Google LLC
+//
+// 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.
+
+#ifndef SOURCE_OPT_REMOVE_DONTINLINE_PASS_H_
+#define SOURCE_OPT_REMOVE_DONTINLINE_PASS_H_
+
+#include "source/opt/pass.h"
+
+namespace spvtools {
+namespace opt {
+
+// See optimizer.hpp for documentation.
+class RemoveDontInline : public Pass {
+ public:
+ const char* name() const override { return "remove-dont-inline"; }
+ Status Process() override;
+
+ private:
+ // Clears the DontInline function control from every function in the module.
+ // Returns true of a change was made.
+ bool ClearDontInlineFunctionControl();
+
+ // Clears the DontInline function control from |function|.
+ // Returns true of a change was made.
+ bool ClearDontInlineFunctionControl(Function* function);
+};
+
+} // namespace opt
+} // namespace spvtools
+
+#endif // SOURCE_OPT_REMOVE_DONTINLINE_PASS_H_
diff --git a/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt
index 759d4237..f50fddad 100644
--- a/test/opt/CMakeLists.txt
+++ b/test/opt/CMakeLists.txt
@@ -82,6 +82,7 @@ add_spvtools_unittest(TARGET opt
propagator_test.cpp
reduce_load_size_test.cpp
redundancy_elimination_test.cpp
+ remove_dontinline_test.cpp
remove_unused_interface_variables_test.cpp
register_liveness.cpp
relax_float_ops_test.cpp
diff --git a/test/opt/remove_dontinline_test.cpp b/test/opt/remove_dontinline_test.cpp
new file mode 100644
index 00000000..c5425e8c
--- /dev/null
+++ b/test/opt/remove_dontinline_test.cpp
@@ -0,0 +1,127 @@
+// Copyright (c) 2017 Google 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 <vector>
+
+#include "test/opt/pass_fixture.h"
+#include "test/opt/pass_utils.h"
+
+namespace spvtools {
+namespace opt {
+namespace {
+
+using StrengthReductionBasicTest = PassTest<::testing::Test>;
+
+TEST_F(StrengthReductionBasicTest, ClearDontInline) {
+ const std::vector<const char*> text = {
+ // clang-format off
+ "OpCapability Shader",
+ "%1 = OpExtInstImport \"GLSL.std.450\"",
+ "OpMemoryModel Logical GLSL450",
+ "OpEntryPoint Vertex %main \"main\"",
+ "%void = OpTypeVoid",
+ "%4 = OpTypeFunction %void",
+"; CHECK: OpFunction %void None",
+ "%main = OpFunction %void DontInline %4",
+ "%8 = OpLabel",
+ "OpReturn",
+ "OpFunctionEnd"
+ // clang-format on
+ };
+
+ SinglePassRunAndMatch<RemoveDontInline>(JoinAllInsts(text), true);
+}
+
+TEST_F(StrengthReductionBasicTest, LeaveUnchanged1) {
+ const std::vector<const char*> text = {
+ // clang-format off
+ "OpCapability Shader",
+ "%1 = OpExtInstImport \"GLSL.std.450\"",
+ "OpMemoryModel Logical GLSL450",
+ "OpEntryPoint Vertex %main \"main\"",
+ "%void = OpTypeVoid",
+ "%4 = OpTypeFunction %void",
+ "%main = OpFunction %void None %4",
+ "%8 = OpLabel",
+ "OpReturn",
+ "OpFunctionEnd"
+ // clang-format on
+ };
+
+ EXPECT_EQ(Pass::Status::SuccessWithoutChange,
+ std::get<1>(SinglePassRunAndDisassemble<RemoveDontInline>(
+ JoinAllInsts(text), false, true)));
+}
+
+TEST_F(StrengthReductionBasicTest, LeaveUnchanged2) {
+ const std::vector<const char*> text = {
+ // clang-format off
+ "OpCapability Shader",
+ "%1 = OpExtInstImport \"GLSL.std.450\"",
+ "OpMemoryModel Logical GLSL450",
+ "OpEntryPoint Vertex %main \"main\"",
+ "%void = OpTypeVoid",
+ "%4 = OpTypeFunction %void",
+ "%main = OpFunction %void Inline %4",
+ "%8 = OpLabel",
+ "OpReturn",
+ "OpFunctionEnd"
+ // clang-format on
+ };
+
+ EXPECT_EQ(Pass::Status::SuccessWithoutChange,
+ std::get<1>(SinglePassRunAndDisassemble<RemoveDontInline>(
+ JoinAllInsts(text), false, true)));
+}
+
+TEST_F(StrengthReductionBasicTest, ClearMultipleDontInline) {
+ const std::vector<const char*> text = {
+ // clang-format off
+ "OpCapability Shader",
+ "%1 = OpExtInstImport \"GLSL.std.450\"",
+ "OpMemoryModel Logical GLSL450",
+ "OpEntryPoint Vertex %main1 \"main1\"",
+ "OpEntryPoint Vertex %main2 \"main2\"",
+ "OpEntryPoint Vertex %main3 \"main3\"",
+ "OpEntryPoint Vertex %main4 \"main4\"",
+ "%void = OpTypeVoid",
+ "%4 = OpTypeFunction %void",
+ "; CHECK: OpFunction %void None",
+ "%main1 = OpFunction %void DontInline %4",
+ "%8 = OpLabel",
+ "OpReturn",
+ "OpFunctionEnd",
+ "; CHECK: OpFunction %void Inline",
+ "%main2 = OpFunction %void Inline %4",
+ "%9 = OpLabel",
+ "OpReturn",
+ "OpFunctionEnd",
+ "; CHECK: OpFunction %void Pure",
+ "%main3 = OpFunction %void DontInline|Pure %4",
+ "%10 = OpLabel",
+ "OpReturn",
+ "OpFunctionEnd",
+ "; CHECK: OpFunction %void None",
+ "%main4 = OpFunction %void None %4",
+ "%11 = OpLabel",
+ "OpReturn",
+ "OpFunctionEnd"
+ // clang-format on
+ };
+
+ SinglePassRunAndMatch<RemoveDontInline>(JoinAllInsts(text), true);
+}
+} // namespace
+} // namespace opt
+} // namespace spvtools