Skip to content

Commit 93f8e52

Browse files
authored
[FunctionAttrs] Improve handling of alias-preserving intrinsic calls (llvm#68453)
Fixes llvm#68270 The function attribute analysis handles many instructions, like addrspacecast, which do not themselves read or write memory but which transform pointers into other values in the same alias set. There are intrinsic functions, such as ptrmask or the AMDGPU-specific make.buffer.rsrc, which also preserve membership in alias sets without capturing. This commit adds the addrspacecast-like behavior to these calls.
1 parent ebf4c69 commit 93f8e52

File tree

4 files changed

+94
-18
lines changed

4 files changed

+94
-18
lines changed

llvm/lib/Transforms/IPO/FunctionAttrs.cpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,15 @@ determinePointerAccessAttrs(Argument *A,
654654
// must be a data operand (e.g. argument or operand bundle)
655655
const unsigned UseIndex = CB.getDataOperandNo(U);
656656

657-
if (!CB.doesNotCapture(UseIndex)) {
657+
// Some intrinsics (for instance ptrmask) do not capture their results,
658+
// but return results thas alias their pointer argument, and thus should
659+
// be handled like GEP or addrspacecast above.
660+
if (isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(
661+
&CB, /*MustPreserveNullness=*/false)) {
662+
for (Use &UU : CB.uses())
663+
if (Visited.insert(&UU).second)
664+
Worklist.push_back(&UU);
665+
} else if (!CB.doesNotCapture(UseIndex)) {
658666
if (!CB.onlyReadsMemory())
659667
// If the callee can save a copy into other memory, then simply
660668
// scanning uses of the call is insufficient. We have no way
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes
2+
; RUN: opt -passes=function-attrs -S < %s | FileCheck --check-prefixes=COMMON,FNATTRS %s
3+
; RUN: opt -passes=attributor-light -S < %s | FileCheck --check-prefixes=COMMON,ATTRIBUTOR %s
4+
5+
;; target triple = "amdgcn-amd-amdhsa"
6+
target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-ni:7:8"
7+
8+
define amdgpu_kernel void @test_make_buffer_rsrc(ptr %p, ptr %q) {
9+
; FNATTRS: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite)
10+
; FNATTRS-LABEL: define {{[^@]+}}@test_make_buffer_rsrc
11+
; FNATTRS-SAME: (ptr nocapture readonly [[P:%.*]], ptr nocapture writeonly [[Q:%.*]]) #[[ATTR0:[0-9]+]] {
12+
; FNATTRS-NEXT: [[P_RSRC:%.*]] = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p0(ptr [[P]], i16 0, i32 4, i32 822243328)
13+
; FNATTRS-NEXT: [[Q_RSRC:%.*]] = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p0(ptr [[Q]], i16 0, i32 4, i32 822243328)
14+
; FNATTRS-NEXT: [[V:%.*]] = call i8 @llvm.amdgcn.raw.ptr.buffer.load.i8(ptr addrspace(8) [[P_RSRC]], i32 0, i32 0, i32 0)
15+
; FNATTRS-NEXT: call void @llvm.amdgcn.raw.ptr.buffer.store.i8(i8 [[V]], ptr addrspace(8) [[Q_RSRC]], i32 0, i32 0, i32 0)
16+
; FNATTRS-NEXT: ret void
17+
;
18+
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
19+
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_make_buffer_rsrc
20+
; ATTRIBUTOR-SAME: (ptr nocapture nofree readonly [[P:%.*]], ptr nocapture nofree writeonly [[Q:%.*]]) #[[ATTR0:[0-9]+]] {
21+
; ATTRIBUTOR-NEXT: [[P_RSRC:%.*]] = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p0(ptr [[P]], i16 0, i32 4, i32 822243328) #[[ATTR4:[0-9]+]]
22+
; ATTRIBUTOR-NEXT: [[Q_RSRC:%.*]] = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p0(ptr [[Q]], i16 0, i32 4, i32 822243328) #[[ATTR4]]
23+
; ATTRIBUTOR-NEXT: [[V:%.*]] = call i8 @llvm.amdgcn.raw.ptr.buffer.load.i8(ptr addrspace(8) nocapture readonly [[P_RSRC]], i32 0, i32 0, i32 0) #[[ATTR5:[0-9]+]]
24+
; ATTRIBUTOR-NEXT: call void @llvm.amdgcn.raw.ptr.buffer.store.i8(i8 [[V]], ptr addrspace(8) nocapture writeonly [[Q_RSRC]], i32 0, i32 0, i32 0) #[[ATTR6:[0-9]+]]
25+
; ATTRIBUTOR-NEXT: ret void
26+
;
27+
%p.rsrc = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p0(ptr %p, i16 0, i32 4, i32 822243328)
28+
%q.rsrc = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p0(ptr %q, i16 0, i32 4, i32 822243328)
29+
%v = call i8 @llvm.amdgcn.raw.ptr.buffer.load.i8(ptr addrspace(8) %p.rsrc, i32 0, i32 0, i32 0)
30+
call void @llvm.amdgcn.raw.ptr.buffer.store.i8(i8 %v, ptr addrspace(8) %q.rsrc, i32 0, i32 0, i32 0)
31+
ret void
32+
}
33+
34+
; Function Attrs: mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none)
35+
declare ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p0(ptr readnone, i16, i32, i32) #0
36+
37+
; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: read)
38+
declare i8 @llvm.amdgcn.raw.ptr.buffer.load.i8(ptr addrspace(8) nocapture readonly, i32, i32, i32 immarg) #1
39+
40+
; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: write)
41+
declare void @llvm.amdgcn.raw.ptr.buffer.store.i8(i8, ptr addrspace(8) nocapture writeonly, i32, i32, i32 immarg) #2
42+
43+
attributes #0 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) }
44+
attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: read) }
45+
attributes #2 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: write) }
46+
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
47+
; COMMON: {{.*}}

