aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2005-09-29 03:31:23 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2005-09-29 03:31:23 +0000
commit0f8594eee973eb004228f171b4649cb3cb9aa536 (patch)
tree31982fcfb5affaad07795757ddfef347ec078819 /gcc
parent4bc7cba79582442c601bf69094b351833ad61b76 (diff)
downloadgcc-0f8594eee973eb004228f171b4649cb3cb9aa536.zip
gcc-0f8594eee973eb004228f171b4649cb3cb9aa536.tar.gz
gcc-0f8594eee973eb004228f171b4649cb3cb9aa536.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/config/i386/i386.md90
-rw-r--r--gcc/expmed.c13
-rw-r--r--gcc/optabs.c19
4 files changed, 111 insertions, 22 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f427dbf..fdbecf6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2005-09-28 Mark Mitchell <mark@codesourcery.com>
+
+ 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 <amodra@bigpond.net.au>
PR target/24102
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 8bfa037..6b1beaf 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 5da9084..19d972d 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 31212cb..bc859205 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. */