[llvm-dev] Optionally using value numbering in Simplify*
Friedman, Eli via llvm-dev
llvm-dev at lists.llvm.org
Fri Mar 3 13:40:26 PST 2017
On 3/3/2017 1:14 PM, Daniel Berlin wrote:
> On Fri, Mar 3, 2017 at 12:39 PM, Friedman, Eli
> <efriedma at codeaurora.org <mailto:efriedma at codeaurora.org>> wrote:
>
> On 3/3/2017 11:51 AM, Daniel Berlin via llvm-dev wrote:
>
> So i have a testcase (see PR31792, and cond_br2.llin GVN) that
> current GVN can simplify because it replaces instructions as
> it goes. It's an example of a larger issue that pops up quite
> a lot
> I would appreciate thoughts on what to do about it
> it amounts to something like this (but again, it happens a lot):
>
> live = gep thing, 0
> live2 = gep thing, 1
> branch i1 provablytrue,, mergeblock, otherbb
> otherbb:
> dead = something else
> br mergeblock
> merge block
> a = phi(live, dead)
> b = live2
> result = icmp sge a, b
>
> both GVN and NewGVN prove provablytrue to be true, and phi to
> be equivalent to live.
>
> GVN transforms this piece at time, and so by the time
> simplifycmpinst sees the icmp, it is
>
> result = icmp sge <live2, live>
>
> It proves result true.
>
> NewGVN is an analysis, and so it doesn't transform the ir, and
> simplifycmpinst (rightfully) does not try to walk everything,
> everywhere, to prove something. It also couldn't know that
> dead is dead. So it doesn't see that result is true.
>
>
> Why aren't we calling SimplifyCmpInst(pred, live, live2, ...)?
>
>
> We do.
> The example is a bit contrived, the real example has a phi in the way
> of computing the gep offset, and SimplifyCmpInst does walking and
> matching, so this won't work anyway.
>
> See computePointerICmp:
>
> Constant *LHSOffset = stripAndComputeConstantOffsets(DL, LHS);
> Constant *RHSOffset = stripAndComputeConstantOffsets(DL, RHS);
>
> This in turn walks and collects the offsets. One of those is a phi we
> know to be equivalent to a constant ...
>
> Or are you expecting SimplifyCmpInst(pred, live, dead, ...) to
> call back into GVN to find values equivalent to "dead"?
>
>
> The top level call we already get right.
> But all of these simplifiers do not just do top level things. Some go
> looking, so we need them to call back in in some cases.
Okay, makes sense.
>
>
>
> The upshot is that it takes two passes of newgvn to get the
> same result as gvn.
>
> I'm trying to decide what to about this case. As i said, it
> happens a lot.
>
> It would be pretty trivial to make a "VNImpl" interface that
> has a few functions (that can be fulfilled by any value
> numbering that is an analysis), have newgvn implement it, and
> use it in Simplify*.
>
> (It would take work to make GVN work here because of how many
> places it modifies the ir during value numbering. It also
> modifies as it goes, so the only advantage would be from
> unreachable blocks it discovers)
>
> But before i add another argument to functions taking a ton
> already[1], i wanted to ask whether anyone had any opinion on
> whether it's worth doing.
>
> VNImpl would probably look something like:
> class VNImpl{
> // return true if A and B are equivalent
> bool areEquivalent(Value *A, Value *B);
> // find a value that dominates A that is equivalent to it
> Value *findDominatingEquivalent(Value *A);
> // obviousn
> bool isBlockReachable(BasicBock *BB);
> }
>
>
> I'm not sure how you expect InstructionSimplify to use
> findDominatingEquivalent.
>
>
> Most places it uses strict equality and doesn't care. In all of those
> cases newgvn has a single unique (but not always dominating) leader it
> could give and we could call it findEquivalent
>
> But simplify* does expect the end result to dominate the original
> instruction, and this is guaranteed by the docs :P.
> We could give up on these, or we could actually just use it at the end.
> Any instruction that it returns we could just find the equivalent that
> dominates the original operand, or return null.
> Besides that, there is one place (valueDominatesPhi) that actually
> checks dominance where we would change. Not doing so is just a missed
> opt.
Hmm... for the purpose of GVN, I guess we don't care if it dominates?
We could make that a flag or something.
Internally, InstructionSimplify already sticks all its state into a
Query, so it might make sense to expose that, and let GVN customize the
behavior a bit.
>
>
> Does it have to call findDominatingEquivalent every time it tries
> to match() on a Value (or otherwise examine it)?
>
> It depends on how many places go walking.
> As I said, we get the top level calls right, and that's enough for a
> *lot* of cases.
> Just not a few that want to do some sort of collection or matching of
> operands of operands. We could make a vmatch that understands value
> equivalency if we need to.
>
> That seems extremely invasive in the sense that there would be a
> lot of places to change, and no good way to make sure we actually
> caught all the places which need to be changed.
>
> First, all are just missed optimization if you miss them, not
> correctness.
>
>
> Second actually, for newgvn there is. we can assert that for anything
> it uses, lookupOperandLeader(V) == V.
> We add these at the beginning of each function for the rhs and lhs
> arguments (and others as appropriate), and along with vmatch, should
> catch just about every case if not every one.
>
Okay.
Do you know how much of an impact this sort of missed optimization has
in practice? Introducing a bunch of table lookups to NewGVN's uses of
InstructionSimplify will probably affect compile-time, so there's a
tradeoff here.
-Eli
--
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170303/16357a13/attachment.html>
More information about the llvm-dev
mailing list