mirror of
https://gitee.com/openharmony/third_party_spirv-tools
synced 2024-11-23 07:20:28 +00:00
Merge blocks in reducer (#2353)
Fixes #2120 Enhanced the reducer so that it can merge blocks together, leveraging the functionality extracted from the block_merge pass in the optimizer.
This commit is contained in:
parent
453b7c85c8
commit
37861ac106
@ -14,6 +14,8 @@
|
||||
set(SPIRV_TOOLS_REDUCE_SOURCES
|
||||
change_operand_reduction_opportunity.h
|
||||
change_operand_to_undef_reduction_opportunity.h
|
||||
merge_blocks_reduction_opportunity.h
|
||||
merge_blocks_reduction_opportunity_finder.h
|
||||
operand_to_const_reduction_opportunity_finder.h
|
||||
operand_to_undef_reduction_opportunity_finder.h
|
||||
operand_to_dominating_id_reduction_opportunity_finder.h
|
||||
@ -30,6 +32,8 @@ set(SPIRV_TOOLS_REDUCE_SOURCES
|
||||
|
||||
change_operand_reduction_opportunity.cpp
|
||||
change_operand_to_undef_reduction_opportunity.cpp
|
||||
merge_blocks_reduction_opportunity.cpp
|
||||
merge_blocks_reduction_opportunity_finder.cpp
|
||||
operand_to_const_reduction_opportunity_finder.cpp
|
||||
operand_to_undef_reduction_opportunity_finder.cpp
|
||||
operand_to_dominating_id_reduction_opportunity_finder.cpp
|
||||
|
67
source/reduce/merge_blocks_reduction_opportunity.cpp
Normal file
67
source/reduce/merge_blocks_reduction_opportunity.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2019 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 "merge_blocks_reduction_opportunity.h"
|
||||
#include "source/opt/block_merge_util.h"
|
||||
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
using namespace opt;
|
||||
|
||||
MergeBlocksReductionOpportunity::MergeBlocksReductionOpportunity(
|
||||
IRContext* context, Function* function, BasicBlock* block) {
|
||||
// Precondition: the terminator has to be OpBranch.
|
||||
assert(block->terminator()->opcode() == SpvOpBranch);
|
||||
context_ = context;
|
||||
function_ = function;
|
||||
// Get the successor block associated with the OpBranch.
|
||||
successor_block_ =
|
||||
context->cfg()->block(block->terminator()->GetSingleWordInOperand(0));
|
||||
}
|
||||
|
||||
bool MergeBlocksReductionOpportunity::PreconditionHolds() {
|
||||
// By construction, it is not possible for the merging of A->B to disable the
|
||||
// merging of C->D, even when B and C are the same block.
|
||||
return true;
|
||||
}
|
||||
|
||||
void MergeBlocksReductionOpportunity::Apply() {
|
||||
// While the original block that targeted the successor may not exist anymore
|
||||
// (it might have been merged with another block), some block must exist that
|
||||
// targets the successor. Find it.
|
||||
|
||||
const auto predecessors = context_->cfg()->preds(successor_block_->id());
|
||||
assert(1 == predecessors.size() &&
|
||||
"For a successor to be merged into its predecessor, exactly one "
|
||||
"predecessor must be present.");
|
||||
const uint32_t predecessor_id = predecessors[0];
|
||||
|
||||
for (auto bi = function_->begin(); bi != function_->end(); ++bi) {
|
||||
if (bi->id() == predecessor_id) {
|
||||
blockmergeutil::MergeWithSuccessor(context_, function_, bi);
|
||||
// Block merging changes the control flow graph, so invalidate it.
|
||||
context_->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
assert(false &&
|
||||
"Unreachable: we should have found a block with the desired id.");
|
||||
}
|
||||
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
53
source/reduce/merge_blocks_reduction_opportunity.h
Normal file
53
source/reduce/merge_blocks_reduction_opportunity.h
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2019 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_REDUCE_MERGE_BLOCKS_REDUCTION_OPPORTUNITY_H_
|
||||
#define SOURCE_REDUCE_MERGE_BLOCKS_REDUCTION_OPPORTUNITY_H_
|
||||
|
||||
#include "reduction_opportunity.h"
|
||||
#include "source/opt/basic_block.h"
|
||||
#include "source/opt/function.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
// An opportunity to merge two blocks into one.
|
||||
class MergeBlocksReductionOpportunity : public ReductionOpportunity {
|
||||
public:
|
||||
// Creates the opportunity to merge |block| with its successor, where |block|
|
||||
// is inside |function|, and |context| is the enclosing IR context.
|
||||
MergeBlocksReductionOpportunity(opt::IRContext* context,
|
||||
opt::Function* function,
|
||||
opt::BasicBlock* block);
|
||||
|
||||
bool PreconditionHolds() override;
|
||||
|
||||
protected:
|
||||
void Apply() override;
|
||||
|
||||
private:
|
||||
opt::IRContext* context_;
|
||||
opt::Function* function_;
|
||||
|
||||
// Rather than holding on to the block that can be merged with its successor,
|
||||
// we hold on to its successor. This is because the predecessor block might
|
||||
// get merged with *its* predecessor, and so will no longer exist, while the
|
||||
// successor will continue to exist until this opportunity gets applied.
|
||||
opt::BasicBlock* successor_block_;
|
||||
};
|
||||
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_REDUCE_MERGE_BLOCKS_REDUCTION_OPPORTUNITY_H_
|
48
source/reduce/merge_blocks_reduction_opportunity_finder.cpp
Normal file
48
source/reduce/merge_blocks_reduction_opportunity_finder.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2019 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/reduce/merge_blocks_reduction_opportunity_finder.h"
|
||||
#include "source/opt/block_merge_util.h"
|
||||
#include "source/reduce/merge_blocks_reduction_opportunity.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
using namespace opt;
|
||||
|
||||
std::string MergeBlocksReductionOpportunityFinder::GetName() const {
|
||||
return "MergeBlocksReductionOpportunityFinder";
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>>
|
||||
MergeBlocksReductionOpportunityFinder::GetAvailableOpportunities(
|
||||
opt::IRContext* context) const {
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> result;
|
||||
|
||||
// Consider every block in every function.
|
||||
for (auto& function : *context->module()) {
|
||||
for (auto& block : function) {
|
||||
// See whether it is possible to merge this block with its successor.
|
||||
if (blockmergeutil::CanMergeWithSuccessor(context, &block)) {
|
||||
// It is, so record an opportunity to do this.
|
||||
result.push_back(spvtools::MakeUnique<MergeBlocksReductionOpportunity>(
|
||||
context, &function, &block));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
42
source/reduce/merge_blocks_reduction_opportunity_finder.h
Normal file
42
source/reduce/merge_blocks_reduction_opportunity_finder.h
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2019 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_REDUCE_MERGE_BLOCKS_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
#define SOURCE_REDUCE_MERGE_BLOCKS_REDUCTION_OPPORTUNITY_FINDER_H_
|
||||
|
||||
#include "source/reduce/reduction_opportunity_finder.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
|
||||
// A finder of opportunities to merge blocks together.
|
||||
class MergeBlocksReductionOpportunityFinder
|
||||
: public ReductionOpportunityFinder {
|
||||
public:
|
||||
MergeBlocksReductionOpportunityFinder() = default;
|
||||
|
||||
~MergeBlocksReductionOpportunityFinder() override = default;
|
||||
|
||||
std::string GetName() const final;
|
||||
|
||||
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||
opt::IRContext* context) const final;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_REDUCE_MERGE_BLOCKS_REDUCTION_OPPORTUNITY_FINDER_H_
|
@ -13,7 +13,8 @@
|
||||
# limitations under the License.
|
||||
|
||||
add_spvtools_unittest(TARGET reduce
|
||||
SRCS operand_to_constant_test.cpp
|
||||
SRCS merge_blocks_test.cpp
|
||||
operand_to_constant_test.cpp
|
||||
operand_to_undef_test.cpp
|
||||
operand_to_dominating_id_test.cpp
|
||||
reduce_test_util.cpp
|
||||
|
513
test/reduce/merge_blocks_test.cpp
Normal file
513
test/reduce/merge_blocks_test.cpp
Normal file
@ -0,0 +1,513 @@
|
||||
// Copyright (c) 2019 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 "reduce_test_util.h"
|
||||
#include "source/opt/build_module.h"
|
||||
#include "source/reduce/merge_blocks_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/reduction_opportunity.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace reduce {
|
||||
namespace {
|
||||
|
||||
TEST(MergeBlocksReductionPassTest, BasicCheck) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%10 = OpConstant %6 2
|
||||
%11 = OpConstant %6 3
|
||||
%12 = OpConstant %6 4
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
OpStore %8 %9
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
OpStore %8 %10
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
OpStore %8 %11
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
OpStore %8 %12
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, shader, kReduceAssembleOption);
|
||||
const auto ops =
|
||||
MergeBlocksReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
ASSERT_EQ(5, ops.size());
|
||||
|
||||
// Try order 3, 0, 2, 4, 1
|
||||
|
||||
ASSERT_TRUE(ops[3]->PreconditionHolds());
|
||||
ops[3]->TryToApply();
|
||||
|
||||
std::string after_op_3 = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%10 = OpConstant %6 2
|
||||
%11 = OpConstant %6 3
|
||||
%12 = OpConstant %6 4
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
OpStore %8 %9
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
OpStore %8 %10
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
OpStore %8 %11
|
||||
OpStore %8 %12
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CheckEqual(env, after_op_3, context.get());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
ops[0]->TryToApply();
|
||||
|
||||
std::string after_op_0 = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%10 = OpConstant %6 2
|
||||
%11 = OpConstant %6 3
|
||||
%12 = OpConstant %6 4
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
OpStore %8 %10
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
OpStore %8 %11
|
||||
OpStore %8 %12
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CheckEqual(env, after_op_0, context.get());
|
||||
|
||||
ASSERT_TRUE(ops[2]->PreconditionHolds());
|
||||
ops[2]->TryToApply();
|
||||
|
||||
std::string after_op_2 = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%10 = OpConstant %6 2
|
||||
%11 = OpConstant %6 3
|
||||
%12 = OpConstant %6 4
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
OpStore %8 %10
|
||||
OpStore %8 %11
|
||||
OpStore %8 %12
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CheckEqual(env, after_op_2, context.get());
|
||||
|
||||
ASSERT_TRUE(ops[4]->PreconditionHolds());
|
||||
ops[4]->TryToApply();
|
||||
|
||||
std::string after_op_4 = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%10 = OpConstant %6 2
|
||||
%11 = OpConstant %6 3
|
||||
%12 = OpConstant %6 4
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
OpStore %8 %10
|
||||
OpStore %8 %11
|
||||
OpStore %8 %12
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CheckEqual(env, after_op_4, context.get());
|
||||
|
||||
ASSERT_TRUE(ops[1]->PreconditionHolds());
|
||||
ops[1]->TryToApply();
|
||||
|
||||
std::string after_op_1 = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%10 = OpConstant %6 2
|
||||
%11 = OpConstant %6 3
|
||||
%12 = OpConstant %6 4
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpStore %8 %10
|
||||
OpStore %8 %11
|
||||
OpStore %8 %12
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CheckEqual(env, after_op_1, context.get());
|
||||
}
|
||||
|
||||
TEST(MergeBlocksReductionPassTest, Loops) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %10 "i"
|
||||
OpName %29 "i"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%11 = OpConstant %6 0
|
||||
%18 = OpConstant %6 10
|
||||
%19 = OpTypeBool
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%29 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %45
|
||||
%45 = OpLabel
|
||||
OpStore %10 %11
|
||||
OpBranch %12
|
||||
%12 = OpLabel
|
||||
OpLoopMerge %14 %15 None
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
%17 = OpLoad %6 %10
|
||||
OpBranch %46
|
||||
%46 = OpLabel
|
||||
%20 = OpSLessThan %19 %17 %18
|
||||
OpBranchConditional %20 %13 %14
|
||||
%13 = OpLabel
|
||||
%21 = OpLoad %6 %10
|
||||
OpBranch %47
|
||||
%47 = OpLabel
|
||||
%22 = OpLoad %6 %8
|
||||
%23 = OpIAdd %6 %22 %21
|
||||
OpStore %8 %23
|
||||
%24 = OpLoad %6 %10
|
||||
%25 = OpLoad %6 %8
|
||||
%26 = OpIAdd %6 %25 %24
|
||||
OpStore %8 %26
|
||||
OpBranch %48
|
||||
%48 = OpLabel
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
%27 = OpLoad %6 %10
|
||||
%28 = OpIAdd %6 %27 %9
|
||||
OpStore %10 %28
|
||||
OpBranch %12
|
||||
%14 = OpLabel
|
||||
OpStore %29 %11
|
||||
OpBranch %49
|
||||
%49 = OpLabel
|
||||
OpBranch %30
|
||||
%30 = OpLabel
|
||||
OpLoopMerge %32 %33 None
|
||||
OpBranch %34
|
||||
%34 = OpLabel
|
||||
%35 = OpLoad %6 %29
|
||||
%36 = OpSLessThan %19 %35 %18
|
||||
OpBranch %50
|
||||
%50 = OpLabel
|
||||
OpBranchConditional %36 %31 %32
|
||||
%31 = OpLabel
|
||||
%37 = OpLoad %6 %29
|
||||
%38 = OpLoad %6 %8
|
||||
%39 = OpIAdd %6 %38 %37
|
||||
OpStore %8 %39
|
||||
%40 = OpLoad %6 %29
|
||||
%41 = OpLoad %6 %8
|
||||
%42 = OpIAdd %6 %41 %40
|
||||
OpStore %8 %42
|
||||
OpBranch %33
|
||||
%33 = OpLabel
|
||||
%43 = OpLoad %6 %29
|
||||
%44 = OpIAdd %6 %43 %9
|
||||
OpBranch %51
|
||||
%51 = OpLabel
|
||||
OpStore %29 %44
|
||||
OpBranch %30
|
||||
%32 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, shader, kReduceAssembleOption);
|
||||
const auto ops =
|
||||
MergeBlocksReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
ASSERT_EQ(11, ops.size());
|
||||
|
||||
for (auto& ri : ops) {
|
||||
ASSERT_TRUE(ri->PreconditionHolds());
|
||||
ri->TryToApply();
|
||||
}
|
||||
|
||||
std::string after = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %10 "i"
|
||||
OpName %29 "i"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%11 = OpConstant %6 0
|
||||
%18 = OpConstant %6 10
|
||||
%19 = OpTypeBool
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%29 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpStore %10 %11
|
||||
OpBranch %12
|
||||
%12 = OpLabel
|
||||
%17 = OpLoad %6 %10
|
||||
%20 = OpSLessThan %19 %17 %18
|
||||
OpLoopMerge %14 %13 None
|
||||
OpBranchConditional %20 %13 %14
|
||||
%13 = OpLabel
|
||||
%21 = OpLoad %6 %10
|
||||
%22 = OpLoad %6 %8
|
||||
%23 = OpIAdd %6 %22 %21
|
||||
OpStore %8 %23
|
||||
%24 = OpLoad %6 %10
|
||||
%25 = OpLoad %6 %8
|
||||
%26 = OpIAdd %6 %25 %24
|
||||
OpStore %8 %26
|
||||
%27 = OpLoad %6 %10
|
||||
%28 = OpIAdd %6 %27 %9
|
||||
OpStore %10 %28
|
||||
OpBranch %12
|
||||
%14 = OpLabel
|
||||
OpStore %29 %11
|
||||
OpBranch %30
|
||||
%30 = OpLabel
|
||||
%35 = OpLoad %6 %29
|
||||
%36 = OpSLessThan %19 %35 %18
|
||||
OpLoopMerge %32 %31 None
|
||||
OpBranchConditional %36 %31 %32
|
||||
%31 = OpLabel
|
||||
%37 = OpLoad %6 %29
|
||||
%38 = OpLoad %6 %8
|
||||
%39 = OpIAdd %6 %38 %37
|
||||
OpStore %8 %39
|
||||
%40 = OpLoad %6 %29
|
||||
%41 = OpLoad %6 %8
|
||||
%42 = OpIAdd %6 %41 %40
|
||||
OpStore %8 %42
|
||||
%43 = OpLoad %6 %29
|
||||
%44 = OpIAdd %6 %43 %9
|
||||
OpStore %29 %44
|
||||
OpBranch %30
|
||||
%32 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CheckEqual(env, after, context.get());
|
||||
}
|
||||
|
||||
TEST(MergeBlocksReductionPassTest, MergeWithOpPhi) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %10 "y"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
%11 = OpLoad %6 %8
|
||||
OpBranch %12
|
||||
%12 = OpLabel
|
||||
%13 = OpPhi %6 %11 %5
|
||||
OpStore %10 %13
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, shader, kReduceAssembleOption);
|
||||
const auto ops =
|
||||
MergeBlocksReductionOpportunityFinder().GetAvailableOpportunities(
|
||||
context.get());
|
||||
ASSERT_EQ(1, ops.size());
|
||||
|
||||
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||
ops[0]->TryToApply();
|
||||
|
||||
std::string after = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %10 "y"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
%11 = OpLoad %6 %8
|
||||
OpStore %10 %11
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CheckEqual(env, after, context.get());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace reduce
|
||||
} // namespace spvtools
|
@ -20,6 +20,7 @@
|
||||
#include "source/opt/build_module.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
#include "source/opt/log.h"
|
||||
#include "source/reduce/merge_blocks_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/operand_to_const_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h"
|
||||
#include "source/reduce/operand_to_undef_reduction_opportunity_finder.h"
|
||||
@ -240,6 +241,8 @@ int main(int argc, const char** argv) {
|
||||
reducer.AddReductionPass(
|
||||
spvtools::MakeUnique<
|
||||
StructuredLoopToSelectionReductionOpportunityFinder>());
|
||||
reducer.AddReductionPass(
|
||||
spvtools::MakeUnique<MergeBlocksReductionOpportunityFinder>());
|
||||
|
||||
reducer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user