Skip to content

Commit 740057d

Browse files
committed
[funcattrs] Infer writeonly argument attribute
This change extends the current logic for inferring readonly and readnone argument attributes to also infer writeonly. This change is deliberately minimal; there's a couple of areas for follow up. * I left out all call handling and thus any benefit from the SCC walk. When examining the test changes, I realized the existing code is imprecise, and am going to fix that in it's own revision before adding in the writeonly handling. (Mostly because updating the tests is hard when I, the human, can't figure out whether the result is correct.) * I left out handling for storing a value (as opposed to storing to a pointer). This should benefit readonly/readnone as well, and applies to a bunch of other instructions. Seemed worth having as a separate review. Differential Revision: https://reviews.llvm.org/D114963
1 parent a9036f2 commit 740057d

17 files changed

+102
-71
lines changed

clang/test/CodeGen/SystemZ/systemz-inline-asm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ double test_f64(double f, double g) {
123123
long double test_f128(long double f, long double g) {
124124
asm("axbr %0, %2" : "=f" (f) : "0" (f), "f" (g));
125125
return f;
126-
// CHECK: define{{.*}} void @test_f128(fp128* noalias nocapture sret(fp128) align 8 [[DEST:%.*]], fp128* nocapture readonly %0, fp128* nocapture readonly %1)
126+
// CHECK: define{{.*}} void @test_f128(fp128* noalias nocapture writeonly sret(fp128) align 8 [[DEST:%.*]], fp128* nocapture readonly %0, fp128* nocapture readonly %1)
127127
// CHECK: %f = load fp128, fp128* %0
128128
// CHECK: %g = load fp128, fp128* %1
129129
// CHECK: [[RESULT:%.*]] = tail call fp128 asm "axbr $0, $2", "=f,0,f"(fp128 %f, fp128 %g)

clang/test/CodeGen/aarch64-sve-acle-__ARM_FEATURE_SVE_VECTOR_OPERATORS.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ typedef int8_t vec_int8 __attribute__((vector_size(N / 8)));
5959
// CHECK128-NEXT: ret <16 x i8> [[CASTFIXEDSVE]]
6060

6161
// CHECK-LABEL: define{{.*}} void @f2(
62-
// CHECK-SAME: <[[#div(VBITS,8)]] x i8>* noalias nocapture sret(<[[#div(VBITS,8)]] x i8>) align 16 %agg.result, <[[#div(VBITS,8)]] x i8>* nocapture readonly %0)
62+
// CHECK-SAME: <[[#div(VBITS,8)]] x i8>* noalias nocapture writeonly sret(<[[#div(VBITS,8)]] x i8>) align 16 %agg.result, <[[#div(VBITS,8)]] x i8>* nocapture readonly %0)
6363
// CHECK-NEXT: entry:
6464
// CHECK-NEXT: [[X:%.*]] = load <[[#div(VBITS,8)]] x i8>, <[[#div(VBITS,8)]] x i8>* [[TMP0:%.*]], align 16, [[TBAA6:!tbaa !.*]]
6565
// CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 31)

clang/test/CodeGen/arm-vfp16-arguments2.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,27 +37,27 @@ struct S5 : B1 {
3737
B1 M[1];
3838
};
3939

40-
// CHECK-SOFT: define{{.*}} void @_Z2f12S1(%struct.S1* noalias nocapture sret(%struct.S1) align 8 %agg.result, [2 x i64] %s1.coerce)
40+
// CHECK-SOFT: define{{.*}} void @_Z2f12S1(%struct.S1* noalias nocapture writeonly sret(%struct.S1) align 8 %agg.result, [2 x i64] %s1.coerce)
4141
// CHECK-HARD: define{{.*}} arm_aapcs_vfpcc [2 x <2 x i32>] @_Z2f12S1([2 x <2 x i32>] returned %s1.coerce)
4242
// CHECK-FULL: define{{.*}} arm_aapcs_vfpcc %struct.S1 @_Z2f12S1(%struct.S1 returned %s1.coerce)
4343
struct S1 f1(struct S1 s1) { return s1; }
4444

45-
// CHECK-SOFT: define{{.*}} void @_Z2f22S2(%struct.S2* noalias nocapture sret(%struct.S2) align 8 %agg.result, [4 x i32] %s2.coerce)
45+
// CHECK-SOFT: define{{.*}} void @_Z2f22S2(%struct.S2* noalias nocapture writeonly sret(%struct.S2) align 8 %agg.result, [4 x i32] %s2.coerce)
4646
// CHECK-HARD: define{{.*}} arm_aapcs_vfpcc [2 x <2 x i32>] @_Z2f22S2([2 x <2 x i32>] returned %s2.coerce)
4747
// CHECK-FULL: define{{.*}} arm_aapcs_vfpcc %struct.S2 @_Z2f22S2(%struct.S2 returned %s2.coerce)
4848
struct S2 f2(struct S2 s2) { return s2; }
4949

50-
// CHECK-SOFT: define{{.*}} void @_Z2f32S3(%struct.S3* noalias nocapture sret(%struct.S3) align 8 %agg.result, [2 x i64] %s3.coerce)
50+
// CHECK-SOFT: define{{.*}} void @_Z2f32S3(%struct.S3* noalias nocapture writeonly sret(%struct.S3) align 8 %agg.result, [2 x i64] %s3.coerce)
5151
// CHECK-HARD: define{{.*}} arm_aapcs_vfpcc [2 x <2 x i32>] @_Z2f32S3([2 x <2 x i32>] returned %s3.coerce)
5252
// CHECK-FULL: define{{.*}} arm_aapcs_vfpcc %struct.S3 @_Z2f32S3(%struct.S3 returned %s3.coerce)
5353
struct S3 f3(struct S3 s3) { return s3; }
5454

55-
// CHECK-SOFT: define{{.*}} void @_Z2f42S4(%struct.S4* noalias nocapture sret(%struct.S4) align 8 %agg.result, [2 x i64] %s4.coerce)
55+
// CHECK-SOFT: define{{.*}} void @_Z2f42S4(%struct.S4* noalias nocapture writeonly sret(%struct.S4) align 8 %agg.result, [2 x i64] %s4.coerce)
5656
// CHECK-HARD: define{{.*}} arm_aapcs_vfpcc [2 x <2 x i32>] @_Z2f42S4([2 x <2 x i32>] returned %s4.coerce)
5757
// CHECK-FULL: define{{.*}} arm_aapcs_vfpcc %struct.S4 @_Z2f42S4(%struct.S4 returned %s4.coerce)
5858
struct S4 f4(struct S4 s4) { return s4; }
5959

60-
// CHECK-SOFT: define{{.*}} void @_Z2f52S5(%struct.S5* noalias nocapture sret(%struct.S5) align 8 %agg.result, [2 x i64] %s5.coerce)
60+
// CHECK-SOFT: define{{.*}} void @_Z2f52S5(%struct.S5* noalias nocapture writeonly sret(%struct.S5) align 8 %agg.result, [2 x i64] %s5.coerce)
6161
// CHECK-HARD: define{{.*}} arm_aapcs_vfpcc %struct.S5 @_Z2f52S5(%struct.S5 returned %s5.coerce)
6262
// CHECK-FULL: define{{.*}} arm_aapcs_vfpcc %struct.S5 @_Z2f52S5(%struct.S5 returned %s5.coerce)
6363
struct S5 f5(struct S5 s5) { return s5; }

clang/test/CodeGen/mips-vector-return.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ typedef float v4sf __attribute__ ((__vector_size__ (16)));
88
typedef double v4df __attribute__ ((__vector_size__ (32)));
99
typedef int v4i32 __attribute__ ((__vector_size__ (16)));
1010

11-
// O32-LABEL: define dso_local void @test_v4sf(<4 x float>* noalias nocapture sret
11+
// O32-LABEL: define dso_local void @test_v4sf(<4 x float>* noalias nocapture writeonly sret
1212
// N64: define inreg { i64, i64 } @test_v4sf
1313
v4sf test_v4sf(float a) {
1414
return (v4sf){0.0f, a, 0.0f, 0.0f};
1515
}
1616

17-
// O32-LABEL: define dso_local void @test_v4df(<4 x double>* noalias nocapture sret
18-
// N64-LABEL: define void @test_v4df(<4 x double>* noalias nocapture sret
17+
// O32-LABEL: define dso_local void @test_v4df(<4 x double>* noalias nocapture writeonly sret
18+
// N64-LABEL: define void @test_v4df(<4 x double>* noalias nocapture writeonly sret
1919
v4df test_v4df(double a) {
2020
return (v4df){0.0, a, 0.0, 0.0};
2121
}

clang/test/CodeGen/mips64-nontrivial-return.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class D : public B {
1010

1111
extern D gd0;
1212

13-
// CHECK: _Z4foo1v(%class.D* noalias nocapture sret
13+
// CHECK: _Z4foo1v(%class.D* noalias nocapture writeonly sret
1414

1515
D foo1(void) {
1616
return gd0;

clang/test/CodeGen/ms-mixed-ptr-sizes.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,41 +7,41 @@ struct Foo {
77
};
88
void use_foo(struct Foo *f);
99
void test_sign_ext(struct Foo *f, int * __ptr32 __sptr i) {
10-
// X64-LABEL: define dso_local void @test_sign_ext({{.*}}i32 addrspace(270)* %i)
11-
// X86-LABEL: define dso_local void @test_sign_ext(%struct.Foo* %f, i32* %i)
10+
// X64-LABEL: define dso_local void @test_sign_ext({{.*}}i32 addrspace(270)* writeonly %i)
11+
// X86-LABEL: define dso_local void @test_sign_ext(%struct.Foo* %f, i32* writeonly %i)
1212
// X64: %{{.+}} = addrspacecast i32 addrspace(270)* %i to i32*
1313
// X86: %{{.+}} = addrspacecast i32* %i to i32 addrspace(272)*
1414
f->p64 = i;
1515
use_foo(f);
1616
}
1717
void test_zero_ext(struct Foo *f, int * __ptr32 __uptr i) {
18-
// X64-LABEL: define dso_local void @test_zero_ext({{.*}}i32 addrspace(271)* %i)
19-
// X86-LABEL: define dso_local void @test_zero_ext({{.*}}i32 addrspace(271)* %i)
18+
// X64-LABEL: define dso_local void @test_zero_ext({{.*}}i32 addrspace(271)* writeonly %i)
19+
// X86-LABEL: define dso_local void @test_zero_ext({{.*}}i32 addrspace(271)* writeonly %i)
2020
// X64: %{{.+}} = addrspacecast i32 addrspace(271)* %i to i32*
2121
// X86: %{{.+}} = addrspacecast i32 addrspace(271)* %i to i32 addrspace(272)*
2222
f->p64 = i;
2323
use_foo(f);
2424
}
2525
void test_trunc(struct Foo *f, int * __ptr64 i) {
26-
// X64-LABEL: define dso_local void @test_trunc(%struct.Foo* %f, i32* %i)
27-
// X86-LABEL: define dso_local void @test_trunc({{.*}}i32 addrspace(272)* %i)
26+
// X64-LABEL: define dso_local void @test_trunc(%struct.Foo* %f, i32* writeonly %i)
27+
// X86-LABEL: define dso_local void @test_trunc({{.*}}i32 addrspace(272)* writeonly %i)
2828
// X64: %{{.+}} = addrspacecast i32* %i to i32 addrspace(270)*
2929
// X86: %{{.+}} = addrspacecast i32 addrspace(272)* %i to i32*
3030
f->p32 = i;
3131
use_foo(f);
3232
}
3333
void test_noop(struct Foo *f, int * __ptr32 i) {
34-
// X64-LABEL: define dso_local void @test_noop({{.*}}i32 addrspace(270)* %i)
35-
// X86-LABEL: define dso_local void @test_noop({{.*}}i32* %i)
34+
// X64-LABEL: define dso_local void @test_noop({{.*}}i32 addrspace(270)* writeonly %i)
35+
// X86-LABEL: define dso_local void @test_noop({{.*}}i32* writeonly %i)
3636
// X64-NOT: addrspacecast
3737
// X86-NOT: addrspacecast
3838
f->p32 = i;
3939
use_foo(f);
4040
}
4141

4242
void test_other(struct Foo *f, __attribute__((address_space(10))) int *i) {
43-
// X64-LABEL: define dso_local void @test_other({{.*}}i32 addrspace(10)* %i)
44-
// X86-LABEL: define dso_local void @test_other({{.*}}i32 addrspace(10)* %i)
43+
// X64-LABEL: define dso_local void @test_other({{.*}}i32 addrspace(10)* writeonly %i)
44+
// X86-LABEL: define dso_local void @test_other({{.*}}i32 addrspace(10)* writeonly %i)
4545
// X64: %{{.+}} = addrspacecast i32 addrspace(10)* %i to i32 addrspace(270)*
4646
// X86: %{{.+}} = addrspacecast i32 addrspace(10)* %i to i32*
4747
f->p32 = (int * __ptr32)i;

clang/test/CodeGenOpenCL/amdgpu-abi-struct-coerce.cl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ different_size_type_pair func_different_size_type_pair_ret()
439439
return s;
440440
}
441441

442-
// CHECK: define{{.*}} void @func_flexible_array_ret(%struct.flexible_array addrspace(5)* noalias nocapture sret(%struct.flexible_array) align 4 %agg.result)
442+
// CHECK: define{{.*}} void @func_flexible_array_ret(%struct.flexible_array addrspace(5)* noalias nocapture writeonly sret(%struct.flexible_array) align 4 %agg.result)
443443
flexible_array func_flexible_array_ret()
444444
{
445445
flexible_array s = { 0 };

clang/test/CodeGenOpenCL/amdgpu-call-kernel.cl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// REQUIRES: amdgpu-registered-target
22
// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -S -emit-llvm -o - %s | FileCheck %s
3-
// CHECK: define{{.*}} amdgpu_kernel void @test_call_kernel(i32 addrspace(1)* nocapture %out)
3+
// CHECK: define{{.*}} amdgpu_kernel void @test_call_kernel(i32 addrspace(1)* nocapture writeonly %out)
44
// CHECK: store i32 4, i32 addrspace(1)* %out, align 4
55

66
kernel void test_kernel(global int *out)

clang/test/CodeGenOpenCL/kernels-have-spir-cc-by-default.cl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@ kernel void test_single(int_single input, global int* output) {
2828
// CHECK: spir_kernel
2929
// AMDGCN: define{{.*}} amdgpu_kernel void @test_single
3030
// CHECK: struct.int_single* nocapture {{.*}} byval(%struct.int_single)
31-
// CHECK: i32* nocapture %output
31+
// CHECK: i32* nocapture writeonly %output
3232
output[0] = input.a;
3333
}
3434

3535
kernel void test_pair(int_pair input, global int* output) {
3636
// CHECK: spir_kernel
3737
// AMDGCN: define{{.*}} amdgpu_kernel void @test_pair
3838
// CHECK: struct.int_pair* nocapture {{.*}} byval(%struct.int_pair)
39-
// CHECK: i32* nocapture %output
39+
// CHECK: i32* nocapture writeonly %output
4040
output[0] = (int)input.a;
4141
output[1] = (int)input.b;
4242
}
@@ -45,7 +45,7 @@ kernel void test_kernel(test_struct input, global int* output) {
4545
// CHECK: spir_kernel
4646
// AMDGCN: define{{.*}} amdgpu_kernel void @test_kernel
4747
// CHECK: struct.test_struct* nocapture {{.*}} byval(%struct.test_struct)
48-
// CHECK: i32* nocapture %output
48+
// CHECK: i32* nocapture writeonly %output
4949
output[0] = input.elementA;
5050
output[1] = input.elementB;
5151
output[2] = (int)input.elementC;
@@ -59,7 +59,7 @@ kernel void test_kernel(test_struct input, global int* output) {
5959
void test_function(int_pair input, global int* output) {
6060
// CHECK-NOT: spir_kernel
6161
// AMDGCN-NOT: define{{.*}} amdgpu_kernel void @test_function
62-
// CHECK: i64 %input.coerce0, i64 %input.coerce1, i32* nocapture %output
62+
// CHECK: i64 %input.coerce0, i64 %input.coerce1, i32* nocapture writeonly %output
6363
output[0] = (int)input.a;
6464
output[1] = (int)input.b;
6565
}

llvm/lib/Transforms/IPO/FunctionAttrs.cpp

Lines changed: 62 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ STATISTIC(NumNoCapture, "Number of arguments marked nocapture");
7676
STATISTIC(NumReturned, "Number of arguments marked returned");
7777
STATISTIC(NumReadNoneArg, "Number of arguments marked readnone");
7878
STATISTIC(NumReadOnlyArg, "Number of arguments marked readonly");
79+
STATISTIC(NumWriteOnlyArg, "Number of arguments marked writeonly");
7980
STATISTIC(NumNoAlias, "Number of function returns marked noalias");
8081
STATISTIC(NumNonNullReturn, "Number of function returns marked nonnull");
8182
STATISTIC(NumNoRecurse, "Number of functions marked as norecurse");
@@ -649,8 +650,8 @@ struct GraphTraits<ArgumentGraph *> : public GraphTraits<ArgumentGraphNode *> {
649650

650651
/// Returns Attribute::None, Attribute::ReadOnly or Attribute::ReadNone.
651652
static Attribute::AttrKind
652-
determinePointerReadAttrs(Argument *A,
653-
const SmallPtrSet<Argument *, 8> &SCCNodes) {
653+
determinePointerAccessAttrs(Argument *A,
654+
const SmallPtrSet<Argument *, 8> &SCCNodes) {
654655
SmallVector<Use *, 32> Worklist;
655656
SmallPtrSet<Use *, 32> Visited;
656657

@@ -659,14 +660,18 @@ determinePointerReadAttrs(Argument *A,
659660
return Attribute::None;
660661

661662
bool IsRead = false;
662-
// We don't need to track IsWritten. If A is written to, return immediately.
663+
bool IsWrite = false;
663664

664665
for (Use &U : A->uses()) {
665666
Visited.insert(&U);
666667
Worklist.push_back(&U);
667668
}
668669

669670
while (!Worklist.empty()) {
671+
if (IsWrite && IsRead)
672+
// No point in searching further..
673+
return Attribute::None;
674+
670675
Use *U = Worklist.pop_back_val();
671676
Instruction *I = cast<Instruction>(U->getUser());
672677

@@ -763,6 +768,15 @@ determinePointerReadAttrs(Argument *A,
763768
IsRead = true;
764769
break;
765770

771+
case Instruction::Store:
772+
// A volatile store has side effects beyond what writeonly can be relied
773+
// upon.
774+
if (cast<StoreInst>(I)->isVolatile())
775+
return Attribute::None;
776+
777+
IsWrite = true;
778+
break;
779+
766780
case Instruction::ICmp:
767781
case Instruction::Ret:
768782
break;
@@ -772,7 +786,14 @@ determinePointerReadAttrs(Argument *A,
772786
}
773787
}
774788

775-
return IsRead ? Attribute::ReadOnly : Attribute::ReadNone;
789+
if (IsWrite && IsRead)
790+
return Attribute::None;
791+
else if (IsRead)
792+
return Attribute::ReadOnly;
793+
else if (IsWrite)
794+
return Attribute::WriteOnly;
795+
else
796+
return Attribute::ReadNone;
776797
}
777798

778799
/// Deduce returned attributes for the SCC.
@@ -865,9 +886,10 @@ static bool addArgumentAttrsFromCallsites(Function &F) {
865886
return Changed;
866887
}
867888

868-
static bool addReadAttr(Argument *A, Attribute::AttrKind R) {
869-
assert((R == Attribute::ReadOnly || R == Attribute::ReadNone)
870-
&& "Must be a Read attribute.");
889+
static bool addAccessAttr(Argument *A, Attribute::AttrKind R) {
890+
assert((R == Attribute::ReadOnly || R == Attribute::ReadNone ||
891+
R == Attribute::WriteOnly)
892+
&& "Must be an access attribute.");
871893
assert(A && "Argument must not be null.");
872894

873895
// If the argument already has the attribute, nothing needs to be done.
@@ -880,7 +902,12 @@ static bool addReadAttr(Argument *A, Attribute::AttrKind R) {
880902
A->removeAttr(Attribute::ReadOnly);
881903
A->removeAttr(Attribute::ReadNone);
882904
A->addAttr(R);
883-
R == Attribute::ReadOnly ? ++NumReadOnlyArg : ++NumReadNoneArg;
905+
if (R == Attribute::ReadOnly)
906+
++NumReadOnlyArg;
907+
else if (R == Attribute::WriteOnly)
908+
++NumWriteOnlyArg;
909+
else
910+
++NumReadNoneArg;
884911
return true;
885912
}
886913

@@ -945,15 +972,15 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
945972
// Otherwise, it's captured. Don't bother doing SCC analysis on it.
946973
}
947974
if (!HasNonLocalUses && !A->onlyReadsMemory()) {
948-
// Can we determine that it's readonly/readnone without doing an SCC?
949-
// Note that we don't allow any calls at all here, or else our result
950-
// will be dependent on the iteration order through the functions in the
951-
// SCC.
975+
// Can we determine that it's readonly/readnone/writeonly without doing
976+
// an SCC? Note that we don't allow any calls at all here, or else our
977+
// result will be dependent on the iteration order through the
978+
// functions in the SCC.
952979
SmallPtrSet<Argument *, 8> Self;
953980
Self.insert(&*A);
954-
Attribute::AttrKind R = determinePointerReadAttrs(&*A, Self);
981+
Attribute::AttrKind R = determinePointerAccessAttrs(&*A, Self);
955982
if (R != Attribute::None)
956-
if (addReadAttr(A, R))
983+
if (addAccessAttr(A, R))
957984
Changed.insert(F);
958985
}
959986
}
@@ -1023,35 +1050,39 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
10231050
Changed.insert(A->getParent());
10241051
}
10251052

1026-
// We also want to compute readonly/readnone. With a small number of false
1027-
// negatives, we can assume that any pointer which is captured isn't going
1028-
// to be provably readonly or readnone, since by definition we can't
1029-
// analyze all uses of a captured pointer.
1053+
// We also want to compute readonly/readnone/writeonly. With a small number
1054+
// of false negatives, we can assume that any pointer which is captured
1055+
// isn't going to be provably readonly or readnone, since by definition
1056+
// we can't analyze all uses of a captured pointer.
10301057
//
10311058
// The false negatives happen when the pointer is captured by a function
10321059
// that promises readonly/readnone behaviour on the pointer, then the
10331060
// pointer's lifetime ends before anything that writes to arbitrary memory.
10341061
// Also, a readonly/readnone pointer may be returned, but returning a
10351062
// pointer is capturing it.
10361063

1037-
Attribute::AttrKind ReadAttr = Attribute::ReadNone;
1038-
for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) {
1064+
auto meetAccessAttr = [](Attribute::AttrKind A, Attribute::AttrKind B) {
1065+
if (A == B)
1066+
return A;
1067+
if (A == Attribute::ReadNone)
1068+
return B;
1069+
if (B == Attribute::ReadNone)
1070+
return A;
1071+
return Attribute::None;
1072+
};
1073+
1074+
Attribute::AttrKind AccessAttr = Attribute::ReadNone;
1075+
for (unsigned i = 0, e = ArgumentSCC.size();
1076+
i != e && AccessAttr != Attribute::None; ++i) {
10391077
Argument *A = ArgumentSCC[i]->Definition;
1040-
Attribute::AttrKind K = determinePointerReadAttrs(A, ArgumentSCCNodes);
1041-
if (K == Attribute::ReadNone)
1042-
continue;
1043-
if (K == Attribute::ReadOnly) {
1044-
ReadAttr = Attribute::ReadOnly;
1045-
continue;
1046-
}
1047-
ReadAttr = K;
1048-
break;
1078+
Attribute::AttrKind K = determinePointerAccessAttrs(A, ArgumentSCCNodes);
1079+
AccessAttr = meetAccessAttr(AccessAttr, K);
10491080
}
10501081

1051-
if (ReadAttr != Attribute::None) {
1082+
if (AccessAttr != Attribute::None) {
10521083
for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) {
10531084
Argument *A = ArgumentSCC[i]->Definition;
1054-
if (addReadAttr(A, ReadAttr))
1085+
if (addAccessAttr(A, AccessAttr))
10551086
Changed.insert(A->getParent());
10561087
}
10571088
}

llvm/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ define void @test0_yes(i32* %p) nounwind {
1515
ret void
1616
}
1717

18-
; CHECK: define void @test0_no(i32* nocapture %p) #1 {
18+
; CHECK: define void @test0_no(i32* nocapture writeonly %p) #1 {
1919
define void @test0_no(i32* %p) nounwind {
2020
store i32 0, i32* %p, !tbaa !2
2121
ret void

llvm/test/Feature/OperandBundles/pr26510.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
declare void @foo() readnone
1212

13-
; CHECK-LABEL: define i8* @test(i8* %p)
13+
; CHECK-LABEL: define i8* @test(i8* writeonly %p)
1414
; CHECK: %a = alloca i8*, align 8
1515
; CHECK: store i8* %p, i8** %a, align 8
1616
; CHECK: call void @foo() [ "abc"(i8** %a) ]

llvm/test/Transforms/Coroutines/coro-async.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ entry:
256256
unreachable
257257
}
258258

259-
; CHECK-LABEL: define swiftcc void @my_async_function2(%async.task* %task, %async.actor* %actor, i8* %async.ctxt)
259+
; CHECK-LABEL: define swiftcc void @my_async_function2(%async.task* %task, %async.actor* %actor, i8* writeonly %async.ctxt)
260260
; CHECK-SAME: #[[FRAMEPOINTER:[0-9]+]]
261261
; CHECK-SAME: !dbg ![[SP3:[0-9]+]]
262262
; CHECK: store i8* %async.ctxt,
@@ -269,7 +269,7 @@ entry:
269269
; CHECK: tail call swiftcc void @asyncSuspend(i8* [[CALLEE_CTXT]], %async.task* %task, %async.actor* %actor)
270270
; CHECK: ret void
271271

272-
; CHECK-LABEL: define internal swiftcc void @my_async_function2.resume.0(i8* %0, i8* nocapture readnone %1, i8* nocapture readonly %2)
272+
; CHECK-LABEL: define internal swiftcc void @my_async_function2.resume.0(i8* writeonly %0, i8* nocapture readnone %1, i8* nocapture readonly %2)
273273
; CHECK-SAME: #[[FRAMEPOINTER]]
274274
; CHECK-SAME: !dbg ![[SP4:[0-9]+]]
275275
; CHECK: [[CALLEE_CTXT_ADDR:%.*]] = bitcast i8* %2 to i8**

0 commit comments

Comments
 (0)