mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2025-01-13 01:40:14 +00:00
99fe61e724
This re-implements the -Oconfig=<file> flag to use a new API that takes a list of command-line flags representing optimization passes. This moves the processing of flags that create new optimization passes out of spirv-opt and into the library API. Useful for other tools that want to incorporate a facility similar to -Oconfig. The main changes are: 1- Add a new public function Optimizer::RegisterPassesFromFlags. This takes a vector of strings. Each string is assumed to have the form '--pass_name[=pass_args]'. It creates and registers into the pass manager all the passes specified in the vector. Each pass is validated internally. Failure to create a pass instance causes the function to return false and a diagnostic is emitted to the registered message consumer. 2- Re-implements -Oconfig in spirv-opt to use the new API.
214 lines
7.0 KiB
C++
214 lines
7.0 KiB
C++
// 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 <gmock/gmock.h>
|
|
|
|
#include "spirv-tools/libspirv.hpp"
|
|
#include "spirv-tools/optimizer.hpp"
|
|
|
|
#include "pass_fixture.h"
|
|
|
|
namespace spvtools {
|
|
namespace opt {
|
|
namespace {
|
|
|
|
using ::testing::Eq;
|
|
|
|
TEST(Optimizer, CanRunNullPassWithDistinctInputOutputVectors) {
|
|
SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
|
|
std::vector<uint32_t> binary_in;
|
|
tools.Assemble("OpName %foo \"foo\"\n%foo = OpTypeVoid", &binary_in);
|
|
|
|
Optimizer opt(SPV_ENV_UNIVERSAL_1_0);
|
|
opt.RegisterPass(CreateNullPass());
|
|
std::vector<uint32_t> binary_out;
|
|
opt.Run(binary_in.data(), binary_in.size(), &binary_out);
|
|
|
|
std::string disassembly;
|
|
tools.Disassemble(binary_out.data(), binary_out.size(), &disassembly);
|
|
EXPECT_THAT(disassembly, Eq("OpName %foo \"foo\"\n%foo = OpTypeVoid\n"));
|
|
}
|
|
|
|
TEST(Optimizer, CanRunTransformingPassWithDistinctInputOutputVectors) {
|
|
SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
|
|
std::vector<uint32_t> binary_in;
|
|
tools.Assemble("OpName %foo \"foo\"\n%foo = OpTypeVoid", &binary_in);
|
|
|
|
Optimizer opt(SPV_ENV_UNIVERSAL_1_0);
|
|
opt.RegisterPass(CreateStripDebugInfoPass());
|
|
std::vector<uint32_t> binary_out;
|
|
opt.Run(binary_in.data(), binary_in.size(), &binary_out);
|
|
|
|
std::string disassembly;
|
|
tools.Disassemble(binary_out.data(), binary_out.size(), &disassembly);
|
|
EXPECT_THAT(disassembly, Eq("%void = OpTypeVoid\n"));
|
|
}
|
|
|
|
TEST(Optimizer, CanRunNullPassWithAliasedVectors) {
|
|
SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
|
|
std::vector<uint32_t> binary;
|
|
tools.Assemble("OpName %foo \"foo\"\n%foo = OpTypeVoid", &binary);
|
|
|
|
Optimizer opt(SPV_ENV_UNIVERSAL_1_0);
|
|
opt.RegisterPass(CreateNullPass());
|
|
opt.Run(binary.data(), binary.size(), &binary); // This is the key.
|
|
|
|
std::string disassembly;
|
|
tools.Disassemble(binary.data(), binary.size(), &disassembly);
|
|
EXPECT_THAT(disassembly, Eq("OpName %foo \"foo\"\n%foo = OpTypeVoid\n"));
|
|
}
|
|
|
|
TEST(Optimizer, CanRunNullPassWithAliasedVectorDataButDifferentSize) {
|
|
SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
|
|
std::vector<uint32_t> binary;
|
|
tools.Assemble("OpName %foo \"foo\"\n%foo = OpTypeVoid", &binary);
|
|
|
|
Optimizer opt(SPV_ENV_UNIVERSAL_1_0);
|
|
opt.RegisterPass(CreateNullPass());
|
|
auto orig_size = binary.size();
|
|
// Now change the size. Add a word that will be ignored
|
|
// by the optimizer.
|
|
binary.push_back(42);
|
|
EXPECT_THAT(orig_size + 1, Eq(binary.size()));
|
|
opt.Run(binary.data(), orig_size, &binary); // This is the key.
|
|
// The binary vector should have been rewritten.
|
|
EXPECT_THAT(binary.size(), Eq(orig_size));
|
|
|
|
std::string disassembly;
|
|
tools.Disassemble(binary.data(), binary.size(), &disassembly);
|
|
EXPECT_THAT(disassembly, Eq("OpName %foo \"foo\"\n%foo = OpTypeVoid\n"));
|
|
}
|
|
|
|
TEST(Optimizer, CanRunTransformingPassWithAliasedVectors) {
|
|
SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
|
|
std::vector<uint32_t> binary;
|
|
tools.Assemble("OpName %foo \"foo\"\n%foo = OpTypeVoid", &binary);
|
|
|
|
Optimizer opt(SPV_ENV_UNIVERSAL_1_0);
|
|
opt.RegisterPass(CreateStripDebugInfoPass());
|
|
opt.Run(binary.data(), binary.size(), &binary); // This is the key
|
|
|
|
std::string disassembly;
|
|
tools.Disassemble(binary.data(), binary.size(), &disassembly);
|
|
EXPECT_THAT(disassembly, Eq("%void = OpTypeVoid\n"));
|
|
}
|
|
|
|
TEST(Optimizer, CanValidateFlags) {
|
|
Optimizer opt(SPV_ENV_UNIVERSAL_1_0);
|
|
EXPECT_FALSE(opt.FlagHasValidForm("bad-flag"));
|
|
EXPECT_TRUE(opt.FlagHasValidForm("-O"));
|
|
EXPECT_TRUE(opt.FlagHasValidForm("-Os"));
|
|
EXPECT_FALSE(opt.FlagHasValidForm("-O2"));
|
|
EXPECT_TRUE(opt.FlagHasValidForm("--this_flag"));
|
|
}
|
|
|
|
TEST(Optimizer, CanRegisterPassesFromFlags) {
|
|
SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
|
|
Optimizer opt(SPV_ENV_UNIVERSAL_1_0);
|
|
|
|
spv_message_level_t msg_level;
|
|
const char* msg_fname;
|
|
spv_position_t msg_position;
|
|
const char* msg;
|
|
auto examine_message = [&msg_level, &msg_fname, &msg_position, &msg](
|
|
spv_message_level_t ml, const char* f,
|
|
const spv_position_t& p, const char* m) {
|
|
msg_level = ml;
|
|
msg_fname = f;
|
|
msg_position = p;
|
|
msg = m;
|
|
};
|
|
opt.SetMessageConsumer(examine_message);
|
|
|
|
std::vector<std::string> pass_flags = {
|
|
"--strip-debug",
|
|
"--strip-reflect",
|
|
"--set-spec-const-default-value=23:42 21:12",
|
|
"--if-conversion",
|
|
"--freeze-spec-const",
|
|
"--inline-entry-points-exhaustive",
|
|
"--inline-entry-points-opaque",
|
|
"--convert-local-access-chains",
|
|
"--eliminate-dead-code-aggressive",
|
|
"--eliminate-insert-extract",
|
|
"--eliminate-local-single-block",
|
|
"--eliminate-local-single-store",
|
|
"--merge-blocks",
|
|
"--merge-return",
|
|
"--eliminate-dead-branches",
|
|
"--eliminate-dead-functions",
|
|
"--eliminate-local-multi-store",
|
|
"--eliminate-common-uniform",
|
|
"--eliminate-dead-const",
|
|
"--eliminate-dead-inserts",
|
|
"--eliminate-dead-variables",
|
|
"--fold-spec-const-op-composite",
|
|
"--loop-unswitch",
|
|
"--scalar-replacement=300",
|
|
"--scalar-replacement",
|
|
"--strength-reduction",
|
|
"--unify-const",
|
|
"--flatten-decorations",
|
|
"--compact-ids",
|
|
"--cfg-cleanup",
|
|
"--local-redundancy-elimination",
|
|
"--loop-invariant-code-motion",
|
|
"--reduce-load-size",
|
|
"--redundancy-elimination",
|
|
"--private-to-local",
|
|
"--remove-duplicates",
|
|
"--workaround-1209",
|
|
"--replace-invalid-opcode",
|
|
"--simplify-instructions",
|
|
"--ssa-rewrite",
|
|
"--copy-propagate-arrays",
|
|
"--loop-fission=20",
|
|
"--loop-fusion=2",
|
|
"--loop-unroll",
|
|
"--vector-dce",
|
|
"--loop-unroll-partial=3",
|
|
"--loop-peeling",
|
|
"--ccp",
|
|
"-O",
|
|
"-Os",
|
|
"--legalize-hlsl"};
|
|
EXPECT_TRUE(opt.RegisterPassesFromFlags(pass_flags));
|
|
|
|
// Test some invalid flags.
|
|
EXPECT_FALSE(opt.RegisterPassFromFlag("-O2"));
|
|
EXPECT_EQ(msg_level, SPV_MSG_ERROR);
|
|
|
|
EXPECT_FALSE(opt.RegisterPassFromFlag("-loop-unroll"));
|
|
EXPECT_EQ(msg_level, SPV_MSG_ERROR);
|
|
|
|
EXPECT_FALSE(opt.RegisterPassFromFlag("--set-spec-const-default-value"));
|
|
EXPECT_EQ(msg_level, SPV_MSG_ERROR);
|
|
|
|
EXPECT_FALSE(opt.RegisterPassFromFlag("--scalar-replacement=s"));
|
|
EXPECT_EQ(msg_level, SPV_MSG_ERROR);
|
|
|
|
EXPECT_FALSE(opt.RegisterPassFromFlag("--loop-fission=-4"));
|
|
EXPECT_EQ(msg_level, SPV_MSG_ERROR);
|
|
|
|
EXPECT_FALSE(opt.RegisterPassFromFlag("--loop-fusion=xx"));
|
|
EXPECT_EQ(msg_level, SPV_MSG_ERROR);
|
|
|
|
EXPECT_FALSE(opt.RegisterPassFromFlag("--loop-unroll-partial"));
|
|
EXPECT_EQ(msg_level, SPV_MSG_ERROR);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace opt
|
|
} // namespace spvtools
|