summaryrefslogtreecommitdiff
path: root/gcc/config/sh
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2012-03-08 10:11:09 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2012-03-08 10:11:09 +0000
commit6195c0dd4e15f50ac89491b48e050751f8231304 (patch)
tree1f49de2cfcd902f18c22b5539315d7b0fb4db972 /gcc/config/sh
parentd7ce7f9586bca838e0dcc7e39100ffe6edcd74f3 (diff)
downloadgcc-6195c0dd4e15f50ac89491b48e050751f8231304.tar.gz
2012-03-08 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk [future 4.8] rev 185094 using svnmerge 2011-03-08 Basile Starynkevitch <basile@starynkevitch.net> [gcc/] * melt-build.tpl (meltframe.args): Add -Iinclude-fixed if it exists. * melt-build.mk: Regenerate. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@185096 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/sh')
-rw-r--r--gcc/config/sh/constraints.md4
-rw-r--r--gcc/config/sh/linux.h15
-rw-r--r--gcc/config/sh/predicates.md2
-rw-r--r--gcc/config/sh/sh-protos.h3
-rw-r--r--gcc/config/sh/sh.c97
-rw-r--r--gcc/config/sh/sh.h6
-rw-r--r--gcc/config/sh/sh.md177
-rw-r--r--gcc/config/sh/sh.opt6
-rw-r--r--gcc/config/sh/sync.md108
9 files changed, 326 insertions, 92 deletions
diff --git a/gcc/config/sh/constraints.md b/gcc/config/sh/constraints.md
index f122a486385..12a4a990201 100644
--- a/gcc/config/sh/constraints.md
+++ b/gcc/config/sh/constraints.md
@@ -1,5 +1,5 @@
;; Constraint definitions for Renesas / SuperH SH.
-;; Copyright (C) 2007, 2008, 2011 Free Software Foundation, Inc.
+;; Copyright (C) 2007, 2008, 2011, 2012 Free Software Foundation, Inc.
;;
;; This file is part of GCC.
;;
@@ -139,7 +139,7 @@
(match_test "ival >= 0 && ival <= 255")))
(define_constraint "K12"
- "An unsigned 8-bit constant, as used in SH2A 12-bit displacement addressing."
+ "An unsigned 12-bit constant, as used in SH2A 12-bit displacement addressing."
(and (match_code "const_int")
(match_test "ival >= 0 && ival <= 4095")))
diff --git a/gcc/config/sh/linux.h b/gcc/config/sh/linux.h
index a5c2734214b..904a7823bf2 100644
--- a/gcc/config/sh/linux.h
+++ b/gcc/config/sh/linux.h
@@ -1,5 +1,6 @@
/* Definitions for SH running Linux-based GNU systems using ELF
- Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2010, 2011
+ Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2010, 2011,
+ 2012
Free Software Foundation, Inc.
Contributed by Kazumoto Kojima <kkojima@rr.iij4u.or.jp>
@@ -41,7 +42,7 @@ along with GCC; see the file COPYING3. If not see
#undef TARGET_DEFAULT
#define TARGET_DEFAULT \
(TARGET_CPU_DEFAULT | MASK_USERMODE | TARGET_ENDIAN_DEFAULT \
- | TARGET_OPT_DEFAULT | MASK_SOFT_ATOMIC)
+ | TARGET_OPT_DEFAULT)
#define TARGET_ASM_FILE_END file_end_indicate_exec_stack
@@ -135,3 +136,13 @@ along with GCC; see the file COPYING3. If not see
/* Install the __sync libcalls. */
#undef TARGET_INIT_LIBFUNCS
#define TARGET_INIT_LIBFUNCS sh_init_sync_libfuncs
+
+#undef SUBTARGET_OVERRIDE_OPTIONS
+#define SUBTARGET_OVERRIDE_OPTIONS \
+ do \
+ { \
+ /* Defaulting to -msoft-atomic. */ \
+ if (global_options_set.x_TARGET_SOFT_ATOMIC == 0) \
+ TARGET_SOFT_ATOMIC = 1; \
+ } \
+ while (0)
diff --git a/gcc/config/sh/predicates.md b/gcc/config/sh/predicates.md
index 00fd6af44bb..9745d63267e 100644
--- a/gcc/config/sh/predicates.md
+++ b/gcc/config/sh/predicates.md
@@ -1,5 +1,5 @@
;; Predicate definitions for Renesas / SuperH SH.
-;; Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010
+;; Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2012
;; Free Software Foundation, Inc.
;;
;; This file is part of GCC.
diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h
index ff94b1072f5..a2331e19bb4 100644
--- a/gcc/config/sh/sh-protos.h
+++ b/gcc/config/sh/sh-protos.h
@@ -1,6 +1,6 @@
/* Definitions of target machine for GNU compiler for Renesas / SuperH SH.
Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2003,
- 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
Contributed by Steve Chamberlain (sac@cygnus.com).
Improved by Jim Wilson (wilson@cygnus.com).
@@ -104,7 +104,6 @@ extern int fp_arith_reg_operand (rtx, enum machine_mode);
extern int arith_operand (rtx, enum machine_mode);
extern int arith_reg_or_0_operand (rtx, enum machine_mode);
extern int logical_operand (rtx, enum machine_mode);
-extern int tertiary_reload_operand (rtx, enum machine_mode);
extern int fpscr_operand (rtx, enum machine_mode);
extern int fpul_operand (rtx, enum machine_mode);
extern int commutative_float_operator (rtx, enum machine_mode);
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 5eb96c55e77..4c2d710aea3 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -1,6 +1,6 @@
/* Output routines for GCC for Renesas / SuperH SH.
Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
Contributed by Steve Chamberlain (sac@cygnus.com).
Improved by Jim Wilson (wilson@cygnus.com).
@@ -575,6 +575,11 @@ static const struct attribute_spec sh_attribute_table[] =
/* Machine-specific symbol_ref flags. */
#define SYMBOL_FLAG_FUNCVEC_FUNCTION (SYMBOL_FLAG_MACH_DEP << 0)
+/* The tas.b instruction sets the 7th bit in the byte, i.e. 0x80. This value
+ is used by optabs.c atomic op expansion code as well as in sync.md. */
+#undef TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
+#define TARGET_ATOMIC_TEST_AND_SET_TRUEVAL 0x80
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Implement TARGET_OPTION_OVERRIDE macro. Validate and override
@@ -816,20 +821,42 @@ sh_option_override (void)
}
}
+ /* Adjust loop, jump and function alignment values (in bytes), if those
+ were not specified by the user using -falign-loops, -falign-jumps
+ and -falign-functions options.
+ 32 bit alignment is better for speed, because instructions can be
+ fetched as a pair from a longword boundary. For size use 16 bit
+ alignment to get more compact code.
+ Aligning all jumps increases the code size, even if it might
+ result in slightly faster code. Thus, it is set to the smallest
+ alignment possible if not specified by the user. */
if (align_loops == 0)
- align_loops = 1 << (TARGET_SH5 ? 3 : 2);
+ {
+ if (TARGET_SH5)
+ align_loops = 8;
+ else
+ align_loops = optimize_size ? 2 : 4;
+ }
+
if (align_jumps == 0)
- align_jumps = 1 << CACHE_LOG;
+ {
+ if (TARGET_SHMEDIA)
+ align_jumps = 1 << CACHE_LOG;
+ else
+ align_jumps = 2;
+ }
else if (align_jumps < (TARGET_SHMEDIA ? 4 : 2))
align_jumps = TARGET_SHMEDIA ? 4 : 2;
- /* Allocation boundary (in *bytes*) for the code of a function.
- SH1: 32 bit alignment is faster, because instructions are always
- fetched as a pair from a longword boundary.
- SH2 .. SH5 : align to cache line start. */
if (align_functions == 0)
- align_functions
- = optimize_size ? FUNCTION_BOUNDARY/8 : (1 << CACHE_LOG);
+ {
+ if (TARGET_SHMEDIA)
+ align_functions = optimize_size
+ ? FUNCTION_BOUNDARY/8 : (1 << CACHE_LOG);
+ else
+ align_functions = optimize_size ? 2 : 4;
+ }
+
/* The linker relaxation code breaks when a function contains
alignments that are larger than that at the start of a
compilation unit. */
@@ -2806,22 +2833,26 @@ shiftcosts (rtx x)
{
int value;
+ /* There is no pattern for constant first operand. */
+ if (CONST_INT_P (XEXP (x, 0)))
+ return MAX_COST;
+
if (TARGET_SHMEDIA)
- return 1;
+ return COSTS_N_INSNS (1);
if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
{
if (GET_MODE (x) == DImode
&& CONST_INT_P (XEXP (x, 1))
&& INTVAL (XEXP (x, 1)) == 1)
- return 2;
+ return COSTS_N_INSNS (2);
/* Everything else is invalid, because there is no pattern for it. */
return MAX_COST;
}
/* If shift by a non constant, then this will be expensive. */
if (!CONST_INT_P (XEXP (x, 1)))
- return SH_DYNAMIC_SHIFT_COST;
+ return COSTS_N_INSNS (SH_DYNAMIC_SHIFT_COST);
/* Otherwise, return the true cost in instructions. Cope with out of range
shift counts more or less arbitrarily. */
@@ -2833,10 +2864,10 @@ shiftcosts (rtx x)
/* If SH3, then we put the constant in a reg and use shad. */
if (cost > 1 + SH_DYNAMIC_SHIFT_COST)
cost = 1 + SH_DYNAMIC_SHIFT_COST;
- return cost;
+ return COSTS_N_INSNS (cost);
}
else
- return shift_insns[value];
+ return COSTS_N_INSNS (shift_insns[value]);
}
/* Return the cost of an AND/XOR/IOR operation. */
@@ -3069,7 +3100,7 @@ sh_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
case ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
- *total = COSTS_N_INSNS (shiftcosts (x));
+ *total = shiftcosts (x);
return true;
case DIV:
@@ -5342,6 +5373,9 @@ sh_loop_align (rtx label)
{
rtx next = label;
+ if (! optimize || optimize_size)
+ return 0;
+
do
next = next_nonnote_insn (next);
while (next && LABEL_P (next));
@@ -8133,10 +8167,8 @@ sh_dwarf_register_span (rtx reg)
return
gen_rtx_PARALLEL (VOIDmode,
gen_rtvec (2,
- gen_rtx_REG (SFmode,
- DBX_REGISTER_NUMBER (regno+1)),
- gen_rtx_REG (SFmode,
- DBX_REGISTER_NUMBER (regno))));
+ gen_rtx_REG (SFmode, regno + 1),
+ gen_rtx_REG (SFmode, regno)));
}
static enum machine_mode
@@ -9201,13 +9233,6 @@ fldi_ok (void)
return 1;
}
-int
-tertiary_reload_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- enum rtx_code code = GET_CODE (op);
- return code == MEM || (TARGET_SH4 && code == CONST_DOUBLE);
-}
-
/* Return the TLS type for TLS symbols, 0 for otherwise. */
enum tls_model
tls_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
@@ -11499,8 +11524,15 @@ sh_register_move_cost (enum machine_mode mode,
&& REGCLASS_HAS_GENERAL_REG (srcclass))
|| (REGCLASS_HAS_GENERAL_REG (dstclass)
&& REGCLASS_HAS_FP_REG (srcclass)))
- return ((TARGET_SHMEDIA ? 4 : TARGET_FMOVD ? 8 : 12)
- * ((GET_MODE_SIZE (mode) + 7) / 8U));
+ {
+ /* Discourage trying to use fp regs for a pointer. This also
+ discourages fp regs with SImode because Pmode is an alias
+ of SImode on this target. See PR target/48596. */
+ int addend = (mode == Pmode) ? 40 : 0;
+
+ return (((TARGET_SHMEDIA ? 4 : TARGET_FMOVD ? 8 : 12) + addend)
+ * ((GET_MODE_SIZE (mode) + 7) / 8U));
+ }
if ((dstclass == FPUL_REGS
&& REGCLASS_HAS_GENERAL_REG (srcclass))
@@ -11856,15 +11888,8 @@ sh_expand_t_scc (rtx operands[])
val = INTVAL (op1);
if ((code == EQ && val == 1) || (code == NE && val == 0))
emit_insn (gen_movt (result));
- else if (TARGET_SH2A && ((code == EQ && val == 0)
- || (code == NE && val == 1)))
- emit_insn (gen_xorsi3_movrt (result));
else if ((code == EQ && val == 0) || (code == NE && val == 1))
- {
- emit_clobber (result);
- emit_insn (gen_subc (result, result, result));
- emit_insn (gen_addsi3 (result, result, const1_rtx));
- }
+ emit_insn (gen_movnegt (result));
else if (code == EQ || code == NE)
emit_insn (gen_move_insn (result, GEN_INT (code == NE)));
else
diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h
index 7a8b23eac16..7a2af0a2841 100644
--- a/gcc/config/sh/sh.h
+++ b/gcc/config/sh/sh.h
@@ -1,6 +1,6 @@
/* Definitions of target machine for GNU compiler for Renesas / SuperH SH.
Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
Contributed by Steve Chamberlain (sac@cygnus.com).
Improved by Jim Wilson (wilson@cygnus.com).
@@ -579,9 +579,7 @@ extern enum sh_divide_strategy_e sh_div_strategy;
#define LABEL_ALIGN_AFTER_BARRIER(LABEL_AFTER_BARRIER) \
barrier_align (LABEL_AFTER_BARRIER)
-#define LOOP_ALIGN(A_LABEL) \
- ((! optimize || TARGET_HARD_SH4 || optimize_size) \
- ? 0 : sh_loop_align (A_LABEL))
+#define LOOP_ALIGN(A_LABEL) sh_loop_align (A_LABEL)
#define LABEL_ALIGN(A_LABEL) \
( \
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index 71db258cc0a..eb1c85267f3 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -1,6 +1,6 @@
;;- Machine description for Renesas / SuperH SH.
;; Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-;; 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+;; 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
;; Free Software Foundation, Inc.
;; Contributed by Steve Chamberlain (sac@cygnus.com).
;; Improved by Jim Wilson (wilson@cygnus.com).
@@ -3354,15 +3354,6 @@ label:
xori %1, %2, %0"
[(set_attr "type" "arith_media")])
-;; Store the complements of the T bit in a register.
-(define_insn "xorsi3_movrt"
- [(set (match_operand:SI 0 "arith_reg_dest" "=r")
- (xor:SI (reg:SI T_REG)
- (const_int 1)))]
- "TARGET_SH2A"
- "movrt\\t%0"
- [(set_attr "type" "arith")])
-
(define_insn "xordi3"
[(set (match_operand:DI 0 "arith_reg_dest" "=r,r")
(xor:DI (match_operand:DI 1 "arith_reg_operand" "%r,r")
@@ -4387,7 +4378,17 @@ label:
;; Unary arithmetic
;; -------------------------------------------------------------------------
-(define_insn "negc"
+(define_expand "negc"
+ [(parallel [(set (match_operand:SI 0 "arith_reg_dest" "")
+ (neg:SI (plus:SI (reg:SI T_REG)
+ (match_operand:SI 1 "arith_reg_operand" ""))))
+ (set (reg:SI T_REG)
+ (ne:SI (ior:SI (reg:SI T_REG) (match_dup 1))
+ (const_int 0)))])]
+ ""
+ "")
+
+(define_insn "*negc"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(neg:SI (plus:SI (reg:SI T_REG)
(match_operand:SI 1 "arith_reg_operand" "r"))))
@@ -4411,7 +4412,7 @@ label:
[(set (match_operand:DI 0 "arith_reg_dest" "")
(neg:DI (match_operand:DI 1 "arith_reg_operand" "")))
(clobber (reg:SI T_REG))]
- ""
+ "TARGET_SH1"
"")
(define_insn_and_split "*negdi2"
@@ -4462,7 +4463,7 @@ label:
[(set (match_operand:SI 0 "arith_reg_dest" "")
(abs:SI (match_operand:SI 1 "arith_reg_operand" "")))
(clobber (reg:SI T_REG))]
- ""
+ "TARGET_SH1"
"")
(define_insn_and_split "*abssi2"
@@ -4531,6 +4532,82 @@ label:
[(set_attr "type" "arith") ;; poor approximation
(set_attr "length" "4")])
+(define_expand "absdi2"
+ [(set (match_operand:DI 0 "arith_reg_dest" "")
+ (abs:DI (match_operand:DI 1 "arith_reg_operand" "")))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH1"
+ "")
+
+(define_insn_and_split "*absdi2"
+ [(set (match_operand:DI 0 "arith_reg_dest" "=r")
+ (abs:DI (match_operand:DI 1 "arith_reg_operand" "r")))]
+ "TARGET_SH1"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+{
+ int high_word = (TARGET_LITTLE_ENDIAN ? 1 : 0);
+ rtx high_src = operand_subword (operands[1], high_word, 0, DImode);
+ emit_insn (gen_cmpgesi_t (high_src, const0_rtx));
+ emit_insn (gen_negdi_cond (operands[0], operands[1], operands[1],
+ const1_rtx));
+ DONE;
+})
+
+(define_insn_and_split "*negabsdi2"
+ [(set (match_operand:DI 0 "arith_reg_dest" "=r")
+ (neg:DI (abs:DI (match_operand:DI 1 "arith_reg_operand" "r"))))]
+ "TARGET_SH1"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+{
+ int high_word = (TARGET_LITTLE_ENDIAN ? 1 : 0);
+ rtx high_src = operand_subword (operands[1], high_word, 0, DImode);
+
+ emit_insn (gen_cmpgesi_t (high_src, const0_rtx));
+ emit_insn (gen_negdi_cond (operands[0], operands[1], operands[1],
+ const0_rtx));
+ DONE;
+})
+
+(define_insn_and_split "negdi_cond"
+ [(set (match_operand:DI 0 "arith_reg_dest" "=r,r")
+ (if_then_else:DI (eq:SI (reg:SI T_REG)
+ (match_operand:SI 3 "const_int_operand" "M,N"))
+ (match_operand:DI 1 "arith_reg_operand" "r,r")
+ (neg:DI (match_operand:DI 2 "arith_reg_operand" "1,1"))))]
+ "TARGET_SH1"
+ "#"
+ "TARGET_SH1"
+ [(const_int 0)]
+{
+ int low_word = (TARGET_LITTLE_ENDIAN ? 0 : 1);
+ int high_word = (TARGET_LITTLE_ENDIAN ? 1 : 0);
+
+ rtx low_src = operand_subword (operands[1], low_word, 0, DImode);
+ rtx high_src = operand_subword (operands[1], high_word, 0, DImode);
+
+ rtx low_dst = operand_subword (operands[0], low_word, 1, DImode);
+ rtx high_dst = operand_subword (operands[0], high_word, 1, DImode);
+
+ rtx skip_neg_label = gen_label_rtx ();
+
+ emit_insn (gen_movsi (low_dst, low_src));
+ emit_insn (gen_movsi (high_dst, high_src));
+
+ emit_jump_insn (INTVAL (operands[3])
+ ? gen_branch_true (skip_neg_label)
+ : gen_branch_false (skip_neg_label));
+
+ if (!INTVAL (operands[3]))
+ emit_insn (gen_clrt ());
+
+ emit_insn (gen_negc (low_dst, low_src));
+ emit_label_after (skip_neg_label, emit_insn (gen_negc (high_dst, high_src)));
+ DONE;
+})
;; -------------------------------------------------------------------------
;; Zero extension instructions
@@ -9452,6 +9529,13 @@ mov.l\\t1f,r0\\n\\
"movt %0"
[(set_attr "type" "arith")])
+(define_insn "movrt"
+ [(set (match_operand:SI 0 "arith_reg_dest" "=r")
+ (xor:SI (reg:SI T_REG) (const_int 1)))]
+ "TARGET_SH2A"
+ "movrt %0"
+ [(set_attr "type" "arith")])
+
(define_expand "cstore4_media"
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operator:SI 1 "sh_float_comparison_operator"
@@ -9578,40 +9662,55 @@ mov.l\\t1f,r0\\n\\
DONE;
")
-;; sne moves the complement of the T reg to DEST like this:
-;; cmp/eq ...
-;; mov #-1,temp
-;; negc temp,dest
-;; This is better than xoring compare result with 1 because it does
-;; not require r0 and further, the -1 may be CSE-ed or lifted out of a
-;; loop.
+;; Move the complement of the T reg to a reg.
+;; On SH2A the movrt insn can be used.
+;; On anything else than SH2A this has to be done with multiple instructions.
+;; One obvious way would be:
+;; cmp/eq ...
+;; movt r0
+;; xor #1,r0
+;;
+;; However, this puts pressure on r0 in most cases and thus the following is
+;; more appealing:
+;; cmp/eq ...
+;; mov #-1,temp
+;; negc temp,dest
+;;
+;; If the constant -1 can be CSE-ed or lifted out of a loop it effectively
+;; becomes a one instruction operation. Moreover, care must be taken that
+;; the insn can still be combined with inverted compare and branch code
+;; around it.
+;; The expander will reserve the constant -1, the insn makes the whole thing
+;; combinable, the splitter finally emits the insn if it was not combined
+;; away.
+;; Notice that when using the negc variant the T bit also gets inverted.
(define_expand "movnegt"
[(set (match_dup 1) (const_int -1))
- (parallel [(set (match_operand:SI 0 "" "")
- (neg:SI (plus:SI (reg:SI T_REG)
- (match_dup 1))))
- (set (reg:SI T_REG)
- (ne:SI (ior:SI (reg:SI T_REG) (match_dup 1))
- (const_int 0)))])]
+ (parallel [(set (match_operand:SI 0 "arith_reg_dest" "")
+ (xor:SI (reg:SI T_REG) (const_int 1)))
+ (use (match_dup 1))])]
""
- "
{
operands[1] = gen_reg_rtx (SImode);
-}")
-
-;; Recognize mov #-1/negc/neg sequence, and change it to movt/add #-1.
-;; This prevents a regression that occurred when we switched from xor to
-;; mov/neg for sne.
+})
-(define_split
- [(set (match_operand:SI 0 "arith_reg_dest" "")
- (plus:SI (reg:SI T_REG)
- (const_int -1)))]
+(define_insn_and_split "*movnegt"
+ [(set (match_operand:SI 0 "arith_reg_dest" "=r")
+ (xor:SI (reg:SI T_REG) (const_int 1)))
+ (use (match_operand:SI 1 "arith_reg_operand" "r"))]
"TARGET_SH1"
- [(set (match_dup 0) (eq:SI (reg:SI T_REG) (const_int 1)))
- (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1)))]
- "")
+ "#"
+ "&& 1"
+ [(const_int 0)]
+{
+ if (TARGET_SH2A)
+ emit_insn (gen_movrt (operands[0]));
+ else
+ emit_insn (gen_negc (operands[0], operands[1]));
+ DONE;
+}
+ [(set_attr "type" "arith")])
(define_expand "cstoresf4"
[(set (match_operand:SI 0 "register_operand" "=r")
diff --git a/gcc/config/sh/sh.opt b/gcc/config/sh/sh.opt
index ea87d259f39..de23d5eb0b8 100644
--- a/gcc/config/sh/sh.opt
+++ b/gcc/config/sh/sh.opt
@@ -320,9 +320,13 @@ Target Mask(HITACHI) MaskExists
Follow Renesas (formerly Hitachi) / SuperH calling conventions
msoft-atomic
-Target Report Mask(SOFT_ATOMIC)
+Target Report Var(TARGET_SOFT_ATOMIC)
Use software atomic sequences supported by kernel
+menable-tas
+Target Report RejectNegative Var(TARGET_ENABLE_TAS)
+Use tas.b instruction for __atomic_test_and_set
+
mspace
Target RejectNegative Alias(Os)
Deprecated. Use -Os instead
diff --git a/gcc/config/sh/sync.md b/gcc/config/sh/sync.md
index 6b397e28db6..258e048f3c7 100644
--- a/gcc/config/sh/sync.md
+++ b/gcc/config/sh/sync.md
@@ -1,5 +1,5 @@
;; GCC machine description for SH synchronization instructions.
-;; Copyright (C) 2011
+;; Copyright (C) 2011, 2012
;; Free Software Foundation, Inc.
;;
;; This file is part of GCC.
@@ -109,7 +109,7 @@
[(plus "add") (minus "sub") (ior "or") (xor "xor") (and "and")])
(define_expand "atomic_compare_and_swap<mode>"
- [(match_operand:QI 0 "register_operand" "") ;; bool success output
+ [(match_operand:SI 0 "register_operand" "") ;; bool success output
(match_operand:I124 1 "register_operand" "") ;; oldval output
(match_operand:I124 2 "memory_operand" "") ;; memory
(match_operand:I124 3 "register_operand" "") ;; expected input
@@ -131,7 +131,7 @@
else if (<MODE>mode == HImode)
emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[1]),
operands[1]));
- emit_insn (gen_movqi (operands[0], gen_rtx_REG (QImode, T_REG)));
+ emit_insn (gen_movsi (operands[0], gen_rtx_REG (SImode, T_REG)));
DONE;
})
@@ -144,8 +144,8 @@
UNSPECV_CMPXCHG_1))
(set (mem:I124 (match_dup 1))
(unspec_volatile:I124 [(const_int 0)] UNSPECV_CMPXCHG_2))
- (set (reg:QI T_REG)
- (unspec_volatile:QI [(const_int 0)] UNSPECV_CMPXCHG_3))
+ (set (reg:SI T_REG)
+ (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
(clobber (match_scratch:SI 4 "=&u"))
(clobber (reg:SI R0_REG))
(clobber (reg:SI R1_REG))]
@@ -164,6 +164,45 @@
}
[(set_attr "length" "20")])
+(define_expand "atomic_exchange<mode>"
+ [(match_operand:I124 0 "register_operand" "") ;; oldval output
+ (match_operand:I124 1 "memory_operand" "") ;; memory
+ (match_operand:I124 2 "register_operand" "") ;; newval input
+ (match_operand:SI 3 "const_int_operand" "")] ;; memory model
+ "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
+{
+ rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
+ emit_insn (gen_atomic_exchange<mode>_soft
+ (operands[0], addr, operands[2]));
+ if (<MODE>mode == QImode)
+ emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
+ operands[0]));
+ else if (<MODE>mode == HImode)
+ emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
+ operands[0]));
+ DONE;
+})
+
+(define_insn "atomic_exchange<mode>_soft"
+ [(set (match_operand:I124 0 "register_operand" "=&u")
+ (mem:I124 (match_operand:SI 1 "register_operand" "u")))
+ (set (mem:I124 (match_dup 1))
+ (unspec:I124
+ [(match_operand:I124 2 "register_operand" "u")] UNSPEC_ATOMIC))
+ (clobber (reg:SI R0_REG))
+ (clobber (reg:SI R1_REG))]
+ "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
+{
+ return "mova 1f,r0" "\n"
+ " .align 2" "\n"
+ " mov r15,r1" "\n"
+ " mov #(0f-1f),r15" "\n"
+ "0: mov.<i124suffix> @%1,%0" "\n"
+ " mov.<i124suffix> %2,@%1" "\n"
+ "1: mov r1,r15";
+}
+ [(set_attr "length" "14")])
+
(define_expand "atomic_fetch_<fetchop_name><mode>"
[(set (match_operand:I124 0 "register_operand" "")
(match_operand:I124 1 "memory_operand" ""))
@@ -365,3 +404,62 @@
"1: mov r1,r15";
}
[(set_attr "length" "18")])
+
+(define_expand "atomic_test_and_set"
+ [(match_operand:SI 0 "register_operand" "") ;; bool result output
+ (match_operand:QI 1 "memory_operand" "") ;; memory
+ (match_operand:SI 2 "const_int_operand" "")] ;; model
+ "(TARGET_SOFT_ATOMIC || TARGET_ENABLE_TAS) && !TARGET_SHMEDIA"
+{
+ rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
+
+ if (TARGET_ENABLE_TAS)
+ emit_insn (gen_tasb (addr));
+ else
+ {
+ rtx val;
+
+ val = gen_int_mode (targetm.atomic_test_and_set_trueval, QImode);
+ val = force_reg (QImode, val);
+ emit_insn (gen_atomic_test_and_set_soft (addr, val));
+ }
+
+ /* The result of the test op is the inverse of what we are
+ supposed to return. Thus invert the T bit. The inversion will be
+ potentially optimized away and integrated into surrounding code. */
+ emit_insn (gen_movnegt (operands[0]));
+ DONE;
+})
+
+(define_insn "tasb"
+ [(set (reg:SI T_REG)
+ (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
+ (const_int 0)))
+ (set (mem:QI (match_dup 0))
+ (unspec:QI [(const_int 128)] UNSPEC_ATOMIC))]
+ "TARGET_ENABLE_TAS && !TARGET_SHMEDIA"
+ "tas.b @%0"
+ [(set_attr "insn_class" "co_group")])
+
+(define_insn "atomic_test_and_set_soft"
+ [(set (reg:SI T_REG)
+ (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "u"))
+ (const_int 0)))
+ (set (mem:QI (match_dup 0))
+ (unspec:QI [(match_operand:QI 1 "register_operand" "u")] UNSPEC_ATOMIC))
+ (clobber (match_scratch:QI 2 "=&u"))
+ (clobber (reg:SI R0_REG))
+ (clobber (reg:SI R1_REG))]
+ "TARGET_SOFT_ATOMIC && !TARGET_ENABLE_TAS && !TARGET_SHMEDIA"
+{
+ return "mova 1f,r0" "\n"
+ " .align 2" "\n"
+ " mov r15,r1" "\n"
+ " mov #(0f-1f),r15" "\n"
+ "0: mov.b @%0,%2" "\n"
+ " mov.b %1,@%0" "\n"
+ "1: mov r1,r15" "\n"
+ " tst %2,%2";
+}
+ [(set_attr "length" "16")])
+