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?