This is an archive of the discontinued LLVM Phabricator instance.

[TailCallElim] Remove the readonly attribute of byval.
ClosedPublic

Authored by DianQK on Aug 1 2023, 6:47 AM.

Details

Summary

When eliminating a tail call, we modify the values of the arguments.
Therefore, if the byval parameter has a readonly attribute, we have to remove it. It is safe because,
from the perspective of a caller, the byval parameter is always treated as "readonly," even if the readonly attribute is removed.

Fixes https://github.com/llvm/llvm-project/issues/64289.

Diff Detail

Event Timeline

DianQK created this revision.Aug 1 2023, 6:47 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 1 2023, 6:47 AM
DianQK requested review of this revision.Aug 1 2023, 6:47 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 1 2023, 6:47 AM
DianQK edited the summary of this revision. (Show Details)Aug 1 2023, 7:26 AM
nikic accepted this revision.Aug 1 2023, 7:42 AM

LGTM, but maybe wait a day before committing in case somebody disagrees with this approach.

I would also recommend to add a PhaseOrdering test for https://github.com/llvm/llvm-project/issues/64289. This miscompile here is due to an interaction of multiple passes, so I think it's worthwhile to check the full optimization pipeline.

This revision is now accepted and ready to land.Aug 1 2023, 7:42 AM
DianQK added a comment.Aug 1 2023, 7:48 PM

LGTM, but maybe wait a day before committing in case somebody disagrees with this approach.

Do you think we need to add someone else to review it?
TailRecursionElimination.cpp has had very few non-NFC changes recently.

avl added a reviewer: efriedma.Aug 2 2023, 5:17 AM
avl added inline comments.
llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
683

probably, instead of removing readonly attribute we could stop generating it? Otherwise it will be presented or not depending of whether tail recursion elimination is happened.

byval(<ty>)

    This indicates that the pointer parameter should really be passed by value to the function. The attribute implies that a hidden copy of the pointee is made between the caller and the callee, so the callee is unable to modify the value in the caller.

The hidden copy protects original value from modifications done by callee. Having readonly attribute for hidden copy, probably, redundant.

DianQK added inline comments.Aug 2 2023, 5:46 AM
llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
683

Do you mean don't add readonly at PostOrderFunctionAttrsPass?
I don't think so. First rustc/clang can also add the readonly attribute.
I think readonly + byval makes sense. There are more internal invariant representations than only byval.

avl added inline comments.Aug 2 2023, 8:03 AM
llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
683

if readonly is important then we probably should not do tail recursion elimination for readonly + byval as we will write into the readonly data. if it is not important then it should be safe to not set this flag?

efriedma added inline comments.Aug 2 2023, 10:05 AM
llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
683

Marking a byval pointer readonly isn't very useful; MemorySSA can easily analyze a byval argument without the marking in almost all cases.

I would tend towards saying we shouldn't add readonly markings to byval values, if only to reduce the chance of this sort of confusion. But that doesn't really impact this patch: unless we actually make "readonly byval" illegal, TCE needs to handle it anyway.

DianQK added inline comments.Aug 2 2023, 6:19 PM
llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
683

if readonly is important then we probably should not do tail recursion elimination for readonly + byval as we will write into the readonly data. if it is not important then it should be safe to not set this flag?

It is possible to perform a transformation in a way that prevents another, larger optimization.
readonly must make sense. At least until tail recursion elimination, other passes can use readonly.
But I think tail recursion elimination has a better opportunity for optimization than readonly.
In the test case, with tail recursion elimination eventually converted to a ret instruction.

Marking a byval pointer readonly isn't very useful; MemorySSA can easily analyze a byval argument without the marking in almost all cases.

I would tend towards saying we shouldn't add readonly markings to byval values, if only to reduce the chance of this sort of confusion. But that doesn't really impact this patch: unless we actually make "readonly byval" illegal, TCE needs to handle it anyway.

Using readonly we can avoid reusing MemorySSA analysis. This should reduce compilation time. And that covers all cases.
readonly + byval is indeed confusing. But I think this discussion we can clarify the meaning.

  • readonly = Indicates invariance to *internal* and external.
  • byval = Indicates invariance to external.
683

Marking a byval pointer readonly isn't very useful; MemorySSA can easily analyze a byval argument without the marking in almost all cases.

I would tend towards saying we shouldn't add readonly markings to byval values, if only to reduce the chance of this sort of confusion. But that doesn't really impact this patch: unless we actually make "readonly byval" illegal, TCE needs to handle it anyway.

DianQK added a comment.Aug 5 2023, 1:52 AM

In my mind, this is a worse case of mis-compilation.

With the current discussion, we have three methods to address it:

  1. Remove the readonly attribute, which is safe with byval.
  2. Do not add the readonly attribute to byval.
  3. Prevent the tail recursion elimination.

First, all three methods can solve this problem.
But I prefer the first one, and I think there is less opportunity to prevent other optimizations.

DianQK added inline comments.Aug 7 2023, 5:43 PM
llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
683

But that doesn't really impact this patch: unless we actually make "readonly byval" illegal, TCE needs to handle it anyway.

So I think I'd go ahead and submit this patch to fix the miscompilation. If anyone has other ideas they can submit a new patch.

nikic added inline comments.Aug 8 2023, 12:43 PM
llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
683

Yes, please go ahead. If we like, we can forbid byval + readonly in a followup, but it's allowed right now, so we should handle it.

llvm/test/Transforms/PhaseOrdering/pr64289-tce.ll
4

These two RUN lines do the same thing, drop one of them.

DianQK updated this revision to Diff 548339.Aug 8 2023, 1:42 PM

Rebase and remove the duplicate test.

This revision was landed with ongoing or failed builds.Aug 8 2023, 4:08 PM
This revision was automatically updated to reflect the committed changes.