llvm/test/Transforms/FunctionAttrs/nocapture.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ entry:
652652
define void @nocaptureLaunder(ptr %p) {
653653
; FNATTRS: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: write, inaccessiblemem: readwrite)
654654
; FNATTRS-LABEL: define void @nocaptureLaunder
655-
; FNATTRS-SAME: (ptr nocapture [[P:%.*]]) #[[ATTR13:[0-9]+]] {
655+
; FNATTRS-SAME: (ptr nocapture writeonly [[P:%.*]]) #[[ATTR13:[0-9]+]] {
656656
; FNATTRS-NEXT: entry:
657657
; FNATTRS-NEXT: [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[P]])
658658
; FNATTRS-NEXT: store i8 42, ptr [[B]], align 1

llvm/test/Transforms/FunctionAttrs/writeonly.ll

+37-16
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,27 @@ define void @test_atomicrmw(ptr %p) {
178178
ret void
179179
}
180180

181+
define void @test_ptrmask(ptr %p) {
182+
; FNATTRS: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: write)
183+
; FNATTRS-LABEL: define {{[^@]+}}@test_ptrmask
184+
; FNATTRS-SAME: (ptr writeonly [[P:%.*]]) #[[ATTR8:[0-9]+]] {
185+
; FNATTRS-NEXT: [[MASK:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -5)
186+
; FNATTRS-NEXT: store i8 0, ptr [[MASK]], align 1
187+
; FNATTRS-NEXT: ret void
188+
;
189+
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
190+
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_ptrmask
191+
; ATTRIBUTOR-SAME: (ptr nofree writeonly [[P:%.*]]) #[[ATTR3]] {
192+
; ATTRIBUTOR-NEXT: [[MASK:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P]], i64 -5) #[[ATTR9:[0-9]+]]
193+
; ATTRIBUTOR-NEXT: store i8 0, ptr [[MASK]], align 1
194+
; ATTRIBUTOR-NEXT: ret void
195+
;
196+
%mask = call ptr @llvm.ptrmask.p0.i64(ptr %p, i64 -5)
197+
store i8 0, ptr %mask
198+
ret void
199+
}
200+
201+
declare ptr @llvm.ptrmask.p0.i64(ptr, i64)
181202

182203
declare void @direct1_callee(ptr %p)
183204

