diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -1355,6 +1355,25 @@ Ops.push_back(Op->DoPHITranslation(PN->getParent(), InBB)); } + // Check if incoming PHI value can be replaced with constant + // based on implied condition. + BranchInst *TerminatorBI = dyn_cast(InBB->getTerminator()); + const ICmpInst *ICmp = dyn_cast(&I); + if (TerminatorBI && TerminatorBI->isConditional() && ICmp) { + const Value *RHSOp0 = Ops[0]; + const Value *RHSOp1 = Ops[1]; + bool LHSIsTrue = TerminatorBI->getSuccessor(0) == PN->getParent(); + std::optional ImpliedCond = + isImpliedCondition(TerminatorBI->getCondition(), ICmp->getPredicate(), + RHSOp0, RHSOp1, DL, LHSIsTrue); + if (ImpliedCond) { + APInt Constant(I.getType()->getScalarSizeInBits(), ImpliedCond.value()); + NewPhiValues.push_back( + ConstantVector::getIntegerValue(I.getType(), Constant)); + continue; + } + } + // Don't consider the simplification successful if we get back a constant // expression. That's just an instruction in hiding. // Also reject the case where we simplify back to the phi node. We wouldn't diff --git a/llvm/test/Transforms/InstCombine/phi.ll b/llvm/test/Transforms/InstCombine/phi.ll --- a/llvm/test/Transforms/InstCombine/phi.ll +++ b/llvm/test/Transforms/InstCombine/phi.ll @@ -1670,18 +1670,15 @@ define i1 @cmp_eq_phi_node_can_fold_1(ptr %C) { ; CHECK-LABEL: @cmp_eq_phi_node_can_fold_1( ; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[TMP2]], -48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[SUB_IS_ZERO:%.*]], label [[JOIN:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 48 +; CHECK-NEXT: br i1 [[TMP2]], label [[SUB_IS_ZERO:%.*]], label [[JOIN:%.*]] ; CHECK: sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 +; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 +; CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[TMP3]], align 1 +; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i8 [[TMP4]], 0 ; CHECK-NEXT: br label [[JOIN]] ; CHECK: join: -; CHECK-NEXT: [[TMP8:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP7]], [[SUB_IS_ZERO]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP8]], 0 +; CHECK-NEXT: [[CMP:%.*]] = phi i1 [ false, [[TMP0:%.*]] ], [ [[TMP5]], [[SUB_IS_ZERO]] ] ; CHECK-NEXT: ret i1 [[CMP]] ; %1 = load i8, ptr %C, align 1 @@ -1705,25 +1702,20 @@ define i1 @cmp_eq_phi_node_can_fold_2(ptr %C) { ; CHECK-LABEL: @cmp_eq_phi_node_can_fold_2( ; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[TMP2]], -48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[SUB_IS_ZERO:%.*]], label [[JOIN:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 48 +; CHECK-NEXT: br i1 [[TMP2]], label [[SUB_IS_ZERO:%.*]], label [[JOIN:%.*]] ; CHECK: sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 -; CHECK-NEXT: [[TMP8:%.*]] = add nsw i32 [[TMP7]], -49 -; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 0 -; CHECK-NEXT: br i1 [[TMP9]], label [[SUB_IS_ZERO1:%.*]], label [[JOIN]] +; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 +; CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[TMP3]], align 1 +; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i8 [[TMP4]], 49 +; CHECK-NEXT: br i1 [[TMP5]], label [[SUB_IS_ZERO1:%.*]], label [[JOIN]] ; CHECK: sub_is_zero1: -; CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2 -; CHECK-NEXT: [[TMP11:%.*]] = load i8, ptr [[TMP10]], align 1 -; CHECK-NEXT: [[TMP12:%.*]] = zext i8 [[TMP11]] to i32 +; CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2 +; CHECK-NEXT: [[TMP7:%.*]] = load i8, ptr [[TMP6]], align 1 +; CHECK-NEXT: [[TMP8:%.*]] = icmp eq i8 [[TMP7]], 0 ; CHECK-NEXT: br label [[JOIN]] ; CHECK: join: -; CHECK-NEXT: [[TMP13:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP8]], [[SUB_IS_ZERO]] ], [ [[TMP12]], [[SUB_IS_ZERO1]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP13]], 0 +; CHECK-NEXT: [[CMP:%.*]] = phi i1 [ false, [[TMP0:%.*]] ], [ false, [[SUB_IS_ZERO]] ], [ [[TMP8]], [[SUB_IS_ZERO1]] ] ; CHECK-NEXT: ret i1 [[CMP]] ; %1 = load i8, ptr %C, align 1 @@ -1755,18 +1747,15 @@ define i1 @cmp_ne_phi_node_can_fold_1(ptr %C) { ; CHECK-LABEL: @cmp_ne_phi_node_can_fold_1( ; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[TMP2]], -48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[SUB_IS_ZERO:%.*]], label [[JOIN:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 48 +; CHECK-NEXT: br i1 [[TMP2]], label [[SUB_IS_ZERO:%.*]], label [[JOIN:%.*]] ; CHECK: sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 +; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 +; CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[TMP3]], align 1 +; CHECK-NEXT: [[TMP5:%.*]] = icmp ne i8 [[TMP4]], 0 ; CHECK-NEXT: br label [[JOIN]] ; CHECK: join: -; CHECK-NEXT: [[TMP8:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP7]], [[SUB_IS_ZERO]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP8]], 0 +; CHECK-NEXT: [[CMP:%.*]] = phi i1 [ true, [[TMP0:%.*]] ], [ [[TMP5]], [[SUB_IS_ZERO]] ] ; CHECK-NEXT: ret i1 [[CMP]] ; %1 = load i8, ptr %C, align 1 @@ -1790,25 +1779,20 @@ define i1 @cmp_ne_phi_node_can_fold_2(ptr %C) { ; CHECK-LABEL: @cmp_ne_phi_node_can_fold_2( ; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[TMP2]], -48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[SUB_IS_ZERO:%.*]], label [[JOIN:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 48 +; CHECK-NEXT: br i1 [[TMP2]], label [[SUB_IS_ZERO:%.*]], label [[JOIN:%.*]] ; CHECK: sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 -; CHECK-NEXT: [[TMP8:%.*]] = add nsw i32 [[TMP7]], -49 -; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 0 -; CHECK-NEXT: br i1 [[TMP9]], label [[SUB_IS_ZERO1:%.*]], label [[JOIN]] +; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 +; CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[TMP3]], align 1 +; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i8 [[TMP4]], 49 +; CHECK-NEXT: br i1 [[TMP5]], label [[SUB_IS_ZERO1:%.*]], label [[JOIN]] ; CHECK: sub_is_zero1: -; CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2 -; CHECK-NEXT: [[TMP11:%.*]] = load i8, ptr [[TMP10]], align 1 -; CHECK-NEXT: [[TMP12:%.*]] = zext i8 [[TMP11]] to i32 +; CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2 +; CHECK-NEXT: [[TMP7:%.*]] = load i8, ptr [[TMP6]], align 1 +; CHECK-NEXT: [[TMP8:%.*]] = icmp ne i8 [[TMP7]], 0 ; CHECK-NEXT: br label [[JOIN]] ; CHECK: join: -; CHECK-NEXT: [[TMP13:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP8]], [[SUB_IS_ZERO]] ], [ [[TMP12]], [[SUB_IS_ZERO1]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP13]], 0 +; CHECK-NEXT: [[CMP:%.*]] = phi i1 [ true, [[TMP0:%.*]] ], [ true, [[SUB_IS_ZERO]] ], [ [[TMP8]], [[SUB_IS_ZERO1]] ] ; CHECK-NEXT: ret i1 [[CMP]] ; %1 = load i8, ptr %C, align 1