diff --git a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp @@ -1367,6 +1367,14 @@ return nullptr; } +bool phiAllConstantOperandsAreZero(PHINode &PN) { + size_t ZeroConstCount = 0; + for (Value *V : PN.operands()) + if (Constant *ConstVA = dyn_cast(V)) + if (ConstVA->isZeroValue()) + ZeroConstCount += 1; + return ZeroConstCount == PN.getNumOperands() - 1; +} // PHINode simplification // Instruction *InstCombinerImpl::visitPHINode(PHINode &PN) { @@ -1465,6 +1473,23 @@ return &PN; } } + if (phiAllConstantOperandsAreZero(PN)) { + for (Value *Operands : PN.operands()) { + if (Instruction *Fmul = dyn_cast(Operands)) { + if (Fmul->getOpcode() != Instruction::FMul || !Fmul->hasNoInfs() || + !Fmul->hasNoNaNs() || !Fmul->hasNoSignedZeros()) + break; + for (Value *InstOperand : Fmul->operands()) { + if (PHINode *PhiOperand = dyn_cast(InstOperand)) { + if (PhiOperand != &PN) + continue; + auto *ZeroVal = Constant::getNullValue(PN.getType()); + replaceInstUsesWith(PN, ZeroVal); + } + } + } + } + } // We sometimes end up with phi cycles that non-obviously end up being the // same value, for example: diff --git a/llvm/test/Transforms/InstCombine/remove-loop-phi-fastmul.ll b/llvm/test/Transforms/InstCombine/remove-loop-phi-fastmul.ll --- a/llvm/test/Transforms/InstCombine/remove-loop-phi-fastmul.ll +++ b/llvm/test/Transforms/InstCombine/remove-loop-phi-fastmul.ll @@ -3,19 +3,14 @@ define double @test_mul_fast_flags() { ; CHECK-LABEL: @test_mul_fast_flags( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[ARR_D:%.*]] = alloca [1000 x double], align 8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[I_02:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ] -; CHECK-NEXT: [[F_PROD_01:%.*]] = phi double [ 0.000000e+00, [[ENTRY]] ], [ [[MUL:%.*]], [[FOR_BODY]] ] -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [1000 x double], ptr [[ARR_D]], i64 0, i64 [[I_02]] -; CHECK-NEXT: [[TMP0:%.*]] = load double, ptr [[ARRAYIDX]], align 8 -; CHECK-NEXT: [[MUL]] = fmul fast double [[F_PROD_01]], [[TMP0]] ; CHECK-NEXT: [[INC]] = add i64 [[I_02]], 1 ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 1000 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[END:%.*]] ; CHECK: end: -; CHECK-NEXT: ret double [[MUL]] +; CHECK-NEXT: ret double 0.000000e+00 ; entry: %arr_d = alloca [1000 x double], align 8 @@ -147,19 +142,14 @@ define double @test_phi_non_constant_operand() { ; CHECK-LABEL: @test_phi_non_constant_operand( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[ARR_D:%.*]] = alloca [1000 x double], align 8 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[I_02:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ] -; CHECK-NEXT: [[F_PROD_01:%.*]] = phi double [ 0.000000e+00, [[ENTRY]] ], [ [[MUL:%.*]], [[FOR_BODY]] ] -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [1000 x double], ptr [[ARR_D]], i64 0, i64 [[I_02]] -; CHECK-NEXT: [[TMP0:%.*]] = load double, ptr [[ARRAYIDX]], align 8 -; CHECK-NEXT: [[MUL]] = fmul fast double [[F_PROD_01]], [[TMP0]] ; CHECK-NEXT: [[INC]] = add i64 [[I_02]], 1 ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 1000 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[END:%.*]] ; CHECK: end: -; CHECK-NEXT: ret double [[MUL]] +; CHECK-NEXT: ret double 0.000000e+00 ; entry: %arr_d = alloca [1000 x double], align 8 @@ -220,21 +210,16 @@ define double @test_multiple_phi_operands() { ; CHECK-LABEL: @test_multiple_phi_operands( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[ARR_D:%.*]] = alloca [1000 x double], align 8 ; CHECK-NEXT: br i1 false, label [[FOR_BODY:%.*]], label [[ENTRY_2:%.*]] ; CHECK: entry_2: ; CHECK-NEXT: br label [[FOR_BODY]] ; CHECK: for.body: ; CHECK-NEXT: [[I_02:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ 0, [[ENTRY_2]] ], [ [[INC:%.*]], [[FOR_BODY]] ] -; CHECK-NEXT: [[F_PROD_01:%.*]] = phi double [ 0.000000e+00, [[ENTRY]] ], [ 0.000000e+00, [[ENTRY_2]] ], [ [[MUL:%.*]], [[FOR_BODY]] ] -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [1000 x double], ptr [[ARR_D]], i64 0, i64 [[I_02]] -; CHECK-NEXT: [[TMP0:%.*]] = load double, ptr [[ARRAYIDX]], align 8 -; CHECK-NEXT: [[MUL]] = fmul fast double [[F_PROD_01]], [[TMP0]] ; CHECK-NEXT: [[INC]] = add i64 [[I_02]], 1 ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[INC]], 1000 ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[END:%.*]] ; CHECK: end: -; CHECK-NEXT: ret double [[MUL]] +; CHECK-NEXT: ret double 0.000000e+00 ; entry: %arr_d = alloca [1000 x double], align 8