Add support for SmartMIPS ASE.
2007-07-05 Sandra Loosemore <sandra@codesourcery.com> David Ung <davidu@mips.com> Add support for SmartMIPS ASE. gcc/ * optabs.c (expand_binop_directly): New, broken out from... (expand_binop): Here. Make it try rotating in the other direction even when the second operand isn't constant. * config/mips/mips.md (*lwxs): New. * config/mips/mips.opt (msmartmips): New. * config/mips/mips.c (mips_lwxs_address_p): New. (mips_rtx_costs): Make it recognize scaled indexed addressing. * config/mips/mips.h (TARGET_CPU_CPP_BUILTINS): Define __mips_smartmips when compiling for TARGET_SMARTMIPS. (ISA_HAS_ROR): Define for TARGET_SMARTMIPS. (ISA_HAS_LWXS): New. (ASM_SPEC): Add -msmartmips/-mno-smartmips. * doc/invoke.texi (MIPS Options): Document -msmartmips/-mno-smartmips. * testsuite/gcc.target/mips/smartmips-lwxs.c: New test case. * testsuite/gcc.target/mips/smartmips-ror-1.c: New test case. * testsuite/gcc.target/mips/smartmips-ror-2.c: New test case. * testsuite/gcc.target/mips/smartmips-ror-3.c: New test case. * testsuite/gcc.target/mips/smartmips-ror-4.c: New test case. Co-Authored-By: David Ung <davidu@mips.com> From-SVN: r126370
This commit is contained in:
parent
6fd2892a68
commit
0aa222d17b
@ -1,3 +1,27 @@
|
|||||||
|
2007-07-05 Sandra Loosemore <sandra@codesourcery.com>
|
||||||
|
David Ung <davidu@mips.com>
|
||||||
|
|
||||||
|
Add support for SmartMIPS ASE.
|
||||||
|
|
||||||
|
* optabs.c (expand_binop_directly): New, broken out from...
|
||||||
|
(expand_binop): Here. Make it try rotating in the other
|
||||||
|
direction even when the second operand isn't constant.
|
||||||
|
* config/mips/mips.md (*lwxs): New.
|
||||||
|
* config/mips/mips.opt (msmartmips): New.
|
||||||
|
* config/mips/mips.c (mips_lwxs_address_p): New.
|
||||||
|
(mips_rtx_costs): Make it recognize scaled indexed addressing.
|
||||||
|
* config/mips/mips.h (TARGET_CPU_CPP_BUILTINS): Define
|
||||||
|
__mips_smartmips when compiling for TARGET_SMARTMIPS.
|
||||||
|
(ISA_HAS_ROR): Define for TARGET_SMARTMIPS.
|
||||||
|
(ISA_HAS_LWXS): New.
|
||||||
|
(ASM_SPEC): Add -msmartmips/-mno-smartmips.
|
||||||
|
* doc/invoke.texi (MIPS Options): Document -msmartmips/-mno-smartmips.
|
||||||
|
* testsuite/gcc.target/mips/smartmips-lwxs.c: New test case.
|
||||||
|
* testsuite/gcc.target/mips/smartmips-ror-1.c: New test case.
|
||||||
|
* testsuite/gcc.target/mips/smartmips-ror-2.c: New test case.
|
||||||
|
* testsuite/gcc.target/mips/smartmips-ror-3.c: New test case.
|
||||||
|
* testsuite/gcc.target/mips/smartmips-ror-4.c: New test case.
|
||||||
|
|
||||||
2007-07-05 Dorit Nuzman <dorit@il.ibm.com>
|
2007-07-05 Dorit Nuzman <dorit@il.ibm.com>
|
||||||
|
|
||||||
* tree-vectorizer.c (new_loop_vec_info): Initialize
|
* tree-vectorizer.c (new_loop_vec_info): Initialize
|
||||||
|
@ -2682,6 +2682,26 @@ m16_nsimm8_8 (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
|
|||||||
return m16_check_op (op, (- 0x7f) << 3, 0x80 << 3, 7);
|
return m16_check_op (op, (- 0x7f) << 3, 0x80 << 3, 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return true if ADDR matches the pattern for the lwxs load scaled indexed
|
||||||
|
address instruction. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
mips_lwxs_address_p (rtx addr)
|
||||||
|
{
|
||||||
|
if (ISA_HAS_LWXS
|
||||||
|
&& GET_CODE (addr) == PLUS
|
||||||
|
&& REG_P (XEXP (addr, 1)))
|
||||||
|
{
|
||||||
|
rtx offset = XEXP (addr, 0);
|
||||||
|
if (GET_CODE (offset) == MULT
|
||||||
|
&& REG_P (XEXP (offset, 0))
|
||||||
|
&& GET_CODE (XEXP (offset, 1)) == CONST_INT
|
||||||
|
&& INTVAL (XEXP (offset, 1)) == 4)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
mips_rtx_costs (rtx x, int code, int outer_code, int *total)
|
mips_rtx_costs (rtx x, int code, int outer_code, int *total)
|
||||||
{
|
{
|
||||||
@ -2778,13 +2798,21 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total)
|
|||||||
case MEM:
|
case MEM:
|
||||||
{
|
{
|
||||||
/* If the address is legitimate, return the number of
|
/* If the address is legitimate, return the number of
|
||||||
instructions it needs, otherwise use the default handling. */
|
instructions it needs. */
|
||||||
int n = mips_address_insns (XEXP (x, 0), GET_MODE (x));
|
rtx addr = XEXP (x, 0);
|
||||||
|
int n = mips_address_insns (addr, GET_MODE (x));
|
||||||
if (n > 0)
|
if (n > 0)
|
||||||
{
|
{
|
||||||
*total = COSTS_N_INSNS (n + 1);
|
*total = COSTS_N_INSNS (n + 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
/* Check for scaled indexed address. */
|
||||||
|
if (mips_lwxs_address_p (addr))
|
||||||
|
{
|
||||||
|
*total = COSTS_N_INSNS (2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/* Otherwise use the default handling. */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,6 +366,9 @@ extern const struct mips_rtx_cost_data *mips_cost;
|
|||||||
\
|
\
|
||||||
if (TARGET_MIPS3D) \
|
if (TARGET_MIPS3D) \
|
||||||
builtin_define ("__mips3d"); \
|
builtin_define ("__mips3d"); \
|
||||||
|
\
|
||||||
|
if (TARGET_SMARTMIPS) \
|
||||||
|
builtin_define ("__mips_smartmips"); \
|
||||||
\
|
\
|
||||||
if (TARGET_DSP) \
|
if (TARGET_DSP) \
|
||||||
builtin_define ("__mips_dsp"); \
|
builtin_define ("__mips_dsp"); \
|
||||||
@ -733,7 +736,8 @@ extern const struct mips_rtx_cost_data *mips_cost;
|
|||||||
#define ISA_HAS_ROR ((ISA_MIPS32R2 \
|
#define ISA_HAS_ROR ((ISA_MIPS32R2 \
|
||||||
|| TARGET_MIPS5400 \
|
|| TARGET_MIPS5400 \
|
||||||
|| TARGET_MIPS5500 \
|
|| TARGET_MIPS5500 \
|
||||||
|| TARGET_SR71K) \
|
|| TARGET_SR71K \
|
||||||
|
|| TARGET_SMARTMIPS) \
|
||||||
&& !TARGET_MIPS16)
|
&& !TARGET_MIPS16)
|
||||||
|
|
||||||
/* ISA has data prefetch instructions. This controls use of 'pref'. */
|
/* ISA has data prefetch instructions. This controls use of 'pref'. */
|
||||||
@ -768,6 +772,9 @@ extern const struct mips_rtx_cost_data *mips_cost;
|
|||||||
/* ISA has instructions for accessing top part of 64-bit fp regs. */
|
/* ISA has instructions for accessing top part of 64-bit fp regs. */
|
||||||
#define ISA_HAS_MXHC1 (TARGET_FLOAT64 && ISA_MIPS32R2)
|
#define ISA_HAS_MXHC1 (TARGET_FLOAT64 && ISA_MIPS32R2)
|
||||||
|
|
||||||
|
/* ISA has lwxs instruction (load w/scaled index address. */
|
||||||
|
#define ISA_HAS_LWXS (TARGET_SMARTMIPS && !TARGET_MIPS16)
|
||||||
|
|
||||||
/* True if the result of a load is not available to the next instruction.
|
/* True if the result of a load is not available to the next instruction.
|
||||||
A nop will then be needed between instructions like "lw $4,..."
|
A nop will then be needed between instructions like "lw $4,..."
|
||||||
and "addiu $4,$4,1". */
|
and "addiu $4,$4,1". */
|
||||||
@ -883,6 +890,7 @@ extern const struct mips_rtx_cost_data *mips_cost;
|
|||||||
%{mdmx} %{mno-mdmx:-no-mdmx} \
|
%{mdmx} %{mno-mdmx:-no-mdmx} \
|
||||||
%{mdsp} %{mno-dsp} \
|
%{mdsp} %{mno-dsp} \
|
||||||
%{mdspr2} %{mno-dspr2} \
|
%{mdspr2} %{mno-dspr2} \
|
||||||
|
%{msmartmips} %{mno-smartmips} \
|
||||||
%{mmt} %{mno-mt} \
|
%{mmt} %{mno-mt} \
|
||||||
%{mfix-vr4120} %{mfix-vr4130} \
|
%{mfix-vr4120} %{mfix-vr4130} \
|
||||||
%(subtarget_asm_optimizing_spec) \
|
%(subtarget_asm_optimizing_spec) \
|
||||||
|
@ -3654,6 +3654,21 @@
|
|||||||
[(set_attr "type" "fpidxstore")
|
[(set_attr "type" "fpidxstore")
|
||||||
(set_attr "mode" "<ANYF:UNITMODE>")])
|
(set_attr "mode" "<ANYF:UNITMODE>")])
|
||||||
|
|
||||||
|
;; Scaled indexed address load.
|
||||||
|
;; Per md.texi, we only need to look for a pattern with multiply in the
|
||||||
|
;; address expression, not shift.
|
||||||
|
|
||||||
|
(define_insn "*lwxs"
|
||||||
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
||||||
|
(mem:SI (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d")
|
||||||
|
(const_int 4))
|
||||||
|
(match_operand:SI 2 "register_operand" "d"))))]
|
||||||
|
"ISA_HAS_LWXS"
|
||||||
|
"lwxs\t%0,%1(%2)"
|
||||||
|
[(set_attr "type" "load")
|
||||||
|
(set_attr "mode" "SI")
|
||||||
|
(set_attr "length" "4")])
|
||||||
|
|
||||||
;; 16-bit Integer moves
|
;; 16-bit Integer moves
|
||||||
|
|
||||||
;; Unlike most other insns, the move insns can't be split with
|
;; Unlike most other insns, the move insns can't be split with
|
||||||
|
@ -209,6 +209,10 @@ msingle-float
|
|||||||
Target Report RejectNegative Mask(SINGLE_FLOAT)
|
Target Report RejectNegative Mask(SINGLE_FLOAT)
|
||||||
Restrict the use of hardware floating-point instructions to 32-bit operations
|
Restrict the use of hardware floating-point instructions to 32-bit operations
|
||||||
|
|
||||||
|
msmartmips
|
||||||
|
Target Report RejectNegative Mask(SMARTMIPS)
|
||||||
|
Use SmartMIPS instructions
|
||||||
|
|
||||||
msoft-float
|
msoft-float
|
||||||
Target Report RejectNegative Mask(SOFT_FLOAT)
|
Target Report RejectNegative Mask(SOFT_FLOAT)
|
||||||
Prevent the use of all hardware floating-point instructions
|
Prevent the use of all hardware floating-point instructions
|
||||||
|
@ -622,6 +622,7 @@ Objective-C and Objective-C++ Dialects}.
|
|||||||
-mshared -mno-shared -mxgot -mno-xgot -mgp32 -mgp64 @gol
|
-mshared -mno-shared -mxgot -mno-xgot -mgp32 -mgp64 @gol
|
||||||
-mfp32 -mfp64 -mhard-float -msoft-float @gol
|
-mfp32 -mfp64 -mhard-float -msoft-float @gol
|
||||||
-msingle-float -mdouble-float -mdsp -mno-dsp -mdspr2 -mno-dspr2 @gol
|
-msingle-float -mdouble-float -mdsp -mno-dsp -mdspr2 -mno-dspr2 @gol
|
||||||
|
-msmartmips -mno-smartmips @gol
|
||||||
-mpaired-single -mno-paired-single -mdmx -mno-mdmx @gol
|
-mpaired-single -mno-paired-single -mdmx -mno-mdmx @gol
|
||||||
-mips3d -mno-mips3d -mmt -mno-mt @gol
|
-mips3d -mno-mips3d -mmt -mno-mt @gol
|
||||||
-mlong64 -mlong32 -msym32 -mno-sym32 @gol
|
-mlong64 -mlong32 -msym32 -mno-sym32 @gol
|
||||||
@ -11662,6 +11663,12 @@ Use (do not use) the MIPS DSP ASE. @xref{MIPS DSP Built-in Functions}.
|
|||||||
Use (do not use) the MIPS DSP ASE REV 2. @xref{MIPS DSP Built-in Functions}.
|
Use (do not use) the MIPS DSP ASE REV 2. @xref{MIPS DSP Built-in Functions}.
|
||||||
The option @option{-mdspr2} implies @option{-mdsp}.
|
The option @option{-mdspr2} implies @option{-mdsp}.
|
||||||
|
|
||||||
|
@item -msmartmips
|
||||||
|
@itemx -mno-smartmips
|
||||||
|
@opindex msmartmips
|
||||||
|
@opindex mno-smartmips
|
||||||
|
Use (do not use) the MIPS SmartMIPS ASE.
|
||||||
|
|
||||||
@item -mpaired-single
|
@item -mpaired-single
|
||||||
@itemx -mno-paired-single
|
@itemx -mno-paired-single
|
||||||
@opindex mpaired-single
|
@opindex mpaired-single
|
||||||
|
246
gcc/optabs.c
246
gcc/optabs.c
@ -1246,6 +1246,113 @@ swap_commutative_operands_with_target (rtx target, rtx op0, rtx op1)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper function for expand_binop: handle the case where there
|
||||||
|
is an insn that directly implements the indicated operation.
|
||||||
|
Returns null if this is not possible. */
|
||||||
|
static rtx
|
||||||
|
expand_binop_directly (enum machine_mode mode, optab binoptab,
|
||||||
|
rtx op0, rtx op1,
|
||||||
|
rtx target, int unsignedp, enum optab_methods methods,
|
||||||
|
int commutative_op, rtx last)
|
||||||
|
{
|
||||||
|
int icode = (int) binoptab->handlers[(int) mode].insn_code;
|
||||||
|
enum machine_mode mode0 = insn_data[icode].operand[1].mode;
|
||||||
|
enum machine_mode mode1 = insn_data[icode].operand[2].mode;
|
||||||
|
enum machine_mode tmp_mode;
|
||||||
|
rtx pat;
|
||||||
|
rtx xop0 = op0, xop1 = op1;
|
||||||
|
rtx temp;
|
||||||
|
|
||||||
|
if (target)
|
||||||
|
temp = target;
|
||||||
|
else
|
||||||
|
temp = gen_reg_rtx (mode);
|
||||||
|
|
||||||
|
/* If it is a commutative operator and the modes would match
|
||||||
|
if we would swap the operands, we can save the conversions. */
|
||||||
|
if (commutative_op)
|
||||||
|
{
|
||||||
|
if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1
|
||||||
|
&& GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0)
|
||||||
|
{
|
||||||
|
rtx tmp;
|
||||||
|
|
||||||
|
tmp = op0; op0 = op1; op1 = tmp;
|
||||||
|
tmp = xop0; xop0 = xop1; xop1 = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In case the insn wants input operands in modes different from
|
||||||
|
those of the actual operands, convert the operands. It would
|
||||||
|
seem that we don't need to convert CONST_INTs, but we do, so
|
||||||
|
that they're properly zero-extended, sign-extended or truncated
|
||||||
|
for their mode. */
|
||||||
|
|
||||||
|
if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
|
||||||
|
xop0 = convert_modes (mode0,
|
||||||
|
GET_MODE (op0) != VOIDmode
|
||||||
|
? GET_MODE (op0)
|
||||||
|
: mode,
|
||||||
|
xop0, unsignedp);
|
||||||
|
|
||||||
|
if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
|
||||||
|
xop1 = convert_modes (mode1,
|
||||||
|
GET_MODE (op1) != VOIDmode
|
||||||
|
? GET_MODE (op1)
|
||||||
|
: mode,
|
||||||
|
xop1, unsignedp);
|
||||||
|
|
||||||
|
/* Now, if insn's predicates don't allow our operands, put them into
|
||||||
|
pseudo regs. */
|
||||||
|
|
||||||
|
if (!insn_data[icode].operand[1].predicate (xop0, mode0)
|
||||||
|
&& mode0 != VOIDmode)
|
||||||
|
xop0 = copy_to_mode_reg (mode0, xop0);
|
||||||
|
|
||||||
|
if (!insn_data[icode].operand[2].predicate (xop1, mode1)
|
||||||
|
&& mode1 != VOIDmode)
|
||||||
|
xop1 = copy_to_mode_reg (mode1, xop1);
|
||||||
|
|
||||||
|
if (binoptab == vec_pack_trunc_optab
|
||||||
|
|| binoptab == vec_pack_usat_optab
|
||||||
|
|| binoptab == vec_pack_ssat_optab
|
||||||
|
|| binoptab == vec_pack_ufix_trunc_optab
|
||||||
|
|| binoptab == vec_pack_sfix_trunc_optab)
|
||||||
|
{
|
||||||
|
/* The mode of the result is different then the mode of the
|
||||||
|
arguments. */
|
||||||
|
tmp_mode = insn_data[icode].operand[0].mode;
|
||||||
|
if (GET_MODE_NUNITS (tmp_mode) != 2 * GET_MODE_NUNITS (mode))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tmp_mode = mode;
|
||||||
|
|
||||||
|
if (!insn_data[icode].operand[0].predicate (temp, tmp_mode))
|
||||||
|
temp = gen_reg_rtx (tmp_mode);
|
||||||
|
|
||||||
|
pat = GEN_FCN (icode) (temp, xop0, xop1);
|
||||||
|
if (pat)
|
||||||
|
{
|
||||||
|
/* If PAT is composed of more than one insn, try to add an appropriate
|
||||||
|
REG_EQUAL note to it. If we can't because TEMP conflicts with an
|
||||||
|
operand, call expand_binop again, this time without a target. */
|
||||||
|
if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
|
||||||
|
&& ! add_equal_note (pat, temp, binoptab->code, xop0, xop1))
|
||||||
|
{
|
||||||
|
delete_insns_since (last);
|
||||||
|
return expand_binop (mode, binoptab, op0, op1, NULL_RTX,
|
||||||
|
unsignedp, methods);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit_insn (pat);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_insns_since (last);
|
||||||
|
return NULL_RTX;
|
||||||
|
}
|
||||||
|
|
||||||
/* Generate code to perform an operation specified by BINOPTAB
|
/* Generate code to perform an operation specified by BINOPTAB
|
||||||
on operands OP0 and OP1, with result having machine-mode MODE.
|
on operands OP0 and OP1, with result having machine-mode MODE.
|
||||||
|
|
||||||
@ -1275,7 +1382,6 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
|
|||||||
|| binoptab->code == ROTATERT);
|
|| binoptab->code == ROTATERT);
|
||||||
rtx entry_last = get_last_insn ();
|
rtx entry_last = get_last_insn ();
|
||||||
rtx last;
|
rtx last;
|
||||||
bool first_pass_p = true;
|
|
||||||
|
|
||||||
class = GET_MODE_CLASS (mode);
|
class = GET_MODE_CLASS (mode);
|
||||||
|
|
||||||
@ -1329,123 +1435,43 @@ 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 we can do it with a three-operand insn, do so. */
|
||||||
|
|
||||||
if (methods != OPTAB_MUST_WIDEN
|
if (methods != OPTAB_MUST_WIDEN
|
||||||
&& binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
|
&& binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
|
||||||
{
|
{
|
||||||
int icode = (int) binoptab->handlers[(int) mode].insn_code;
|
temp = expand_binop_directly (mode, binoptab, op0, op1, target,
|
||||||
enum machine_mode mode0 = insn_data[icode].operand[1].mode;
|
unsignedp, methods, commutative_op, last);
|
||||||
enum machine_mode mode1 = insn_data[icode].operand[2].mode;
|
if (temp)
|
||||||
enum machine_mode tmp_mode;
|
return temp;
|
||||||
rtx pat;
|
|
||||||
rtx xop0 = op0, xop1 = op1;
|
|
||||||
|
|
||||||
if (target)
|
|
||||||
temp = target;
|
|
||||||
else
|
|
||||||
temp = gen_reg_rtx (mode);
|
|
||||||
|
|
||||||
/* If it is a commutative operator and the modes would match
|
|
||||||
if we would swap the operands, we can save the conversions. */
|
|
||||||
if (commutative_op)
|
|
||||||
{
|
|
||||||
if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1
|
|
||||||
&& GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0)
|
|
||||||
{
|
|
||||||
rtx tmp;
|
|
||||||
|
|
||||||
tmp = op0; op0 = op1; op1 = tmp;
|
|
||||||
tmp = xop0; xop0 = xop1; xop1 = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* In case the insn wants input operands in modes different from
|
|
||||||
those of the actual operands, convert the operands. It would
|
|
||||||
seem that we don't need to convert CONST_INTs, but we do, so
|
|
||||||
that they're properly zero-extended, sign-extended or truncated
|
|
||||||
for their mode. */
|
|
||||||
|
|
||||||
if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
|
|
||||||
xop0 = convert_modes (mode0,
|
|
||||||
GET_MODE (op0) != VOIDmode
|
|
||||||
? GET_MODE (op0)
|
|
||||||
: mode,
|
|
||||||
xop0, unsignedp);
|
|
||||||
|
|
||||||
if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
|
|
||||||
xop1 = convert_modes (mode1,
|
|
||||||
GET_MODE (op1) != VOIDmode
|
|
||||||
? GET_MODE (op1)
|
|
||||||
: mode,
|
|
||||||
xop1, unsignedp);
|
|
||||||
|
|
||||||
/* Now, if insn's predicates don't allow our operands, put them into
|
|
||||||
pseudo regs. */
|
|
||||||
|
|
||||||
if (!insn_data[icode].operand[1].predicate (xop0, mode0)
|
|
||||||
&& mode0 != VOIDmode)
|
|
||||||
xop0 = copy_to_mode_reg (mode0, xop0);
|
|
||||||
|
|
||||||
if (!insn_data[icode].operand[2].predicate (xop1, mode1)
|
|
||||||
&& mode1 != VOIDmode)
|
|
||||||
xop1 = copy_to_mode_reg (mode1, xop1);
|
|
||||||
|
|
||||||
if (binoptab == vec_pack_trunc_optab
|
|
||||||
|| binoptab == vec_pack_usat_optab
|
|
||||||
|| binoptab == vec_pack_ssat_optab
|
|
||||||
|| binoptab == vec_pack_ufix_trunc_optab
|
|
||||||
|| binoptab == vec_pack_sfix_trunc_optab)
|
|
||||||
{
|
|
||||||
/* The mode of the result is different then the mode of the
|
|
||||||
arguments. */
|
|
||||||
tmp_mode = insn_data[icode].operand[0].mode;
|
|
||||||
if (GET_MODE_NUNITS (tmp_mode) != 2 * GET_MODE_NUNITS (mode))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
tmp_mode = mode;
|
|
||||||
|
|
||||||
if (!insn_data[icode].operand[0].predicate (temp, tmp_mode))
|
|
||||||
temp = gen_reg_rtx (tmp_mode);
|
|
||||||
|
|
||||||
pat = GEN_FCN (icode) (temp, xop0, xop1);
|
|
||||||
if (pat)
|
|
||||||
{
|
|
||||||
/* If PAT is composed of more than one insn, try to add an appropriate
|
|
||||||
REG_EQUAL note to it. If we can't because TEMP conflicts with an
|
|
||||||
operand, call ourselves again, this time without a target. */
|
|
||||||
if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
|
|
||||||
&& ! add_equal_note (pat, temp, binoptab->code, xop0, xop1))
|
|
||||||
{
|
|
||||||
delete_insns_since (last);
|
|
||||||
return expand_binop (mode, binoptab, op0, op1, NULL_RTX,
|
|
||||||
unsignedp, methods);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit_insn (pat);
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
delete_insns_since (last);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we were trying to rotate by a constant value, and that didn't
|
/* If we were trying to rotate, and that didn't work, try rotating
|
||||||
work, try rotating the other direction before falling back to
|
the other direction before falling back to shifts and bitwise-or. */
|
||||||
shifts and bitwise-or. */
|
if (((binoptab == rotl_optab
|
||||||
if (first_pass_p
|
&& rotr_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
|
||||||
&& (binoptab == rotl_optab || binoptab == rotr_optab)
|
|| (binoptab == rotr_optab
|
||||||
&& class == MODE_INT
|
&& rotl_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing))
|
||||||
&& GET_CODE (op1) == CONST_INT
|
&& class == MODE_INT)
|
||||||
&& INTVAL (op1) > 0
|
|
||||||
&& (unsigned int) INTVAL (op1) < GET_MODE_BITSIZE (mode))
|
|
||||||
{
|
{
|
||||||
first_pass_p = false;
|
optab otheroptab = (binoptab == rotl_optab ? rotr_optab : rotl_optab);
|
||||||
op1 = GEN_INT (GET_MODE_BITSIZE (mode) - INTVAL (op1));
|
rtx newop1;
|
||||||
binoptab = binoptab == rotl_optab ? rotr_optab : rotl_optab;
|
int bits = GET_MODE_BITSIZE (mode);
|
||||||
goto retry;
|
|
||||||
|
if (GET_CODE (op1) == CONST_INT)
|
||||||
|
newop1 = GEN_INT (bits - INTVAL (op1));
|
||||||
|
else if (targetm.shift_truncation_mask (mode) == bits - 1)
|
||||||
|
newop1 = negate_rtx (mode, op1);
|
||||||
|
else
|
||||||
|
newop1 = expand_binop (mode, sub_optab,
|
||||||
|
GEN_INT (bits), op1,
|
||||||
|
NULL_RTX, unsignedp, OPTAB_DIRECT);
|
||||||
|
|
||||||
|
temp = expand_binop_directly (mode, otheroptab, op0, newop1,
|
||||||
|
target, unsignedp, methods,
|
||||||
|
commutative_op, last);
|
||||||
|
if (temp)
|
||||||
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If this is a multiply, see if we can do a widening operation that
|
/* If this is a multiply, see if we can do a widening operation that
|
||||||
|
8
gcc/testsuite/gcc.target/mips/smartmips-lwxs.c
Normal file
8
gcc/testsuite/gcc.target/mips/smartmips-lwxs.c
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-mips-options "-O -msmartmips -mno-mips16" } */
|
||||||
|
|
||||||
|
int scaled_indexed_word_load (int a[], int b)
|
||||||
|
{
|
||||||
|
return a[b];
|
||||||
|
}
|
||||||
|
/* { dg-final { scan-assembler "\tlwxs\t" } } */
|
8
gcc/testsuite/gcc.target/mips/smartmips-ror-1.c
Normal file
8
gcc/testsuite/gcc.target/mips/smartmips-ror-1.c
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-mips-options "-O -msmartmips -mno-mips16" } */
|
||||||
|
|
||||||
|
int rotate_left (unsigned a, unsigned s)
|
||||||
|
{
|
||||||
|
return (a << s) | (a >> (32 - s));
|
||||||
|
}
|
||||||
|
/* { dg-final { scan-assembler "\tror\t" } } */
|
8
gcc/testsuite/gcc.target/mips/smartmips-ror-2.c
Normal file
8
gcc/testsuite/gcc.target/mips/smartmips-ror-2.c
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-mips-options "-O -msmartmips -mno-mips16" } */
|
||||||
|
|
||||||
|
int rotate_right (unsigned a, unsigned s)
|
||||||
|
{
|
||||||
|
return (a >> s) | (a << (32 - s));
|
||||||
|
}
|
||||||
|
/* { dg-final { scan-assembler "\tror\t" } } */
|
10
gcc/testsuite/gcc.target/mips/smartmips-ror-3.c
Normal file
10
gcc/testsuite/gcc.target/mips/smartmips-ror-3.c
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-mips-options "-O -msmartmips -mno-mips16" } */
|
||||||
|
|
||||||
|
#define S 13
|
||||||
|
|
||||||
|
int rotate_left_constant (unsigned a)
|
||||||
|
{
|
||||||
|
return (a << S) | (a >> (32 - S));
|
||||||
|
}
|
||||||
|
/* { dg-final { scan-assembler "\tror\t" } } */
|
10
gcc/testsuite/gcc.target/mips/smartmips-ror-4.c
Normal file
10
gcc/testsuite/gcc.target/mips/smartmips-ror-4.c
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-mips-options "-O -msmartmips -mno-mips16" } */
|
||||||
|
|
||||||
|
#define S 13
|
||||||
|
|
||||||
|
int rotate_right_constant (unsigned a)
|
||||||
|
{
|
||||||
|
return (a >> S) | (a << (32 - S));
|
||||||
|
}
|
||||||
|
/* { dg-final { scan-assembler "\tror\t" } } */
|
Loading…
x
Reference in New Issue
Block a user