[PATCH] Add iterator for PHINode value/BB pair
Duncan P. N. Exon Smith
dexonsmith at apple.com
Tue Jul 21 20:21:18 PDT 2015
> On 2015-Jul-21, at 18:55, Pete Cooper <peter_cooper at apple.com> wrote:
>
> Hi David, Duncan
>
> This is another iterator which i’d like to use to enable more foreach loops in LLVM.
>
> This time its for returning both the value and basic block from a phi node. Its very common to need both of these together, but currently involves a manual loop to do so.
>
> The code here is similar to generic_gep_type_iterator where i’m wrapping an iterator (in this case 2) and on updates to the iterators I update the ‘Pair’ field. operator* then returns the Pair when requested.
>
> An alternative would be to only update Pair in operator*, but that would require making the field mutable.
>
> I’ve added a single use of this in BasicAliasAnalysis. A grep of the code finds 47 total loops over PN[.,->]getNumIncomingValues(), of which around 40 look eligible to use this.
>
> Comments welcome.
>
> Cheers,
> Pete
>
> <phinode.diff>
> diff --git a/include/llvm/IR/Instructions.h b/include/llvm/IR/Instructions.h
> index 07d5f11..d6b5b80 100644
> --- a/include/llvm/IR/Instructions.h
> +++ b/include/llvm/IR/Instructions.h
> @@ -2377,6 +2377,90 @@ public:
>
> const_op_range incoming_values() const { return operands(); }
>
> + /// This contains a value and basic block corresponding to a single incoming
> + /// value/block pair.
> + class PHINodeEdge {
> + private:
> + Value *Val;
> + BasicBlock *BB;
> +
> + public:
> + PHINodeEdge(Value *Val,
> + BasicBlock *BB) : Val(Val), BB(BB) { }
> +
> + Value *getValue() const { return Val; }
> + BasicBlock *getBlock() const { return BB; }
> + };
Any reason this isn't just POD?
struct PHINodeEdge {
Value *Val;
BasicBlock *BB;
};
> +
> + /// This class provides iterator support for edges which
> + /// provide access to both the value and block on an incoming edge without
> + /// needing to manage indices.
> + template<typename OpIteratorTy, typename BlockIteratorTy>
> + class edge_iterator : public std::iterator<std::forward_iterator_tag,
> + PHINodeEdge, ptrdiff_t> {
> +
> + OpIteratorTy Values;
> + BlockIteratorTy Blocks;
> + PHINodeEdge Pair;
s/Pair/Edge/ ?
> + explicit edge_iterator(OpIteratorTy Values, BlockIteratorTy Blocks)
> + : Values(Values), Blocks(Blocks), Pair(*Values, *Blocks) {
If `Values` and `Blocks` are end iterators, this could be an invalid
dereference.
> + }
> + friend class PHINode;
> + public:
> + typedef std::iterator<std::forward_iterator_tag,
> + PHINodeEdge, ptrdiff_t>::reference reference;
> + typedef std::iterator<std::forward_iterator_tag,
> + PHINodeEdge, ptrdiff_t>::pointer pointer;
> +
> + edge_iterator(const edge_iterator &I)
> + : Values(I.Values), Blocks(I.Blocks), Pair(*Values, *Blocks) {}
Why not `= default`?
> + edge_iterator()
> + : Values(OpIteratorTy()), Blocks(BlockIteratorTy()),
> + Pair(*Values, *Blocks) {}
This looks like a null dereference.
> +
> + bool operator==(const edge_iterator &x) const {
> + return Values == x.Values && Blocks == x.Blocks;
> + }
> + bool operator!=(const edge_iterator &x) const {
> + return !operator==(x);
> + }
> +
> + // Iterator traversal: forward iteration only.
> + // Preincrement
> + edge_iterator &operator++() {
> + ++Values;
> + ++Blocks;
> + Pair = PHINodeEdge(*Values, *Blocks);
Could be a dereference of invalid.
> + return *this;
> + }
> +
> + // Postincrement
> + edge_iterator operator++(int) {
> + edge_iterator tmp = *this; ++*this; return tmp;
> + }
> +
> + /// Retrieve a pointer to the current user node.
> + const PHINodeEdge &operator*() const {
If you drop the requirements from `forward_iterator` to
`input_iterator`, then you're allowed to return a `PHINodeEdge` by-value
here instead of by-reference (unfortunately this makes it illegal to use
a bunch of STL algorithms; STL iterator traits are completely broken
IMO).
> + return Pair;
> + }
> + };
> +
> + typedef edge_iterator<op_iterator, block_iterator> MutableEdgeType;
> + iterator_range<MutableEdgeType> incoming_edges() {
> + return iterator_range<MutableEdgeType>(MutableEdgeType(op_begin(),
> + block_begin()),
> + MutableEdgeType(op_end(),
> + block_end()));
> + }
> +
> + typedef edge_iterator<const_op_iterator, const_block_iterator> ConstEdgeType;
> + iterator_range<ConstEdgeType> incoming_edges() const {
> + return iterator_range<ConstEdgeType>(ConstEdgeType(op_begin(),
> + block_begin()),
> + ConstEdgeType(op_end(),
> + block_end()));
> + }
> +
> /// getNumIncomingValues - Return the number of incoming edges
> ///
> unsigned getNumIncomingValues() const { return getNumOperands(); }
More information about the llvm-commits
mailing list