From 0f8594eee973eb004228f171b4649cb3cb9aa536 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Thu, 29 Sep 2005 03:31:23 +0000 Subject: [PATCH] re PR middle-end/17886 (variable rotate and unsigned long long rotate should be better optimized) PR 17886 * expmed.c (expand_shift): Move logic to reverse rotation direction when rotating by constants ... * optabs.c (expand_binop): ... here. * config/i386/i386.md (rotrdi3): Handle 32-bit mode. (ix86_rotrdi3): New pattern. (rotldi3): Handle 32-bit mode. (ix86_rotldi3): New pattern. From-SVN: r104761 --- gcc/ChangeLog | 11 +++++ gcc/config/i386/i386.md | 90 ++++++++++++++++++++++++++++++++++++----- gcc/expmed.c | 13 ------ gcc/optabs.c | 19 +++++++++ 4 files changed, 111 insertions(+), 22 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f427dbf225d..fdbecf6c709 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2005-09-28 Mark Mitchell + + PR 17886 + * expmed.c (expand_shift): Move logic to reverse rotation + direction when rotating by constants ... + * optabs.c (expand_binop): ... here. + * config/i386/i386.md (rotrdi3): Handle 32-bit mode. + (ix86_rotrdi3): New pattern. + (rotldi3): Handle 32-bit mode. + (ix86_rotldi3): New pattern. + 2005-09-29 Alan Modra PR target/24102 diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 8bfa037a8cc..6b1beaf0204 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -12004,13 +12004,49 @@ ;; Rotate instructions (define_expand "rotldi3" - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (rotate:DI (match_operand:DI 1 "nonimmediate_operand" "") + [(set (match_operand:DI 0 "shiftdi_operand" "") + (rotate:DI (match_operand:DI 1 "shiftdi_operand" "") (match_operand:QI 2 "nonmemory_operand" ""))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "ix86_expand_binary_operator (ROTATE, DImode, operands); DONE;") + "" +{ + if (TARGET_64BIT) + { + ix86_expand_binary_operator (ROTATE, DImode, operands); + DONE; + } + if (!const_1_to_31_operand (operands[2], VOIDmode)) + FAIL; + emit_insn (gen_ix86_rotldi3 (operands[0], operands[1], operands[2])); + DONE; +}) +;; Implement rotation using two double-precision shift instructions +;; and a scratch register. +(define_insn_and_split "ix86_rotldi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (rotate:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:QI 2 "const_1_to_31_operand" "I"))) + (clobber (reg:CC FLAGS_REG)) + (clobber (match_scratch:SI 3 "=&r"))] + "!TARGET_64BIT" + "" + "&& reload_completed" + [(set (match_dup 3) (match_dup 4)) + (parallel + [(set (match_dup 4) + (ior:SI (ashift:SI (match_dup 4) (match_dup 2)) + (lshiftrt:SI (match_dup 5) + (minus:QI (const_int 32) (match_dup 2))))) + (clobber (reg:CC FLAGS_REG))]) + (parallel + [(set (match_dup 5) + (ior:SI (ashift:SI (match_dup 5) (match_dup 2)) + (lshiftrt:SI (match_dup 3) + (minus:QI (const_int 32) (match_dup 2))))) + (clobber (reg:CC FLAGS_REG))])] + "split_di (operands, 1, operands + 4, operands + 5);") + (define_insn "*rotlsi3_1_one_bit_rex64" [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") (rotate:DI (match_operand:DI 1 "nonimmediate_operand" "0") @@ -12192,12 +12228,48 @@ (set_attr "mode" "QI")]) (define_expand "rotrdi3" - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (rotatert:DI (match_operand:DI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) + [(set (match_operand:DI 0 "shiftdi_operand" "") + (rotate:DI (match_operand:DI 1 "shiftdi_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "ix86_expand_binary_operator (ROTATERT, DImode, operands); DONE;") + "" +{ + if (TARGET_64BIT) + { + ix86_expand_binary_operator (ROTATERT, DImode, operands); + DONE; + } + if (!const_1_to_31_operand (operands[2], VOIDmode)) + FAIL; + emit_insn (gen_ix86_rotrdi3 (operands[0], operands[1], operands[2])); + DONE; +}) + +;; Implement rotation using two double-precision shift instructions +;; and a scratch register. +(define_insn_and_split "ix86_rotrdi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (rotatert:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:QI 2 "const_1_to_31_operand" "I"))) + (clobber (reg:CC FLAGS_REG)) + (clobber (match_scratch:SI 3 "=&r"))] + "!TARGET_64BIT" + "" + "&& reload_completed" + [(set (match_dup 3) (match_dup 4)) + (parallel + [(set (match_dup 4) + (ior:SI (ashiftrt:SI (match_dup 4) (match_dup 2)) + (ashift:SI (match_dup 5) + (minus:QI (const_int 32) (match_dup 2))))) + (clobber (reg:CC FLAGS_REG))]) + (parallel + [(set (match_dup 5) + (ior:SI (ashiftrt:SI (match_dup 5) (match_dup 2)) + (ashift:SI (match_dup 3) + (minus:QI (const_int 32) (match_dup 2))))) + (clobber (reg:CC FLAGS_REG))])] + "split_di (operands, 1, operands + 4, operands + 5);") (define_insn "*rotrdi3_1_one_bit_rex64" [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") diff --git a/gcc/expmed.c b/gcc/expmed.c index 5da9084651f..19d972d2ad3 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -2237,19 +2237,6 @@ expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted, temp = expand_binop (mode, left ? rotl_optab : rotr_optab, shifted, op1, target, unsignedp, methods); - - /* If we don't have the rotate, but we are rotating by a constant - that is in range, try a rotate in the opposite direction. */ - - if (temp == 0 && GET_CODE (op1) == CONST_INT - && INTVAL (op1) > 0 - && (unsigned int) INTVAL (op1) < GET_MODE_BITSIZE (mode)) - temp = expand_binop (mode, - left ? rotr_optab : rotl_optab, - shifted, - GEN_INT (GET_MODE_BITSIZE (mode) - - INTVAL (op1)), - target, unsignedp, methods); } else if (unsignedp) temp = expand_binop (mode, diff --git a/gcc/optabs.c b/gcc/optabs.c index 31212cbc007..bc859205279 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -1049,6 +1049,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, || binoptab->code == ROTATERT); rtx entry_last = get_last_insn (); rtx last; + bool first_pass_p; class = GET_MODE_CLASS (mode); @@ -1098,6 +1099,8 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, } } + retry: + /* If we can do it with a three-operand insn, do so. */ if (methods != OPTAB_MUST_WIDEN @@ -1183,6 +1186,22 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, delete_insns_since (last); } + /* If we were trying to rotate by a constant value, and that didn't + work, try rotating the other direction before falling back to + shifts and bitwise-or. */ + if (first_pass_p + && (binoptab == rotl_optab || binoptab == rotr_optab) + && class == MODE_INT + && GET_CODE (op1) == CONST_INT + && INTVAL (op1) > 0 + && (unsigned int) INTVAL (op1) < GET_MODE_BITSIZE (mode)) + { + first_pass_p = false; + op1 = GEN_INT (GET_MODE_BITSIZE (mode) - INTVAL (op1)); + binoptab = binoptab == rotl_optab ? rotr_optab : rotl_optab; + goto retry; + } + /* If this is a multiply, see if we can do a widening operation that takes operands of this mode and makes a wider mode. */ -- 2.30.2