mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-12 11:40:14 +00:00
05de650371
Fixes https://crbug.com/oss-fuzz48578 * Adds structural reachability to basic blocks * calculated in same manner as reachability, but using structural successors * Change structured CFG validation to use structural reachability instead of reachability * Fix some invalid reducer cases
321 lines
11 KiB
C++
321 lines
11 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 the structural successors of the BasicBlock
|
|
std::vector<BasicBlock*>* structural_predecessors() {
|
|
return &structural_predecessors_;
|
|
}
|
|
|
|
/// Returns the structural predecessors of the BasicBlock
|
|
const std::vector<BasicBlock*>* structural_predecessors() const {
|
|
return &structural_predecessors_;
|
|
}
|
|
|
|
/// Returns the structural successors of the BasicBlock
|
|
std::vector<BasicBlock*>* structural_successors() {
|
|
return &structural_successors_;
|
|
}
|
|
|
|
/// Returns the structural predecessors of the BasicBlock
|
|
const std::vector<BasicBlock*>* structural_successors() const {
|
|
return &structural_successors_;
|
|
}
|
|
|
|
/// Returns true if the block is reachable in the CFG.
|
|
bool reachable() const { return reachable_; }
|
|
|
|
/// Returns true if the block is structurally reachable in the CFG.
|
|
bool structurally_reachable() const { return structurally_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 structural reachability of the basic block in the CFG
|
|
void set_structurally_reachable(bool reachability) {
|
|
structurally_reachable_ = reachability;
|
|
}
|
|
|
|
/// Sets the type of the BasicBlock
|
|
void set_type(BlockType type) {
|
|
if (type == kBlockTypeUndefined)
|
|
type_.reset();
|
|
else
|
|
type_.set(type);
|
|
}
|
|
|
|
/// Sets the immediate dominator of this basic block
|
|
///
|
|
/// @param[in] dom_block The dominator block
|
|
void SetImmediateDominator(BasicBlock* dom_block);
|
|
|
|
/// Sets the immediate dominator of this basic block
|
|
///
|
|
/// @param[in] dom_block The dominator block
|
|
void SetImmediateStructuralDominator(BasicBlock* dom_block);
|
|
|
|
/// Sets the immediate post dominator of this basic block
|
|
///
|
|
/// @param[in] pdom_block The post dominator block
|
|
void SetImmediateStructuralPostDominator(BasicBlock* pdom_block);
|
|
|
|
/// Returns the immediate dominator of this basic block
|
|
BasicBlock* immediate_dominator();
|
|
|
|
/// Returns the immediate dominator of this basic block
|
|
const BasicBlock* immediate_dominator() const;
|
|
|
|
/// Returns the immediate dominator of this basic block
|
|
BasicBlock* immediate_structural_dominator();
|
|
|
|
/// Returns the immediate dominator of this basic block
|
|
const BasicBlock* immediate_structural_dominator() const;
|
|
|
|
/// Returns the immediate post dominator of this basic block
|
|
BasicBlock* immediate_structural_post_dominator();
|
|
|
|
/// Returns the immediate post dominator of this basic block
|
|
const BasicBlock* immediate_structural_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 structurally dominates the other block.
|
|
/// Assumes structural dominators have been computed.
|
|
bool structurally_dominates(const BasicBlock& other) const;
|
|
|
|
/// Returns true if this block structurally postdominates the other block.
|
|
/// Assumes structural dominators have been computed.
|
|
bool structurally_postdominates(const BasicBlock& other) const;
|
|
|
|
void RegisterStructuralSuccessor(BasicBlock* block) {
|
|
block->structural_predecessors_.push_back(this);
|
|
structural_successors_.push_back(block);
|
|
}
|
|
|
|
/// @brief A BasicBlock dominator iterator class
|
|
///
|
|
/// This iterator will iterate over the (post)dominators of the block
|
|
class DominatorIterator {
|
|
public:
|
|
using iterator_category = std::forward_iterator_tag;
|
|
using value_type = BasicBlock*;
|
|
using pointer = value_type*;
|
|
using reference = value_type&;
|
|
using difference_type = std::ptrdiff_t;
|
|
|
|
/// @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 dominator iterator which points to the current block
|
|
const DominatorIterator structural_dom_begin() const;
|
|
|
|
/// Returns a dominator iterator which points to the current block
|
|
DominatorIterator structural_dom_begin();
|
|
|
|
/// Returns a dominator iterator which points to one element past the first
|
|
/// block
|
|
const DominatorIterator structural_dom_end() const;
|
|
|
|
/// Returns a dominator iterator which points to one element past the first
|
|
/// block
|
|
DominatorIterator structural_dom_end();
|
|
|
|
/// Returns a post dominator iterator which points to the current block
|
|
const DominatorIterator structural_pdom_begin() const;
|
|
/// Returns a post dominator iterator which points to the current block
|
|
DominatorIterator structural_pdom_begin();
|
|
|
|
/// Returns a post dominator iterator which points to one element past the
|
|
/// last block
|
|
const DominatorIterator structural_pdom_end() const;
|
|
|
|
/// Returns a post dominator iterator which points to one element past the
|
|
/// last block
|
|
DominatorIterator structural_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 structural dominator of the BasicBlock
|
|
BasicBlock* immediate_structural_dominator_;
|
|
|
|
/// Pointer to the immediate structural post dominator of the BasicBlock
|
|
BasicBlock* immediate_structural_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_;
|
|
|
|
/// True if the block is structurally reachable in the CFG
|
|
bool structurally_reachable_;
|
|
|
|
/// label of this block, if any.
|
|
const Instruction* label_;
|
|
|
|
/// Terminator of this block.
|
|
const Instruction* terminator_;
|
|
|
|
std::vector<BasicBlock*> structural_predecessors_;
|
|
std::vector<BasicBlock*> structural_successors_;
|
|
};
|
|
|
|
/// @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_
|