Message ID | 20231121160633.2174974-1-rearnsha@arm.com |
---|---|
State | New |
Headers | show |
Series | arm: libgcc: provide implementations of __sync_synchronize | expand |
On 21/11/2023 16:06, Richard Earnshaw wrote: > I'm going to hold off for 24 hours on this to give some chance for > feedback before committing. Is using EXTRA_PARTS in this way > acceptable? If not, what method would you recommend? Is there a > better way of achieving this than using --defsym (which seems to have > the side effect of causing the target function to be included in the > image even if the function isn't actually used)? > > R. > > Prior to Armv6 there was no architected method to synchronize data > across processors. Armv6 saw the first introduction of > multi-processor support, using a CP15 operation; but this was > deprecated in Armv7 and is not supported on m-profile devices of any > form. Armv7 (and armv6-m) and later support data synchronization via > the DMB instruction. > > This all leads to difficulties when linking programs as the user > generally needs to know which synchronization method is needed, but > there seems no easy way around this, when there are no OS-related > primitives available. > > I've addressed this by adding multiple variants of __sync_synchronize > to libgcc, one for each of the above use cases. I've named these > __sync_synchronize_none, __sync_synchronize_cp15dmb and > __sync_synchronize_dmb. I've also added three specs files that can be > used to direct the linker to pick the appropriate implementation. > Using specs fragments for this is preferable to directing the user to > directly use --defsym as the latter has to be placed at the correct > position on the command line to be effective and the spec rule ensures > this automatically. > > I've also added a default implementation of __sync_synchronize. The > default implementation will use DMB if that is available in the target > ISA, or fall back to a nul-implementation if it isn't. In the latter > case it will cause the linker (GNU LD) to emit a warning that > specifies how to pick a specific implementation. I've chosen not to > permit this default to use the CP15 solution as that has been > deprecated. I've now pushed this. R. > > libgcc: > > * config.host (arm*-*-eabi* | arm*-*-rtems*): > Add arm/t-sync to the makefile rules. > * config/arm/lib1funcs.S (__sync_synchronize_none) > (__sync_synchronize_cp15dmb, __sync_synchronize_dmb) > (__sync_synchronize): New functions. > * config/arm/t-sync: New file. > * config/arm/sync-none.specs: Likewise. > * config/arm/sync-dmb.specs: Likewise. > * config/arm/sync-cp15dmb.specs: Likewise. > --- > libgcc/config.host | 2 +- > libgcc/config/arm/lib1funcs.S | 72 ++++++++++++++++++++++++++++ > libgcc/config/arm/sync-cp15dmb.specs | 4 ++ > libgcc/config/arm/sync-dmb.specs | 4 ++ > libgcc/config/arm/sync-none.specs | 4 ++ > libgcc/config/arm/t-sync | 13 +++++ > 6 files changed, 98 insertions(+), 1 deletion(-) > create mode 100644 libgcc/config/arm/sync-cp15dmb.specs > create mode 100644 libgcc/config/arm/sync-dmb.specs > create mode 100644 libgcc/config/arm/sync-none.specs > create mode 100644 libgcc/config/arm/t-sync >
diff --git a/libgcc/config.host b/libgcc/config.host index 6afe8e56f7e..694e3e9f54c 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -554,7 +554,7 @@ arm*-*-eabi* | arm*-*-symbianelf* | arm*-*-rtems*) tm_file="$tm_file arm/bpabi-lib.h" case ${host} in arm*-*-eabi* | arm*-*-rtems*) - tmake_file="${tmake_file} arm/t-bpabi t-crtfm" + tmake_file="${tmake_file} arm/t-bpabi arm/t-sync t-crtfm" extra_parts="crtbegin.o crtend.o crti.o crtn.o" ;; arm*-*-symbianelf*) diff --git a/libgcc/config/arm/lib1funcs.S b/libgcc/config/arm/lib1funcs.S index d02a57c4564..78887861616 100644 --- a/libgcc/config/arm/lib1funcs.S +++ b/libgcc/config/arm/lib1funcs.S @@ -2147,6 +2147,78 @@ LSYM(Lchange_\register): SIZE (__gnu_thumb1_case_uhi) #endif +#ifdef L_sync_none + /* Null implementation of __sync_synchronize, for use when + it is known that the system is single threaded. */ + .text + .align 0 + FUNC_START sync_synchronize_none + bx lr + FUNC_END sync_synchronize_none +#endif + +#ifdef L_sync_dmb + /* Full memory barrier using DMB. Requires Armv7 (all profiles) + or armv6-m, or later. */ + .text + .align 0 +#if __ARM_ARCH_PROFILE == 'M' + .arch armv6-m +#else + .arch armv7-a +#endif + FUNC_START sync_synchronize_dmb + /* M-profile devices only support SY as the synchronization level, + but that's probably what we want here anyway. */ + dmb + RET + FUNC_END sync_synchronize_dmb +#endif + +#ifdef L_sync_cp15dmb +#ifndef NOT_ISA_TARGET_32BIT + /* Implementation of DMB using CP15 operations. This was first + defined in Armv6, but deprecated in Armv7 and can give + sub-optimal performance. */ + .text + .align 0 + ARM_FUNC_START sync_synchronize_cp15dmb + mcr p15, 0, r0, c7, c10, 5 + RET + FUNC_END sync_synchronize_cp15dmb +#endif +#endif + +#ifdef L_sync_synchronize + /* Generic version of the synchronization primitive. If we know + that DMB exists, then use it. Otherwise, arrange for a link + time warning explaining how to pick a suitable alternative. + We choose not to use CP15DMB because it is performance + deprecated. We only define this function if generating + ELF binaries as otherwise we can't rely on the warning being + generated. */ + +#ifdef __ELF__ + .text + .align 0 + FUNC_START sync_synchronize +#if __ARM_ARCH >= 7 || __ARM_ARCH_PROFILE == 'M' + dmb +#endif + RET + FUNC_END sync_synchronize +#if !(__ARM_ARCH >= 7 || __ARM_ARCH_PROFILE == 'M') + .section .gnu.warning.__sync_synchronize + .align 0 + .ascii "This implementation of __sync_synchronize is a stub with " + .ascii "no effect. Relink with\n" + .ascii " -specs=sync-{none,dmb,cp15dmb}.specs\n" + .ascii "to specify exactly which barrier format to use and avoid " + .ascii "this warning.\n\0" +#endif +#endif +#endif + #ifdef L_thumb1_case_si .text diff --git a/libgcc/config/arm/sync-cp15dmb.specs b/libgcc/config/arm/sync-cp15dmb.specs new file mode 100644 index 00000000000..0bb64b97a0d --- /dev/null +++ b/libgcc/config/arm/sync-cp15dmb.specs @@ -0,0 +1,4 @@ +%rename link sync_sync_link + +*link: +--defsym=__sync_synchronize=__sync_synchronize_cp15dmb %(sync_sync_link) diff --git a/libgcc/config/arm/sync-dmb.specs b/libgcc/config/arm/sync-dmb.specs new file mode 100644 index 00000000000..13e59bdd22d --- /dev/null +++ b/libgcc/config/arm/sync-dmb.specs @@ -0,0 +1,4 @@ +%rename link sync_sync_link + +*link: +--defsym=__sync_synchronize=__sync_synchronize_dmb %(sync_sync_link) diff --git a/libgcc/config/arm/sync-none.specs b/libgcc/config/arm/sync-none.specs new file mode 100644 index 00000000000..0aa49602c8b --- /dev/null +++ b/libgcc/config/arm/sync-none.specs @@ -0,0 +1,4 @@ +%rename link sync_sync_link + +*link: +--defsym=__sync_synchronize=__sync_synchronize_none %(sync_sync_link) diff --git a/libgcc/config/arm/t-sync b/libgcc/config/arm/t-sync new file mode 100644 index 00000000000..5fd050ec997 --- /dev/null +++ b/libgcc/config/arm/t-sync @@ -0,0 +1,13 @@ +LIB1ASMFUNCS += _sync_none _sync_dmb _sync_cp15dmb _sync_synchronize + +EXTRA_PARTS += sync-none.specs sync-dmb.specs sync-cp15dmb.specs + +sync-none.specs: $(srcdir)/config/arm/sync-none.specs + cp $< . + +sync-dmb.specs: $(srcdir)/config/arm/sync-dmb.specs + cp $< . + +sync-cp15dmb.specs: $(srcdir)/config/arm/sync-cp15dmb.specs + cp $< . +