aboutsummaryrefslogtreecommitdiff
path: root/gcc/expmed.c
diff options
context:
space:
mode:
authorRichard Kenner <kenner@gcc.gnu.org>1992-12-28 06:07:52 -0500
committerRichard Kenner <kenner@gcc.gnu.org>1992-12-28 06:07:52 -0500
commitcbec710efcae143355573a17944f821557fb78af (patch)
tree5a9ae9474bf0930c30e3e87969569654cc2c1555 /gcc/expmed.c
parent85d2e16cf73d8c815b73fe2d4680512a5669a768 (diff)
downloadgcc-cbec710efcae143355573a17944f821557fb78af.zip
gcc-cbec710efcae143355573a17944f821557fb78af.tar.gz
gcc-cbec710efcae143355573a17944f821557fb78af.tar.bz2
(expand_shift): If rotating by a constant, try both directions of rotate...
(expand_shift): If rotating by a constant, try both directions of rotate; if can't open-code a rotate, do it as a pair of shifts followed by an IOR. From-SVN: r2971
Diffstat (limited to 'gcc/expmed.c')
-rw-r--r--gcc/expmed.c47
1 files changed, 46 insertions, 1 deletions
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 2c95a86..0d18c5d 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -1535,11 +1535,56 @@ expand_shift (code, mode, shifted, amount, target, unsignedp)
if (methods == OPTAB_WIDEN)
continue;
else if (methods == OPTAB_LIB_WIDEN)
- methods = OPTAB_LIB;
+ {
+ /* If we are rotating by a constant that is valid and
+ we have been unable to open-code this by a rotation,
+ do it as the IOR of two shifts. I.e., to rotate A
+ by N bits, compute (A << N) | ((unsigned) A >> (C - N))
+ where C is the bitsize of A.
+
+ It is theoretically possible that the target machine might
+ not be able to perform either shift and hence we would
+ be making two libcalls rather than just the one for the
+ shift (similarly if IOR could not be done). We will allow
+ this extremely unlikely lossage to avoid complicating the
+ code below. */
+
+ if (GET_CODE (op1) == CONST_INT && INTVAL (op1) > 0
+ && INTVAL (op1) < GET_MODE_BITSIZE (mode))
+ {
+ rtx subtarget = target == shifted ? 0 : target;
+ rtx temp1;
+ tree other_amount
+ = build_int_2 (GET_MODE_BITSIZE (mode) - INTVAL (op1), 0);
+
+ shifted = force_reg (mode, shifted);
+
+ temp = expand_shift (left ? LSHIFT_EXPR : RSHIFT_EXPR,
+ mode, shifted, amount, subtarget, 1);
+ temp1 = expand_shift (left ? RSHIFT_EXPR : LSHIFT_EXPR,
+ mode, shifted, other_amount, 0, 1);
+ return expand_binop (mode, ior_optab, temp, temp1, target,
+ unsignedp, methods);
+ }
+ else
+ methods = OPTAB_LIB;
+ }
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 && 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)
{