Skip to content

Commit 34d381f

Browse files
authored
[NewGVN] Fix lifetime coercion (llvm#141477)
Before commit 14dee0a, NewGVN would not miscompile the function foo, because `isMustAlias` would return false for non-pointers, particularly for `lifetime.start`. We need to check whether the loaded pointer is defined by`lifetime.start` in order to safely simplify the load to uninitialized memory. For `getInitialValueOfAllocation`, the behavior depends on the allocation function. Therefore, we take a conservative approach: we check whether it's a pointer type. If it is, then—based on the earlier check—we know that the allocation function defines the loaded pointer.
1 parent 89fd7b3 commit 34d381f

File tree

2 files changed

+14
-10
lines changed

2 files changed

+14
-10
lines changed

llvm/lib/Transforms/Scalar/NewGVN.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,23 +1529,26 @@ NewGVN::performSymbolicLoadCoercion(Type *LoadType, Value *LoadPtr,
15291529
}
15301530
}
15311531

1532+
if (auto *II = dyn_cast<IntrinsicInst>(DepInst)) {
1533+
auto *LifetimePtr = II->getOperand(1);
1534+
if (II->getIntrinsicID() == Intrinsic::lifetime_start &&
1535+
(LoadPtr == lookupOperandLeader(LifetimePtr) ||
1536+
AA->isMustAlias(LoadPtr, LifetimePtr)))
1537+
return createConstantExpression(UndefValue::get(LoadType));
1538+
}
1539+
15321540
// All of the below are only true if the loaded pointer is produced
15331541
// by the dependent instruction.
1534-
if (LoadPtr != lookupOperandLeader(DepInst) &&
1535-
DepInst->getType()->isPointerTy() && !AA->isMustAlias(LoadPtr, DepInst))
1542+
if (!DepInst->getType()->isPointerTy() ||
1543+
(LoadPtr != lookupOperandLeader(DepInst) &&
1544+
!AA->isMustAlias(LoadPtr, DepInst)))
15361545
return nullptr;
15371546
// If this load really doesn't depend on anything, then we must be loading an
15381547
// undef value. This can happen when loading for a fresh allocation with no
15391548
// intervening stores, for example. Note that this is only true in the case
15401549
// that the result of the allocation is pointer equal to the load ptr.
15411550
if (isa<AllocaInst>(DepInst)) {
15421551
return createConstantExpression(UndefValue::get(LoadType));
1543-
}
1544-
// If this load occurs either right after a lifetime begin,
1545-
// then the loaded value is undefined.
1546-
else if (auto *II = dyn_cast<IntrinsicInst>(DepInst)) {
1547-
if (II->getIntrinsicID() == Intrinsic::lifetime_start)
1548-
return createConstantExpression(UndefValue::get(LoadType));
15491552
} else if (auto *InitVal =
15501553
getInitialValueOfAllocation(DepInst, TLI, LoadType))
15511554
return createConstantExpression(InitVal);

llvm/test/Transforms/NewGVN/coercion-different-ptr.ll

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; RUN: opt -S -passes=newgvn < %s | FileCheck %s
33

44

5-
; FIXME: MemorySSA says that load1 depends on the lifetime start.
5+
; MemorySSA says that load1 depends on the lifetime start.
66
; That's OK since MemorySSA is may-alias; however, NewGVN should
77
; check whether the lifetime start *actually* defines the loaded pointer
88
; before simplifying to uninitialized memory.
@@ -13,7 +13,8 @@ define void @foo(ptr %arg) {
1313
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca i8, align 16
1414
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1, ptr [[ALLOCA]])
1515
; CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr [[ARG]], align 8
16-
; CHECK-NEXT: [[CALL:%.*]] = call ptr undef(ptr [[ALLOCA]])
16+
; CHECK-NEXT: [[LOAD1:%.*]] = load ptr, ptr [[LOAD]], align 8
17+
; CHECK-NEXT: [[CALL:%.*]] = call ptr [[LOAD1]](ptr [[ALLOCA]])
1718
; CHECK-NEXT: ret void
1819
;
1920
bb:

0 commit comments

Comments
 (0)