This is an archive of the discontinued LLVM Phabricator instance.

[IR] Add an iterator and range accessor for the PHI nodes of a basic block.
ClosedPublic

Authored by chandlerc on May 24 2017, 7:55 PM.

Details

Summary

This allows writing much more natural and readable range based for loops
directly over the PHI nodes. It also takes advantage of the same tricks
for terminating the sequence as the hand coded versions.

I've replaced one example of this mostly to showcase the difference and
I've added a unit test to make sure the facilities really work the way
they're intended. I want to use this inside of SimpleLoopUnswitch but it
seems generally nice.

Diff Detail

Repository
rL LLVM

Event Timeline

chandlerc created this revision.May 24 2017, 7:55 PM
dblaikie added inline comments.
include/llvm/IR/BasicBlock.h
286 ↗(On Diff #100197)

Generally prefer to use non-member op overloads where possible (but maybe the iterator_facade isn't compatible with this? Not sure). That way LHS and RHS conversions happen equally - relevant for, say, const+non-const_iterator comparisons.

293 ↗(On Diff #100197)

Seems weird to build an iterator in every increment, though I imagine it's cheap - any reason to do this rather than to keep the iterator as a member (rather than the pointer as a member)?

304–306 ↗(On Diff #100197)

Usually I expect to see this done the other way around - having the non-const version delegate to the const version. Otherwise the const version is technically UB when invoked on a const object (since it casts away constness, calls a function, etc). Though I realize that means needing an explicit conversion from const iterator to non-const iterator - maybe easier to have two implementations then, given it's short/simple.

unittests/IR/BasicBlockTest.cpp
67 ↗(On Diff #100197)

const_casts /to/ const kind of weird me out (because they're rare & so I'm only really used to seeing const_casts removing const - takes a bit to read when they're adding it). Should we have an llvm::implicit_cast?

Should it be "const auto &" on the LHS, if this is a const iterator?

chandlerc added inline comments.May 24 2017, 8:12 PM
include/llvm/IR/BasicBlock.h
286 ↗(On Diff #100197)

I have no idea, but all the uses of iterator_facade_base follow this pattern. I'd somewhat rather not try to fix this in this patch....

293 ↗(On Diff #100197)

It avoids the dyn_cast on every dereference (or having more state).

304–306 ↗(On Diff #100197)

Why is it UB to cast away const even on a const object? I don't think anything makes that UB.

The UB thing is to *modify* a const object. But the non-const function here doesn't do that, so it seems fine?

I can have two implementations, but then I have to put them both out-of-line because the implementation of this method cannot be written in this header (requires the definition of the PHINode type which requires the definition of the BasicBlock type...)

unittests/IR/BasicBlockTest.cpp
67 ↗(On Diff #100197)

To the first point: what would you suggest I write? I don't really care, this seemed to work.

To the second point: why? auto will deduce const just fine... adding const myself won't really surface any bugs. I guess I always prefer to write less when there is no reason to write more...

dblaikie accepted this revision.May 24 2017, 11:07 PM
dblaikie added inline comments.
include/llvm/IR/BasicBlock.h
286 ↗(On Diff #100197)

Rightio

293 ↗(On Diff #100197)

Presumably only a cast, not a dyn_cast, right? (isa on increment, cast on deref?)

but sure

304–306 ↗(On Diff #100197)

Fair - can't find anything that says it's UB to call a non-const function on a const object, but weirds me out a bit because it'd make it pretty easy to leak a non-const pointer/mutate state by accident, so I'd tend to prefer the inverse phrasing, but I realize it's a bit awkward. Up to you.

unittests/IR/BasicBlockTest.cpp
67 ↗(On Diff #100197)

I'd love an implicit_cast - if you want to add one while you're at it, but I understand that's a whole nother thing with test cases, etc.

I figure const, &, and * are short enough that the relative cost/benefit is worthwhile to include them. The LLVM style guide does at least call for '*' when auto is deducing to a pointer (/when that matters - if it's some opaque typedef that the code doesn't care about pointerness, I suppose '*' wouldn't be used) & I've always assumed (incorrectly, now that I look) that the style guide said the same about const. At least that's my habit.

Up to you.

This revision is now accepted and ready to land.May 24 2017, 11:07 PM

Thanks for all the comments Dave! I'm gonna land this with the fix below, but do let me know if you want any further work here.

include/llvm/IR/BasicBlock.h
304–306 ↗(On Diff #100197)

Digging around, we do this ... pretty frequently. And I dunno that having an explicit conversion from a const_iterator to non-const iterator is any less weird. In both cases, we're stripping off const and doing something with it.

Anyways, I'm gonna leave this as-is for now as it doesn't seem uncommon. Happy to revisit this if you and/or others come the consensus that we really want to shift away from this.

unittests/IR/BasicBlockTest.cpp
67 ↗(On Diff #100197)

Adding const here.

Happy for this to switch to an implicit cast if/when one shows up, but I'm gonna resist shaving that yak today. ;]

This revision was automatically updated to reflect the committed changes.