mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-12 19:50:09 +00:00
3b13040cf9
* Added a reduction pass to replace ids with ids of the same type that dominate them. * Introduce helper method for querying whether an operand type is an input id.
115 lines
4.8 KiB
C++
115 lines
4.8 KiB
C++
// Copyright (c) 2018 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 "operand_to_dominating_id_reduction_pass.h"
|
|
#include "change_operand_reduction_opportunity.h"
|
|
#include "source/opt/instruction.h"
|
|
|
|
namespace spvtools {
|
|
namespace reduce {
|
|
|
|
using namespace opt;
|
|
|
|
std::vector<std::unique_ptr<ReductionOpportunity>>
|
|
OperandToDominatingIdReductionPass::GetAvailableOpportunities(
|
|
opt::IRContext* context) const {
|
|
std::vector<std::unique_ptr<ReductionOpportunity>> result;
|
|
|
|
// Go through every instruction in every block, considering it as a potential
|
|
// dominator of other instructions. We choose this order for two reasons:
|
|
//
|
|
// (1) it is profitable for multiple opportunities to replace the same id x by
|
|
// different dominating ids y and z to be discontiguous, as they are
|
|
// incompatible.
|
|
//
|
|
// (2) We want to prioritise opportunities to replace an id with a more
|
|
// distant dominator. Intuitively, in a human-readable programming language
|
|
// if we have a complex expression e with many sub-expressions, we would like
|
|
// to prioritise replacing e with its smallest sub-expressions; generalising
|
|
// this idea to dominating ids this roughly corresponds to more distant
|
|
// dominators.
|
|
for (auto& function : *context->module()) {
|
|
for (auto dominating_block = function.begin();
|
|
dominating_block != function.end(); ++dominating_block) {
|
|
for (auto& dominating_inst : *dominating_block) {
|
|
if (dominating_inst.HasResultId() && dominating_inst.type_id()) {
|
|
// Consider replacing any operand with matching type in a dominated
|
|
// instruction with the id generated by this instruction.
|
|
GetOpportunitiesForDominatingInst(
|
|
&result, &dominating_inst, dominating_block, &function, context);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void OperandToDominatingIdReductionPass::GetOpportunitiesForDominatingInst(
|
|
std::vector<std::unique_ptr<ReductionOpportunity>>* opportunities,
|
|
opt::Instruction* candidate_dominator,
|
|
opt::Function::iterator candidate_dominator_block, opt::Function* function,
|
|
opt::IRContext* context) const {
|
|
assert(candidate_dominator->HasResultId());
|
|
assert(candidate_dominator->type_id());
|
|
auto dominator_analysis = context->GetDominatorAnalysis(function);
|
|
// SPIR-V requires a block to precede all blocks it dominates, so it suffices
|
|
// to search from the candidate dominator block onwards.
|
|
for (auto block = candidate_dominator_block; block != function->end();
|
|
++block) {
|
|
if (!dominator_analysis->Dominates(&*candidate_dominator_block, &*block)) {
|
|
// If the candidate dominator block doesn't dominate this block then there
|
|
// cannot be any of the desired reduction opportunities in this block.
|
|
continue;
|
|
}
|
|
for (auto& inst : *block) {
|
|
// We iterate through the operands using an explicit index (rather
|
|
// than using a lambda) so that we use said index in the construction
|
|
// of a ChangeOperandReductionOpportunity
|
|
for (uint32_t index = 0; index < inst.NumOperands(); index++) {
|
|
const auto& operand = inst.GetOperand(index);
|
|
if (spvIsInIdType(operand.type)) {
|
|
const auto id = operand.words[0];
|
|
auto def = context->get_def_use_mgr()->GetDef(id);
|
|
assert(def);
|
|
if (!context->get_instr_block(def)) {
|
|
// The definition does not come from a block; e.g. it might be a
|
|
// constant. It is thus not relevant to this pass.
|
|
continue;
|
|
}
|
|
// Sanity check that we don't get here if the argument is a constant.
|
|
assert(!context->get_constant_mgr()->GetConstantFromInst(def));
|
|
if (def->type_id() != candidate_dominator->type_id()) {
|
|
// The types need to match.
|
|
continue;
|
|
}
|
|
if (candidate_dominator != def &&
|
|
dominator_analysis->Dominates(candidate_dominator, def)) {
|
|
// A hit: the candidate dominator strictly dominates the definition.
|
|
opportunities->push_back(
|
|
MakeUnique<ChangeOperandReductionOpportunity>(
|
|
&inst, index, candidate_dominator->result_id()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string OperandToDominatingIdReductionPass::GetName() const {
|
|
return "OperandToDominatingIdReductionPass";
|
|
}
|
|
|
|
} // namespace reduce
|
|
} // namespace spvtools
|