Skip to content

Commit cda5790

Browse files
authored
[Inliner] Don't propagate memory attributes to byval params (#93381)
Memory restrictions for params to the inlined function do not apply to the copies logically made when that function further passes its own params as byval. In other words, imagine that `@foo()` calls `@bar(ptr readonly %p)` which in turn calls `@baz(ptr byval("...") %p)` (passing the same `%p`). This is fully legal - `baz` is allowed to modify its copy of the object referenced by `%p` because the argument is passed by value. However, when inlining `@bar` into `@foo`, we can't say that the callsite is now `@baz(ptr readonly byval("...") %p)`, as this would mean that `@baz` is not allowed to modify it's copy of the object pointed to by `%p`. LangRef says: "The copy is considered to belong to the caller not the callee (for example, readonly functions should not write to byval parameters)". This fixes a miscompile introduced by PR #89024 in a program in the Google codebase.
1 parent a4a4366 commit cda5790

File tree

2 files changed

+24
-0
lines changed

2 files changed

+24
-0
lines changed

llvm/lib/Transforms/Utils/InlineFunction.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,6 +1389,12 @@ static void AddParamAndFnBasicAttributes(const CallBase &CB,
13891389
if (!Arg)
13901390
continue;
13911391

1392+
if (AL.hasParamAttr(I, Attribute::ByVal))
1393+
// It's unsound to propagate memory attributes to byval arguments.
1394+
// Even if CalledFunction doesn't e.g. write to the argument,
1395+
// the call to NewInnerCB may write to its by-value copy.
1396+
continue;
1397+
13921398
unsigned ArgNo = Arg->getArgNo();
13931399
// If so, propagate its access attributes.
13941400
AL = AL.addParamAttributes(Context, I, ValidParamAttrs[ArgNo]);

llvm/test/Transforms/Inline/access-attributes-prop.ll

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
declare void @bar1(ptr %p)
77
declare void @bar2(ptr %p, ptr %p2)
88
declare void @bar3(ptr writable %p)
9+
declare void @bar4(ptr byval([4 x i32]) %p)
910
define dso_local void @foo1_rdonly(ptr readonly %p) {
1011
; CHECK-LABEL: define {{[^@]+}}@foo1_rdonly
1112
; CHECK-SAME: (ptr readonly [[P:%.*]]) {
@@ -186,6 +187,15 @@ define dso_local void @foo2_through_obj(ptr %p, ptr %p2) {
186187
ret void
187188
}
188189

190+
define dso_local void @foo_byval_readonly(ptr readonly %p) {
191+
; CHECK-LABEL: define {{[^@]+}}@foo_byval_readonly
192+
; CHECK-SAME: (ptr readonly [[P:%.*]])
193+
; CHECK-NEXT: call void @bar4(ptr byval([4 x i32]) [[P]])
194+
; CHECK-NEXT: ret void
195+
call void @bar4(ptr byval([4 x i32]) %p)
196+
ret void
197+
}
198+
189199
define void @prop_param_func_decl(ptr %p) {
190200
; CHECK-LABEL: define {{[^@]+}}@prop_param_func_decl
191201
; CHECK-SAME: (ptr [[P:%.*]]) {
@@ -539,3 +549,11 @@ define void @prop_no_conflict_writable2(ptr %p) {
539549
ret void
540550
}
541551

552+
define void @prop_byval_readonly(ptr %p) {
553+
; CHECK-LABEL: define {{[^@]+}}@prop_byval_readonly
554+
; CHECK-SAME: (ptr [[P:%.*]]) {
555+
; CHECK-NEXT: call void @bar4(ptr byval([4 x i32]) [[P]])
556+
; CHECK-NEXT: ret void
557+
call void @foo_byval_readonly(ptr %p)
558+
ret void
559+
}

0 commit comments

Comments
 (0)