Hello! Attached patch splits bswap patterns on 32bit targets by hand, as is the case with all other DImode patterns. The patch takes into account memory operands, where it swaps high/low word load according to bswap/movbe insn availability, and generates xcgh %rX, %rY for reg-reg swaps, avoiding a move to/from temporary register.
2012-05-06 Uros Bizjak <ubiz...@gmail.com> PR target/53227 * config/i386/i386.md (swap<mode>): Rename from *swap<mode>. (bswapdi2): Split from bswap<mode>2. Use nonnimediate_operand predicate for operand 1. Force operand 1 to register for TARGET_BSWAP. (bswapsi2): Ditto. (*bswapdi2_doubleword): New insn pattern. (*bswap<mode>2): Rename from *bswap<mode>2_1. Patch was bootstrapped and regression tested on x86_64-pc-linux-gnu. Committed to mainline SVN. Uros.
Index: i386.md =================================================================== --- i386.md (revision 187211) +++ i386.md (working copy) @@ -2406,7 +2406,7 @@ (set_attr "memory" "load") (set_attr "mode" "<MODE>")]) -(define_insn "*swap<mode>" +(define_insn "swap<mode>" [(set (match_operand:SWI48 0 "register_operand" "+r") (match_operand:SWI48 1 "register_operand" "+r")) (set (match_dup 1) @@ -12487,13 +12487,71 @@ (set_attr "type" "bitmanip") (set_attr "mode" "SI")]) -(define_expand "bswap<mode>2" - [(set (match_operand:SWI48 0 "register_operand") - (bswap:SWI48 (match_operand:SWI48 1 "register_operand")))] +(define_expand "bswapdi2" + [(set (match_operand:DI 0 "register_operand") + (bswap:DI (match_operand:DI 1 "nonimmediate_operand")))] "" { - if (<MODE>mode == SImode && !(TARGET_BSWAP || TARGET_MOVBE)) + if (TARGET_64BIT && !TARGET_MOVBE) + operands[1] = force_reg (DImode, operands[1]); +}) + +(define_insn_and_split "*bswapdi2_doubleword" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m") + (bswap:DI + (match_operand:DI 1 "nonimmediate_operand" "0,m,r")))] + "!TARGET_64BIT + && !(MEM_P (operands[0]) && MEM_P (operands[1]))" + "#" + "&& reload_completed" + [(set (match_dup 2) + (bswap:SI (match_dup 1))) + (set (match_dup 0) + (bswap:SI (match_dup 3)))] +{ + split_double_mode (DImode, &operands[0], 2, &operands[0], &operands[2]); + + if (REG_P (operands[0]) && REG_P (operands[1])) { + emit_insn (gen_swapsi (operands[0], operands[2])); + emit_insn (gen_bswapsi2 (operands[0], operands[0])); + emit_insn (gen_bswapsi2 (operands[2], operands[2])); + DONE; + } + + if (!TARGET_MOVBE) + { + if (MEM_P (operands[0])) + { + emit_insn (gen_bswapsi2 (operands[3], operands[3])); + emit_insn (gen_bswapsi2 (operands[1], operands[1])); + + emit_move_insn (operands[0], operands[3]); + emit_move_insn (operands[2], operands[1]); + } + if (MEM_P (operands[1])) + { + emit_move_insn (operands[2], operands[1]); + emit_move_insn (operands[0], operands[3]); + + emit_insn (gen_bswapsi2 (operands[2], operands[2])); + emit_insn (gen_bswapsi2 (operands[0], operands[0])); + } + DONE; + } +}) + +(define_expand "bswapsi2" + [(set (match_operand:SI 0 "register_operand") + (bswap:SI (match_operand:SI 1 "nonimmediate_operand")))] + "" +{ + if (TARGET_MOVBE) + ; + else if (TARGET_BSWAP) + operands[1] = force_reg (SImode, operands[1]); + else + { rtx x = operands[0]; emit_move_insn (x, operands[1]); @@ -12519,7 +12577,7 @@ (set_attr "prefix_extra" "*,1,1") (set_attr "mode" "<MODE>")]) -(define_insn "*bswap<mode>2_1" +(define_insn "*bswap<mode>2" [(set (match_operand:SWI48 0 "register_operand" "=r") (bswap:SWI48 (match_operand:SWI48 1 "register_operand" "0")))] "TARGET_BSWAP"