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,13 @@ return nullptr; } +bool phiAllConstantOperandsAreZero(PHINode &PN) { + for (Value *V : PN.operands()) + if (Constant *ConstVA = dyn_cast(V)) + if (!ConstVA->isZeroValue()) + return false; + return true; +} // PHINode simplification // Instruction *InstCombinerImpl::visitPHINode(PHINode &PN) { @@ -1465,6 +1472,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()) { + for (Value *InstOperand : Fmul->operands()) { + if (PHINode *PhiOperand = dyn_cast(InstOperand)) { + if (PhiOperand == &PN) { + 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 new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/remove-loop-phi-fastmul.ll @@ -0,0 +1,130 @@ +; RUN: opt < %s -passes=instcombine -S | FileCheck %s +define double @test_mul_fast_flags() { +entry: + %arr_d = alloca [1000 x double], align 8 + br label %for.cond + +; CHECK-LABEL: for.cond: +; CHECK-NOT: [[PHI_1:%.*]] = phi double [ 0.000000e+00, [[ENTRY_1:%.*]] ], [ [[MUL_1:%.*]] [[LOOPBODY_1:%.*]] ] +; CHECK-NEXT: [[PHI_2:%.*]] = phi i64 [ 0, [[ENTRY_2:%.*]] ], [ [[INC_1:%.*]] [[LOOPBODY_2:%.*]] ] +for.cond: + %f_prod.0 = phi double [0.000000e+00, %entry], [%mul, %for.body] + %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.body ] + %cmp = icmp ult i64 %i.0, 1000 + br i1 %cmp, label %for.body, label %end + +end: + ret double %f_prod.0 + +for.body: + %arrayidx = getelementptr inbounds [1000 x double], ptr %arr_d, i64 0, i64 %i.0 + %0 = load double, ptr %arrayidx, align 8 + %mul = fmul fast double %f_prod.0, %0 + %inc = add i64 %i.0, 1 + br label %for.cond + +} + +define double @test_phi_nnan_flag_enabled() { +entry: + %arr_d = alloca [1000 x double], align 8 + br label %for.cond + +; CHECK-LABEL: for.cond: +; CHECK: [[PHI_3:%.*]] = phi double [ 0.000000e+00, [[ENTRY_3:%.*]] ], [ [[MUL_2:%.*]] [[LOOPBODY_3:%.*]] ] +; CHECK-NEXT: [[PHI_4:%.*]] = phi i64 [ 0, [[ENTRY_4:%.*]] ], [ [[INC_2:%.*]] [[LOOPBODY_4:%.*]] ] +for.cond: + %f_prod.0 = phi double [0.000000e+00, %entry], [%mul, %for.body] + %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.body ] + %cmp = icmp ult i64 %i.0, 1000 + br i1 %cmp, label %for.body, label %end + +end: + ret double %f_prod.0 + +for.body: + %arrayidx = getelementptr inbounds [1000 x double], ptr %arr_d, i64 0, i64 %i.0 + %0 = load double, ptr %arrayidx, align 8 + %mul = fmul nnan double %f_prod.0, %0 + %inc = add i64 %i.0, 1 + br label %for.cond + +} + +define double @test_phi_ninf_flag_enabled() { +entry: + %arr_d = alloca [1000 x double], align 8 + br label %for.cond + +; CHECK-LABEL: for.cond: +; CHECK: [[PHI_5:%.*]] = phi double [ 0.000000e+00, [[ENTRY_5:%.*]] ], [ [[MUL_3:%.*]] [[LOOPBODY_5:%.*]] ] +; CHECK-NEXT: [[PHI_6:%.*]] = phi i64 [ 0, [[ENTRY_6:%.*]] ], [ [[INC_3:%.*]] [[LOOPBODY_6:%.*]] ] +for.cond: + %f_prod.0 = phi double [0.000000e+00, %entry], [%mul, %for.body] + %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.body ] + %cmp = icmp ult i64 %i.0, 1000 + br i1 %cmp, label %for.body, label %end + +end: + ret double %f_prod.0 + +for.body: + %arrayidx = getelementptr inbounds [1000 x double], ptr %arr_d, i64 0, i64 %i.0 + %0 = load double, ptr %arrayidx, align 8 + %mul = fmul ninf double %f_prod.0, %0 + %inc = add i64 %i.0, 1 + br label %for.cond + +} + +define double @test_phi_nsz_flag_enabled() { +entry: + %arr_d = alloca [1000 x double], align 8 + br label %for.cond + +; CHECK-LABEL: for.cond: +; CHECK: [[PHI_7:%.*]] = phi double [ 0.000000e+00, [[ENTRY_7:%.*]] ], [ [[MUL_4:%.*]] [[LOOPBODY_7:%.*]] ] +; CHECK-NEXT: [[PHI_8:%.*]] = phi i64 [ 0, [[ENTRY_8:%.*]] ], [ [[INC_4:%.*]] [[LOOPBODY_8:%.*]] ] +for.cond: + %f_prod.0 = phi double [0.000000e+00, %entry], [%mul, %for.body] + %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.body ] + %cmp = icmp ult i64 %i.0, 1000 + br i1 %cmp, label %for.body, label %end + +end: + ret double %f_prod.0 + +for.body: + %arrayidx = getelementptr inbounds [1000 x double], ptr %arr_d, i64 0, i64 %i.0 + %0 = load double, ptr %arrayidx, align 8 + %mul = fmul ninf double %f_prod.0, %0 + %inc = add i64 %i.0, 1 + br label %for.cond + +} + +define double @test_phi_initalise_to_non_zero() { +entry: + %arr_d = alloca [1000 x double], align 8 + br label %for.cond + +; CHECK-LABEL: for.cond: +; CHECK-NEXT: [[PHI_9:%.*]] = phi double [ 1.000000e+00, [[ENTRY_9:%.*]] ], [ [[MUL_5:%.*]] [[LOOPBODY_9:%.*]] ] +; CHECK-NEXT: [[PHI_10:%.*]] = phi i64 [ 0, [[ENTRY_10:%.*]] ], [ [[INC_5:%.*]] [[LOOPBODY_10:%.*]] ] +for.cond: + %f_prod.0 = phi double [1.000000e+00, %entry], [%mul, %for.body] + %i.0 = phi i64 [ 0, %entry ], [ %inc, %for.body ] + %cmp = icmp ult i64 %i.0, 1000 + br i1 %cmp, label %for.body, label %end + +end: + ret double %f_prod.0 + +for.body: + %arrayidx = getelementptr inbounds [1000 x double], ptr %arr_d, i64 0, i64 %i.0 + %0 = load double, ptr %arrayidx, align 8 + %mul = fmul fast double %f_prod.0, %0 + %inc = add i64 %i.0, 1 + br label %for.cond + +} \ No newline at end of file