diff options
author | hp <hp@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-06-01 05:49:16 +0000 |
---|---|---|
committer | hp <hp@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-06-01 05:49:16 +0000 |
commit | 2ef7687b7b3f425f303f876738212a0f0ee883fb (patch) | |
tree | 3748c4b19fefbeba9a6320eb38c3640e4c85681f | |
parent | 4f2e7aceb7414af39652beeaef7fe213b170d8f6 (diff) | |
download | gcc-2ef7687b7b3f425f303f876738212a0f0ee883fb.tar.gz |
Add CRIS atomic patterns for 1, 2, and 4 bytes.
* config/cris/cris.c (cris_emit_trap_for_misalignment): New function.
* config/cris/cris-protos.h: Declare it.
* config/cris/cris.h [!TARGET_DEFAULT, TARGET_CPU_DEFAULT == 32]
(TARGET_DEFAULT): Add alignment by 32.
[!TARGET_DEFAULT, TARGET_CPU_DEFAULT == 10] (TARGET_DEFAULT): New
case, as TARGET_CPU_DEFAULT == 0 but with alignment as for
TARGET_CPU_DEFAULT == 32.
(TARGET_TRAP_UNALIGNED_ATOMIC): New macro.
* config/cris/cris.md: Include sync.md. Avoid allocating specific
numbers by replacing the define_constants for all UNSPECs with the
equivalent define_c_enum construct.
* config/cris/cris.opt (mtrap-unaligned-atomic): New option.
* config/cris/sync.md: New file.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@188096 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 17 | ||||
-rw-r--r-- | gcc/config/cris/cris-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/cris/cris.c | 33 | ||||
-rw-r--r-- | gcc/config/cris/cris.h | 26 | ||||
-rw-r--r-- | gcc/config/cris/cris.md | 24 | ||||
-rw-r--r-- | gcc/config/cris/cris.opt | 4 | ||||
-rw-r--r-- | gcc/config/cris/sync.md | 288 |
7 files changed, 379 insertions, 14 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5202d7833ed..6f346029058 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2012-06-01 Hans-Peter Nilsson <hp@axis.com> + + Add CRIS atomic patterns for 1, 2, and 4 bytes. + * config/cris/cris.c (cris_emit_trap_for_misalignment): New function. + * config/cris/cris-protos.h: Declare it. + * config/cris/cris.h [!TARGET_DEFAULT, TARGET_CPU_DEFAULT == 32] + (TARGET_DEFAULT): Add alignment by 32. + [!TARGET_DEFAULT, TARGET_CPU_DEFAULT == 10] (TARGET_DEFAULT): New + case, as TARGET_CPU_DEFAULT == 0 but with alignment as for + TARGET_CPU_DEFAULT == 32. + (TARGET_TRAP_UNALIGNED_ATOMIC): New macro. + * config/cris/cris.md: Include sync.md. Avoid allocating specific + numbers by replacing the define_constants for all UNSPECs with the + equivalent define_c_enum construct. + * config/cris/cris.opt (mtrap-unaligned-atomic): New option. + * config/cris/sync.md: New file. + 2012-05-31 Matt Turner <mattst88@gmail.com> * config/mips/4600.md (r4600_imul_si): Rename from r4600_imul. diff --git a/gcc/config/cris/cris-protos.h b/gcc/config/cris/cris-protos.h index 545f821ac0f..8d2d59cbc5c 100644 --- a/gcc/config/cris/cris-protos.h +++ b/gcc/config/cris/cris-protos.h @@ -49,6 +49,7 @@ extern rtx cris_gen_movem_load (rtx, rtx, int); extern rtx cris_emit_movem_store (rtx, rtx, int, bool); extern void cris_expand_pic_call_address (rtx *); extern void cris_order_for_addsi3 (rtx *, int); +extern void cris_emit_trap_for_misalignment (rtx); #endif /* RTX_CODE */ extern void cris_asm_output_label_ref (FILE *, char *); extern void cris_target_asm_named_section (const char *, unsigned int, tree); diff --git a/gcc/config/cris/cris.c b/gcc/config/cris/cris.c index 349f6019e3e..947a6a51416 100644 --- a/gcc/config/cris/cris.c +++ b/gcc/config/cris/cris.c @@ -1922,6 +1922,39 @@ cris_simple_epilogue (void) return true; } +/* Emit checking that MEM is aligned for an access in MODE, failing + that, executing a "break 8" (or call to abort, if "break 8" is + disabled). */ + +void +cris_emit_trap_for_misalignment (rtx mem) +{ + rtx addr, reg, ok_label, and, jmp; + int natural_alignment; + gcc_assert (MEM_P (mem)); + + natural_alignment = GET_MODE_SIZE (GET_MODE (mem)); + addr = XEXP (mem, 0); + reg = force_reg (Pmode, addr); + ok_label = gen_label_rtx (); + + /* This will yield a btstq without a separate register used, usually - + with the exception for PRE hoisting the "and" but not the branch + around the trap: see gcc.dg/target/cris/sync-3s.c. */ + and = gen_rtx_AND (Pmode, reg, GEN_INT (natural_alignment - 1)); + emit_cmp_and_jump_insns (force_reg (SImode, and), const0_rtx, EQ, + NULL_RTX, Pmode, 1, ok_label); + jmp = get_last_insn (); + gcc_assert (JUMP_P (jmp)); + + /* While this isn't mudflap, it is a similar kind of assertion. + If PRED_MUDFLAP stops working, use something else or introduce a + more suitable assertion predication type. */ + predict_insn_def (jmp, PRED_MUDFLAP, TAKEN); + expand_builtin_trap (); + emit_label (ok_label); +} + /* Expand a return insn (just one insn) marked as using SRP or stack slot depending on parameter ON_STACK. */ diff --git a/gcc/config/cris/cris.h b/gcc/config/cris/cris.h index 78fbe684078..0660b494a49 100644 --- a/gcc/config/cris/cris.h +++ b/gcc/config/cris/cris.h @@ -286,15 +286,25 @@ extern int cris_cpu_version; #define TARGET_CPU_DEFAULT CRIS_CPU_BASE #endif -/* Default target_flags if no switches specified. */ +/* Default target_flags if no switches specified. + The alignment-by-32 is to make builtin atomic support for v10 and v32 + work for *-elf for types without specified alignment (like plain + "int"). See top comment in sync.md. */ #ifndef TARGET_DEFAULT # if TARGET_CPU_DEFAULT == 32 # define TARGET_DEFAULT \ (MASK_STACK_ALIGN \ + MASK_CONST_ALIGN + MASK_DATA_ALIGN \ + + MASK_ALIGN_BY_32 \ + MASK_PROLOGUE_EPILOGUE) -# else /* 10 */ -# define TARGET_DEFAULT \ +# elif TARGET_CPU_DEFAULT == 10 +# define TARGET_DEFAULT \ + (MASK_SIDE_EFFECT_PREFIXES + MASK_STACK_ALIGN \ + + MASK_CONST_ALIGN + MASK_DATA_ALIGN \ + + MASK_ALIGN_BY_32 \ + + MASK_PROLOGUE_EPILOGUE + MASK_MUL_BUG) +# else /* 0 */ +# define TARGET_DEFAULT \ (MASK_SIDE_EFFECT_PREFIXES + MASK_STACK_ALIGN \ + MASK_CONST_ALIGN + MASK_DATA_ALIGN \ + MASK_PROLOGUE_EPILOGUE + MASK_MUL_BUG) @@ -314,6 +324,16 @@ extern int cris_cpu_version; #define TARGET_TRAP_USING_BREAK8 \ (cris_trap_using_break8 == 2 ? TARGET_HAS_BREAK : cris_trap_using_break8) +/* The < v10 atomics turn off interrupts, so they don't need alignment. + Incidentally, by default alignment is off there causing variables to + be default unaligned all over, so we'd have to make support + libraries use a proper atomic type (instead of "int"), one we'd + specify as aligned. */ +#define TARGET_TRAP_UNALIGNED_ATOMIC \ + (cris_trap_unaligned_atomic == 2 \ + ? (TARGET_V32 || cris_cpu_version == 10) \ + : cris_trap_unaligned_atomic) + /* Node: Storage Layout */ #define BITS_BIG_ENDIAN 0 diff --git a/gcc/config/cris/cris.md b/gcc/config/cris/cris.md index 7d691f5a0b5..4b9d4c3986d 100644 --- a/gcc/config/cris/cris.md +++ b/gcc/config/cris/cris.md @@ -55,46 +55,46 @@ ;; The movsi for a gotless symbol could be split (post reload). -(define_constants +(define_c_enum "" [ ;; PLT reference from call expansion: operand 0 is the address, ;; the mode is VOIDmode. Always wrapped in CONST. ;; The value is relative to the GOT. - (CRIS_UNSPEC_PLT_GOTREL 0) + CRIS_UNSPEC_PLT_GOTREL ;; PLT reference from call expansion: operand 0 is the address, ;; the mode is VOIDmode. Always wrapped in CONST. ;; The value is relative to the PC. It's arch-dependent whether ;; the offset counts from the start or the end of the current item. - (CRIS_UNSPEC_PLT_PCREL 1) + CRIS_UNSPEC_PLT_PCREL ;; The address of the global offset table as a source operand. - (CRIS_UNSPEC_GOT 2) + CRIS_UNSPEC_GOT ;; The offset from the global offset table to the operand. - (CRIS_UNSPEC_GOTREL 3) + CRIS_UNSPEC_GOTREL ;; The PC-relative offset to the operand. It's arch-dependent whether ;; the offset counts from the start or the end of the current item. - (CRIS_UNSPEC_PCREL 4) + CRIS_UNSPEC_PCREL ;; The index into the global offset table of a symbol, while ;; also generating a GOT entry for the symbol. - (CRIS_UNSPEC_GOTREAD 5) + CRIS_UNSPEC_GOTREAD ;; Similar to CRIS_UNSPEC_GOTREAD, but also generating a PLT entry. - (CRIS_UNSPEC_PLTGOTREAD 6) + CRIS_UNSPEC_PLTGOTREAD ;; Condition for v32 casesi jump, since it needs to have if_then_else ;; form with register as one branch and default label as other. ;; Operand 0 is const_int 0. - (CRIS_UNSPEC_CASESI 7) + CRIS_UNSPEC_CASESI ;; Stack frame deallocation barrier. - (CRIS_UNSPEC_FRAME_DEALLOC 8) + CRIS_UNSPEC_FRAME_DEALLOC ;; Swap all 32 bits of the operand; 31 <=> 0, 30 <=> 1... - (CRIS_UNSPEC_SWAP_BITS 9) + CRIS_UNSPEC_SWAP_BITS ]) ;; Register numbers. @@ -4165,6 +4165,8 @@ 3 [(match_dup 0) (match_dup 1)]))] "") + +(include "sync.md") ;; Splits for all cases in side-effect insns where (possibly after reload ;; and register allocation) rx and ry in [rx=ry+i] are equal. diff --git a/gcc/config/cris/cris.opt b/gcc/config/cris/cris.opt index 3c2e338ffee..ebbddaa422e 100644 --- a/gcc/config/cris/cris.opt +++ b/gcc/config/cris/cris.opt @@ -179,6 +179,10 @@ mtrap-using-break8 Target Report Var(cris_trap_using_break8) Init(2) Emit traps as \"break 8\", default for CRIS v3 and up. If disabled, calls to abort() are used. +mtrap-unaligned-atomic +Target Report Var(cris_trap_unaligned_atomic) Init(2) +Emit checks causing \"break 8\" instructions to execute when applying atomic builtins on misaligned memory + ; TARGET_SVINTO: Currently this just affects alignment. FIXME: ; Redundant with TARGET_ALIGN_BY_32, or put machine stuff here? ; This and the others below could just as well be variables and diff --git a/gcc/config/cris/sync.md b/gcc/config/cris/sync.md new file mode 100644 index 00000000000..6acd2b61158 --- /dev/null +++ b/gcc/config/cris/sync.md @@ -0,0 +1,288 @@ +;; GCC machine description for CRIS atomic memory sequences. +;; Copyright (C) 2012 +;; Free Software Foundation, Inc. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; <http://www.gnu.org/licenses/>. + +;; The CRIS atomic support yields code in three flavors, depending on +;; the CPU for which code is generated: +;; +;; - Plain old CRIS v0 (..v8) +;; - CRIS v10 (as used in ETRAX 100 LX) +;; - CRIS v32 (as used in ETRAX FS) +;; +;; The last two alternatives are similar, of LL/SC type. They may +;; fail for other reasons; an exception, a cache miss or a bus request +;; from other parts of the system. The difference between them is +;; just in what condition-codes are used to track LL and success or +;; failure for the store. See the chapter on integral read-write +;; operations, chapter 1.13 in "ETRAX 100LX Programmers Manual", +;; <http://www.axis.com/files/tech_notes/etrax_100lx_prog_man-050519.pdf> +;; and chapter 2.1 in "ETRAX FS Designer's reference", +;; <http://www.axis.com/files/manuals/etrax_fs_des_ref-070821.pdf>. +;; Note that the datum being stored has to be contained fully within a +;; cache-line to be integral. A failure to store the data integrally +;; will be flagged, but the store may still have happened in part, +;; which translates most usefully into the data having to be +;; "naturally aligned" to work. Natural alignment is verified in the +;; generated code and will by default cause for unaligned pointers a +;; "break 8" to be executed or optionally a call to abort(). Beware +;; that options -m16bit and -m8bit may cause data to be unaligned +;; where it was otherwise aligned. Data has a better chance of being +;; aligned if it is declared with e.g. __attribute__ ((__align__ (4))). +;; +;; The "plain old v0..v8 flavor" just assumes there's a single CPU in +;; the system, that no other parts of the system have access to memory +;; used for atomic accesses and since there's no user mode without +;; access to interrupt flags (another assumption), it just turns off +;; interrupts while doing the access. Here, alignment is neither +;; required nor asserted. + +(define_c_enum "" + [ + CRIS_UNSPEC_ATOMIC_OP + CRIS_UNSPEC_ATOMIC_SWAP_MEM + CRIS_UNSPEC_ATOMIC_SWAP_BOOL + ]) + +(define_constants [(CRIS_CCR_INTERRUPT_BIT 5)]) + +;; We use "mult" as a placeholder for "nand" (which does not have a +;; separate binary rtx operation) so we can use an iterator in the +;; define_expand and define_insn and avoid having a separate +;; mostly-identical copy. You will see the "mult" operator in rtl +;; dumps, but it shouldn't matter as its use has one of its operands +;; inside an unspec_volatile. + +(define_code_iterator atomic_op [plus minus ior and xor mult]) + +(define_code_attr atomic_op_name + [(plus "add") (minus "sub") (and "and") (ior "or") (xor "xor") (mult "nand")]) + +;; Pairs of these are used to insert the "not" after the "and" for nand. +(define_code_attr atomic_op_mnem_pre ;; Upper-case only to sinplify testing. + [(plus "Add.d") (minus "Sub.d") (and "And.d") (ior "Or.d") (xor "Xor") + (mult "aNd.d")]) +(define_code_attr atomic_op_mnem_post_op3 + [(plus "") (minus "") (and "") (ior "") (xor "") (mult "not %3\;")]) + +(define_expand "atomic_fetch_<atomic_op_name><mode>" + [(match_operand:BWD 0 "register_operand") + (match_operand:BWD 1 "memory_operand") + (match_operand:BWD 2 "register_operand") + (match_operand 3) + (atomic_op:BWD (match_dup 0) (match_dup 1))] + "" +{ + if (<MODE>mode != QImode && TARGET_TRAP_UNALIGNED_ATOMIC) + cris_emit_trap_for_misalignment (operands[1]); + + expand_mem_thread_fence (INTVAL (operands[3])); + emit_insn (gen_cris_atomic_fetch_<atomic_op_name><mode>_1 (operands[0], + operands[1], + operands[2])); + expand_mem_thread_fence (INTVAL (operands[3])); + DONE; +}) + +(define_insn "cris_atomic_fetch_<atomic_op_name><mode>_1" + [(set (match_operand:BWD 1 "memory_operand" "+Q") + (atomic_op:BWD + (unspec_volatile:BWD [(match_dup 1)] CRIS_UNSPEC_ATOMIC_OP) + ;; FIXME: relax this for plus, minus, and, ior. + (match_operand:BWD 2 "register_operand" "r"))) + (set (match_operand:BWD 0 "register_operand" "=&r") + (match_dup 1)) + (clobber (match_scratch:SI 3 "=&r"))] + "" +{ + /* Can't be too sure; better ICE if this happens. */ + gcc_assert (!reg_overlap_mentioned_p (operands[2], operands[1])); + + if (TARGET_V32) + return + "clearf p\n" + ".Lsync.%=:\;" + "move<m> %1,%0\;" + "move.d %0,%3\;" + "<atomic_op_mnem_pre> %2,%3\;<atomic_op_mnem_post_op3>" + "ax\;" + "move<m> %3,%1\;" + "bcs .Lsync.%=\;" + "clearf p"; + else if (cris_cpu_version == 10) + return + "clearf\n" + ".Lsync.%=:\;" + "move<m> %1,%0\;" + "move.d %0,%3\;" + "<atomic_op_mnem_pre> %2,%3\;<atomic_op_mnem_post_op3>" + "ax\;" + "move<m> %3,%1\;" + "bwf .Lsync.%=\;" + "clearf"; + else + { + /* This one is for CRIS versions without load-locked-store-conditional + machinery; assume single-core-non-shared-memory without user + mode/supervisor mode distinction, and just disable interrupts + while performing the operation. + Rather than making this pattern more complex by freeing another + register or stack position to save condition codes (the value + of the interrupt-enabled bit), we check whether interrupts were + enabled before we disabled them and branch to a version + with/without afterwards re-enabling them. */ + rtx ops[5]; + + /* We have no available macro to stringify CRIS_CCR_INTERRUPT_BIT. */ + memcpy (ops, operands, sizeof(ops)); + ops[4] = GEN_INT (CRIS_CCR_INTERRUPT_BIT); + + output_asm_insn ("move $ccr,%3\;" + "di\;" + "move<m> %1,%0\;" + "btstq %4,%3", + ops); + return + "bmi .Lsync.irqon.%=\;" + "move.d %0,%3\;" + + "<atomic_op_mnem_pre> %2,%3\;<atomic_op_mnem_post_op3>" + "ba .Lsync.irqoff.%=\;" + "move<m> %3,%1\n" + + ".Lsync.irqon.%=:\;" + "<atomic_op_mnem_pre> %2,%3\;<atomic_op_mnem_post_op3>" + "move<m> %3,%1\;" + "ei\n" + ".Lsync.irqoff.%=:"; + } +}) + +;; This pattern is more-or-less assumed to always exist if any of the +;; other atomic patterns exist (see e.g. comment at the +;; can_compare_and_swap_p call in omp-low.c, 4.8 era). We'd slightly +;; prefer atomic_exchange<mode> over this, but having both would be +;; redundant. +(define_expand "atomic_compare_and_swap<mode>" + [(match_operand:SI 0 "register_operand") + (match_operand:BWD 1 "register_operand") + (match_operand:BWD 2 "memory_operand") + (match_operand:BWD 3 "general_operand") + (match_operand:BWD 4 "register_operand") + (match_operand 5) + (match_operand 6) + (match_operand 7)] + "" +{ + if (<MODE>mode != QImode && TARGET_TRAP_UNALIGNED_ATOMIC) + cris_emit_trap_for_misalignment (operands[2]); + + expand_mem_thread_fence (INTVAL (operands[6])); + emit_insn (gen_cris_atomic_compare_and_swap<mode>_1 (operands[0], + operands[1], + operands[2], + operands[3], + operands[4])); + expand_mem_thread_fence (INTVAL (operands[6])); + DONE; +}) + +(define_insn "cris_atomic_compare_and_swap<mode>_1" + [(set (match_operand:SI 0 "register_operand" "=&r") + (unspec_volatile:SI + [(match_operand:BWD 2 "memory_operand" "+Q") + (match_operand:BWD 3 "general_operand" "g")] + CRIS_UNSPEC_ATOMIC_SWAP_BOOL)) + (set (match_operand:BWD 1 "register_operand" "=&r") (match_dup 2)) + (set (match_dup 2) + (unspec_volatile:BWD + [(match_dup 2) + (match_dup 3) + (match_operand:BWD 4 "register_operand" "r")] + CRIS_UNSPEC_ATOMIC_SWAP_MEM))] + "" +{ + if (TARGET_V32) + return + "clearf p\n" + ".Lsync.repeat.%=:\;" + "move<m> %2,%1\;" + "cmp<m> %3,%1\;" + "bne .Lsync.after.%=\;" + "seq %0\;" + + "ax\;" + "move<m> %4,%2\;" + "bcs .Lsync.repeat.%=\;" + "clearf p\n" + ".Lsync.after.%=:"; + else if (cris_cpu_version == 10) + return + "clearf\n" + ".Lsync.repeat.%=:\;" + "move<m> %2,%1\;" + "cmp<m> %3,%1\;" + "bne .Lsync.after.%=\;" + "seq %0\;" + + "ax\;" + "move<m> %4,%2\;" + "bwf .Lsync.repeat.%=\;" + "clearf\n" + ".Lsync.after.%=:"; + else + { + /* This one is for CRIS versions without load-locked-store-conditional + machinery; assume single-core-non-shared-memory without user + mode/supervisor mode distinction, and just disable interrupts + while performing the operation. + Rather than making this pattern more complex by freeing another + register or stack position to save condition codes (the value + of the interrupt-enabled bit), we check whether interrupts were + enabled before we disabled them and branch to a version + with/without afterwards re-enabling them. */ + rtx ops[4]; + + /* We have no available macro to stringify CRIS_CCR_INTERRUPT_BIT. */ + memcpy (ops, operands, sizeof(ops)); + ops[3] = GEN_INT (CRIS_CCR_INTERRUPT_BIT); + + output_asm_insn ("move $ccr,%0\;" + "di\;" + "move<m> %2,%1\;" + "btstq %3,%0", + ops); + return + "bmi .Lsync.irqon.%=\;" + "nop\;" + + "cmp<m> %3,%1\;" + "bne .Lsync.after.%=\;" + "seq %0\;" + "ba .Lsync.after.%=\;" + "move<m> %4,%2\n" + + ".Lsync.irqon.%=:\;" + "cmp<m> %3,%1\;" + "bne .Lsync.after.%=\;" + "seq %0\;" + "move<m> %4,%2\;" + "ei\n" + ".Lsync.after.%=:"; + } +}) |