@@ -197,14 +218,14 @@ declare void @direct2_callee(ptr %p) writeonly
197218
define void @direct2(ptr %p) {
198219
; FNATTRS: Function Attrs: memory(write)
199220
; FNATTRS-LABEL: define {{[^@]+}}@direct2
200-
; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR8:[0-9]+]] {
221+
; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR10:[0-9]+]] {
201222
; FNATTRS-NEXT: call void @direct2_callee(ptr [[P]])
202223
; FNATTRS-NEXT: ret void
203224
;
204225
; ATTRIBUTOR: Function Attrs: memory(write)
205226
; ATTRIBUTOR-LABEL: define {{[^@]+}}@direct2
206-
; ATTRIBUTOR-SAME: (ptr writeonly [[P:%.*]]) #[[ATTR7:[0-9]+]] {
207-
; ATTRIBUTOR-NEXT: call void @direct2_callee(ptr [[P]]) #[[ATTR7]]
227+
; ATTRIBUTOR-SAME: (ptr writeonly [[P:%.*]]) #[[ATTR8:[0-9]+]] {
228+
; ATTRIBUTOR-NEXT: call void @direct2_callee(ptr [[P]]) #[[ATTR8]]
208229
; ATTRIBUTOR-NEXT: ret void
209230
;
210231
call void @direct2_callee(ptr %p)
@@ -215,14 +236,14 @@ define void @direct2(ptr %p) {
215236
define void @direct2b(ptr %p) {
216237
; FNATTRS: Function Attrs: memory(write)
217238
; FNATTRS-LABEL: define {{[^@]+}}@direct2b
218-
; FNATTRS-SAME: (ptr nocapture writeonly [[P:%.*]]) #[[ATTR8]] {
239+
; FNATTRS-SAME: (ptr nocapture writeonly [[P:%.*]]) #[[ATTR10]] {
219240
; FNATTRS-NEXT: call void @direct2_callee(ptr nocapture [[P]])
220241
; FNATTRS-NEXT: ret void
221242
;
222243
; ATTRIBUTOR: Function Attrs: memory(write)
223244
; ATTRIBUTOR-LABEL: define {{[^@]+}}@direct2b
224-
; ATTRIBUTOR-SAME: (ptr nocapture writeonly [[P:%.*]]) #[[ATTR7]] {
225-
; ATTRIBUTOR-NEXT: call void @direct2_callee(ptr nocapture writeonly [[P]]) #[[ATTR7]]
245+
; ATTRIBUTOR-SAME: (ptr nocapture writeonly [[P:%.*]]) #[[ATTR8]] {
246+
; ATTRIBUTOR-NEXT: call void @direct2_callee(ptr nocapture writeonly [[P]]) #[[ATTR8]]
226247
; ATTRIBUTOR-NEXT: ret void
227248
;
228249
call void @direct2_callee(ptr nocapture %p)
@@ -304,14 +325,14 @@ define void @fptr_test2(ptr %p, ptr %f) {
304325
define void @fptr_test3(ptr %p, ptr %f) {
305326
; FNATTRS: Function Attrs: memory(write)
306327
; FNATTRS-LABEL: define {{[^@]+}}@fptr_test3
307-
; FNATTRS-SAME: (ptr nocapture writeonly [[P:%.*]], ptr nocapture readonly [[F:%.*]]) #[[ATTR8]] {
308-
; FNATTRS-NEXT: call void [[F]](ptr nocapture [[P]]) #[[ATTR8]]
328+
; FNATTRS-SAME: (ptr nocapture writeonly [[P:%.*]], ptr nocapture readonly [[F:%.*]]) #[[ATTR10]] {
329+
; FNATTRS-NEXT: call void [[F]](ptr nocapture [[P]]) #[[ATTR10]]
309330
; FNATTRS-NEXT: ret void
310331
;
311332
; ATTRIBUTOR: Function Attrs: memory(write)
312333
; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test3
313-
; ATTRIBUTOR-SAME: (ptr nocapture writeonly [[P:%.*]], ptr nocapture nofree nonnull writeonly [[F:%.*]]) #[[ATTR7]] {
314-
; ATTRIBUTOR-NEXT: call void [[F]](ptr nocapture [[P]]) #[[ATTR7]]
334+
; ATTRIBUTOR-SAME: (ptr nocapture writeonly [[P:%.*]], ptr nocapture nofree nonnull writeonly [[F:%.*]]) #[[ATTR8]] {
335+
; ATTRIBUTOR-NEXT: call void [[F]](ptr nocapture [[P]]) #[[ATTR8]]
315336
; ATTRIBUTOR-NEXT: ret void
316337
;
317338
call void %f(ptr nocapture %p) writeonly
@@ -321,12 +342,12 @@ define void @fptr_test3(ptr %p, ptr %f) {
321342
define void @test_argmem_none_callee(ptr %p) {
322343
; FNATTRS-LABEL: define {{[^@]+}}@test_argmem_none_callee
323344
; FNATTRS-SAME: (ptr nocapture readnone [[P:%.*]]) {
324-
; FNATTRS-NEXT: call void @direct1_callee(ptr nocapture [[P]]) #[[ATTR9:[0-9]+]]
345+
; FNATTRS-NEXT: call void @direct1_callee(ptr nocapture [[P]]) #[[ATTR11:[0-9]+]]
325346
; FNATTRS-NEXT: ret void
326347
;
327348
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_argmem_none_callee
328349
; ATTRIBUTOR-SAME: (ptr nocapture [[P:%.*]]) {
329-
; ATTRIBUTOR-NEXT: call void @direct1_callee(ptr nocapture [[P]]) #[[ATTR8:[0-9]+]]
350+
; ATTRIBUTOR-NEXT: call void @direct1_callee(ptr nocapture [[P]]) #[[ATTR10:[0-9]+]]
330351
; ATTRIBUTOR-NEXT: ret void
331352
;
332353
call void @direct1_callee(ptr nocapture %p) memory(readwrite, argmem: none)
@@ -336,12 +357,12 @@ define void @test_argmem_none_callee(ptr %p) {
336357
define void @test_argmem_read_callee(ptr %p) {
337358
; FNATTRS-LABEL: define {{[^@]+}}@test_argmem_read_callee
338359
; FNATTRS-SAME: (ptr nocapture readonly [[P:%.*]]) {
339-
; FNATTRS-NEXT: call void @direct1_callee(ptr nocapture [[P]]) #[[ATTR10:[0-9]+]]
360+
; FNATTRS-NEXT: call void @direct1_callee(ptr nocapture [[P]]) #[[ATTR12:[0-9]+]]
340361
; FNATTRS-NEXT: ret void
341362
;
342363
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_argmem_read_callee
343364
; ATTRIBUTOR-SAME: (ptr nocapture [[P:%.*]]) {
344-
; ATTRIBUTOR-NEXT: call void @direct1_callee(ptr nocapture [[P]]) #[[ATTR9:[0-9]+]]
365+
; ATTRIBUTOR-NEXT: call void @direct1_callee(ptr nocapture [[P]]) #[[ATTR11:[0-9]+]]
345366
; ATTRIBUTOR-NEXT: ret void
346367
;
347368
call void @direct1_callee(ptr nocapture %p) memory(readwrite, argmem: read)
@@ -351,12 +372,12 @@ define void @test_argmem_read_callee(ptr %p) {
351372
define void @test_argmem_write_callee(ptr %p) {
352373
; FNATTRS-LABEL: define {{[^@]+}}@test_argmem_write_callee
353374
; FNATTRS-SAME: (ptr nocapture writeonly [[P:%.*]]) {
354-
; FNATTRS-NEXT: call void @direct1_callee(ptr nocapture [[P]]) #[[ATTR11:[0-9]+]]
375+
; FNATTRS-NEXT: call void @direct1_callee(ptr nocapture [[P]]) #[[ATTR13:[0-9]+]]
355376
; FNATTRS-NEXT: ret void
356377
;
357378
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_argmem_write_callee
358379
; ATTRIBUTOR-SAME: (ptr nocapture [[P:%.*]]) {
359-
; ATTRIBUTOR-NEXT: call void @direct1_callee(ptr nocapture [[P]]) #[[ATTR10:[0-9]+]]
380+
; ATTRIBUTOR-NEXT: call void @direct1_callee(ptr nocapture [[P]]) #[[ATTR12:[0-9]+]]
360381
; ATTRIBUTOR-NEXT: ret void
361382
;
362383
call void @direct1_callee(ptr nocapture %p) memory(readwrite, argmem: write)

0 commit comments

Comments
 (0)