[llvm-dev] Adding Extended-SSA to LLVM
Nuno Lopes via llvm-dev
llvm-dev at lists.llvm.org
Sun Feb 5 12:25:15 PST 2017
Hi Daniel,
Many thanks for working on this!
SSI/e-SSA is the only way I'm aware of for doing efficient sparse analyses,
so I'm definitely in favor of adding support for it in LLVM!
I read the discussion so far and did a cursory review of the patches, and I
have just a few questions:
- Is your plan to keep e-SSA form all the time (do it once and maintain it
throughout the pipeline), or do it in the passes that need it and then get
of it at end of the pass? My concern (similar to Sanjoy's) is the increased
overhead for matching patterns and so on. For example, how would
instcombine work? Would we change the m_*() matchers to know how to see
through the intrinsic?
- What you've implemented never creates phi nodes, right? (as opposed to
ABCD paper)
At least it seems that the current algorithm seems to bail out if the
successor has multiple predecessors. This might be an ok abstraction for
GVN, but for things like CVP it's probably not. CVP merges information
incoming from multiple edges (as any other fancier abstractions we may want
to have in the future will).
Any plans to support this? (i.e., is the current algorithm "easily"
upgradable to support this scenario?)
- For a function/intrinsic marked as "returned(1) readnone", the obvious
optimization to do would be to RAUW the return with the argument (and kill
the function call altogether -- assuming readnone allows that; but I lost
track of that discussion). Does instcombine do that? I understand that
piggybacking on this existing feature is a good thing, but I'm just
wondering if, say, InstCombine won't simply revert e-SSA?
- In processBranch/processAssume you also consider branches on ANDs/ORs of
comparisons, and then each comparison is processed individually. However,
this seems incorrect for one of the branches:
if (a && b) {
...
} else {
// holds: !a OR !b
use(a)
use(b)
}
Right now it seems that the information that is attached to the else branch
is !a AND !b, which would be incorrect. I haven't seen the client of this
analysis, so this is just speculation, but the interface doesn't seem to
have any indication for this case. Or maybe I'm misreading the code :)
- Now slightly unrelated: do you know of other representations capable of
handling relational analyses? For example, with e-SSA:
if (x+y > 0) {
// predicate info attached to 'x+y' only
use(x)
}
So at use(x) no information will be available, even if we know that FWIW
'x+y > 0' holds there. I don't think LLVM has any analysis that can track
these kind of symbolic relations, but I was just curious if there's anything
out there that can handle such analyses?
Thanks,
Nuno
-----Original Message-----
From: Daniel Berlin via llvm-dev
Sent: Thursday, February 2, 2017 4:51 AM
Subject: [llvm-dev] Adding Extended-SSA to LLVM
Hey folks,
After a long amount of discussion both offline and on, I put a
pass/intrinsic to add extended SSA up at http://reviews.llvm.org/D29316.
Sean asked me to share it more broadly on llvm-dev, so here you go :)
For those not familiar with extended-SSA, it's described in the paper "ABCD:
Eliminating Array Bounds Checks on Demand".
There is a very large amount of explanation in the summary of the review
that i don't want to paste here , but the short version is:
1. We make copies of variables where they are used in comparisons that lead
to assumes or branches and it's possible to determine something about their
value from the branch.
IE
define i32 @test1(i32 %x) {
%cmp = icmp eq i32 %x, 50
br i1 %cmp, label %true, label %false
true:
ret i32 %x
false:
ret i32 1
}
becomes
define i32 @test1(i32 %x) {
%cmp = icmp eq i32 %x, 50
br i1 %cmp, label %true, label %false
true: ; preds = %0
; Has predicate info
; branch predicate info { TrueEdge: 1 Comparison: %cmp = icmp eq i32 %x,
50 }
%x.0 = call i32 @llvm.predicateinfo.i32(i32 %x)
ret i32 %x.0
false: ; preds = %0
ret i32 1
}
All uses that are dominated by the predicate info are renamed to use it.
2. We do so very quickly (it takes about 600ms to do 2 million blocks with
comparisons, by comparison, most passes simply crash or take forever on the
same file. As an example, GVN takes 500 seconds), and only insert when and
where the operands are used.
3. The intrinsics are marked so they do not affect optimization (and
currently, passes that use them all destroy them). They also can detect when
they've been moved to make sure they are still valid if need me.
4. They could be updated pretty easily if we wanted
With one real downside:
5. We modify the IR in an analysis to do so :(
The main user at the moment is NewGVN, which uses it to do the equivalent of
GVN's propagateEquality. I'd be happy to make it a utility called from
NewGVN instead of an analysis. A number of folks online and off asked me to
make it usable for others, so i did that :) Some folks want to use it to
cleanup existing passes (EarlyCSE, etc), some want to use it in new passes.
FWIW: A number of alternate approaches were tried for NewGVN. The review
details the different approaches other passes take and their tradeoffs.
Three approaches have been tried for NewGVN over the years prior to mainline
submission (NewGVN deliberately tries to be an analysis followed by
elimination, unlike our existing passes, which try to eliminate as they go).
This one is the clear winner in terms of speed, simplicity, maintainability,
and what it covers.
Thoughts welcome,
Dan
More information about the llvm-dev
mailing list