Commit 0aa222d1 by Sandra Loosemore Committed by Sandra Loosemore

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
parent 6fd2892a
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) ...@@ -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) ...@@ -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;
} }
......
...@@ -367,6 +367,9 @@ extern const struct mips_rtx_cost_data *mips_cost; ...@@ -367,6 +367,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; ...@@ -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; ...@@ -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; ...@@ -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 @@ ...@@ -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 ...@@ -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}. ...@@ -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}. ...@@ -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
......
...@@ -1246,102 +1246,22 @@ swap_commutative_operands_with_target (rtx target, rtx op0, rtx op1) ...@@ -1246,102 +1246,22 @@ swap_commutative_operands_with_target (rtx target, rtx op0, rtx op1)
} }
/* Generate code to perform an operation specified by BINOPTAB /* Helper function for expand_binop: handle the case where there
on operands OP0 and OP1, with result having machine-mode MODE. is an insn that directly implements the indicated operation.
Returns null if this is not possible. */
UNSIGNEDP is for the case where we have to widen the operands static rtx
to perform the operation. It says to use zero-extension. expand_binop_directly (enum machine_mode mode, optab binoptab,
rtx op0, rtx op1,
If TARGET is nonzero, the value rtx target, int unsignedp, enum optab_methods methods,
is generated there, if it is convenient to do so. int commutative_op, rtx last)
In all cases an rtx is returned for the locus of the value;
this may or may not be TARGET. */
rtx
expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
rtx target, int unsignedp, enum optab_methods methods)
{ {
enum optab_methods next_methods
= (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN
? OPTAB_WIDEN : methods);
enum mode_class class;
enum machine_mode wider_mode;
rtx temp;
int commutative_op = 0;
int shift_op = (binoptab->code == ASHIFT
|| binoptab->code == ASHIFTRT
|| binoptab->code == LSHIFTRT
|| binoptab->code == ROTATE
|| binoptab->code == ROTATERT);
rtx entry_last = get_last_insn ();
rtx last;
bool first_pass_p = true;
class = GET_MODE_CLASS (mode);
/* If subtracting an integer constant, convert this into an addition of
the negated constant. */
if (binoptab == sub_optab && GET_CODE (op1) == CONST_INT)
{
op1 = negate_rtx (mode, op1);
binoptab = add_optab;
}
/* If we are inside an appropriately-short loop and we are optimizing,
force expensive constants into a register. */
if (CONSTANT_P (op0) && optimize
&& rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1))
{
if (GET_MODE (op0) != VOIDmode)
op0 = convert_modes (mode, VOIDmode, op0, unsignedp);
op0 = force_reg (mode, op0);
}
if (CONSTANT_P (op1) && optimize
&& ! shift_op && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1))
{
if (GET_MODE (op1) != VOIDmode)
op1 = convert_modes (mode, VOIDmode, op1, unsignedp);
op1 = force_reg (mode, op1);
}
/* Record where to delete back to if we backtrack. */
last = get_last_insn ();
/* If operation is commutative,
try to make the first operand a register.
Even better, try to make it the same as the target.
Also try to make the last operand a constant. */
if (GET_RTX_CLASS (binoptab->code) == RTX_COMM_ARITH
|| binoptab == smul_widen_optab
|| binoptab == umul_widen_optab
|| binoptab == smul_highpart_optab
|| binoptab == umul_highpart_optab)
{
commutative_op = 1;
if (swap_commutative_operands_with_target (target, op0, op1))
{
temp = op1;
op1 = op0;
op0 = temp;
}
}
retry:
/* If we can do it with a three-operand insn, do so. */
if (methods != OPTAB_MUST_WIDEN
&& binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
int icode = (int) binoptab->handlers[(int) mode].insn_code; int icode = (int) binoptab->handlers[(int) mode].insn_code;
enum machine_mode mode0 = insn_data[icode].operand[1].mode; enum machine_mode mode0 = insn_data[icode].operand[1].mode;
enum machine_mode mode1 = insn_data[icode].operand[2].mode; enum machine_mode mode1 = insn_data[icode].operand[2].mode;
enum machine_mode tmp_mode; enum machine_mode tmp_mode;
rtx pat; rtx pat;
rtx xop0 = op0, xop1 = op1; rtx xop0 = op0, xop1 = op1;
rtx temp;
if (target) if (target)
temp = target; temp = target;
...@@ -1416,7 +1336,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, ...@@ -1416,7 +1336,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
{ {
/* If PAT is composed of more than one insn, try to add an appropriate /* 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 REG_EQUAL note to it. If we can't because TEMP conflicts with an
operand, call ourselves again, this time without a target. */ operand, call expand_binop again, this time without a target. */
if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
&& ! add_equal_note (pat, temp, binoptab->code, xop0, xop1)) && ! add_equal_note (pat, temp, binoptab->code, xop0, xop1))
{ {
...@@ -1428,24 +1348,130 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, ...@@ -1428,24 +1348,130 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
emit_insn (pat); emit_insn (pat);
return temp; return temp;
} }
else
delete_insns_since (last); delete_insns_since (last);
return NULL_RTX;
}
/* Generate code to perform an operation specified by BINOPTAB
on operands OP0 and OP1, with result having machine-mode MODE.
UNSIGNEDP is for the case where we have to widen the operands
to perform the operation. It says to use zero-extension.
If TARGET is nonzero, the value
is generated there, if it is convenient to do so.
In all cases an rtx is returned for the locus of the value;
this may or may not be TARGET. */
rtx
expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
rtx target, int unsignedp, enum optab_methods methods)
{
enum optab_methods next_methods
= (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN
? OPTAB_WIDEN : methods);
enum mode_class class;
enum machine_mode wider_mode;
rtx temp;
int commutative_op = 0;
int shift_op = (binoptab->code == ASHIFT
|| binoptab->code == ASHIFTRT
|| binoptab->code == LSHIFTRT
|| binoptab->code == ROTATE
|| binoptab->code == ROTATERT);
rtx entry_last = get_last_insn ();
rtx last;
class = GET_MODE_CLASS (mode);
/* If subtracting an integer constant, convert this into an addition of
the negated constant. */
if (binoptab == sub_optab && GET_CODE (op1) == CONST_INT)
{
op1 = negate_rtx (mode, op1);
binoptab = add_optab;
} }
/* If we were trying to rotate by a constant value, and that didn't /* If we are inside an appropriately-short loop and we are optimizing,
work, try rotating the other direction before falling back to force expensive constants into a register. */
shifts and bitwise-or. */ if (CONSTANT_P (op0) && optimize
if (first_pass_p && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1))
&& (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; if (GET_MODE (op0) != VOIDmode)
op1 = GEN_INT (GET_MODE_BITSIZE (mode) - INTVAL (op1)); op0 = convert_modes (mode, VOIDmode, op0, unsignedp);
binoptab = binoptab == rotl_optab ? rotr_optab : rotl_optab; op0 = force_reg (mode, op0);
goto retry; }
if (CONSTANT_P (op1) && optimize
&& ! shift_op && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1))
{
if (GET_MODE (op1) != VOIDmode)
op1 = convert_modes (mode, VOIDmode, op1, unsignedp);
op1 = force_reg (mode, op1);
}
/* Record where to delete back to if we backtrack. */
last = get_last_insn ();
/* If operation is commutative,
try to make the first operand a register.
Even better, try to make it the same as the target.
Also try to make the last operand a constant. */
if (GET_RTX_CLASS (binoptab->code) == RTX_COMM_ARITH
|| binoptab == smul_widen_optab
|| binoptab == umul_widen_optab
|| binoptab == smul_highpart_optab
|| binoptab == umul_highpart_optab)
{
commutative_op = 1;
if (swap_commutative_operands_with_target (target, op0, op1))
{
temp = op1;
op1 = op0;
op0 = temp;
}
}
/* If we can do it with a three-operand insn, do so. */
if (methods != OPTAB_MUST_WIDEN
&& binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
temp = expand_binop_directly (mode, binoptab, op0, op1, target,
unsignedp, methods, commutative_op, last);
if (temp)
return temp;
}
/* If we were trying to rotate, and that didn't work, try rotating
the other direction before falling back to shifts and bitwise-or. */
if (((binoptab == rotl_optab
&& rotr_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
|| (binoptab == rotr_optab
&& rotl_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing))
&& class == MODE_INT)
{
optab otheroptab = (binoptab == rotl_optab ? rotr_optab : rotl_optab);
rtx newop1;
int bits = GET_MODE_BITSIZE (mode);
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
......
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment