Skip to content

Commit 1c99cc6

Browse files
committed
[EarlyCSE] Insert unreachable for !noundef undef load
This extends llvm#96639 for mem2reg to earlycse. If we try to replace a load with !noundef metadata by undef, insert a non-terminator unreachable. I've added a handleLoadOfUndef() helper for this purpose, which is shared between mem2reg and earlycse (and in the future also gvn etc). This also provides a place to experiment with replacing uninit loads with freeze poison.
1 parent 0e11a7e commit 1c99cc6

File tree

6 files changed

+33
-17
lines changed

6 files changed

+33
-17
lines changed

llvm/include/llvm/Transforms/Utils/Local.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,11 @@ void copyMetadataForLoad(LoadInst &Dest, const LoadInst &Source);
428428
/// its original position.
429429
void patchReplacementInstruction(Instruction *I, Value *Repl);
430430

431+
/// Handle undef values when replacing a load \p I with the loaded value
432+
/// \p Repl. If \p Repl is undef, this will introduce a non-terminator
433+
/// unreachable for !noundef loads.
434+
Value *handleLoadOfUndef(Instruction &I, Value *Repl);
435+
431436
// Replace each use of 'From' with 'To', if that use does not belong to basic
432437
// block where 'From' is defined. Returns the number of replacements made.
433438
unsigned replaceNonLocalUsesWith(Instruction *From, Value *To);

llvm/lib/Transforms/Scalar/EarlyCSE.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,6 +1585,7 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
15851585
LLVM_DEBUG(dbgs() << "Skipping due to debug counter\n");
15861586
continue;
15871587
}
1588+
Op = handleLoadOfUndef(Inst, Op);
15881589
if (InVal.IsLoad)
15891590
if (auto *I = dyn_cast<Instruction>(Op))
15901591
combineMetadataForCSE(I, &Inst, false);

llvm/lib/Transforms/Utils/Local.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3450,6 +3450,19 @@ void llvm::patchReplacementInstruction(Instruction *I, Value *Repl) {
34503450
combineMetadataForCSE(ReplInst, I, false);
34513451
}
34523452

