From 1b5539c804940cf6d88e41d4484428c208edccd3 Mon Sep 17 00:00:00 2001 From: rth Date: Tue, 13 Feb 2007 16:42:12 +0000 Subject: [PATCH] * config/i386/i386.md (bswapsi_1): Rename from bswapsi2, remove flags clobber. (bswapsi2): New expander, emit code for !TARGET_BSWAP. (bswaphi_lowpart): New. (bswapdi2): Rename from bswapdi2_rex, remove flags clobber, remove TARGET_BSWAP test. Delete expander of the same name. * optabs.c (widen_bswap, expand_doubleword_bswap): New. (expand_unop): Use them. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@121884 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 12 +++++++ gcc/config/i386/i386.md | 61 +++++++++++++++++++---------------- gcc/optabs.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 129 insertions(+), 29 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 77028165963..96ff9accdfb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2007-02-13 Richard Henderson + + * config/i386/i386.md (bswapsi_1): Rename from bswapsi2, + remove flags clobber. + (bswapsi2): New expander, emit code for !TARGET_BSWAP. + (bswaphi_lowpart): New. + (bswapdi2): Rename from bswapdi2_rex, remove flags clobber, + remove TARGET_BSWAP test. Delete expander of the same name. + + * optabs.c (widen_bswap, expand_doubleword_bswap): New. + (expand_unop): Use them. + 2007-02-13 Uros Bizjak * config/i386/i386.md (cmpdi_ccno_1_rex64, *cmpsi_ccno_1, diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 488005b4bc3..0b529c2112a 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -14994,43 +14994,50 @@ (set_attr "type" "bitmanip") (set_attr "mode" "SI")]) -(define_insn "bswapsi2" +(define_expand "bswapsi2" + [(set (match_operand:SI 0 "register_operand" "") + (bswap:SI (match_operand:SI 1 "register_operand" "")))] + "" +{ + if (!TARGET_BSWAP) + { + rtx x = operands[0]; + + emit_move_insn (x, operands[1]); + emit_insn (gen_bswaphi_lowpart (gen_lowpart (HImode, x))); + emit_insn (gen_rotlsi3 (x, x, GEN_INT (16))); + emit_insn (gen_bswaphi_lowpart (gen_lowpart (HImode, x))); + DONE; + } +}) + +(define_insn "*bswapsi_1" [(set (match_operand:SI 0 "register_operand" "=r") - (bswap:SI (match_operand:SI 1 "register_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] + (bswap:SI (match_operand:SI 1 "register_operand" "0")))] "TARGET_BSWAP" - "bswap\t%k0" + "bswap\t%0" [(set_attr "prefix_0f" "1") (set_attr "length" "2")]) -(define_insn "*bswapdi2_rex" +(define_insn "bswaphi_lowpart" + [(set (strict_low_part (match_operand:HI 0 "register_operand" "+Q")) + (bswap:HI (match_dup 0)))] + "" + "xchg{b}\t%h0, %b0" + [(set_attr "type" "alu1") + (set_attr "mode" "QI") + (set_attr "pent_pair" "np") + (set_attr "athlon_decode" "vector") + (set_attr "amdfam10_decode" "double")]) + +(define_insn "bswapdi2" [(set (match_operand:DI 0 "register_operand" "=r") - (bswap:DI (match_operand:DI 1 "register_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && TARGET_BSWAP" + (bswap:DI (match_operand:DI 1 "register_operand" "0")))] + "TARGET_64BIT" "bswap\t%0" [(set_attr "prefix_0f" "1") (set_attr "length" "3")]) -(define_expand "bswapdi2" - [(parallel [(set (match_operand:DI 0 "register_operand" "") - (bswap:DI (match_operand:DI 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_BSWAP" - { - if (!TARGET_64BIT) - { - rtx tmp1, tmp2; - tmp1 = gen_reg_rtx (SImode); - tmp2 = gen_reg_rtx (SImode); - emit_insn (gen_bswapsi2 (tmp1, gen_lowpart (SImode, operands[1]))); - emit_insn (gen_bswapsi2 (tmp2, gen_highpart (SImode, operands[1]))); - emit_move_insn (gen_lowpart (SImode, operands[0]), tmp2); - emit_move_insn (gen_highpart (SImode, operands[0]), tmp1); - DONE; - } - }) - (define_expand "clzdi2" [(parallel [(set (match_operand:DI 0 "register_operand" "") diff --git a/gcc/optabs.c b/gcc/optabs.c index e66c115c0c0..c8ec9ef05a5 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -2401,6 +2401,73 @@ widen_clz (enum machine_mode mode, rtx op0, rtx target) return 0; } +/* Try calculating + (bswap:narrow x) + as + (lshiftrt:wide (bswap:wide x) ((width wide) - (width narrow))). */ +static rtx +widen_bswap (enum machine_mode mode, rtx op0, rtx target) +{ + enum mode_class class = GET_MODE_CLASS (mode); + enum machine_mode wider_mode; + rtx x, last; + + if (!CLASS_HAS_WIDER_MODES_P (class)) + return NULL_RTX; + + for (wider_mode = GET_MODE_WIDER_MODE (mode); + wider_mode != VOIDmode; + wider_mode = GET_MODE_WIDER_MODE (wider_mode)) + if (bswap_optab->handlers[wider_mode].insn_code != CODE_FOR_nothing) + goto found; + return NULL_RTX; + + found: + last = get_last_insn (); + + x = widen_operand (op0, wider_mode, mode, true, true); + x = expand_unop (wider_mode, bswap_optab, x, NULL_RTX, true); + + if (x != 0) + x = expand_shift (RSHIFT_EXPR, wider_mode, x, + size_int (GET_MODE_BITSIZE (wider_mode) + - GET_MODE_BITSIZE (mode)), + NULL_RTX, true); + + if (x != 0) + { + if (target == 0) + target = gen_reg_rtx (mode); + emit_move_insn (target, gen_lowpart (mode, x)); + } + else + delete_insns_since (last); + + return target; +} + +/* Try calculating bswap as two bswaps of two word-sized operands. */ + +static rtx +expand_doubleword_bswap (enum machine_mode mode, rtx op, rtx target) +{ + rtx t0, t1; + + t1 = expand_unop (word_mode, bswap_optab, + operand_subword_force (op, 0, mode), NULL_RTX, true); + t0 = expand_unop (word_mode, bswap_optab, + operand_subword_force (op, 1, mode), NULL_RTX, true); + + if (target == 0) + target = gen_reg_rtx (mode); + if (REG_P (target)) + emit_insn (gen_rtx_CLOBBER (VOIDmode, target)); + emit_move_insn (operand_subword (target, 0, 1, mode), t0); + emit_move_insn (operand_subword (target, 1, 1, mode), t1); + + return target; +} + /* Try calculating (parity x) as (and (popcount x) 1), where popcount can also be done in a wider mode. */ static rtx @@ -2639,9 +2706,23 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target, goto try_libcall; } - /* We can't widen a bswap. */ + /* Widening (or narrowing) bswap needs special treatment. */ if (unoptab == bswap_optab) - goto try_libcall; + { + temp = widen_bswap (mode, op0, target); + if (temp) + return temp; + + if (GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD + && unoptab->handlers[word_mode].insn_code != CODE_FOR_nothing) + { + temp = expand_doubleword_bswap (mode, op0, target); + if (temp) + return temp; + } + + goto try_libcall; + } if (CLASS_HAS_WIDER_MODES_P (class)) for (wider_mode = GET_MODE_WIDER_MODE (mode); -- 2.11.4.GIT