Copy avoidance broken on laundering
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
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 = !{}
```
Contributor guide
Research direction
Start with the provided launder-invgrp.ll reproducer and run the three cases under -O3, comparing the redundant-store behavior. Trace the optimization handling of llvm.launder.invariant.group and !invariant.group metadata; done means identifying the cause and capturing the intended copy-elimination behavior in a regression test.
Written by the indexing model from the issue text.
Assessment
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100