SPIRV-Tools/source/opt/dominator_analysis.h
Steven Perron c4dc046399 Copy propagate arrays
The sprir-v generated from HLSL code contain many copyies of very large
arrays.  Not only are these time consumming, but they also cause
problems for drivers because they require too much space.

To work around this, we will implement an array copy propagation.  Note
that we will not implement a complete array data flow analysis in order
to implement this.  We will be looking for very simple cases:

1) The source must never be stored to.
2) The target must be stored to exactly once.
3) The store to the target must be a store to the entire array, and be a
copy of the entire source.
4) All loads of the target must be dominated by the store.

The hard part is keeping all of the types correct.  We do not want to
have to do too large a search to update everything, which may not be
possible, do we give up if we see any instruction that might be hard to
update.

Also in types.h, the element decorations are not stored in an std::map.
This change was done so the hashing algorithm for a Struct is
consistent.  With the std::unordered_map, the traversal order was
non-deterministic leading to the same type getting hashed to different
values.  See |Struct::GetExtraHashWords|.

Contributes to #1416.
2018-03-26 14:44:41 -04:00

141 lines
4.8 KiB
C++

// Copyright (c) 2017 Google 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_DOMINATOR_ANALYSIS_PASS_H_
#define LIBSPIRV_OPT_DOMINATOR_ANALYSIS_PASS_H_
#include <cstdint>
#include <map>
#include "dominator_tree.h"
#include "module.h"
namespace spvtools {
namespace opt {
// Interface to perform dominator or postdominator analysis on a given function.
class DominatorAnalysisBase {
public:
explicit DominatorAnalysisBase(bool is_post_dom) : tree_(is_post_dom) {}
// Calculates the dominator (or postdominator) tree for given function |f|.
inline void InitializeTree(const ir::Function* f, const ir::CFG& cfg) {
tree_.InitializeTree(f, cfg);
}
// Returns true if BasicBlock |a| dominates BasicBlock |b|.
inline bool Dominates(const ir::BasicBlock* a,
const ir::BasicBlock* b) const {
if (!a || !b) return false;
return Dominates(a->id(), b->id());
}
// Returns true if BasicBlock |a| dominates BasicBlock |b|. Same as above only
// using the BasicBlock IDs.
inline bool Dominates(uint32_t a, uint32_t b) const {
return tree_.Dominates(a, b);
}
// Returns true if instruction |a| dominates instruction |b|.
bool Dominates(ir::Instruction* a, ir::Instruction* b) const;
// Returns true if BasicBlock |a| strictly dominates BasicBlock |b|.
inline bool StrictlyDominates(const ir::BasicBlock* a,
const ir::BasicBlock* b) const {
if (!a || !b) return false;
return StrictlyDominates(a->id(), b->id());
}
// Returns true if BasicBlock |a| strictly dominates BasicBlock |b|. Same as
// above only using the BasicBlock IDs.
inline bool StrictlyDominates(uint32_t a, uint32_t b) const {
return tree_.StrictlyDominates(a, b);
}
// Returns the immediate dominator of |node| or returns nullptr if it is has
// no dominator.
inline ir::BasicBlock* ImmediateDominator(const ir::BasicBlock* node) const {
if (!node) return nullptr;
return tree_.ImmediateDominator(node);
}
// Returns the immediate dominator of |node_id| or returns nullptr if it is
// has no dominator. Same as above but operates on IDs.
inline ir::BasicBlock* ImmediateDominator(uint32_t node_id) const {
return tree_.ImmediateDominator(node_id);
}
// Returns true if |node| is reachable from the entry.
inline bool IsReachable(const ir::BasicBlock* node) const {
if (!node) return false;
return tree_.ReachableFromRoots(node->id());
}
// Returns true if |node_id| is reachable from the entry.
inline bool IsReachable(uint32_t node_id) const {
return tree_.ReachableFromRoots(node_id);
}
// Dump the tree structure into the given |out| stream in the dot format.
inline void DumpAsDot(std::ostream& out) const { tree_.DumpTreeAsDot(out); }
// Returns true if this is a postdomiator tree.
inline bool IsPostDominator() const { return tree_.IsPostDominator(); }
// Returns the tree itself for manual operations, such as traversing the
// roots.
// For normal dominance relationships the methods above should be used.
inline DominatorTree& GetDomTree() { return tree_; }
inline const DominatorTree& GetDomTree() const { return tree_; }
// Force the dominator tree to be removed
inline void ClearTree() { tree_.ClearTree(); }
// Applies the std::function |func| to dominator tree nodes in dominator
// order.
void Visit(std::function<bool(DominatorTreeNode*)> func) {
tree_.Visit(func);
}
// Applies the std::function |func| to dominator tree nodes in dominator
// order.
void Visit(std::function<bool(const DominatorTreeNode*)> func) const {
tree_.Visit(func);
}
// Returns the most immediate basic block that dominates both |b1| and |b2|.
// If there is no such basic block, nullptr is returned.
ir::BasicBlock* CommonDominator(ir::BasicBlock* b1, ir::BasicBlock* b2) const;
protected:
DominatorTree tree_;
};
// Derived class for normal dominator analysis.
class DominatorAnalysis : public DominatorAnalysisBase {
public:
DominatorAnalysis() : DominatorAnalysisBase(false) {}
};
// Derived class for postdominator analysis.
class PostDominatorAnalysis : public DominatorAnalysisBase {
public:
PostDominatorAnalysis() : DominatorAnalysisBase(true) {}
};
} // namespace opt
} // namespace spvtools
#endif // LIBSPIRV_OPT_DOMINATOR_ANALYSIS_PASS_H_