https://gcc.gnu.org/g:09737d9605521df9232d9990006c44955064f44e
commit r15-1738-g09737d9605521df9232d9990006c44955064f44e Author: liuhongt <hongtao....@intel.com> Date: Tue Jun 18 15:52:02 2024 +0800 Match IEEE min/max with UNSPEC_IEEE_{MIN,MAX}. These versions of the min/max patterns implement exactly the operations min = (op1 < op2 ? op1 : op2) max = (!(op1 < op2) ? op1 : op2) gcc/ChangeLog: PR target/115517 * config/i386/sse.md (*minmax<mode>3_1): New pre_reload define_insn_and_split. (*minmax<mode>3_2): Ditto. Diff: --- gcc/config/i386/sse.md | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index 3d790af3a2c..694b4b8f07c 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -3096,6 +3096,69 @@ (set_attr "prefix" "<mask_prefix3>") (set_attr "mode" "<MODE>")]) +(define_insn_and_split "*minmax<mode>3_1" + [(set (match_operand:VFH 0 "register_operand") + (vec_merge:VFH + (match_operand:VFH 1 "nonimmediate_operand") + (match_operand:VFH 2 "nonimmediate_operand") + (unspec:<avx512fmaskmode> + [(match_operand:VFH 3 "nonimmediate_operand") + (match_operand:VFH 4 "nonimmediate_operand") + (match_operand:SI 5 "const_0_to_31_operand")] + UNSPEC_PCMP)))] + "TARGET_SSE && ix86_pre_reload_split () + && ((rtx_equal_p (operands[1], operands[3]) + && rtx_equal_p (operands[2], operands[4])) + || (rtx_equal_p (operands[1], operands[4]) + && rtx_equal_p (operands[2], operands[3]))) + && (INTVAL (operands[5]) == 1 || INTVAL (operands[5]) == 14)" + "#" + "&& 1" + [(const_int 0)] + { + int u = UNSPEC_IEEE_MIN; + if ((INTVAL (operands[5]) == 1 && rtx_equal_p (operands[1], operands[4])) + || (INTVAL (operands[5]) == 14 && rtx_equal_p (operands[1], operands[3]))) + u = UNSPEC_IEEE_MAX; + + if (MEM_P (operands[1])) + operands[1] = force_reg (<MODE>mode, operands[1]); + rtvec v = gen_rtvec (2, operands[1], operands[2]); + rtx tmp = gen_rtx_UNSPEC (<MODE>mode, v, u); + emit_move_insn (operands[0], tmp); + DONE; + }) + +(define_insn_and_split "*minmax<mode>3_2" + [(set (match_operand:VF_128_256 0 "register_operand") + (unspec:VF_128_256 + [(match_operand:VF_128_256 1 "nonimmediate_operand") + (match_operand:VF_128_256 2 "nonimmediate_operand") + (lt:VF_128_256 + (match_operand:VF_128_256 3 "nonimmediate_operand") + (match_operand:VF_128_256 4 "nonimmediate_operand"))] + UNSPEC_BLENDV))] + "TARGET_SSE && ix86_pre_reload_split () + && ((rtx_equal_p (operands[1], operands[3]) + && rtx_equal_p (operands[2], operands[4])) + || (rtx_equal_p (operands[1], operands[4]) + && rtx_equal_p (operands[2], operands[3])))" + "#" + "&& 1" + [(const_int 0)] + { + int u = UNSPEC_IEEE_MIN; + if (rtx_equal_p (operands[1], operands[3])) + u = UNSPEC_IEEE_MAX; + + if (MEM_P (operands[2])) + force_reg (<MODE>mode, operands[2]); + rtvec v = gen_rtvec (2, operands[2], operands[1]); + rtx tmp = gen_rtx_UNSPEC (<MODE>mode, v, u); + emit_move_insn (operands[0], tmp); + DONE; + }) + ;; These versions of the min/max patterns implement exactly the operations ;; min = (op1 < op2 ? op1 : op2) ;; max = (!(op1 < op2) ? op1 : op2)