| Issue |
184148
|
| Summary |
Copy avoidance break on laundering
|
| Labels |
new issue
|
| Assignees |
|
| Reporter |
SchrodingerZhu
|
Consider the following LLVM IR:
```llvm
; launder-invgrp.ll
; Test interaction between llvm.launder.invariant.group and !invariant.group metadata.
declare ptr @llvm.launder.invariant.group.p0(ptr)
declare void @use_i64(i64)
!0 = !{} ; an invariant.group marker node
; ---------------------------
; Case A: load/store through same pointer
; ---------------------------
define void @caseA(ptr %p) {
entry:
%x = load i64, ptr %p, align 8, !invariant.group !0
%p8 = getelementptr i8, ptr %p, i64 8
%y = load i64, ptr %p8, align 8, !invariant.group !0
; prevent %x/%y from becoming unused and disappearing too early
call void @use_i64(i64 %x)
call void @use_i64(i64 %y)
; “store back what we loaded”
store i64 %x, ptr %p, align 8, !invariant.group !0
store i64 %y, ptr %p8, align 8, !invariant.group !0
ret void
}
; ---------------------------
; Case B: launder exists but stores are still through %p
; ---------------------------
define void @caseB_store_through_p(ptr %p) {
entry:
%x = load i64, ptr %p, align 8, !invariant.group !0
%p8 = getelementptr i8, ptr %p, i64 8
%y = load i64, ptr %p8, align 8, !invariant.group !0
%q = call ptr @llvm.launder.invariant.group.p0(ptr %p)
call void @use_i64(i64 %x)
call void @use_i64(i64 %y)
store i64 %x, ptr %p, align 8, !invariant.group !0
store i64 %y, ptr %p8, align 8, !invariant.group !0
; keep %q live (so launder isn't trivially DCE'd)
%qq = ptrtoint ptr %q to i64
call void @use_i64(i64 %qq)
ret void
}
; ---------------------------
; Case C: laundered pointer is used as store base
; ---------------------------
define void @caseC_store_through_launder(ptr %p) {
entry:
%x = load i64, ptr %p, align 8, !invariant.group !0
%p8 = getelementptr i8, ptr %p, i64 8
%y = load i64, ptr %p8, align 8, !invariant.group !0
%q = call ptr @llvm.launder.invariant.group.p0(ptr %p)
%q8 = getelementptr i8, ptr %q, i64 8
call void @use_i64(i64 %x)
call void @use_i64(i64 %y)
store i64 %x, ptr %q, align 8, !invariant.group !0
store i64 %y, ptr %q8, align 8, !invariant.group !0
ret void
}
```
Under `-O3`, it seems that the laundering break the analysis that avoid the redundant copying:
```llvm
; ModuleID = 'more2.ll'
source_filename = "more2.ll"
; Function Attrs: mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(inaccessiblemem: readwrite)
declare ptr @llvm.launder.invariant.group.p0(ptr) #0
declare void @use_i64(i64) local_unnamed_addr
define void @caseA(ptr readonly captures(none) %p) local_unnamed_addr {
entry:
%x = load i64, ptr %p, align 8, !invariant.group !0
%p8 = getelementptr i8, ptr %p, i64 8
%y = load i64, ptr %p8, align 8, !invariant.group !0
tail call void @use_i64(i64 %x)
tail call void @use_i64(i64 %y)
ret void
}
define void @caseB_store_through_p(ptr %p) local_unnamed_addr {
entry:
%x = load i64, ptr %p, align 8, !invariant.group !0
%p8 = getelementptr i8, ptr %p, i64 8
%y = load i64, ptr %p8, align 8, !invariant.group !0
%q = tail call ptr @llvm.launder.invariant.group.p0(ptr nonnull %p)
tail call void @use_i64(i64 %x)
tail call void @use_i64(i64 %y)
%qq = ptrtoint ptr %q to i64
tail call void @use_i64(i64 %qq)
ret void
}
define void @caseC_store_through_launder(ptr captures(none) %p) local_unnamed_addr {
entry:
%x = load i64, ptr %p, align 8, !invariant.group !0
%p8 = getelementptr i8, ptr %p, i64 8
%y = load i64, ptr %p8, align 8, !invariant.group !0
%q = tail call ptr @llvm.launder.invariant.group.p0(ptr nonnull %p)
%q8 = getelementptr i8, ptr %q, i64 8
tail call void @use_i64(i64 %x)
tail call void @use_i64(i64 %y)
store i64 %x, ptr %q, align 8, !invariant.group !0
store i64 %y, ptr %q8, align 8, !invariant.group !0
ret void
}
attributes #0 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(inaccessiblemem: readwrite) }
!0 = !{}
```
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs