This patch updates InstCombine to use poison constant to represent the resulting value of (either semantically or syntactically) unreachable instrs, or a don't-care value of an unreachable store instruction.
This allows more aggressive folding of unused results, as shown in llvm/test/Transforms/InstCombine/getelementptr.ll .
Reviewed By: nikic
Differential Revision: https://reviews.llvm.org/D104602
!CalleeF->isDeclaration()) {
Instruction *OldCall = &Call;
CreateNonTerminatorUnreachable(OldCall);
- // If OldCall does not return void then replaceInstUsesWith undef.
+ // If OldCall does not return void then replaceInstUsesWith poison.
// This allows ValueHandlers and custom metadata to adjust itself.
if (!OldCall->getType()->isVoidTy())
- replaceInstUsesWith(*OldCall, UndefValue::get(OldCall->getType()));
+ replaceInstUsesWith(*OldCall, PoisonValue::get(OldCall->getType()));
if (isa<CallInst>(OldCall))
return eraseInstFromFunction(*OldCall);
}
}
+ // Calling a null function pointer is undefined if a null address isn't
+ // dereferenceable.
if ((isa<ConstantPointerNull>(Callee) &&
!NullPointerIsDefined(Call.getFunction())) ||
isa<UndefValue>(Callee)) {
- // If Call does not return void then replaceInstUsesWith undef.
+ // If Call does not return void then replaceInstUsesWith poison.
// This allows ValueHandlers and custom metadata to adjust itself.
if (!Call.getType()->isVoidTy())
- replaceInstUsesWith(Call, UndefValue::get(Call.getType()));
+ replaceInstUsesWith(Call, PoisonValue::get(Call.getType()));
if (Call.isTerminator()) {
// Can't remove an invoke or callbr because we cannot change the CFG.
NewV = combineLoadToNewType(*LI, DestTy);
// Remove the old load and its use in the old phi, which itself becomes
// dead once the whole transform finishes.
- replaceInstUsesWith(*LI, UndefValue::get(LI->getType()));
+ replaceInstUsesWith(*LI, PoisonValue::get(LI->getType()));
eraseInstFromFunction(*LI);
} else if (auto *BCI = dyn_cast<BitCastInst>(V)) {
NewV = BCI->getOperand(0);
// that this code is not reachable. We do this instead of inserting
// an unreachable instruction directly because we cannot modify the
// CFG.
- StoreInst *SI = new StoreInst(UndefValue::get(LI.getType()),
+ StoreInst *SI = new StoreInst(PoisonValue::get(LI.getType()),
Constant::getNullValue(Op->getType()), &LI);
SI->setDebugLoc(LI.getDebugLoc());
- return replaceInstUsesWith(LI, UndefValue::get(LI.getType()));
+ return replaceInstUsesWith(LI, PoisonValue::get(LI.getType()));
}
if (Op->hasOneUse()) {
IC.Builder.SetInsertPoint(USI);
combineStoreToNewValue(IC, *USI, NewLI);
}
- IC.replaceInstUsesWith(*LI, UndefValue::get(LI->getType()));
+ IC.replaceInstUsesWith(*LI, PoisonValue::get(LI->getType()));
IC.eraseInstFromFunction(*LI);
return true;
}
// store X, null -> turns into 'unreachable' in SimplifyCFG
// store X, GEP(null, Y) -> turns into 'unreachable' in SimplifyCFG
if (canSimplifyNullStoreOrGEP(SI)) {
- if (!isa<UndefValue>(Val))
- return replaceOperand(SI, 0, UndefValue::get(Val->getType()));
+ if (!isa<PoisonValue>(Val))
+ return replaceOperand(SI, 0, PoisonValue::get(Val->getType()));
return nullptr; // Do not modify these!
}
// If we have no users, they must be all self uses, just nuke the PHI.
if (PHIUsers.empty())
- return replaceInstUsesWith(FirstPhi, UndefValue::get(FirstPhi.getType()));
+ return replaceInstUsesWith(FirstPhi, PoisonValue::get(FirstPhi.getType()));
// If this phi node is transformable, create new PHIs for all the pieces
// extracted out of it. First, sort the users by their offset and size.
}
// Replace all the remaining uses of the PHI nodes (self uses and the lshrs)
- // with undefs.
- Value *Undef = UndefValue::get(FirstPhi.getType());
+ // with poison.
+ Value *Poison = PoisonValue::get(FirstPhi.getType());
for (unsigned i = 1, e = PHIsToSlice.size(); i != e; ++i)
- replaceInstUsesWith(*PHIsToSlice[i], Undef);
- return replaceInstUsesWith(FirstPhi, Undef);
+ replaceInstUsesWith(*PHIsToSlice[i], Poison);
+ return replaceInstUsesWith(FirstPhi, Poison);
}
static Value *SimplifyUsingControlFlow(InstCombiner &Self, PHINode &PN,
SmallPtrSet<PHINode*, 16> PotentiallyDeadPHIs;
PotentiallyDeadPHIs.insert(&PN);
if (DeadPHICycle(PU, PotentiallyDeadPHIs))
- return replaceInstUsesWith(PN, UndefValue::get(PN.getType()));
+ return replaceInstUsesWith(PN, PoisonValue::get(PN.getType()));
}
// If this phi has a single use, and if that use just computes a value for
if (PHIUser->hasOneUse() &&
(isa<BinaryOperator>(PHIUser) || isa<GetElementPtrInst>(PHIUser)) &&
PHIUser->user_back() == &PN) {
- return replaceInstUsesWith(PN, UndefValue::get(PN.getType()));
+ return replaceInstUsesWith(PN, PoisonValue::get(PN.getType()));
}
// When a PHI is used only to be compared with zero, it is safe to replace
// an incoming value proved as known nonzero with any non-zero constant.
} else {
// Casts, GEP, or anything else: we're about to delete this instruction,
// so it can not have any valid uses.
- replaceInstUsesWith(*I, UndefValue::get(I->getType()));
+ replaceInstUsesWith(*I, PoisonValue::get(I->getType()));
}
eraseInstFromFunction(*I);
}
return nullptr;
// A value may still have uses before we process it here (for example, in
- // another unreachable block), so convert those to undef.
- replaceInstUsesWith(*Prev, UndefValue::get(Prev->getType()));
+ // another unreachable block), so convert those to poison.
+ replaceInstUsesWith(*Prev, PoisonValue::get(Prev->getType()));
eraseInstFromFunction(*Prev);
return &I;
}
if (*EV.idx_begin() == 0) {
Instruction::BinaryOps BinOp = WO->getBinaryOp();
Value *LHS = WO->getLHS(), *RHS = WO->getRHS();
- replaceInstUsesWith(*WO, UndefValue::get(WO->getType()));
+ // Replace the old instruction's uses with poison.
+ replaceInstUsesWith(*WO, PoisonValue::get(WO->getType()));
eraseInstFromFunction(*WO);
return BinaryOperator::Create(BinOp, LHS, RHS);
}
; ALL: br i1 %tobool, label %entry.cond.end_crit_edge, label %cond.false, !dbg [[LOC_15_6:![0-9]+]]
; ALL: entry.cond.end_crit_edge:
; GVN: %.pre = load %struct.node*, %struct.node** null, align 8, !dbg [[LOC_16_13:![0-9]+]]
-; INSTCOMBINE:store %struct.node* undef, %struct.node** null, align 536870912, !dbg [[LOC_16_13:![0-9]+]]
+; INSTCOMBINE:store %struct.node* poison, %struct.node** null, align 536870912, !dbg [[LOC_16_13:![0-9]+]]
cond.false:
%0 = bitcast %struct.desc* %desc to i8***, !dbg !11
; ordering imposed.
define i32 @test9() {
; CHECK-LABEL: @test9(
-; CHECK-NEXT: store i32 undef, i32* null, align 536870912
-; CHECK-NEXT: ret i32 undef
+; CHECK-NEXT: store i32 poison, i32* null, align 536870912
+; CHECK-NEXT: ret i32 poison
;
%x = load atomic i32, i32* null unordered, align 4
ret i32 %x
; ordering imposed.
define i32 @test12() {
; CHECK-LABEL: @test12(
-; CHECK-NEXT: store atomic i32 undef, i32* null unordered, align 536870912
+; CHECK-NEXT: store atomic i32 poison, i32* null unordered, align 536870912
; CHECK-NEXT: ret i32 0
;
store atomic i32 0, i32* null unordered, align 4
define {}* @minimal_invariant_start_use(i8 %x) {
; CHECK-LABEL: @minimal_invariant_start_use(
-; CHECK-NEXT: ret {}* undef
+; CHECK-NEXT: ret {}* poison
;
%a = alloca i8
%i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %a)
define void @test25() {
; CHECK-LABEL: @test25(
; CHECK-NEXT: entry:
-; CHECK-NEXT: store i64 undef, i64* null, align 536870912
+; CHECK-NEXT: store i64 poison, i64* null, align 536870912
; CHECK-NEXT: tail call void @foo25(i32 0, i64 0)
; CHECK-NEXT: unreachable
;
define i32 @test29(i8* %start, i32 %X) nounwind {
; CHECK-LABEL: @test29(
; CHECK-NEXT: entry:
-; CHECK-NEXT: store i64 undef, i64* null, align 536870912
-; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr i8, i8* [[START:%.*]], i64 undef
-; CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[X:%.*]] to i64
-; CHECK-NEXT: [[ADD_PTR212:%.*]] = getelementptr i8, i8* [[START]], i64 [[TMP0]]
-; CHECK-NEXT: [[CMP214:%.*]] = icmp ugt i8* [[ADD_PTR212]], [[ADD_PTR]]
-; CHECK-NEXT: br i1 [[CMP214]], label [[IF_THEN216:%.*]], label [[IF_END363:%.*]]
+; CHECK-NEXT: store i64 poison, i64* null, align 536870912
+; CHECK-NEXT: br i1 poison, label [[IF_THEN216:%.*]], label [[IF_END363:%.*]]
; CHECK: if.then216:
; CHECK-NEXT: ret i32 1
; CHECK: if.end363:
define i32 @load_gep_null_inbounds(i64 %X) {
; CHECK-LABEL: @load_gep_null_inbounds(
-; CHECK-NEXT: store i32 undef, i32* null, align 536870912
-; CHECK-NEXT: ret i32 undef
+; CHECK-NEXT: store i32 poison, i32* null, align 536870912
+; CHECK-NEXT: ret i32 poison
;
%V = getelementptr inbounds i32, i32* null, i64 %X
%R = load i32, i32* %V
define i32 @load_gep_null_not_inbounds(i64 %X) {
; CHECK-LABEL: @load_gep_null_not_inbounds(
-; CHECK-NEXT: store i32 undef, i32* null, align 536870912
-; CHECK-NEXT: ret i32 undef
+; CHECK-NEXT: store i32 poison, i32* null, align 536870912
+; CHECK-NEXT: ret i32 poison
;
%V = getelementptr i32, i32* null, i64 %X
%R = load i32, i32* %V
; CHECK: cond.true133:
; CHECK-NEXT: br label [[COND_END144:%.*]]
; CHECK: cond.false138:
-; CHECK-NEXT: store %type_2* undef, %type_2** null, align 536870912
+; CHECK-NEXT: store %type_2* poison, %type_2** null, align 536870912
; CHECK-NEXT: br label [[COND_END144]]
; CHECK: cond.end144:
; CHECK-NEXT: br label [[WHILE_COND]]
define void @test1(i32* %P) {
; CHECK-LABEL: @test1(
; CHECK-NEXT: store i32 123, i32* undef, align 4
-; CHECK-NEXT: store i32 undef, i32* null, align 536870912
+; CHECK-NEXT: store i32 poison, i32* null, align 536870912
; CHECK-NEXT: ret void
;
store i32 undef, i32* %P
define void @store_at_gep_off_null_inbounds(i64 %offset) {
; CHECK-LABEL: @store_at_gep_off_null_inbounds(
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i32, i32* null, i64 [[OFFSET:%.*]]
-; CHECK-NEXT: store i32 undef, i32* [[PTR]], align 4
+; CHECK-NEXT: store i32 poison, i32* [[PTR]], align 4
; CHECK-NEXT: ret void
;
%ptr = getelementptr inbounds i32, i32 *null, i64 %offset
define void @store_at_gep_off_null_not_inbounds(i64 %offset) {
; CHECK-LABEL: @store_at_gep_off_null_not_inbounds(
; CHECK-NEXT: [[PTR:%.*]] = getelementptr i32, i32* null, i64 [[OFFSET:%.*]]
-; CHECK-NEXT: store i32 undef, i32* [[PTR]], align 4
+; CHECK-NEXT: store i32 poison, i32* [[PTR]], align 4
; CHECK-NEXT: ret void
;
%ptr = getelementptr i32, i32 *null, i64 %offset
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[STOREMERGE:%.*]] = phi i32 [ 42, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY:%.*]] ]
-; CHECK-NEXT: store i32 [[STOREMERGE]], i32* [[GI:%.*]], align 4, [[TBAA0:!tbaa !.*]]
+; CHECK-NEXT: store i32 [[STOREMERGE]], i32* [[GI:%.*]], align 4, !tbaa [[TBAA0:![0-9]+]]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[STOREMERGE]], [[N:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[STOREMERGE]] to i64
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds float, float* [[A:%.*]], i64 [[IDXPROM]]
-; CHECK-NEXT: store float 0.000000e+00, float* [[ARRAYIDX]], align 4, [[TBAA4:!tbaa !.*]]
-; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[GI]], align 4, [[TBAA0]]
+; CHECK-NEXT: store float 0.000000e+00, float* [[ARRAYIDX]], align 4, !tbaa [[TBAA4:![0-9]+]]
+; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[GI]], align 4, !tbaa [[TBAA0]]
; CHECK-NEXT: [[INC]] = add nsw i32 [[TMP0]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.end: