Otherwise, inlining costs may be pessimized by dead constants.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Looks reasonable to me.
llvm/test/Transforms/Inline/last-callsite.ll | ||
---|---|---|
263–264 | This doesn't preserve the spirit of the test. You should replace the constant expression with something that doesn't fold, e.g. use mul instead of icmp ne. |
Preserve the spirit of last-callsite.ll test
llvm/test/Transforms/Inline/last-callsite.ll | ||
---|---|---|
263–264 | Ah sorry, I meant to leave a comment about this. Fixed. |
llvm/lib/Analysis/InlineCost.cpp | ||
---|---|---|
1862 | From a separation of concerns perspective, I think this should rather happen after a successful inline, rather than when computing cost. |
llvm/lib/Analysis/InlineCost.cpp | ||
---|---|---|
1862 | +1, an analysis shouldn't be changing the IR |
llvm/lib/Analysis/InlineCost.cpp | ||
---|---|---|
1862 | This already happens after a successful inline. The problem is that we also need it to happen before the hasOneUse() check below. The operation could be move to the point where the cost model is queried though. |
llvm/lib/Analysis/InlineCost.cpp | ||
---|---|---|
1862 | Hmm... IIUC, right now, after the first time a callee is inlined, removeDeadConstantUsers() is called, and next time its cost is computed it'll be accurate. The problem is the first time, correct? Does this feel like a normalization pass is missing, i.e. before inlining, we go over all functions in a module and removeDeadConstantUsers()? |
llvm/lib/Analysis/InlineCost.cpp | ||
---|---|---|
1862 | wouldn't that still do it more than the necessary number of times? |
llvm/lib/Analysis/InlineCost.cpp | ||
---|---|---|
1862 | yeah we're calling removeDeadUsersOfConstant more than necessary, but I don't think it should matter that much. I don't think it's worth all the extra code and extra pass to optimize this |
I don't have commit rights--please commit this as Erik Desjardins <erikdesjardinspublic@gmail.com>
llvm/lib/Analysis/InlineCost.cpp | ||
---|---|---|
1862 | Looking more at it - it modifies IR though, right? I'm a bit troubled that it modifies IR and there's no trigger (unless I'm missing something) invalidating analyses. Do we handle the Uses/Users relations differently for some reason? |
(moving this to a main thread so we don't have to reply to a thread on code in an old revision)
hmm, does removing dead constant users invalidate analyses? that's an interesting question. I guess technically yes it should, although not sure it'll matter in practice.
I think we have three options
- mtrofin's original idea of adding a cleanup pass before the inliner that calls removeDeadConstantUsers on each function, and we invalidate non-cfg analyses if we make any changes
- add Constant::hasOneLiveUse() and use that in InlineCost.cpp rather than modifying IR
- keep doing what we're doing here and assume that no analyses rely on dead constant users
imo we can get away with the current patch
any thoughts?
I like the second option. It addresses the original issue and removes any
fragility. I think option 3 invalidates the contract analyses have with the
system (i.e. IR mutation => analysis invalidated), and we shouldn't take
it, it leads to fragility and maintenance costs, and I offer the relatively
recent memory of the cgscc pass and immutable analyses and invalidation as
illustration of how not fun diagnosing these kinds of issues are.
Passing-by remark: i really don't see why would any analysis depend on *dead* constant use.
If they do, they sound really fragile. The obvious fix for them is to actually signal that;
i believe there was some VH-like thing for that?
Looking at usages of removeDeadConstantUsers() in other passes...
Calls on code paths where analyses are always invalidated:
https://github.com/llvm/llvm-project/blob/75e8eb2b10b15b027608adb0d3eaaefbd19e5993/llvm/lib/Transforms/IPO/AlwaysInliner.cpp#L104
https://github.com/llvm/llvm-project/blob/75e8eb2b10b15b027608adb0d3eaaefbd19e5993/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp#L249
https://github.com/llvm/llvm-project/blob/75e8eb2b10b15b027608adb0d3eaaefbd19e5993/llvm/lib/Transforms/IPO/ElimAvailExtern.cpp#L46
https://github.com/llvm/llvm-project/blob/75e8eb2b10b15b027608adb0d3eaaefbd19e5993/llvm/lib/Transforms/IPO/ElimAvailExtern.cpp#L59
https://github.com/llvm/llvm-project/blob/75e8eb2b10b15b027608adb0d3eaaefbd19e5993/llvm/lib/Transforms/IPO/Inliner.cpp#L891 (hmm, can probably remove this one if we decide to land this patch as-is)
https://github.com/llvm/llvm-project/blob/75e8eb2b10b15b027608adb0d3eaaefbd19e5993/llvm/lib/Transforms/Utils/CallGraphUpdater.cpp#L33
https://github.com/llvm/llvm-project/blob/75e8eb2b10b15b027608adb0d3eaaefbd19e5993/llvm/lib/Transforms/Utils/CallGraphUpdater.cpp#L51
https://github.com/llvm/llvm-project/blob/75e8eb2b10b15b027608adb0d3eaaefbd19e5993/llvm/lib/Transforms/Utils/CallGraphUpdater.cpp#L124
Calls on code paths where analyses may or may not be invalidated:
https://github.com/llvm/llvm-project/blob/75e8eb2b10b15b027608adb0d3eaaefbd19e5993/llvm/lib/Transforms/IPO/ConstantMerge.cpp#L161
https://github.com/llvm/llvm-project/blob/75e8eb2b10b15b027608adb0d3eaaefbd19e5993/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp#L768
https://github.com/llvm/llvm-project/blob/75e8eb2b10b15b027608adb0d3eaaefbd19e5993/llvm/lib/Transforms/IPO/GlobalDCE.cpp#L458
https://github.com/llvm/llvm-project/blob/75e8eb2b10b15b027608adb0d3eaaefbd19e5993/llvm/lib/Transforms/IPO/GlobalOpt.cpp#L1345
https://github.com/llvm/llvm-project/blob/75e8eb2b10b15b027608adb0d3eaaefbd19e5993/llvm/lib/Transforms/IPO/GlobalOpt.cpp#L2506
https://github.com/llvm/llvm-project/blob/75e8eb2b10b15b027608adb0d3eaaefbd19e5993/llvm/lib/Transforms/IPO/Inliner.cpp#L598
https://github.com/llvm/llvm-project/blob/75e8eb2b10b15b027608adb0d3eaaefbd19e5993/llvm/lib/Transforms/Scalar/JumpThreading.cpp#L1024
https://github.com/llvm/llvm-project/blob/75e8eb2b10b15b027608adb0d3eaaefbd19e5993/llvm/lib/Transforms/Scalar/SCCP.cpp#L447
...the existing code can't really decide either way.
An analysis could count uses, for example; or could enumerate constants in
a module and refine some calculation from that set, but
removeDeadUsersOfConstant may delete some such constants.
(what's a "VH-like thing"?)
I think, there is a lot of things that could happen,
but if llvm development is driven by FUD,
as opposed to written guarantees and test-cases,
a forward progress may be somewhat restricted.
(what's a "VH-like thing"?)
ValueHandle, so that the use is actually kept alive,
not just by a rouge constant expression.
I think we're talking about different things, sorry if I miscommunicated.
My concern is this: say you have a pass. The pass modifies IR
(specifically, deletes Constants). Should the pass manager be informed of
that so it may appropriately invalidate analyses?
thanks for doing this, some small comments, otherwise lgtm
llvm/include/llvm/IR/Constant.h | ||
---|---|---|
211 | is this currently needed anywhere other than the implementation of hasOneLiveUse? I'd recommend removing it - we can always introduce it later. | |
217 | is this used anywhere? If not, no need to introduce it. it'd also keep the implementation of constantHasLiveUses simpler. | |
llvm/lib/IR/Constants.cpp | ||
718 | If you're concerned about the fact that both have the same traversal logic, rather than a comment (which is fragile to change), you could, for example, have a utility common to both removeDeadUsersOfConstant and to constantIsDead that takes a function_ref for what to do after the while/for loop. |
llvm/include/llvm/IR/Constant.h | ||
---|---|---|
217 | +1 |
I don't have commit access--please commit this on my behalf (Erik Desjardins <erikdesjardinspublic@gmail.com>)
Looks like the check failure is due to it failing to update the status on phabricator, the tests passed (and they pass locally)
ack, I'll do it (wanted to wait for AM my time in case there are actual build breaks)
is this currently needed anywhere other than the implementation of hasOneLiveUse? I'd recommend removing it - we can always introduce it later.