This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH: Add SmartMIPS support
- From: Sandra Loosemore <sandra at codesourcery dot com>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Cc: David Ung <davidu at mips dot com>, Nigel Stephens <nigel at mips dot com>, Guy Morrogh <guym at mips dot com>
- Date: Wed, 04 Jul 2007 12:33:34 -0400
- Subject: PATCH: Add SmartMIPS support
This patch includes a piece that is not MIPS-specific to make expand_binop
smarter about trying both left and right rotate patterns.
OK to commit?
-Sandra
2007-07-04 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_mult): 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.
Index: gcc/optabs.c
===================================================================
*** gcc/optabs.c (revision 126323)
--- gcc/optabs.c (working copy)
*************** swap_commutative_operands_with_target (r
*** 1246,1251 ****
--- 1246,1358 ----
}
+ /* 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
on operands OP0 and OP1, with result having machine-mode MODE.
*************** expand_binop (enum machine_mode mode, op
*** 1275,1281 ****
|| binoptab->code == ROTATERT);
rtx entry_last = get_last_insn ();
rtx last;
- bool first_pass_p = true;
class = GET_MODE_CLASS (mode);
--- 1382,1387 ----
*************** expand_binop (enum machine_mode mode, op
*** 1329,1451 ****
}
}
- 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;
! 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;
!
! 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
! 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
--- 1435,1477 ----
}
}
/* 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
Index: gcc/config/mips/mips.md
===================================================================
*** gcc/config/mips/mips.md (revision 126323)
--- gcc/config/mips/mips.md (working copy)
***************
*** 3619,3624 ****
--- 3619,3639 ----
[(set_attr "type" "fpidxstore")
(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_mult"
+ [(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
;; Unlike most other insns, the move insns can't be split with
Index: gcc/config/mips/mips.opt
===================================================================
*** gcc/config/mips/mips.opt (revision 126323)
--- gcc/config/mips/mips.opt (working copy)
*************** msingle-float
*** 209,214 ****
--- 209,218 ----
Target Report RejectNegative Mask(SINGLE_FLOAT)
Restrict the use of hardware floating-point instructions to 32-bit operations
+ msmartmips
+ Target Report RejectNegative Mask(SMARTMIPS)
+ Use SmartMIPS instructions
+
msoft-float
Target Report RejectNegative Mask(SOFT_FLOAT)
Prevent the use of all hardware floating-point instructions
Index: gcc/config/mips/mips.c
===================================================================
*** gcc/config/mips/mips.c (revision 126323)
--- gcc/config/mips/mips.c (working copy)
*************** m16_nsimm8_8 (rtx op, enum machine_mode
*** 2682,2687 ****
--- 2684,2709 ----
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
mips_rtx_costs (rtx x, int code, int outer_code, int *total)
{
*************** mips_rtx_costs (rtx x, int code, int out
*** 2778,2790 ****
case MEM:
{
/* If the address is legitimate, return the number of
! instructions it needs, otherwise use the default handling. */
! int n = mips_address_insns (XEXP (x, 0), GET_MODE (x));
if (n > 0)
{
*total = COSTS_N_INSNS (n + 1);
return true;
}
return false;
}
--- 2800,2820 ----
case MEM:
{
/* If the address is legitimate, return the number of
! instructions it needs. */
! rtx addr = XEXP (x, 0);
! int n = mips_address_insns (addr, GET_MODE (x));
if (n > 0)
{
*total = COSTS_N_INSNS (n + 1);
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;
}
Index: gcc/config/mips/mips.h
===================================================================
*** gcc/config/mips/mips.h (revision 126323)
--- gcc/config/mips/mips.h (working copy)
*************** extern const struct mips_rtx_cost_data *
*** 366,371 ****
--- 366,374 ----
\
if (TARGET_MIPS3D) \
builtin_define ("__mips3d"); \
+ \
+ if (TARGET_SMARTMIPS) \
+ builtin_define ("__mips_smartmips"); \
\
if (TARGET_DSP) \
builtin_define ("__mips_dsp"); \
*************** extern const struct mips_rtx_cost_data *
*** 733,739 ****
#define ISA_HAS_ROR ((ISA_MIPS32R2 \
|| TARGET_MIPS5400 \
|| TARGET_MIPS5500 \
! || TARGET_SR71K) \
&& !TARGET_MIPS16)
/* ISA has data prefetch instructions. This controls use of 'pref'. */
--- 736,743 ----
#define ISA_HAS_ROR ((ISA_MIPS32R2 \
|| TARGET_MIPS5400 \
|| TARGET_MIPS5500 \
! || TARGET_SR71K \
! || TARGET_SMARTMIPS) \
&& !TARGET_MIPS16)
/* ISA has data prefetch instructions. This controls use of 'pref'. */
*************** extern const struct mips_rtx_cost_data *
*** 768,773 ****
--- 772,780 ----
/* ISA has instructions for accessing top part of 64-bit fp regs. */
#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.
A nop will then be needed between instructions like "lw $4,..."
and "addiu $4,$4,1". */
*************** extern const struct mips_rtx_cost_data *
*** 883,888 ****
--- 890,896 ----
%{mdmx} %{mno-mdmx:-no-mdmx} \
%{mdsp} %{mno-dsp} \
%{mdspr2} %{mno-dspr2} \
+ %{msmartmips} %{mno-smartmips} \
%{mmt} %{mno-mt} \
%{mfix-vr4120} %{mfix-vr4130} \
%(subtarget_asm_optimizing_spec) \
Index: gcc/doc/invoke.texi
===================================================================
*** gcc/doc/invoke.texi (revision 126323)
--- gcc/doc/invoke.texi (working copy)
*************** Objective-C and Objective-C++ Dialects}.
*** 622,627 ****
--- 622,628 ----
-mshared -mno-shared -mxgot -mno-xgot -mgp32 -mgp64 @gol
-mfp32 -mfp64 -mhard-float -msoft-float @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
-mips3d -mno-mips3d -mmt -mno-mt @gol
-mlong64 -mlong32 -msym32 -mno-sym32 @gol
*************** Use (do not use) the MIPS DSP ASE. @xre
*** 11662,11667 ****
--- 11663,11674 ----
Use (do not use) the MIPS DSP ASE REV 2. @xref{MIPS DSP Built-in Functions}.
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
@itemx -mno-paired-single
@opindex mpaired-single
Index: gcc/testsuite/gcc.target/mips/smartmips-lwxs.c
===================================================================
*** gcc/testsuite/gcc.target/mips/smartmips-lwxs.c (revision 0)
--- gcc/testsuite/gcc.target/mips/smartmips-lwxs.c (revision 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" } } */
Index: gcc/testsuite/gcc.target/mips/smartmips-ror-1.c
===================================================================
*** gcc/testsuite/gcc.target/mips/smartmips-ror-1.c (revision 0)
--- gcc/testsuite/gcc.target/mips/smartmips-ror-1.c (revision 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" } } */
Index: gcc/testsuite/gcc.target/mips/smartmips-ror-2.c
===================================================================
*** gcc/testsuite/gcc.target/mips/smartmips-ror-2.c (revision 0)
--- gcc/testsuite/gcc.target/mips/smartmips-ror-2.c (revision 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" } } */
Index: gcc/testsuite/gcc.target/mips/smartmips-ror-3.c
===================================================================
*** gcc/testsuite/gcc.target/mips/smartmips-ror-3.c (revision 0)
--- gcc/testsuite/gcc.target/mips/smartmips-ror-3.c (revision 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" } } */
Index: gcc/testsuite/gcc.target/mips/smartmips-ror-4.c
===================================================================
*** gcc/testsuite/gcc.target/mips/smartmips-ror-4.c (revision 0)
--- gcc/testsuite/gcc.target/mips/smartmips-ror-4.c (revision 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" } } */