3453+
Value *llvm::handleLoadOfUndef(Instruction &I, Value *Repl) {
3454+
if (isa<UndefValue>(Repl) && I.hasMetadata(LLVMContext::MD_noundef)) {
3455+
// Insert non-terminator unreachable.
3456+
LLVMContext &Ctx = I.getContext();
3457+
new StoreInst(ConstantInt::getTrue(Ctx),
3458+
PoisonValue::get(PointerType::getUnqual(Ctx)),
3459+
/*isVolatile=*/false, Align(1), &I);
3460+
return PoisonValue::get(Repl->getType());
3461+
}
3462+
3463+
return Repl;
3464+
}
3465+
34533466
template <typename RootType, typename ShouldReplaceFn>
34543467
static unsigned replaceDominatedUsesWith(Value *From, Value *To,
34553468
const RootType &Root,

llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -453,21 +453,14 @@ static void addAssumeNonNull(AssumptionCache *AC, LoadInst *LI) {
453453
static void convertMetadataToAssumes(LoadInst *LI, Value *Val,
454454
const DataLayout &DL, AssumptionCache *AC,
455455
const DominatorTree *DT) {
456-
if (isa<UndefValue>(Val) && LI->hasMetadata(LLVMContext::MD_noundef)) {
457-
// Insert non-terminator unreachable.
458-
LLVMContext &Ctx = LI->getContext();
459-
new StoreInst(ConstantInt::getTrue(Ctx),
460-
PoisonValue::get(PointerType::getUnqual(Ctx)),
461-
/*isVolatile=*/false, Align(1), LI);
462-
return;
463-
}
464-
465456
// If the load was marked as nonnull we don't want to lose that information
466457
// when we erase this Load. So we preserve it with an assume. As !nonnull
467458
// returns poison while assume violations are immediate undefined behavior,
468459
// we can only do this if the value is known non-poison.
460+
// Skip this for undef values, because they have already been converted to
461+
// non-terminator unreachable.
469462
if (AC && LI->getMetadata(LLVMContext::MD_nonnull) &&
470-
LI->getMetadata(LLVMContext::MD_noundef) &&
463+
LI->getMetadata(LLVMContext::MD_noundef) && !isa<UndefValue>(Val) &&
471464
!isKnownNonZero(Val, SimplifyQuery(DL, DT, AC, LI)))
472465
addAssumeNonNull(AC, LI);
473466
}
@@ -567,6 +560,7 @@ rewriteSingleStoreAlloca(AllocaInst *AI, AllocaInfo &Info, LargeBlockInfo &LBI,
567560
if (ReplVal == LI)
568561
ReplVal = PoisonValue::get(LI->getType());
569562

563+
ReplVal = handleLoadOfUndef(*LI, ReplVal);
570564
convertMetadataToAssumes(LI, ReplVal, DL, AC, &DT);
571565
LI->replaceAllUsesWith(ReplVal);
572566
LI->eraseFromParent();
@@ -676,6 +670,7 @@ promoteSingleBlockAlloca(AllocaInst *AI, const AllocaInfo &Info,
676670
ReplVal = std::prev(I)->second->getOperand(0);
677671
}
678672

673+
ReplVal = handleLoadOfUndef(*LI, ReplVal);
679674
convertMetadataToAssumes(LI, ReplVal, DL, AC, &DT);
680675

681676
// If the replacement value is the load, this must occur in unreachable
@@ -1162,6 +1157,7 @@ void PromoteMem2Reg::RenamePass(BasicBlock *BB, BasicBlock *Pred,
11621157
continue;
11631158

11641159
Value *V = IncomingVals[AI->second];
1160+
V = handleLoadOfUndef(*LI, V);
11651161
convertMetadataToAssumes(LI, V, SQ.DL, AC, &DT);
11661162

11671163
// Anything using the load now uses the current value.

llvm/test/Transforms/EarlyCSE/flags.ll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ define ptr @store_to_load_forward(ptr %p, ptr %p2) {
106106
define i32 @load_undef_noundef(ptr %p) {
107107
; CHECK-LABEL: @load_undef_noundef(
108108
; CHECK-NEXT: store i32 undef, ptr [[P:%.*]], align 4
109-
; CHECK-NEXT: ret i32 undef
109+
; CHECK-NEXT: store i1 true, ptr poison, align 1
110+
; CHECK-NEXT: ret i32 poison
110111
;
111112
store i32 undef, ptr %p
112113
%v = load i32, ptr %p, !noundef !{}

llvm/test/Transforms/Mem2Reg/preserve-nonnull-load-metadata.ll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ define ptr @no_store_single_load_noundef() {
144144
; CHECK-LABEL: @no_store_single_load_noundef(
145145
; CHECK-NEXT: entry:
146146
; CHECK-NEXT: store i1 true, ptr poison, align 1
147-
; CHECK-NEXT: ret ptr undef
147+
; CHECK-NEXT: ret ptr poison
148148
;
149149
entry:
150150
%buf = alloca ptr
@@ -158,10 +158,10 @@ define ptr @no_store_multiple_loads_noundef(i1 %c) {
158158
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
159159
; CHECK: if:
160160
; CHECK-NEXT: store i1 true, ptr poison, align 1
161-
; CHECK-NEXT: ret ptr undef
161+
; CHECK-NEXT: ret ptr poison
162162
; CHECK: else:
163163
; CHECK-NEXT: store i1 true, ptr poison, align 1
164-
; CHECK-NEXT: ret ptr undef
164+
; CHECK-NEXT: ret ptr poison
165165
;
166166
entry:
167167
%buf = alloca ptr
@@ -180,7 +180,7 @@ define ptr @no_store_single_load_nonnull_noundef() {
180180
; CHECK-LABEL: @no_store_single_load_nonnull_noundef(
181181
; CHECK-NEXT: entry:
182182
; CHECK-NEXT: store i1 true, ptr poison, align 1
183-
; CHECK-NEXT: ret ptr undef
183+
; CHECK-NEXT: ret ptr poison
184184
;
185185
entry:
186186
%buf = alloca ptr
@@ -194,10 +194,10 @@ define ptr @no_store_multiple_loads_nonnull_noundef(i1 %c) {
194194
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
195195
; CHECK: if:
196196
; CHECK-NEXT: store i1 true, ptr poison, align 1
197-
; CHECK-NEXT: ret ptr undef
197+
; CHECK-NEXT: ret ptr poison
198198
; CHECK: else:
199199
; CHECK-NEXT: store i1 true, ptr poison, align 1
200-
; CHECK-NEXT: ret ptr undef
200+
; CHECK-NEXT: ret ptr poison
201201
;
202202
entry:
203203
%buf = alloca ptr

0 commit comments

Comments
 (0)