SPIRV-Tools/source/opt/dead_branch_elim_pass.h
Steven Perron efe12ff5a1 Have all MemPasses preserve the def-use manager.
Originally the passes that extended from MemPass were those that are
of the def-use manager.  I am assuming they would be able to preserve
it because of that.

Added a check to verify consistency of the IRContext. The IRContext
relies on the pass to tell it if something is invalidated.
It is possible that the pass lied.  To help identify those situations,
we will check if the valid analyses are correct after each pass.

This will be enabled by default for the debug build, and disabled in the
production build.  It can be disabled in the debug build by adding
"-DSPIRV_CHECK_CONTEXT=OFF" to the cmake command.
2017-11-10 11:17:12 -05:00

111 lines
3.9 KiB
C++

// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG 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.
#ifndef LIBSPIRV_OPT_DEAD_BRANCH_ELIM_PASS_H_
#define LIBSPIRV_OPT_DEAD_BRANCH_ELIM_PASS_H_
#include <algorithm>
#include <map>
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include "basic_block.h"
#include "def_use_manager.h"
#include "mem_pass.h"
#include "module.h"
namespace spvtools {
namespace opt {
// See optimizer.hpp for documentation.
class DeadBranchElimPass : public MemPass {
using cbb_ptr = const ir::BasicBlock*;
public:
using GetBlocksFunction =
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
DeadBranchElimPass();
const char* name() const override { return "eliminate-dead-branches"; }
Status Process(ir::IRContext* context) override;
ir::IRContext::Analysis GetPreservedAnalyses() override {
return ir::IRContext::kAnalysisDefUse;
}
private:
// If |condId| is boolean constant, return conditional value in |condVal| and
// return true, otherwise return false.
bool GetConstCondition(uint32_t condId, bool* condVal);
// If |valId| is a 32-bit integer constant, return value via |value| and
// return true, otherwise return false.
bool GetConstInteger(uint32_t valId, uint32_t* value);
// Add branch to |labelId| to end of block |bp|.
void AddBranch(uint32_t labelId, ir::BasicBlock* bp);
// Add selction merge of |labelId| to end of block |bp|.
void AddSelectionMerge(uint32_t labelId, ir::BasicBlock* bp);
// Add conditional branch of |condId|, |trueLabId| and |falseLabId| to end
// of block |bp|.
void AddBranchConditional(uint32_t condId, uint32_t trueLabId,
uint32_t falseLabId, ir::BasicBlock* bp);
// If block |bp| contains conditional branch or switch preceeded by an
// OpSelctionMerge, return true and return branch and merge instructions
// in |branchInst| and |mergeInst| and the conditional id in |condId|.
bool GetSelectionBranch(ir::BasicBlock* bp, ir::Instruction** branchInst,
ir::Instruction** mergeInst, uint32_t* condId);
// Return true if |labelId| has any non-phi, non-backedge references
bool HasNonPhiNonBackedgeRef(uint32_t labelId);
// Compute backedges for blocks in |structuredOrder|.
void ComputeBackEdges(std::list<ir::BasicBlock*>& structuredOrder);
// For function |func|, look for BranchConditionals with constant condition
// and convert to a Branch to the indicated label. Delete resulting dead
// blocks. Assumes only structured control flow in shader. Note some such
// branches and blocks may be left to avoid creating invalid control flow.
// TODO(greg-lunarg): Remove remaining constant conditional branches and
// dead blocks.
bool EliminateDeadBranches(ir::Function* func);
// Initialize extensions whitelist
void InitExtensions();
// Return true if all extensions in this module are allowed by this pass.
bool AllExtensionsSupported() const;
void Initialize(ir::IRContext* c);
Pass::Status ProcessImpl();
// All backedge branches in current function
std::unordered_set<ir::Instruction*> backedges_;
// Extensions supported by this pass.
std::unordered_set<std::string> extensions_whitelist_;
};
} // namespace opt
} // namespace spvtools
#endif // LIBSPIRV_OPT_DEAD_BRANCH_ELIM_PASS_H_