summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhp <hp@138bc75d-0d04-0410-961f-82ee72b054a4>2012-06-01 05:49:16 +0000
committerhp <hp@138bc75d-0d04-0410-961f-82ee72b054a4>2012-06-01 05:49:16 +0000
commit2ef7687b7b3f425f303f876738212a0f0ee883fb (patch)
tree3748c4b19fefbeba9a6320eb38c3640e4c85681f
parent4f2e7aceb7414af39652beeaef7fe213b170d8f6 (diff)
downloadgcc-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/ChangeLog17
-rw-r--r--gcc/config/cris/cris-protos.h1
-rw-r--r--gcc/config/cris/cris.c33
-rw-r--r--gcc/config/cris/cris.h26
-rw-r--r--gcc/config/cris/cris.md24
-rw-r--r--gcc/config/cris/cris.opt4
-rw-r--r--gcc/config/cris/sync.md288
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.%=:";
+ }
+})