mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-01 15:30:06 +00:00
spirv-reduce: add OperandToUndefReductionPass (#2200)
* Add OperandToUndefReductionPass. Fixes #2115. Also added some tests that are similar to those in OperandToConstantReductionPassTest. In addition, refactor FindOrCreateGlobalUndef into reduction_util.cpp. Fixes #2184. Removed many documentation comments that were identical or very similar to the overridden function's documentation comment.
This commit is contained in:
parent
5ec2d1a8cd
commit
71aa48f91d
@ -13,11 +13,14 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
set(SPIRV_TOOLS_REDUCE_SOURCES
|
set(SPIRV_TOOLS_REDUCE_SOURCES
|
||||||
change_operand_reduction_opportunity.h
|
change_operand_reduction_opportunity.h
|
||||||
|
change_operand_to_undef_reduction_opportunity.h
|
||||||
operand_to_const_reduction_pass.h
|
operand_to_const_reduction_pass.h
|
||||||
|
operand_to_undef_reduction_pass.h
|
||||||
operand_to_dominating_id_reduction_pass.h
|
operand_to_dominating_id_reduction_pass.h
|
||||||
reducer.h
|
reducer.h
|
||||||
reduction_opportunity.h
|
reduction_opportunity.h
|
||||||
reduction_pass.h
|
reduction_pass.h
|
||||||
|
reduction_util.h
|
||||||
remove_instruction_reduction_opportunity.h
|
remove_instruction_reduction_opportunity.h
|
||||||
remove_opname_instruction_reduction_pass.h
|
remove_opname_instruction_reduction_pass.h
|
||||||
remove_unreferenced_instruction_reduction_pass.h
|
remove_unreferenced_instruction_reduction_pass.h
|
||||||
@ -25,11 +28,14 @@ set(SPIRV_TOOLS_REDUCE_SOURCES
|
|||||||
structured_loop_to_selection_reduction_pass.h
|
structured_loop_to_selection_reduction_pass.h
|
||||||
|
|
||||||
change_operand_reduction_opportunity.cpp
|
change_operand_reduction_opportunity.cpp
|
||||||
|
change_operand_to_undef_reduction_opportunity.cpp
|
||||||
operand_to_const_reduction_pass.cpp
|
operand_to_const_reduction_pass.cpp
|
||||||
|
operand_to_undef_reduction_pass.cpp
|
||||||
operand_to_dominating_id_reduction_pass.cpp
|
operand_to_dominating_id_reduction_pass.cpp
|
||||||
reducer.cpp
|
reducer.cpp
|
||||||
reduction_opportunity.cpp
|
reduction_opportunity.cpp
|
||||||
reduction_pass.cpp
|
reduction_pass.cpp
|
||||||
|
reduction_util.cpp
|
||||||
remove_instruction_reduction_opportunity.cpp
|
remove_instruction_reduction_opportunity.cpp
|
||||||
remove_unreferenced_instruction_reduction_pass.cpp
|
remove_unreferenced_instruction_reduction_pass.cpp
|
||||||
remove_opname_instruction_reduction_pass.cpp
|
remove_opname_instruction_reduction_pass.cpp
|
||||||
|
@ -24,8 +24,7 @@ namespace reduce {
|
|||||||
|
|
||||||
using namespace opt;
|
using namespace opt;
|
||||||
|
|
||||||
// Captures the opportunity to change an id operand of an instruction to some
|
// An opportunity to replace an id operand of an instruction with some other id.
|
||||||
// other id.
|
|
||||||
class ChangeOperandReductionOpportunity : public ReductionOpportunity {
|
class ChangeOperandReductionOpportunity : public ReductionOpportunity {
|
||||||
public:
|
public:
|
||||||
// Constructs the opportunity to replace operand |operand_index| of |inst|
|
// Constructs the opportunity to replace operand |operand_index| of |inst|
|
||||||
@ -38,13 +37,9 @@ class ChangeOperandReductionOpportunity : public ReductionOpportunity {
|
|||||||
original_type_(inst->GetOperand(operand_index).type),
|
original_type_(inst->GetOperand(operand_index).type),
|
||||||
new_id_(new_id) {}
|
new_id_(new_id) {}
|
||||||
|
|
||||||
// Determines whether the opportunity can be applied; it may have been viable
|
|
||||||
// when discovered but later disabled by the application of some other
|
|
||||||
// reduction opportunity.
|
|
||||||
bool PreconditionHolds() override;
|
bool PreconditionHolds() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Apply the change of operand.
|
|
||||||
void Apply() override;
|
void Apply() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
// Copyright (c) 2018 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/change_operand_to_undef_reduction_opportunity.h"
|
||||||
|
|
||||||
|
#include "source/opt/ir_context.h"
|
||||||
|
#include "source/reduce/reduction_util.h"
|
||||||
|
|
||||||
|
namespace spvtools {
|
||||||
|
namespace reduce {
|
||||||
|
|
||||||
|
bool ChangeOperandToUndefReductionOpportunity::PreconditionHolds() {
|
||||||
|
// Check that the instruction still has the original operand.
|
||||||
|
return inst_->NumOperands() > operand_index_ &&
|
||||||
|
inst_->GetOperand(operand_index_).words[0] == original_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChangeOperandToUndefReductionOpportunity::Apply() {
|
||||||
|
auto operand = inst_->GetOperand(operand_index_);
|
||||||
|
auto operand_id = operand.words[0];
|
||||||
|
auto operand_id_def = context_->get_def_use_mgr()->GetDef(operand_id);
|
||||||
|
auto operand_type_id = operand_id_def->type_id();
|
||||||
|
// The opportunity should not exist unless this holds.
|
||||||
|
assert(operand_type_id);
|
||||||
|
auto undef_id = FindOrCreateGlobalUndef(context_, operand_type_id);
|
||||||
|
inst_->SetOperand(operand_index_, {undef_id});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace reduce
|
||||||
|
} // namespace spvtools
|
@ -0,0 +1,53 @@
|
|||||||
|
// Copyright (c) 2018 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_CHANGE_OPERAND_TO_UNDEF_REDUCTION_OPPORTUNITY_H_
|
||||||
|
#define SOURCE_REDUCE_CHANGE_OPERAND_TO_UNDEF_REDUCTION_OPPORTUNITY_H_
|
||||||
|
|
||||||
|
#include "source/opt/instruction.h"
|
||||||
|
#include "source/reduce/reduction_opportunity.h"
|
||||||
|
#include "spirv-tools/libspirv.h"
|
||||||
|
|
||||||
|
namespace spvtools {
|
||||||
|
namespace reduce {
|
||||||
|
|
||||||
|
// An opportunity to replace an id operand of an instruction with undef.
|
||||||
|
class ChangeOperandToUndefReductionOpportunity : public ReductionOpportunity {
|
||||||
|
public:
|
||||||
|
// Constructs the opportunity to replace operand |operand_index| of |inst|
|
||||||
|
// with undef.
|
||||||
|
ChangeOperandToUndefReductionOpportunity(opt::IRContext* context,
|
||||||
|
opt::Instruction* inst,
|
||||||
|
uint32_t operand_index)
|
||||||
|
: context_(context),
|
||||||
|
inst_(inst),
|
||||||
|
operand_index_(operand_index),
|
||||||
|
original_id_(inst->GetOperand(operand_index).words[0]) {}
|
||||||
|
|
||||||
|
bool PreconditionHolds() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void Apply() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
opt::IRContext* context_;
|
||||||
|
opt::Instruction* const inst_;
|
||||||
|
const uint32_t operand_index_;
|
||||||
|
const uint32_t original_id_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace reduce
|
||||||
|
} // namespace spvtools
|
||||||
|
|
||||||
|
#endif // SOURCE_REDUCE_CHANGE_OPERAND_TO_UNDEF_REDUCTION_OPPORTUNITY_H_
|
@ -12,9 +12,10 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "operand_to_const_reduction_pass.h"
|
#include "source/reduce/operand_to_const_reduction_pass.h"
|
||||||
#include "change_operand_reduction_opportunity.h"
|
|
||||||
#include "source/opt/instruction.h"
|
#include "source/opt/instruction.h"
|
||||||
|
#include "source/reduce/change_operand_reduction_opportunity.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace reduce {
|
namespace reduce {
|
||||||
|
@ -15,12 +15,12 @@
|
|||||||
#ifndef SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_PASS_H_
|
#ifndef SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_PASS_H_
|
||||||
#define SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_PASS_H_
|
#define SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_PASS_H_
|
||||||
|
|
||||||
#include "reduction_pass.h"
|
#include "source/reduce/reduction_pass.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace reduce {
|
namespace reduce {
|
||||||
|
|
||||||
// A reduction pass for turning id operands of instructions into ids of
|
// A reduction pass for replacing id operands of instructions with ids of
|
||||||
// constants. This reduces the extent to which ids of non-constants are used,
|
// constants. This reduces the extent to which ids of non-constants are used,
|
||||||
// paving the way for instructions that generate them to be eliminated by other
|
// paving the way for instructions that generate them to be eliminated by other
|
||||||
// passes.
|
// passes.
|
||||||
@ -33,12 +33,9 @@ class OperandToConstReductionPass : public ReductionPass {
|
|||||||
|
|
||||||
~OperandToConstReductionPass() override = default;
|
~OperandToConstReductionPass() override = default;
|
||||||
|
|
||||||
// The name of this pass.
|
|
||||||
std::string GetName() const final;
|
std::string GetName() const final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Finds all opportunities for replacing an operand with a constant in the
|
|
||||||
// given module.
|
|
||||||
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||||
opt::IRContext* context) const final;
|
opt::IRContext* context) const final;
|
||||||
|
|
||||||
|
@ -39,12 +39,9 @@ class OperandToDominatingIdReductionPass : public ReductionPass {
|
|||||||
|
|
||||||
~OperandToDominatingIdReductionPass() override = default;
|
~OperandToDominatingIdReductionPass() override = default;
|
||||||
|
|
||||||
// The name of this pass.
|
|
||||||
std::string GetName() const final;
|
std::string GetName() const final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Finds all opportunities for replacing an operand with a dominating
|
|
||||||
// instruction in a given module.
|
|
||||||
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||||
opt::IRContext* context) const final;
|
opt::IRContext* context) const final;
|
||||||
|
|
||||||
|
94
source/reduce/operand_to_undef_reduction_pass.cpp
Normal file
94
source/reduce/operand_to_undef_reduction_pass.cpp
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// Copyright (c) 2018 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/operand_to_undef_reduction_pass.h"
|
||||||
|
|
||||||
|
#include "source/opt/instruction.h"
|
||||||
|
#include "source/reduce/change_operand_to_undef_reduction_opportunity.h"
|
||||||
|
|
||||||
|
namespace spvtools {
|
||||||
|
namespace reduce {
|
||||||
|
|
||||||
|
using namespace opt;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<ReductionOpportunity>>
|
||||||
|
OperandToUndefReductionPass::GetAvailableOpportunities(
|
||||||
|
IRContext* context) const {
|
||||||
|
std::vector<std::unique_ptr<ReductionOpportunity>> result;
|
||||||
|
|
||||||
|
for (auto& function : *context->module()) {
|
||||||
|
for (auto& block : function) {
|
||||||
|
for (auto& inst : block) {
|
||||||
|
// Skip instructions that result in a pointer type.
|
||||||
|
auto type_id = inst.type_id();
|
||||||
|
if (type_id) {
|
||||||
|
auto type_id_def = context->get_def_use_mgr()->GetDef(type_id);
|
||||||
|
if (type_id_def->opcode() == SpvOpTypePointer) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 ChangeOperandToUndefReductionOpportunity
|
||||||
|
for (uint32_t index = 0; index < inst.NumOperands(); index++) {
|
||||||
|
const auto& operand = inst.GetOperand(index);
|
||||||
|
|
||||||
|
if (spvIsInIdType(operand.type)) {
|
||||||
|
const auto operand_id = operand.words[0];
|
||||||
|
auto operand_id_def =
|
||||||
|
context->get_def_use_mgr()->GetDef(operand_id);
|
||||||
|
|
||||||
|
// Skip constant and undef operands.
|
||||||
|
// We always want the reducer to make the module "smaller", which
|
||||||
|
// ensures termination.
|
||||||
|
// Therefore, we assume: id > undef id > constant id.
|
||||||
|
if (spvOpcodeIsConstantOrUndef(operand_id_def->opcode())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't replace function operands with undef.
|
||||||
|
if (operand_id_def->opcode() == SpvOpFunction) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only consider operands that have a type.
|
||||||
|
auto operand_type_id = operand_id_def->type_id();
|
||||||
|
if (operand_type_id) {
|
||||||
|
auto operand_type_id_def =
|
||||||
|
context->get_def_use_mgr()->GetDef(operand_type_id);
|
||||||
|
|
||||||
|
// Skip pointer operands.
|
||||||
|
if (operand_type_id_def->opcode() == SpvOpTypePointer) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push_back(
|
||||||
|
MakeUnique<ChangeOperandToUndefReductionOpportunity>(
|
||||||
|
context, &inst, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string OperandToUndefReductionPass::GetName() const {
|
||||||
|
return "OperandToUndefReductionPass";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace reduce
|
||||||
|
} // namespace spvtools
|
45
source/reduce/operand_to_undef_reduction_pass.h
Normal file
45
source/reduce/operand_to_undef_reduction_pass.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// Copyright (c) 2018 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_OPERAND_TO_UNDEF_REDUCTION_PASS_H_
|
||||||
|
#define SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_PASS_H_
|
||||||
|
|
||||||
|
#include "source/reduce/reduction_pass.h"
|
||||||
|
|
||||||
|
namespace spvtools {
|
||||||
|
namespace reduce {
|
||||||
|
|
||||||
|
// A reduction pass for replacing id operands of instructions with ids of undef.
|
||||||
|
class OperandToUndefReductionPass : public ReductionPass {
|
||||||
|
public:
|
||||||
|
// Creates the reduction pass in the context of the given target environment
|
||||||
|
// |target_env|
|
||||||
|
explicit OperandToUndefReductionPass(const spv_target_env target_env)
|
||||||
|
: ReductionPass(target_env) {}
|
||||||
|
|
||||||
|
~OperandToUndefReductionPass() override = default;
|
||||||
|
|
||||||
|
std::string GetName() const final;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||||
|
opt::IRContext* context) const final;
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace reduce
|
||||||
|
} // namespace spvtools
|
||||||
|
|
||||||
|
#endif // SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_PASS_H_
|
@ -20,23 +20,24 @@
|
|||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace reduce {
|
namespace reduce {
|
||||||
|
|
||||||
// Abstract class capturing an opportunity to apply a reducing transformation.
|
// Abstract class: an opportunity to apply a reducing transformation.
|
||||||
class ReductionOpportunity {
|
class ReductionOpportunity {
|
||||||
public:
|
public:
|
||||||
ReductionOpportunity() = default;
|
ReductionOpportunity() = default;
|
||||||
virtual ~ReductionOpportunity() = default;
|
virtual ~ReductionOpportunity() = default;
|
||||||
|
|
||||||
// Determines whether the opportunity can be applied; it may have been viable
|
// Returns true if this opportunity has not been disabled by the application
|
||||||
// when discovered but later disabled by the application of some other
|
// of another conflicting opportunity.
|
||||||
// reduction opportunity.
|
|
||||||
virtual bool PreconditionHolds() = 0;
|
virtual bool PreconditionHolds() = 0;
|
||||||
|
|
||||||
// A no-op if PreconditoinHolds() returns false; otherwise applies the
|
// Applies the opportunity, mutating the module from which the opportunity was
|
||||||
// opportunity.
|
// created. It is a no-op if PreconditionHolds() returns false.
|
||||||
void TryToApply();
|
void TryToApply();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Apply the reduction opportunity.
|
// Applies the opportunity, mutating the module from which the opportunity was
|
||||||
|
// created.
|
||||||
|
// Precondition: PreconditionHolds() must return true.
|
||||||
virtual void Apply() = 0;
|
virtual void Apply() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,13 +39,13 @@ class ReductionPass {
|
|||||||
|
|
||||||
virtual ~ReductionPass() = default;
|
virtual ~ReductionPass() = default;
|
||||||
|
|
||||||
// Apply the reduction pass to the given binary.
|
// Applies the reduction pass to the given binary.
|
||||||
std::vector<uint32_t> TryApplyReduction(const std::vector<uint32_t>& binary);
|
std::vector<uint32_t> TryApplyReduction(const std::vector<uint32_t>& binary);
|
||||||
|
|
||||||
// Set a consumer to which relevant messages will be directed.
|
// Sets a consumer to which relevant messages will be directed.
|
||||||
void SetMessageConsumer(MessageConsumer consumer);
|
void SetMessageConsumer(MessageConsumer consumer);
|
||||||
|
|
||||||
// Determines whether the granularity with which reduction opportunities are
|
// Returns true if the granularity with which reduction opportunities are
|
||||||
// applied has reached a minimum.
|
// applied has reached a minimum.
|
||||||
bool ReachedMinimumGranularity() const;
|
bool ReachedMinimumGranularity() const;
|
||||||
|
|
||||||
@ -54,8 +54,8 @@ class ReductionPass {
|
|||||||
virtual std::string GetName() const = 0;
|
virtual std::string GetName() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Finds the reduction opportunities relevant to this pass that could be
|
// Finds and returns the reduction opportunities relevant to this pass that
|
||||||
// applied to a given SPIR-V module.
|
// could be applied to the given SPIR-V module.
|
||||||
virtual std::vector<std::unique_ptr<ReductionOpportunity>>
|
virtual std::vector<std::unique_ptr<ReductionOpportunity>>
|
||||||
GetAvailableOpportunities(opt::IRContext* context) const = 0;
|
GetAvailableOpportunities(opt::IRContext* context) const = 0;
|
||||||
|
|
||||||
|
44
source/reduce/reduction_util.cpp
Normal file
44
source/reduce/reduction_util.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (c) 2018 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/reduction_util.h"
|
||||||
|
|
||||||
|
#include "source/opt/ir_context.h"
|
||||||
|
|
||||||
|
namespace spvtools {
|
||||||
|
namespace reduce {
|
||||||
|
|
||||||
|
using namespace opt;
|
||||||
|
|
||||||
|
uint32_t FindOrCreateGlobalUndef(IRContext* context, uint32_t type_id) {
|
||||||
|
for (auto& inst : context->module()->types_values()) {
|
||||||
|
if (inst.opcode() != SpvOpUndef) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (inst.type_id() == type_id) {
|
||||||
|
return inst.result_id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO(2182): this is adapted from MemPass::Type2Undef. In due course it
|
||||||
|
// would be good to factor out this duplication.
|
||||||
|
const uint32_t undef_id = context->TakeNextId();
|
||||||
|
std::unique_ptr<Instruction> undef_inst(
|
||||||
|
new Instruction(context, SpvOpUndef, type_id, undef_id, {}));
|
||||||
|
assert(undef_id == undef_inst->result_id());
|
||||||
|
context->module()->AddGlobalValue(std::move(undef_inst));
|
||||||
|
return undef_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace reduce
|
||||||
|
} // namespace spvtools
|
33
source/reduce/reduction_util.h
Normal file
33
source/reduce/reduction_util.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright (c) 2018 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_REDUCTION_UTIL_H_
|
||||||
|
#define SOURCE_REDUCE_REDUCTION_UTIL_H_
|
||||||
|
|
||||||
|
#include "spirv-tools/libspirv.hpp"
|
||||||
|
|
||||||
|
#include "source/opt/ir_context.h"
|
||||||
|
#include "source/reduce/reduction_opportunity.h"
|
||||||
|
|
||||||
|
namespace spvtools {
|
||||||
|
namespace reduce {
|
||||||
|
|
||||||
|
// Returns an OpUndef id from the global value list that is of the given type,
|
||||||
|
// adding one if it does not exist.
|
||||||
|
uint32_t FindOrCreateGlobalUndef(opt::IRContext* context, uint32_t type_id);
|
||||||
|
|
||||||
|
} // namespace reduce
|
||||||
|
} // namespace spvtools
|
||||||
|
|
||||||
|
#endif // SOURCE_REDUCE_REDUCTION_UTIL_H_
|
@ -23,18 +23,17 @@ namespace reduce {
|
|||||||
|
|
||||||
using namespace opt;
|
using namespace opt;
|
||||||
|
|
||||||
// Captures the opportunity to remove an instruction from the SPIR-V module.
|
// An opportunity to remove an instruction from the SPIR-V module.
|
||||||
class RemoveInstructionReductionOpportunity : public ReductionOpportunity {
|
class RemoveInstructionReductionOpportunity : public ReductionOpportunity {
|
||||||
public:
|
public:
|
||||||
// Constructs the opportunity to remove |inst|.
|
// Constructs the opportunity to remove |inst|.
|
||||||
explicit RemoveInstructionReductionOpportunity(Instruction* inst)
|
explicit RemoveInstructionReductionOpportunity(Instruction* inst)
|
||||||
: inst_(inst) {}
|
: inst_(inst) {}
|
||||||
|
|
||||||
// This kind of opportunity can be unconditionally applied.
|
// Always returns true, as this opportunity can always be applied.
|
||||||
bool PreconditionHolds() override;
|
bool PreconditionHolds() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Remove the instruction.
|
|
||||||
void Apply() override;
|
void Apply() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -21,8 +21,9 @@ namespace spvtools {
|
|||||||
namespace reduce {
|
namespace reduce {
|
||||||
|
|
||||||
// A reduction pass for removing OpName instructions. As well as making the
|
// A reduction pass for removing OpName instructions. As well as making the
|
||||||
// module smaller, removing an OpName instruction may create opportunities to
|
// module smaller, removing an OpName instruction may create opportunities
|
||||||
// remove the instruction that create the id to which the OpName applies.
|
// for subsequently removing the instructions that create the ids to which the
|
||||||
|
// OpName applies.
|
||||||
class RemoveOpNameInstructionReductionPass : public ReductionPass {
|
class RemoveOpNameInstructionReductionPass : public ReductionPass {
|
||||||
public:
|
public:
|
||||||
// Creates the reduction pass in the context of the given target environment
|
// Creates the reduction pass in the context of the given target environment
|
||||||
@ -32,12 +33,9 @@ class RemoveOpNameInstructionReductionPass : public ReductionPass {
|
|||||||
|
|
||||||
~RemoveOpNameInstructionReductionPass() override = default;
|
~RemoveOpNameInstructionReductionPass() override = default;
|
||||||
|
|
||||||
// The name of this pass.
|
|
||||||
std::string GetName() const final;
|
std::string GetName() const final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Finds all opportunities for removing opName instructions in the
|
|
||||||
// given module.
|
|
||||||
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||||
opt::IRContext* context) const final;
|
opt::IRContext* context) const final;
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ namespace reduce {
|
|||||||
|
|
||||||
// A reduction pass for removing non-control-flow instructions in blocks in
|
// A reduction pass for removing non-control-flow instructions in blocks in
|
||||||
// cases where the instruction's id is not referenced. As well as making the
|
// cases where the instruction's id is not referenced. As well as making the
|
||||||
// module smaller, removing an instruction that referenced particular ids may
|
// module smaller, removing an instruction that references particular ids may
|
||||||
// create opportunities for subsequently removing the instructions that
|
// create opportunities for subsequently removing the instructions that
|
||||||
// generated those ids.
|
// generated those ids.
|
||||||
class RemoveUnreferencedInstructionReductionPass : public ReductionPass {
|
class RemoveUnreferencedInstructionReductionPass : public ReductionPass {
|
||||||
@ -35,12 +35,9 @@ class RemoveUnreferencedInstructionReductionPass : public ReductionPass {
|
|||||||
|
|
||||||
~RemoveUnreferencedInstructionReductionPass() override = default;
|
~RemoveUnreferencedInstructionReductionPass() override = default;
|
||||||
|
|
||||||
// The name of this pass.
|
|
||||||
std::string GetName() const final;
|
std::string GetName() const final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Finds all opportunities for removing unreferenced instructions in the
|
|
||||||
// given module.
|
|
||||||
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||||
opt::IRContext* context) const final;
|
opt::IRContext* context) const final;
|
||||||
|
|
||||||
|
@ -12,9 +12,11 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "structured_loop_to_selection_reduction_opportunity.h"
|
#include "source/reduce/structured_loop_to_selection_reduction_opportunity.h"
|
||||||
|
|
||||||
#include "source/opt/aggressive_dead_code_elim_pass.h"
|
#include "source/opt/aggressive_dead_code_elim_pass.h"
|
||||||
#include "source/opt/ir_context.h"
|
#include "source/opt/ir_context.h"
|
||||||
|
#include "source/reduce/reduction_util.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace reduce {
|
namespace reduce {
|
||||||
@ -191,7 +193,7 @@ void StructuredLoopToSelectionReductionOpportunity::
|
|||||||
to_block->ForEachPhiInst([this, &from_id](Instruction* phi_inst) {
|
to_block->ForEachPhiInst([this, &from_id](Instruction* phi_inst) {
|
||||||
// Add to the phi operand an (undef, from_id) pair to reflect the added
|
// Add to the phi operand an (undef, from_id) pair to reflect the added
|
||||||
// edge.
|
// edge.
|
||||||
auto undef_id = FindOrCreateGlobalUndef(phi_inst->type_id());
|
auto undef_id = FindOrCreateGlobalUndef(context_, phi_inst->type_id());
|
||||||
phi_inst->AddOperand(Operand(SPV_OPERAND_TYPE_ID, {undef_id}));
|
phi_inst->AddOperand(Operand(SPV_OPERAND_TYPE_ID, {undef_id}));
|
||||||
phi_inst->AddOperand(Operand(SPV_OPERAND_TYPE_ID, {from_id}));
|
phi_inst->AddOperand(Operand(SPV_OPERAND_TYPE_ID, {from_id}));
|
||||||
});
|
});
|
||||||
@ -273,7 +275,8 @@ void StructuredLoopToSelectionReductionOpportunity::FixNonDominatedIdUses() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
use->SetOperand(index, {FindOrCreateGlobalUndef(def.type_id())});
|
use->SetOperand(index,
|
||||||
|
{FindOrCreateGlobalUndef(context_, def.type_id())});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -296,26 +299,6 @@ bool StructuredLoopToSelectionReductionOpportunity::
|
|||||||
->Dominates(def, use);
|
->Dominates(def, use);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t StructuredLoopToSelectionReductionOpportunity::FindOrCreateGlobalUndef(
|
|
||||||
uint32_t type_id) {
|
|
||||||
for (auto& inst : context_->module()->types_values()) {
|
|
||||||
if (inst.opcode() != SpvOpUndef) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (inst.type_id() == type_id) {
|
|
||||||
return inst.result_id();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO(2182): this is adapted from MemPass::Type2Undef. In due course it
|
|
||||||
// would be good to factor out this duplication.
|
|
||||||
const uint32_t undef_id = context_->TakeNextId();
|
|
||||||
std::unique_ptr<Instruction> undef_inst(
|
|
||||||
new Instruction(context_, SpvOpUndef, type_id, undef_id, {}));
|
|
||||||
assert(undef_id == undef_inst->result_id());
|
|
||||||
context_->module()->AddGlobalValue(std::move(undef_inst));
|
|
||||||
return undef_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
StructuredLoopToSelectionReductionOpportunity::FindOrCreateGlobalVariable(
|
StructuredLoopToSelectionReductionOpportunity::FindOrCreateGlobalVariable(
|
||||||
uint32_t pointer_type_id) {
|
uint32_t pointer_type_id) {
|
||||||
|
@ -15,17 +15,17 @@
|
|||||||
#ifndef SOURCE_REDUCE_CUT_LOOP_REDUCTION_OPPORTUNITY_H_
|
#ifndef SOURCE_REDUCE_CUT_LOOP_REDUCTION_OPPORTUNITY_H_
|
||||||
#define SOURCE_REDUCE_CUT_LOOP_REDUCTION_OPPORTUNITY_H_
|
#define SOURCE_REDUCE_CUT_LOOP_REDUCTION_OPPORTUNITY_H_
|
||||||
|
|
||||||
#include <source/opt/def_use_manager.h>
|
#include "source/opt/def_use_manager.h"
|
||||||
#include "reduction_opportunity.h"
|
|
||||||
#include "source/opt/dominator_analysis.h"
|
#include "source/opt/dominator_analysis.h"
|
||||||
#include "source/opt/function.h"
|
#include "source/opt/function.h"
|
||||||
|
#include "source/reduce/reduction_opportunity.h"
|
||||||
|
|
||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace reduce {
|
namespace reduce {
|
||||||
|
|
||||||
using namespace opt;
|
using namespace opt;
|
||||||
|
|
||||||
// Captures an opportunity to replace a structured loop with a selection.
|
// An opportunity to replace a structured loop with a selection.
|
||||||
class StructuredLoopToSelectionReductionOpportunity
|
class StructuredLoopToSelectionReductionOpportunity
|
||||||
: public ReductionOpportunity {
|
: public ReductionOpportunity {
|
||||||
public:
|
public:
|
||||||
@ -38,13 +38,12 @@ class StructuredLoopToSelectionReductionOpportunity
|
|||||||
loop_construct_header_(loop_construct_header),
|
loop_construct_header_(loop_construct_header),
|
||||||
enclosing_function_(enclosing_function) {}
|
enclosing_function_(enclosing_function) {}
|
||||||
|
|
||||||
// We require the loop header to be reachable. A structured loop might
|
// Returns true if the loop header is reachable. A structured loop might
|
||||||
// become unreachable as a result of turning another structured loop into
|
// become unreachable as a result of turning another structured loop into
|
||||||
// a selection.
|
// a selection.
|
||||||
bool PreconditionHolds() override;
|
bool PreconditionHolds() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Perform the structured loop to selection transformation.
|
|
||||||
void Apply() override;
|
void Apply() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -92,14 +91,6 @@ class StructuredLoopToSelectionReductionOpportunity
|
|||||||
uint32_t use_index,
|
uint32_t use_index,
|
||||||
BasicBlock& def_block);
|
BasicBlock& def_block);
|
||||||
|
|
||||||
// Checks whether the global value list has an OpUndef of the given type,
|
|
||||||
// adding one if not, and returns the id of such an OpUndef.
|
|
||||||
//
|
|
||||||
// TODO(2184): This will likely be used by other reduction passes, so should
|
|
||||||
// be factored out in due course. Parts of the spirv-opt framework provide
|
|
||||||
// similar functionality, so there may be a case for further refactoring.
|
|
||||||
uint32_t FindOrCreateGlobalUndef(uint32_t type_id);
|
|
||||||
|
|
||||||
// Checks whether the global value list has an OpVariable of the given pointer
|
// Checks whether the global value list has an OpVariable of the given pointer
|
||||||
// type, adding one if not, and returns the id of such an OpVariable.
|
// type, adding one if not, and returns the id of such an OpVariable.
|
||||||
//
|
//
|
||||||
|
@ -46,12 +46,9 @@ class StructuredLoopToSelectionReductionPass : public ReductionPass {
|
|||||||
|
|
||||||
~StructuredLoopToSelectionReductionPass() override = default;
|
~StructuredLoopToSelectionReductionPass() override = default;
|
||||||
|
|
||||||
// The name of this pass.
|
|
||||||
std::string GetName() const final;
|
std::string GetName() const final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Finds all opportunities for transforming a structured loop to a selection
|
|
||||||
// in the given module.
|
|
||||||
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities(
|
||||||
opt::IRContext* context) const final;
|
opt::IRContext* context) const final;
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
add_spvtools_unittest(TARGET reduce
|
add_spvtools_unittest(TARGET reduce
|
||||||
SRCS operand_to_constant_reduction_pass_test.cpp
|
SRCS operand_to_constant_reduction_pass_test.cpp
|
||||||
|
operand_to_undef_reduction_pass_test.cpp
|
||||||
operand_to_dominating_id_reduction_pass_test.cpp
|
operand_to_dominating_id_reduction_pass_test.cpp
|
||||||
reduce_test_util.cpp
|
reduce_test_util.cpp
|
||||||
reduce_test_util.h
|
reduce_test_util.h
|
||||||
|
226
test/reduce/operand_to_undef_reduction_pass_test.cpp
Normal file
226
test/reduce/operand_to_undef_reduction_pass_test.cpp
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
// Copyright (c) 2018 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/operand_to_undef_reduction_pass.h"
|
||||||
|
#include "source/opt/build_module.h"
|
||||||
|
#include "test/reduce/reduce_test_util.h"
|
||||||
|
|
||||||
|
namespace spvtools {
|
||||||
|
namespace reduce {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(OperandToUndefReductionPassTest, BasicCheck) {
|
||||||
|
// The following shader has 10 opportunities for replacing with undef.
|
||||||
|
|
||||||
|
// #version 310 es
|
||||||
|
//
|
||||||
|
// precision highp float;
|
||||||
|
//
|
||||||
|
// layout(location=0) out vec4 _GLF_color;
|
||||||
|
//
|
||||||
|
// layout(set = 0, binding = 0) uniform buf0 {
|
||||||
|
// vec2 uniform1;
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// void main()
|
||||||
|
// {
|
||||||
|
// _GLF_color =
|
||||||
|
// vec4( // opportunity
|
||||||
|
// uniform1.x / 2.0, // opportunity x2 (2.0 is const)
|
||||||
|
// uniform1.y / uniform1.x, // opportunity x3
|
||||||
|
// uniform1.x + uniform1.x, // opportunity x3
|
||||||
|
// uniform1.y); // opportunity
|
||||||
|
// }
|
||||||
|
|
||||||
|
std::string original = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
%1 = OpExtInstImport "GLSL.std.450"
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint Fragment %4 "main" %9
|
||||||
|
OpExecutionMode %4 OriginUpperLeft
|
||||||
|
OpSource ESSL 310
|
||||||
|
OpName %4 "main"
|
||||||
|
OpName %9 "_GLF_color"
|
||||||
|
OpName %11 "buf0"
|
||||||
|
OpMemberName %11 0 "uniform1"
|
||||||
|
OpName %13 ""
|
||||||
|
OpDecorate %9 Location 0
|
||||||
|
OpMemberDecorate %11 0 Offset 0
|
||||||
|
OpDecorate %11 Block
|
||||||
|
OpDecorate %13 DescriptorSet 0
|
||||||
|
OpDecorate %13 Binding 0
|
||||||
|
%2 = OpTypeVoid
|
||||||
|
%3 = OpTypeFunction %2
|
||||||
|
%6 = OpTypeFloat 32
|
||||||
|
%7 = OpTypeVector %6 4
|
||||||
|
%8 = OpTypePointer Output %7
|
||||||
|
%9 = OpVariable %8 Output
|
||||||
|
%10 = OpTypeVector %6 2
|
||||||
|
%11 = OpTypeStruct %10
|
||||||
|
%12 = OpTypePointer Uniform %11
|
||||||
|
%13 = OpVariable %12 Uniform
|
||||||
|
%14 = OpTypeInt 32 1
|
||||||
|
%15 = OpConstant %14 0
|
||||||
|
%16 = OpTypeInt 32 0
|
||||||
|
%17 = OpConstant %16 0
|
||||||
|
%18 = OpTypePointer Uniform %6
|
||||||
|
%21 = OpConstant %6 2
|
||||||
|
%23 = OpConstant %16 1
|
||||||
|
%4 = OpFunction %2 None %3
|
||||||
|
%5 = OpLabel
|
||||||
|
%19 = OpAccessChain %18 %13 %15 %17
|
||||||
|
%20 = OpLoad %6 %19
|
||||||
|
%22 = OpFDiv %6 %20 %21 ; opportunity %20 (%21 is const)
|
||||||
|
%24 = OpAccessChain %18 %13 %15 %23
|
||||||
|
%25 = OpLoad %6 %24
|
||||||
|
%26 = OpAccessChain %18 %13 %15 %17
|
||||||
|
%27 = OpLoad %6 %26
|
||||||
|
%28 = OpFDiv %6 %25 %27 ; opportunity %25 %27
|
||||||
|
%29 = OpAccessChain %18 %13 %15 %17
|
||||||
|
%30 = OpLoad %6 %29
|
||||||
|
%31 = OpAccessChain %18 %13 %15 %17
|
||||||
|
%32 = OpLoad %6 %31
|
||||||
|
%33 = OpFAdd %6 %30 %32 ; opportunity %30 %32
|
||||||
|
%34 = OpAccessChain %18 %13 %15 %23
|
||||||
|
%35 = OpLoad %6 %34
|
||||||
|
%36 = OpCompositeConstruct %7 %22 %28 %33 %35 ; opportunity %22 %28 %33 %35
|
||||||
|
OpStore %9 %36 ; opportunity %36
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
// This is the same as original, except where noted.
|
||||||
|
std::string expected = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
%1 = OpExtInstImport "GLSL.std.450"
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint Fragment %4 "main" %9
|
||||||
|
OpExecutionMode %4 OriginUpperLeft
|
||||||
|
OpSource ESSL 310
|
||||||
|
OpName %4 "main"
|
||||||
|
OpName %9 "_GLF_color"
|
||||||
|
OpName %11 "buf0"
|
||||||
|
OpMemberName %11 0 "uniform1"
|
||||||
|
OpName %13 ""
|
||||||
|
OpDecorate %9 Location 0
|
||||||
|
OpMemberDecorate %11 0 Offset 0
|
||||||
|
OpDecorate %11 Block
|
||||||
|
OpDecorate %13 DescriptorSet 0
|
||||||
|
OpDecorate %13 Binding 0
|
||||||
|
%2 = OpTypeVoid
|
||||||
|
%3 = OpTypeFunction %2
|
||||||
|
%6 = OpTypeFloat 32
|
||||||
|
%7 = OpTypeVector %6 4
|
||||||
|
%8 = OpTypePointer Output %7
|
||||||
|
%9 = OpVariable %8 Output
|
||||||
|
%10 = OpTypeVector %6 2
|
||||||
|
%11 = OpTypeStruct %10
|
||||||
|
%12 = OpTypePointer Uniform %11
|
||||||
|
%13 = OpVariable %12 Uniform
|
||||||
|
%14 = OpTypeInt 32 1
|
||||||
|
%15 = OpConstant %14 0
|
||||||
|
%16 = OpTypeInt 32 0
|
||||||
|
%17 = OpConstant %16 0
|
||||||
|
%18 = OpTypePointer Uniform %6
|
||||||
|
%21 = OpConstant %6 2
|
||||||
|
%23 = OpConstant %16 1
|
||||||
|
%37 = OpUndef %6 ; Added undef float as %37
|
||||||
|
%4 = OpFunction %2 None %3
|
||||||
|
%5 = OpLabel
|
||||||
|
%19 = OpAccessChain %18 %13 %15 %17
|
||||||
|
%20 = OpLoad %6 %19
|
||||||
|
%22 = OpFDiv %6 %37 %21 ; Replaced with %37
|
||||||
|
%24 = OpAccessChain %18 %13 %15 %23
|
||||||
|
%25 = OpLoad %6 %24
|
||||||
|
%26 = OpAccessChain %18 %13 %15 %17
|
||||||
|
%27 = OpLoad %6 %26
|
||||||
|
%28 = OpFDiv %6 %37 %37 ; Replaced with %37 twice
|
||||||
|
%29 = OpAccessChain %18 %13 %15 %17
|
||||||
|
%30 = OpLoad %6 %29
|
||||||
|
%31 = OpAccessChain %18 %13 %15 %17
|
||||||
|
%32 = OpLoad %6 %31
|
||||||
|
%33 = OpFAdd %6 %30 %32
|
||||||
|
%34 = OpAccessChain %18 %13 %15 %23
|
||||||
|
%35 = OpLoad %6 %34
|
||||||
|
%36 = OpCompositeConstruct %7 %22 %28 %33 %35
|
||||||
|
OpStore %9 %36
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||||
|
const auto consumer = nullptr;
|
||||||
|
const auto context =
|
||||||
|
BuildModule(env, consumer, original, kReduceAssembleOption);
|
||||||
|
const auto pass = TestSubclass<OperandToUndefReductionPass>(env);
|
||||||
|
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||||
|
|
||||||
|
ASSERT_EQ(10, ops.size());
|
||||||
|
|
||||||
|
// Apply first three opportunities.
|
||||||
|
ASSERT_TRUE(ops[0]->PreconditionHolds());
|
||||||
|
ops[0]->TryToApply();
|
||||||
|
ASSERT_TRUE(ops[1]->PreconditionHolds());
|
||||||
|
ops[1]->TryToApply();
|
||||||
|
ASSERT_TRUE(ops[2]->PreconditionHolds());
|
||||||
|
ops[2]->TryToApply();
|
||||||
|
|
||||||
|
CheckEqual(env, expected, context.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OperandToUndefReductionPassTest, WithCalledFunction) {
|
||||||
|
// The following shader has no opportunities.
|
||||||
|
// Most importantly, the noted function operand is not changed.
|
||||||
|
|
||||||
|
std::string shader = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
%1 = OpExtInstImport "GLSL.std.450"
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint Fragment %4 "main" %10 %12
|
||||||
|
OpExecutionMode %4 OriginUpperLeft
|
||||||
|
OpSource ESSL 310
|
||||||
|
%2 = OpTypeVoid
|
||||||
|
%3 = OpTypeFunction %2
|
||||||
|
%6 = OpTypeFloat 32
|
||||||
|
%7 = OpTypeVector %6 4
|
||||||
|
%8 = OpTypeFunction %7
|
||||||
|
%9 = OpTypePointer Output %7
|
||||||
|
%10 = OpVariable %9 Output
|
||||||
|
%11 = OpTypePointer Input %7
|
||||||
|
%12 = OpVariable %11 Input
|
||||||
|
%13 = OpConstant %6 0
|
||||||
|
%14 = OpConstantComposite %7 %13 %13 %13 %13
|
||||||
|
%4 = OpFunction %2 None %3
|
||||||
|
%5 = OpLabel
|
||||||
|
%15 = OpFunctionCall %7 %16 ; do not replace %16 with undef
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
%16 = OpFunction %7 None %8
|
||||||
|
%17 = OpLabel
|
||||||
|
OpReturnValue %14
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||||
|
const auto consumer = nullptr;
|
||||||
|
const auto context =
|
||||||
|
BuildModule(env, consumer, shader, kReduceAssembleOption);
|
||||||
|
const auto pass = TestSubclass<OperandToUndefReductionPass>(env);
|
||||||
|
const auto ops = pass.WrapGetAvailableOpportunities(context.get());
|
||||||
|
ASSERT_EQ(0, ops.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace reduce
|
||||||
|
} // namespace spvtools
|
@ -22,6 +22,7 @@
|
|||||||
#include "source/opt/log.h"
|
#include "source/opt/log.h"
|
||||||
#include "source/reduce/operand_to_const_reduction_pass.h"
|
#include "source/reduce/operand_to_const_reduction_pass.h"
|
||||||
#include "source/reduce/operand_to_dominating_id_reduction_pass.h"
|
#include "source/reduce/operand_to_dominating_id_reduction_pass.h"
|
||||||
|
#include "source/reduce/operand_to_undef_reduction_pass.h"
|
||||||
#include "source/reduce/reducer.h"
|
#include "source/reduce/reducer.h"
|
||||||
#include "source/reduce/remove_opname_instruction_reduction_pass.h"
|
#include "source/reduce/remove_opname_instruction_reduction_pass.h"
|
||||||
#include "source/reduce/remove_unreferenced_instruction_reduction_pass.h"
|
#include "source/reduce/remove_unreferenced_instruction_reduction_pass.h"
|
||||||
@ -207,6 +208,8 @@ int main(int argc, const char** argv) {
|
|||||||
|
|
||||||
reducer.AddReductionPass(
|
reducer.AddReductionPass(
|
||||||
spvtools::MakeUnique<RemoveOpNameInstructionReductionPass>(target_env));
|
spvtools::MakeUnique<RemoveOpNameInstructionReductionPass>(target_env));
|
||||||
|
reducer.AddReductionPass(
|
||||||
|
spvtools::MakeUnique<OperandToUndefReductionPass>(target_env));
|
||||||
reducer.AddReductionPass(
|
reducer.AddReductionPass(
|
||||||
spvtools::MakeUnique<OperandToConstReductionPass>(target_env));
|
spvtools::MakeUnique<OperandToConstReductionPass>(target_env));
|
||||||
reducer.AddReductionPass(
|
reducer.AddReductionPass(
|
||||||
|
Loading…
Reference in New Issue
Block a user