https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94665
Bug ID: 94665 Summary: missed minmax optimization opportunity for if/else structure. Product: gcc Version: 10.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: rtl-optimization Assignee: unassigned at gcc dot gnu.org Reporter: z.zhanghaijian at huawei dot com Target Milestone: --- Minmax optimization for fortran, for example: SUBROUTINE mydepart(vara,varb,varc,res) REAL, INTENT(IN) :: vara,varb,varc REAL, INTENT(out) :: res res = vara if (res .lt. varb) res = varb if (res .gt. varc) res = varc end SUBROUTINE on aarch64, compile with -O2 -S -funsafe-math-optimizations, the asm: ldr s2, [x0] ldr s0, [x1] ldr s1, [x2] fcmpe s2, s0 fcsel s0, s0, s2, mi fminnm s1, s1, s0 str s1, [x3] ret The second if statement is optimized to fminnm, but the first can not. In fact, it can be optimized to: ldr s2, [x0] ldr s1, [x1] ldr s0, [x2] fmaxnm s1, s2, s1 fminnm s0, s0, s1 str s0, [x3] My proposal: I tracked the generation of fminnm is done in simplify_if_then_else. The reason why the first statement optimization is not done is that the conditions are not met: rtx_equal_p (XEXP (cond, 0), true_rtx) && rtx_equal_p (XEXP (cond, 1), false_rtx). The RTX: (if_then_else:SF (lt (reg:SF 92 [ _1 ]) (reg:SF 93 [ _2 ])) (reg:SF 93 [ _2 ]) (reg:SF 92 [ _1 ])) We can swap the true_rtx/false_rtx, and take the maximum. the patch: diff --git a/gcc/combine.c b/gcc/combine.c --- a/gcc/combine.c +++ b/gcc/combine.c @@ -6641,25 +6641,43 @@ simplify_if_then_else (rtx x) if ((! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations) && comparison_p - && rtx_equal_p (XEXP (cond, 0), true_rtx) - && rtx_equal_p (XEXP (cond, 1), false_rtx) && ! side_effects_p (cond)) - switch (true_code) - { - case GE: - case GT: - return simplify_gen_binary (SMAX, mode, true_rtx, false_rtx); - case LE: - case LT: - return simplify_gen_binary (SMIN, mode, true_rtx, false_rtx); - case GEU: - case GTU: - return simplify_gen_binary (UMAX, mode, true_rtx, false_rtx); - case LEU: - case LTU: - return simplify_gen_binary (UMIN, mode, true_rtx, false_rtx); - default: - break; + { + int swapped = 0; + if (rtx_equal_p (XEXP (cond, 0), false_rtx) + && rtx_equal_p (XEXP (cond, 1), true_rtx)) + { + std::swap (true_rtx, false_rtx); + swapped = 1; + } + + if (rtx_equal_p (XEXP (cond, 0), true_rtx) + && rtx_equal_p (XEXP (cond, 1), false_rtx)) + switch (true_code) + { + case GE: + case GT: + return simplify_gen_binary (swapped ? SMIN : SMAX, + mode, true_rtx, false_rtx); + case LE: + case LT: + return simplify_gen_binary (swapped ? SMAX : SMIN, + mode, true_rtx, false_rtx); + case GEU: + case GTU: + return simplify_gen_binary (swapped ? UMIN : UMAX, + mode, true_rtx, false_rtx); + case LEU: + case LTU: + return simplify_gen_binary (swapped ? UMAX : UMIN, + mode, true_rtx, false_rtx); + default: + break; + } + + /* Restore if not MIN or MAX. */ + if (swapped) + std::swap (true_rtx, false_rtx); } /* If we have (if_then_else COND (OP Z C1) Z) and OP is an identity when its Any suggestions?