SPIRV-Tools/source/opt/eliminate_dead_members_pass.h
Steven Perron 8eddde2e70
Don't change type of input and output var in dead member elim (#2412)
The types of input and output variables must match for the pipeline.  We
cannot see the uses in all of the shader, so dead member
elimination cannot safely change the type of input and output variables.
2019-02-20 18:59:41 -05:00

147 lines
6.1 KiB
C++

// 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_OPT_ELIMINATE_DEAD_MEMBERS_PASS_H_
#define SOURCE_OPT_ELIMINATE_DEAD_MEMBERS_PASS_H_
#include "source/opt/def_use_manager.h"
#include "source/opt/function.h"
#include "source/opt/mem_pass.h"
#include "source/opt/module.h"
namespace spvtools {
namespace opt {
// Remove unused members from structures. The remaining members will remain at
// the same offset.
class EliminateDeadMembersPass : public MemPass {
public:
const char* name() const override { return "eliminate-dead-members"; }
Status Process() override;
IRContext::Analysis GetPreservedAnalyses() override {
return IRContext::kAnalysisDefUse |
IRContext::kAnalysisInstrToBlockMapping |
IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG |
IRContext::kAnalysisDominatorAnalysis |
IRContext::kAnalysisLoopAnalysis |
IRContext::kAnalysisScalarEvolution |
IRContext::kAnalysisRegisterPressure |
IRContext::kAnalysisValueNumberTable |
IRContext::kAnalysisStructuredCFG |
IRContext::kAnalysisBuiltinVarId |
IRContext::kAnalysisIdToFuncMapping;
}
private:
// Populate |used_members_| with the member of structures that are live in the
// current context.
void FindLiveMembers();
// Add to |used_members_| the member of structures that are live in
// |function|.
void FindLiveMembers(const Function& function);
// Add to |used_members_| the member of structures that are live in |inst|.
void FindLiveMembers(const Instruction* inst);
// Add to |used_members_| the members that are live in the |OpStore|
// instruction |inst|.
void MarkMembersAsLiveForStore(const Instruction* inst);
// Add to |used_members_| the members that are live in the |OpCopyMemory*|
// instruction |inst|.
void MarkMembersAsLiveForCopyMemory(const Instruction* inst);
// Add to |used_members_| the members that are live in the
// |OpCompositeExtract| instruction |inst|.
void MarkMembersAsLiveForExtract(const Instruction* inst);
// Add to |used_members_| the members that are live in the |Op*AccessChain|
// instruction |inst|.
void MarkMembersAsLiveForAccessChain(const Instruction* inst);
// Add the member referenced by the OpArrayLength instruction |inst| to
// |uses_members_|.
void MarkMembersAsLiveForArrayLength(const Instruction* inst);
// Remove dead members from structs and updates any instructions that need to
// be updated as a consequence. Return true if something changed.
bool RemoveDeadMembers();
// Update |inst|, which must be an |OpMemberName| or |OpMemberDecorate|
// instruction, so it references the correct member after the struct is
// updated. Return true if something changed.
bool UpdateOpMemberNameOrDecorate(Instruction* inst);
// Update |inst|, which must be an |OpGroupMemberDecorate| instruction, so it
// references the correct member after the struct is updated. Return true if
// something changed.
bool UpdateOpGroupMemberDecorate(Instruction* inst);
// Update the |OpTypeStruct| instruction |inst| my removing the members that
// are not live. Return true if something changed.
bool UpdateOpTypeStruct(Instruction* inst);
// Update the |OpConstantComposite| instruction |inst| to match the change
// made to the type that was being generated. Return true if something
// changed.
bool UpdateConstantComposite(Instruction* inst);
// Update the |Op*AccessChain| instruction |inst| to reference the correct
// members. All members referenced in the access chain must be live. This
// function must be called after the |OpTypeStruct| instruction for the type
// has been updated. Return true if something changed.
bool UpdateAccessChain(Instruction* inst);
// Update the |OpCompositeExtract| instruction |inst| to reference the correct
// members. All members referenced in the instruction must be live. This
// function must be called after the |OpTypeStruct| instruction for the type
// has been updated. Return true if something changed.
bool UpdateCompsiteExtract(Instruction* inst);
// Update the |OpCompositeInsert| instruction |inst| to reference the correct
// members. If the member being inserted is not live, then |inst| is killed.
// This function must be called after the |OpTypeStruct| instruction for the
// type has been updated. Return true if something changed.
bool UpdateCompositeInsert(Instruction* inst);
// Update the |OpArrayLength| instruction |inst| to reference the correct
// member. The member referenced in the instruction must be live. Return true
// if something changed.
bool UpdateOpArrayLength(Instruction* inst);
// Add all of the members of type |type_id| and members of any subtypes to
// |used_members_|.
void MarkTypeAsFullyUsed(uint32_t type_id);
// Add all of the members of the type of the operand |in_idx| in |inst| and
// members of any subtypes to |uses_members_|.
void MarkOperandTypeAsFullyUsed(const Instruction* inst, uint32_t in_idx);
// Return the index of the member that use to be the |member_idx|th member of
// |type_id|. If the member has been removed, |kRemovedMember| is returned.
uint32_t GetNewMemberIndex(uint32_t type_id, uint32_t member_idx);
// A map from a type id to a set of indices representing the members of the
// type that are used, and must be kept.
std::unordered_map<uint32_t, std::set<uint32_t>> used_members_;
void MarkStructOperandsAsFullyUsed(const Instruction* inst);
void MarkPointeeTypeAsFullUsed(uint32_t ptr_type_id);
};
} // namespace opt
} // namespace spvtools
#endif // SOURCE_OPT_ELIMINATE_DEAD_MEMBERS_PASS_H_