Nikita Popov bc7fafbeea
[AA] Take read-only provenance captures into account (#143097)
Update the AA CaptureAnalysis providers to return CaptureComponents, so
we can distinguish between full provenance and read-only provenance
captures.

Use this to restrict "other" memory effects on call from ModRef to Ref.

Ideally we would also apply the same reasoning for escape sources, but
the current API cannot actually convey the necessary information (we can
only say NoAlias or MayAlias, not MayAlias but only via Ref).
2025-06-12 14:13:15 +02:00

93 lines
3.0 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -S -passes=gvn < %s | FileCheck %s
declare void @capture(ptr)
declare void @unknown_call()
define i32 @full_capture() {
; CHECK-LABEL: define i32 @full_capture() {
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @capture(ptr [[A]])
; CHECK-NEXT: store i32 1, ptr [[A]], align 4
; CHECK-NEXT: call void @unknown_call()
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: ret i32 [[V]]
;
%a = alloca i32
call void @capture(ptr %a)
store i32 1, ptr %a
call void @unknown_call()
%v = load i32, ptr %a
ret i32 %v
}
define i32 @address_capture() {
; CHECK-LABEL: define i32 @address_capture() {
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @capture(ptr captures(address) [[A]])
; CHECK-NEXT: store i32 1, ptr [[A]], align 4
; CHECK-NEXT: call void @unknown_call()
; CHECK-NEXT: ret i32 1
;
%a = alloca i32
call void @capture(ptr captures(address) %a)
store i32 1, ptr %a
call void @unknown_call()
%v = load i32, ptr %a
ret i32 %v
}
define i32 @read_provenance_capture() {
; CHECK-LABEL: define i32 @read_provenance_capture() {
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @capture(ptr captures(address, read_provenance) [[A]])
; CHECK-NEXT: store i32 1, ptr [[A]], align 4
; CHECK-NEXT: call void @unknown_call()
; CHECK-NEXT: ret i32 1
;
%a = alloca i32
call void @capture(ptr captures(address, read_provenance) %a)
store i32 1, ptr %a
call void @unknown_call()
%v = load i32, ptr %a
ret i32 %v
}
define i32 @read_provenance_capture_and_full_capture() {
; CHECK-LABEL: define i32 @read_provenance_capture_and_full_capture() {
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @capture(ptr captures(address, read_provenance) [[A]])
; CHECK-NEXT: call void @capture(ptr [[A]])
; CHECK-NEXT: store i32 1, ptr [[A]], align 4
; CHECK-NEXT: call void @unknown_call()
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: ret i32 [[V]]
;
%a = alloca i32
call void @capture(ptr captures(address, read_provenance) %a)
call void @capture(ptr %a)
store i32 1, ptr %a
call void @unknown_call()
%v = load i32, ptr %a
ret i32 %v
}
define i32 @read_provenance_capture_and_full_capture_commuted() {
; CHECK-LABEL: define i32 @read_provenance_capture_and_full_capture_commuted() {
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @capture(ptr [[A]])
; CHECK-NEXT: call void @capture(ptr captures(address, read_provenance) [[A]])
; CHECK-NEXT: store i32 1, ptr [[A]], align 4
; CHECK-NEXT: call void @unknown_call()
; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: ret i32 [[V]]
;
%a = alloca i32
call void @capture(ptr %a)
call void @capture(ptr captures(address, read_provenance) %a)
store i32 1, ptr %a
call void @unknown_call()
%v = load i32, ptr %a
ret i32 %v
}