Skip to content

Commit 3a10f2b

Browse files
[SROA] Conservatively do not split the alloca if ptr is laundered
A miscompilation issue has been addressed with improved checking. Fixes: #105537.
1 parent d4e320e commit 3a10f2b

File tree

3 files changed

+22
-4
lines changed

3 files changed

+22
-4
lines changed

llvm/lib/Transforms/Scalar/SROA.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3522,6 +3522,10 @@ class AllocaSliceRewriter : public InstVisitor<AllocaSliceRewriter, bool> {
35223522
"Unexpected intrinsic!");
35233523
LLVM_DEBUG(dbgs() << " original: " << II << "\n");
35243524

3525+
// Do not record invariant group intrinsics for deletion.
3526+
if (II.isLaunderOrStripInvariantGroup())
3527+
return true;
3528+
35253529
// Record this instruction for deletion.
35263530
Pass.DeadInsts.push_back(&II);
35273531

@@ -3532,9 +3536,6 @@ class AllocaSliceRewriter : public InstVisitor<AllocaSliceRewriter, bool> {
35323536
return true;
35333537
}
35343538

3535-
if (II.isLaunderOrStripInvariantGroup())
3536-
return true;
3537-
35383539
assert(II.getArgOperand(1) == OldPtr);
35393540
// Lifetime intrinsics are only promotable if they cover the whole alloca.
35403541
// Therefore, we drop lifetime intrinsics which don't cover the whole

llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ bool llvm::isAllocaPromotable(const AllocaInst *AI) {
8181
return false;
8282
} else if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(U)) {
8383
if (!II->isLifetimeStartOrEnd() && !II->isDroppable() &&
84-
II->getIntrinsicID() != Intrinsic::fake_use)
84+
II->getIntrinsicID() != Intrinsic::fake_use &&
85+
!II->isLaunderOrStripInvariantGroup())
8586
return false;
8687
} else if (const BitCastInst *BCI = dyn_cast<BitCastInst>(U)) {
8788
if (!onlyUsedByLifetimeMarkersOrDroppableInsts(BCI))

llvm/test/Transforms/SROA/invariant-group.ll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,13 @@ end:
138138
ret void
139139
}
140140

141+
; Conservatively do not split the alloca.
141142
define void @partial_promotion_of_alloca() {
142143
; CHECK-LABEL: @partial_promotion_of_alloca(
143144
; CHECK-NEXT: [[STRUCT_PTR_SROA_2:%.*]] = alloca i32, align 4
145+
; CHECK-NEXT: [[STRUCT_PTR:%.*]] = alloca [[T:%.*]], align 4
144146
; CHECK-NEXT: store volatile i32 0, ptr [[STRUCT_PTR_SROA_2]], align 4
147+
; CHECK-NEXT: [[BARR:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[STRUCT_PTR]])
145148
; CHECK-NEXT: [[STRUCT_PTR_SROA_2_0_STRUCT_PTR_SROA_2_4_LOAD_VAL:%.*]] = load volatile i32, ptr [[STRUCT_PTR_SROA_2]], align 4
146149
; CHECK-NEXT: ret void
147150
;
@@ -155,6 +158,19 @@ define void @partial_promotion_of_alloca() {
155158
ret void
156159
}
157160

161+
define void @memcpy_after_laundering_alloca(ptr %ptr) {
162+
; CHECK-LABEL: @memcpy_after_laundering_alloca(
163+
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca { i64, i64 }, align 8
164+
; CHECK-NEXT: [[LAUNDER:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[ALLOCA]])
165+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[LAUNDER]], ptr [[PTR:%.*]], i64 16, i1 false)
166+
; CHECK-NEXT: ret void
167+
;
168+
%alloca = alloca { i64, i64 }, align 8
169+
%launder = call ptr @llvm.launder.invariant.group.p0(ptr %alloca)
170+
call void @llvm.memcpy.p0.p0.i64(ptr %launder, ptr %ptr, i64 16, i1 false)
171+
ret void
172+
}
173+
158174
declare void @use(ptr)
159175

160176
!0 = !{}

0 commit comments

Comments
 (0)