This is an archive of the discontinued LLVM Phabricator instance.

[Lint] Permit aliasing noalias and readnone arguments
ClosedPublic

Authored by bjope on Aug 11 2023, 10:42 AM.

Details

Summary

If an argument is readnone we know that it isn't dereferenced. Then
it should be OK if that argument alias with a noalias argument.

Diff Detail

Event Timeline

bjope created this revision.Aug 11 2023, 10:42 AM
bjope requested review of this revision.Aug 11 2023, 10:42 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 11 2023, 10:42 AM
bjope added inline comments.Aug 11 2023, 10:46 AM
llvm/lib/Analysis/Lint.cpp
240

Maybe we need to check for NoCapture as well (that would be a bit more defensive at least)?

bjope marked an inline comment as not done.Aug 11 2023, 10:46 AM

For reference, here is an example that made me look at this: https://godbolt.org/z/xY4hE9Kvb
The caller is doing

call void @foo(ptr nonnull sret(%struct.A) align 8 %3, ptr noundef nonnull align 8 %1)

and the callee is

define dso_local void @foo(ptr noalias nocapture writeonly sret(%struct.A) align 8 %0, ptr nocapture noundef readnone align 8 %1) local_unnamed_addr #0

And then memcpyopt will rewrite the call to use same ptr for both arguments, which then result in complaints from lint. But I think that should be OK here.

bjope added inline comments.Aug 11 2023, 11:01 AM
llvm/lib/Analysis/Lint.cpp
240

Given the example from https://godbolt.org/z/xY4hE9Kvb

If I remove NoCapture on the second argument then MemCpyOpt no longer rewrite the call. So then I actually think it would make sense to also check NoCapture here. Right?

bjope added inline comments.Aug 11 2023, 3:45 PM
llvm/lib/Analysis/Lint.cpp
240

I looked a bit more a MemCpyOptPass::performCallSlotOptzn to understand the logic for when it may introduce the IR when passing the ptr in multiple arguments (with some being noalias).
IIUC that transform is based on the several conditions. For example that the pointer is pointing to an uninitialized alloca.
And it also need to check that the pointer isn't captured between the call and the memcpy. For that check it uses PointerMayBeCapturedBefore, and I think that is why the NoCapture attribute makes a difference.
Another check is to verify that the call "does not sneakily access dest". For that check it use AA and callCapturesBefore. Which would detect readnone to derive that the pointer isn't dereferenced via that argument.

Anyway. Not sure if the MemCpyOpt behavior is that important here. The question is when it is allowed to pass a pointer that is used in a noalias argument in another argument.

nikic added a comment.Aug 12 2023, 6:19 AM

There are test failures.

llvm/lib/Analysis/Lint.cpp
240

Should use I.doesNotAccessMemory(ArgNo) to take into account both the call-site and declaration attributes.

I don't think NoCapture is relevant here. noalias is a pure provenance concept, so it only cares about memory accesses. It also applies only for the duration of the call, so it does not matter if the pointer is captured and accessed later.

bjope updated this revision to Diff 549711.Aug 13 2023, 9:41 AM

Updated to use I.doesNotAccessMemory.

nikic accepted this revision.Aug 14 2023, 2:54 AM

LGTM

This revision is now accepted and ready to land.Aug 14 2023, 2:54 AM
This revision was automatically updated to reflect the committed changes.