We currently generate (sometimes pretty long) sequences of integer insns to implement the various cstore patterns. If the CPU has a fast isel, we can use that at the same latency as of just two integer insns (you also get a load immediate of 1, and sometimes one of 0 as well, but those are not in the critical path: they don't depend on any other instruction).
There are a few patterns that already are implemented with just two instructions; so don't use isel in that case (I still need to check all lt/gt/ltu/gtu/le/leu/ge/geu patterns with all SI/DI combinations, one or two might be better without isel). This introduces a new GPR2 mode iterator, for those patterns that use two independent integer modes. It's currently running final testing on power7 powerpc64-linux {-m32,-m64}, and on power8 and power9, powerpc64le-linux. I hope to commit it later today. Segher 2017-11-07 Segher Boessenkool <seg...@kernel.crashing.org> * config/rs6000/rs6000.md (GPR2): New mode_iterator. ("cstore<mode>4"): Don't always expand with rs6000_emit_int_cmove for eq and ne if TARGET_ISEL. (cmp): New code_iterator. (UNS, UNSU_, UNSIK): New code_attrs. (<code><GPR:mode><GPR2:mode>2_isel): New define_insn_and_split. ("eq<mode>3"): New define_expand, rename the define_insn_and_split to... ("eq<mode>3"): ... this. ("ne<mode>3"): New define_expand, rename the define_insn_and_split to... ("ne<mode>3"): ... this. --- gcc/config/rs6000/rs6000.md | 133 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 119 insertions(+), 14 deletions(-) diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index ed5ff39..b800276 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -323,6 +323,9 @@ (define_attr "cell_micro" "not,conditional,always" ; of whole values in GPRs. (define_mode_iterator GPR [SI (DI "TARGET_POWERPC64")]) +; And again, for patterns that need two (potentially) different integer modes. +(define_mode_iterator GPR2 [SI (DI "TARGET_POWERPC64")]) + ; Any supported integer mode. (define_mode_iterator INT [QI HI SI DI TI PTI]) @@ -11780,13 +11783,9 @@ (define_expand "cstore<mode>4" (clobber (match_operand:GPR 0 "gpc_reg_operand"))] "" { - /* Use ISEL if the user asked for it. */ - if (TARGET_ISEL) - rs6000_emit_int_cmove (operands[0], operands[1], const1_rtx, const0_rtx); - /* Expanding EQ and NE directly to some machine instructions does not help but does hurt combine. So don't. */ - else if (GET_CODE (operands[1]) == EQ) + if (GET_CODE (operands[1]) == EQ) emit_insn (gen_eq<mode>3 (operands[0], operands[2], operands[3])); else if (<MODE>mode == Pmode && GET_CODE (operands[1]) == NE) @@ -11798,7 +11797,11 @@ (define_expand "cstore<mode>4" emit_insn (gen_xor<mode>3 (operands[0], tmp, const1_rtx)); } - /* Expanding the unsigned comparisons however helps a lot: all the neg_ltu + /* If ISEL is fast, expand to it. */ + else if (TARGET_ISEL) + rs6000_emit_int_cmove (operands[0], operands[1], const1_rtx, const0_rtx); + + /* Expanding the unsigned comparisons helps a lot: all the neg_ltu etc. combinations magically work out just right. */ else if (<MODE>mode == Pmode && unsigned_comparison_operator (operands[1], VOIDmode)) @@ -12280,18 +12283,102 @@ (define_split "") +(define_code_iterator cmp [eq ne lt ltu gt gtu le leu ge geu]) +(define_code_attr UNS [(eq "CC") + (ne "CC") + (lt "CC") (ltu "CCUNS") + (gt "CC") (gtu "CCUNS") + (le "CC") (leu "CCUNS") + (ge "CC") (geu "CCUNS")]) +(define_code_attr UNSu_ [(eq "") + (ne "") + (lt "") (ltu "u_") + (gt "") (gtu "u_") + (le "") (leu "u_") + (ge "") (geu "u_")]) +(define_code_attr UNSIK [(eq "I") + (ne "I") + (lt "I") (ltu "K") + (gt "I") (gtu "K") + (le "I") (leu "K") + (ge "I") (geu "K")]) + +(define_insn_and_split "<code><GPR:mode><GPR2:mode>2_isel" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (cmp:GPR (match_operand:GPR2 1 "gpc_reg_operand" "r") + (match_operand:GPR2 2 "reg_or_<cmp:UNSu_>short_operand" "r<cmp:UNSIK>"))) + (clobber (match_scratch:GPR 3 "=r")) + (clobber (match_scratch:GPR 4 "=r")) + (clobber (match_scratch:<UNS> 5 "=y"))] + "TARGET_ISEL + && !(<CODE> == EQ && operands[2] == const0_rtx) + && !(<CODE> == NE && operands[2] == const0_rtx + && <GPR:MODE>mode == Pmode && <GPR2:MODE>mode == Pmode)" + "#" + "&& 1" + [(pc)] +{ + if (<CODE> == NE || <CODE> == LE || <CODE> == GE + || <CODE> == LEU || <CODE> == GEU) + operands[3] = const0_rtx; + else + { + if (GET_CODE (operands[3]) == SCRATCH) + operands[3] = gen_reg_rtx (<GPR:MODE>mode); + emit_move_insn (operands[3], const0_rtx); + } + + if (GET_CODE (operands[4]) == SCRATCH) + operands[4] = gen_reg_rtx (<GPR:MODE>mode); + emit_move_insn (operands[4], const1_rtx); + + if (GET_CODE (operands[5]) == SCRATCH) + operands[5] = gen_reg_rtx (<UNS>mode); + + rtx c1 = gen_rtx_COMPARE (<UNS>mode, operands[1], operands[2]); + emit_insn (gen_rtx_SET (operands[5], c1)); + + rtx c2 = gen_rtx_fmt_ee (<CODE>, <GPR:MODE>mode, operands[5], const0_rtx); + rtx x = gen_rtx_IF_THEN_ELSE (<GPR:MODE>mode, c2, operands[4], operands[3]); + emit_move_insn (operands[0], x); + + DONE; +} + [(set (attr "cost") + (if_then_else (match_test "<CODE> == NE || <CODE> == LE || <CODE> == GE + || <CODE> == LEU || <CODE> == GEU") + (const_string "9") + (const_string "10")))]) + (define_mode_attr scc_eq_op2 [(SI "rKLI") (DI "rKJI")]) -(define_insn_and_split "eq<mode>3" +(define_expand "eq<mode>3" + [(parallel [ + (set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (eq:GPR (match_operand:GPR 1 "gpc_reg_operand" "r") + (match_operand:GPR 2 "scc_eq_operand" "<scc_eq_op2>"))) + (clobber (match_scratch:GPR 3 "=r")) + (clobber (match_scratch:GPR 4 "=r"))])] + "" +{ + if (TARGET_ISEL && operands[2] != const0_rtx) + { + emit_insn (gen_eq<mode><mode>2_isel (operands[0], operands[1], + operands[2])); + DONE; + } +}) + +(define_insn_and_split "*eq<mode>3" [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") (eq:GPR (match_operand:GPR 1 "gpc_reg_operand" "r") (match_operand:GPR 2 "scc_eq_operand" "<scc_eq_op2>"))) (clobber (match_scratch:GPR 3 "=r")) (clobber (match_scratch:GPR 4 "=r"))] - "" + "!(TARGET_ISEL && operands[2] != const0_rtx)" "#" - "" + "&& 1" [(set (match_dup 4) (clz:GPR (match_dup 3))) (set (match_dup 0) @@ -12311,16 +12398,34 @@ (define_insn_and_split "eq<mode>3" (const_string "8") (const_string "12")))]) -(define_insn_and_split "ne<mode>3" +(define_expand "ne<mode>3" + [(parallel [ + (set (match_operand:P 0 "gpc_reg_operand" "=r") + (ne:P (match_operand:P 1 "gpc_reg_operand" "r") + (match_operand:P 2 "scc_eq_operand" "<scc_eq_op2>"))) + (clobber (match_scratch:P 3 "=r")) + (clobber (match_scratch:P 4 "=r")) + (clobber (reg:P CA_REGNO))])] + "" +{ + if (TARGET_ISEL && operands[2] != const0_rtx) + { + emit_insn (gen_ne<mode><mode>2_isel (operands[0], operands[1], + operands[2])); + DONE; + } +}) + +(define_insn_and_split "*ne<mode>3" [(set (match_operand:P 0 "gpc_reg_operand" "=r") (ne:P (match_operand:P 1 "gpc_reg_operand" "r") (match_operand:P 2 "scc_eq_operand" "<scc_eq_op2>"))) (clobber (match_scratch:P 3 "=r")) (clobber (match_scratch:P 4 "=r")) (clobber (reg:P CA_REGNO))] - "!TARGET_ISEL" + "!(TARGET_ISEL && operands[2] != const0_rtx)" "#" - "" + "&& 1" [(parallel [(set (match_dup 4) (plus:P (match_dup 3) (const_int -1))) @@ -12573,9 +12678,9 @@ (define_insn_and_split "*nesi3_ext<mode>" (clobber (match_scratch:SI 3 "=r")) (clobber (match_scratch:SI 4 "=r")) (clobber (match_scratch:EXTSI 5 "=r"))] - "" + "!TARGET_ISEL" "#" - "" + "&& 1" [(set (match_dup 4) (clz:SI (match_dup 3))) (set (match_dup 5) -- 1.8.3.1