-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[FunctionAttrs] Treat byval calls as only reading ptrs #122618
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FunctionAttrs] Treat byval calls as only reading ptrs #122618
Conversation
@llvm/pr-subscribers-llvm-analysis @llvm/pr-subscribers-llvm-transforms Author: Alex MacLean (AlexMaclean) ChangesSince byval arguments are passed via a hidden copy of the pointee, they do not have the same semantics as normal pointer arguments. The callee cannot capture or write to the pointer and the copy is a read of the pointer. Full diff: https://github.com/llvm/llvm-project/pull/122618.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index fe9cca01a8f31f..7ac9b70f47902c 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -852,9 +852,10 @@ determinePointerAccessAttrs(Argument *A,
continue;
}
- // Given we've explictily handled the callee operand above, what's left
+ // Given we've explicitly handled the callee operand above, what's left
// must be a data operand (e.g. argument or operand bundle)
const unsigned UseIndex = CB.getDataOperandNo(U);
+ const bool IsByVal = CB.isByValArgument(CB.getArgOperandNo(U));
// Some intrinsics (for instance ptrmask) do not capture their results,
// but return results thas alias their pointer argument, and thus should
@@ -864,7 +865,7 @@ determinePointerAccessAttrs(Argument *A,
for (Use &UU : CB.uses())
if (Visited.insert(&UU).second)
Worklist.push_back(&UU);
- } else if (!CB.doesNotCapture(UseIndex)) {
+ } else if (!(CB.doesNotCapture(UseIndex) || IsByVal)) {
if (!CB.onlyReadsMemory())
// If the callee can save a copy into other memory, then simply
// scanning uses of the call is insufficient. We have no way
@@ -894,7 +895,7 @@ determinePointerAccessAttrs(Argument *A,
// invokes with operand bundles.
if (CB.doesNotAccessMemory(UseIndex)) {
/* nop */
- } else if (!isModSet(ArgMR) || CB.onlyReadsMemory(UseIndex)) {
+ } else if (!isModSet(ArgMR) || CB.onlyReadsMemory(UseIndex) || IsByVal) {
IsRead = true;
} else if (!isRefSet(ArgMR) ||
CB.dataOperandHasImpliedAttr(UseIndex, Attribute::WriteOnly)) {
diff --git a/llvm/test/Transforms/FunctionAttrs/readattrs.ll b/llvm/test/Transforms/FunctionAttrs/readattrs.ll
index 004c0485d764ae..6087160d13ca1d 100644
--- a/llvm/test/Transforms/FunctionAttrs/readattrs.ll
+++ b/llvm/test/Transforms/FunctionAttrs/readattrs.ll
@@ -762,5 +762,27 @@ define void @writable_readnone(ptr writable dereferenceable(4) %p) {
ret void
}
+declare void @byval_param(ptr byval(i32) %p)
+
+define void @call_byval_param(ptr %p) {
+; FNATTRS-LABEL: define {{[^@]+}}@call_byval_param
+; FNATTRS-SAME: (ptr readonly [[P:%.*]]) {
+; FNATTRS-NEXT: call void @byval_param(ptr byval(i32) [[P]])
+; FNATTRS-NEXT: ret void
+;
+; ATTRIBUTOR-LABEL: define {{[^@]+}}@call_byval_param
+; ATTRIBUTOR-SAME: (ptr nocapture readonly [[P:%.*]]) {
+; ATTRIBUTOR-NEXT: call void @byval_param(ptr nocapture readonly byval(i32) [[P]])
+; ATTRIBUTOR-NEXT: ret void
+;
+; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@call_byval_param
+; ATTRIBUTOR-CGSCC-SAME: (ptr nocapture readonly [[P:%.*]]) {
+; ATTRIBUTOR-CGSCC-NEXT: call void @byval_param(ptr nocapture readonly byval(i32) [[P]])
+; ATTRIBUTOR-CGSCC-NEXT: ret void
+;
+ call void @byval_param(ptr byval(i32) %p)
+ ret void
+}
+
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; COMMON: {{.*}}
|
ddc39c5
to
5ebe920
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This basically looks right, but I think at least for doesNotCapture we'd be better off changing the API to automatically check byval. I looked at some of the other callers and many of them don't handle byval either, but should. (You can see in the test that FunctionAttrs infers readonly after your change, but still misses nocapture. That's because CaptureTracking doesn't check for byval.)
Done, I now see @nikic do you think it makes sense to update |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please drop the separate byval check in
(!Call->doesNotCapture(ArgNo) && ArgNo < Call->arg_size() && |
@@ -16,14 +16,10 @@ declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias | |||
define i1 @alloca_forwarding_lifetime_end_clobber() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should update the comment above here, because we now do the optimization by dropping the lifetime intrinsics.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
I'm a bit less sure on that one. |
Fixed!
Sounds good, I will take this up in a separate PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/16/builds/11907 Here is the relevant piece of the build log for the reference
|
Since byval arguments are passed via a hidden copy of the pointee, they do not have the same semantics as normal pointer arguments. The callee cannot capture or write to the pointer and the copy is a read of the pointer.