SPIRV-Tools/source/val/basic_block.h
alan-baker 7221ccf85e
Fix reachability in the validator (#3541)
Fixes #3529

* Make BasicBlock::reachable() only consider static reachability
* Fix reachability calculation to be independent of block order
* add tests
2020-07-15 21:27:03 -04:00

245 lines
7.9 KiB
C++

// Copyright (c) 2015-2016 The Khronos Group 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 SOURCE_VAL_BASIC_BLOCK_H_
#define SOURCE_VAL_BASIC_BLOCK_H_
#include <bitset>
#include <cstdint>
#include <functional>
#include <memory>
#include <vector>
#include "source/latest_version_spirv_header.h"
namespace spvtools {
namespace val {
enum BlockType : uint32_t {
kBlockTypeUndefined,
kBlockTypeSelection,
kBlockTypeLoop,
kBlockTypeMerge,
kBlockTypeBreak,
kBlockTypeContinue,
kBlockTypeReturn,
kBlockTypeCOUNT ///< Total number of block types. (must be the last element)
};
class Instruction;
// This class represents a basic block in a SPIR-V module
class BasicBlock {
public:
/// Constructor for a BasicBlock
///
/// @param[in] id The ID of the basic block
explicit BasicBlock(uint32_t id);
/// Returns the id of the BasicBlock
uint32_t id() const { return id_; }
/// Returns the predecessors of the BasicBlock
const std::vector<BasicBlock*>* predecessors() const {
return &predecessors_;
}
/// Returns the predecessors of the BasicBlock
std::vector<BasicBlock*>* predecessors() { return &predecessors_; }
/// Returns the successors of the BasicBlock
const std::vector<BasicBlock*>* successors() const { return &successors_; }
/// Returns the successors of the BasicBlock
std::vector<BasicBlock*>* successors() { return &successors_; }
/// Returns true if the block is reachable in the CFG
bool reachable() const { return reachable_; }
/// Returns true if BasicBlock is of the given type
bool is_type(BlockType type) const {
if (type == kBlockTypeUndefined) return type_.none();
return type_.test(type);
}
/// Sets the reachability of the basic block in the CFG
void set_reachable(bool reachability) { reachable_ = reachability; }
/// Sets the type of the BasicBlock
void set_type(BlockType type) {
if (type == kBlockTypeUndefined)
type_.reset();
else
type_.set(type);
}
/// Sets the immedate dominator of this basic block
///
/// @param[in] dom_block The dominator block
void SetImmediateDominator(BasicBlock* dom_block);
/// Sets the immedate post dominator of this basic block
///
/// @param[in] pdom_block The post dominator block
void SetImmediatePostDominator(BasicBlock* pdom_block);
/// Returns the immedate dominator of this basic block
BasicBlock* immediate_dominator();
/// Returns the immedate dominator of this basic block
const BasicBlock* immediate_dominator() const;
/// Returns the immedate post dominator of this basic block
BasicBlock* immediate_post_dominator();
/// Returns the immedate post dominator of this basic block
const BasicBlock* immediate_post_dominator() const;
/// Returns the label instruction for the block, or nullptr if not set.
const Instruction* label() const { return label_; }
//// Registers the label instruction for the block.
void set_label(const Instruction* t) { label_ = t; }
/// Registers the terminator instruction for the block.
void set_terminator(const Instruction* t) { terminator_ = t; }
/// Returns the terminator instruction for the block.
const Instruction* terminator() const { return terminator_; }
/// Adds @p next BasicBlocks as successors of this BasicBlock
void RegisterSuccessors(
const std::vector<BasicBlock*>& next = std::vector<BasicBlock*>());
/// Returns true if the id of the BasicBlock matches
bool operator==(const BasicBlock& other) const { return other.id_ == id_; }
/// Returns true if the id of the BasicBlock matches
bool operator==(const uint32_t& other_id) const { return other_id == id_; }
/// Returns true if this block dominates the other block.
/// Assumes dominators have been computed.
bool dominates(const BasicBlock& other) const;
/// Returns true if this block postdominates the other block.
/// Assumes dominators have been computed.
bool postdominates(const BasicBlock& other) const;
/// @brief A BasicBlock dominator iterator class
///
/// This iterator will iterate over the (post)dominators of the block
class DominatorIterator
: public std::iterator<std::forward_iterator_tag, BasicBlock*> {
public:
/// @brief Constructs the end of dominator iterator
///
/// This will create an iterator which will represent the element
/// before the root node of the dominator tree
DominatorIterator();
/// @brief Constructs an iterator for the given block which points to
/// @p block
///
/// @param block The block which is referenced by the iterator
/// @param dominator_func This function will be called to get the immediate
/// (post)dominator of the current block
DominatorIterator(
const BasicBlock* block,
std::function<const BasicBlock*(const BasicBlock*)> dominator_func);
/// @brief Advances the iterator
DominatorIterator& operator++();
/// @brief Returns the current element
const BasicBlock*& operator*();
friend bool operator==(const DominatorIterator& lhs,
const DominatorIterator& rhs);
private:
const BasicBlock* current_;
std::function<const BasicBlock*(const BasicBlock*)> dom_func_;
};
/// Returns a dominator iterator which points to the current block
const DominatorIterator dom_begin() const;
/// Returns a dominator iterator which points to the current block
DominatorIterator dom_begin();
/// Returns a dominator iterator which points to one element past the first
/// block
const DominatorIterator dom_end() const;
/// Returns a dominator iterator which points to one element past the first
/// block
DominatorIterator dom_end();
/// Returns a post dominator iterator which points to the current block
const DominatorIterator pdom_begin() const;
/// Returns a post dominator iterator which points to the current block
DominatorIterator pdom_begin();
/// Returns a post dominator iterator which points to one element past the
/// last block
const DominatorIterator pdom_end() const;
/// Returns a post dominator iterator which points to one element past the
/// last block
DominatorIterator pdom_end();
private:
/// Id of the BasicBlock
const uint32_t id_;
/// Pointer to the immediate dominator of the BasicBlock
BasicBlock* immediate_dominator_;
/// Pointer to the immediate dominator of the BasicBlock
BasicBlock* immediate_post_dominator_;
/// The set of predecessors of the BasicBlock
std::vector<BasicBlock*> predecessors_;
/// The set of successors of the BasicBlock
std::vector<BasicBlock*> successors_;
/// The type of the block
std::bitset<kBlockTypeCOUNT> type_;
/// True if the block is reachable in the CFG
bool reachable_;
/// label of this block, if any.
const Instruction* label_;
/// Terminator of this block.
const Instruction* terminator_;
};
/// @brief Returns true if the iterators point to the same element or if both
/// iterators point to the @p dom_end block
bool operator==(const BasicBlock::DominatorIterator& lhs,
const BasicBlock::DominatorIterator& rhs);
/// @brief Returns true if the iterators point to different elements and they
/// do not both point to the @p dom_end block
bool operator!=(const BasicBlock::DominatorIterator& lhs,
const BasicBlock::DominatorIterator& rhs);
} // namespace val
} // namespace spvtools
#endif // SOURCE_VAL_BASIC_BLOCK_H_