diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-03-08 10:11:09 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-03-08 10:11:09 +0000 |
commit | 6195c0dd4e15f50ac89491b48e050751f8231304 (patch) | |
tree | 1f49de2cfcd902f18c22b5539315d7b0fb4db972 /gcc/config/sh | |
parent | d7ce7f9586bca838e0dcc7e39100ffe6edcd74f3 (diff) | |
download | gcc-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.md | 4 | ||||
-rw-r--r-- | gcc/config/sh/linux.h | 15 | ||||
-rw-r--r-- | gcc/config/sh/predicates.md | 2 | ||||
-rw-r--r-- | gcc/config/sh/sh-protos.h | 3 | ||||
-rw-r--r-- | gcc/config/sh/sh.c | 97 | ||||
-rw-r--r-- | gcc/config/sh/sh.h | 6 | ||||
-rw-r--r-- | gcc/config/sh/sh.md | 177 | ||||
-rw-r--r-- | gcc/config/sh/sh.opt | 6 | ||||
-rw-r--r-- | gcc/config/sh/sync.md | 108 |
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")]) + |