diff --git a/gcc/builtins.c b/gcc/builtins.c index 0f2c8c477df..ecc12e69c14 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -7770,26 +7770,63 @@ expand_builtin_copysign (tree exp, rtx target, rtx subtarget) return expand_copysign (op0, op1, target); } -/* Expand a call to __builtin___clear_cache. */ +/* Emit a call to __builtin___clear_cache. */ -static rtx -expand_builtin___clear_cache (tree exp) +void +default_emit_call_builtin___clear_cache (rtx begin, rtx end) { - if (!targetm.code_for_clear_cache) + rtx callee = gen_rtx_SYMBOL_REF (Pmode, + BUILTIN_ASM_NAME_PTR + (BUILT_IN_CLEAR_CACHE)); + + emit_library_call (callee, + LCT_NORMAL, VOIDmode, + begin, ptr_mode, + end, ptr_mode); +} + +/* Emit a call to __builtin___clear_cache, unless the target specifies + it as do-nothing. This function can be used by trampoline + finalizers to duplicate the effects of expanding a call to the + clear_cache builtin. */ + +void +maybe_emit_call_builtin___clear_cache (rtx begin, rtx end) +{ + if (GET_MODE (begin) != ptr_mode || GET_MODE (end) != ptr_mode) { -#ifdef CLEAR_INSN_CACHE - /* There is no "clear_cache" insn, and __clear_cache() in libgcc - does something. Just do the default expansion to a call to - __clear_cache(). */ - return NULL_RTX; -#else + error ("both arguments to %<__builtin___clear_cache%> must be pointers"); + return; + } + + if (targetm.have_clear_cache ()) + { + /* We have a "clear_cache" insn, and it will handle everything. */ + class expand_operand ops[2]; + + create_address_operand (&ops[0], begin); + create_address_operand (&ops[1], end); + + if (maybe_expand_insn (targetm.code_for_clear_cache, 2, ops)) + return; + } + else + { +#ifndef CLEAR_INSN_CACHE /* There is no "clear_cache" insn, and __clear_cache() in libgcc does nothing. There is no need to call it. Do nothing. */ - return const0_rtx; + return; #endif /* CLEAR_INSN_CACHE */ } - /* We have a "clear_cache" insn, and it will handle everything. */ + targetm.calls.emit_call_builtin___clear_cache (begin, end); +} + +/* Expand a call to __builtin___clear_cache. */ + +static void +expand_builtin___clear_cache (tree exp) +{ tree begin, end; rtx begin_rtx, end_rtx; @@ -7799,25 +7836,16 @@ expand_builtin___clear_cache (tree exp) if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) { error ("both arguments to %<__builtin___clear_cache%> must be pointers"); - return const0_rtx; + return; } - if (targetm.have_clear_cache ()) - { - class expand_operand ops[2]; + begin = CALL_EXPR_ARG (exp, 0); + begin_rtx = expand_expr (begin, NULL_RTX, Pmode, EXPAND_NORMAL); - begin = CALL_EXPR_ARG (exp, 0); - begin_rtx = expand_expr (begin, NULL_RTX, Pmode, EXPAND_NORMAL); + end = CALL_EXPR_ARG (exp, 1); + end_rtx = expand_expr (end, NULL_RTX, Pmode, EXPAND_NORMAL); - end = CALL_EXPR_ARG (exp, 1); - end_rtx = expand_expr (end, NULL_RTX, Pmode, EXPAND_NORMAL); - - create_address_operand (&ops[0], begin_rtx); - create_address_operand (&ops[1], end_rtx); - if (maybe_expand_insn (targetm.code_for_clear_cache, 2, ops)) - return const0_rtx; - } - return const0_rtx; + maybe_emit_call_builtin___clear_cache (begin_rtx, end_rtx); } /* Given a trampoline address, make sure it satisfies TRAMPOLINE_ALIGNMENT. */ @@ -9507,6 +9535,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, && fcode != BUILT_IN_EXECLE && fcode != BUILT_IN_EXECVP && fcode != BUILT_IN_EXECVE + && fcode != BUILT_IN_CLEAR_CACHE && !ALLOCA_FUNCTION_CODE_P (fcode) && fcode != BUILT_IN_FREE) return expand_call (exp, target, ignore); @@ -9696,10 +9725,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, return expand_builtin_next_arg (); case BUILT_IN_CLEAR_CACHE: - target = expand_builtin___clear_cache (exp); - if (target) - return target; - break; + expand_builtin___clear_cache (exp); + return const0_rtx; case BUILT_IN_CLASSIFY_TYPE: return expand_builtin_classify_type (exp); diff --git a/gcc/builtins.h b/gcc/builtins.h index 0ca1cbc9f4d..09379e85d45 100644 --- a/gcc/builtins.h +++ b/gcc/builtins.h @@ -128,6 +128,7 @@ extern tree fold_call_expr (location_t, tree, bool); extern tree fold_builtin_call_array (location_t, tree, tree, int, tree *); extern bool validate_gimple_arglist (const gcall *, ...); extern rtx default_expand_builtin (tree, rtx, rtx, machine_mode, int); +extern void maybe_emit_call_builtin___clear_cache (rtx, rtx); extern bool fold_builtin_next_arg (tree, bool); extern tree do_mpc_arg2 (tree, tree, tree, int, int (*)(mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t)); extern tree fold_call_stmt (gcall *, bool); diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 0208efd88f1..67ffba02d3e 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -11037,10 +11037,10 @@ aarch64_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) /* XXX We should really define a "clear_cache" pattern and use gen_clear_cache(). */ a_tramp = XEXP (m_tramp, 0); - emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"), - LCT_NORMAL, VOIDmode, a_tramp, ptr_mode, - plus_constant (ptr_mode, a_tramp, TRAMPOLINE_SIZE), - ptr_mode); + maybe_emit_call_builtin___clear_cache (a_tramp, + plus_constant (ptr_mode, + a_tramp, + TRAMPOLINE_SIZE)); } static unsigned char diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c index 2a7b1fb48bc..eabc122d5f1 100644 --- a/gcc/config/arc/arc.c +++ b/gcc/config/arc/arc.c @@ -4418,10 +4418,10 @@ arc_initialize_trampoline (rtx tramp, tree fndecl, rtx cxt) GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); emit_move_insn (adjust_address (tramp, SImode, 8), fnaddr); emit_move_insn (adjust_address (tramp, SImode, 12), cxt); - emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"), - LCT_NORMAL, VOIDmode, XEXP (tramp, 0), Pmode, - plus_constant (Pmode, XEXP (tramp, 0), TRAMPOLINE_SIZE), - Pmode); + maybe_emit_call_builtin___clear_cache (XEXP (tramp, 0), + plus_constant (Pmode, + XEXP (tramp, 0), + TRAMPOLINE_SIZE)); } /* Add the given function declaration to emit code in JLI section. */ diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 56ed556b098..2f0ef3b0d3c 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -4170,9 +4170,10 @@ arm_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) } a_tramp = XEXP (m_tramp, 0); - emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"), - LCT_NORMAL, VOIDmode, a_tramp, Pmode, - plus_constant (Pmode, a_tramp, TRAMPOLINE_SIZE), Pmode); + maybe_emit_call_builtin___clear_cache (a_tramp, + plus_constant (ptr_mode, + a_tramp, + TRAMPOLINE_SIZE)); } /* Thumb trampolines should be entered in thumb mode, so set diff --git a/gcc/config/c6x/c6x.c b/gcc/config/c6x/c6x.c index 9aa7ef0620c..78b2bff1fd9 100644 --- a/gcc/config/c6x/c6x.c +++ b/gcc/config/c6x/c6x.c @@ -725,9 +725,10 @@ c6x_initialize_trampoline (rtx tramp, tree fndecl, rtx cxt) } #ifdef CLEAR_INSN_CACHE tramp = XEXP (tramp, 0); - emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__gnu_clear_cache"), - LCT_NORMAL, VOIDmode, tramp, Pmode, - plus_constant (Pmode, tramp, TRAMPOLINE_SIZE), Pmode); + maybe_emit_call_builtin___clear_cache (tramp, + plus_constant (Pmode, + tramp, + TRAMPOLINE_SIZE)); #endif } diff --git a/gcc/config/csky/csky.c b/gcc/config/csky/csky.c index 5aa233677bc..3b03f3f1969 100644 --- a/gcc/config/csky/csky.c +++ b/gcc/config/csky/csky.c @@ -5917,9 +5917,10 @@ csky_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) emit_move_insn (mem, fnaddr); a_tramp = XEXP (m_tramp, 0); - emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"), - LCT_NORMAL, VOIDmode, a_tramp, Pmode, - plus_constant (Pmode, a_tramp, TRAMPOLINE_SIZE), Pmode); + maybe_emit_call_builtin___clear_cache (a_tramp, + plus_constant (Pmode, + a_tramp, + TRAMPOLINE_SIZE)); } diff --git a/gcc/config/m68k/linux.h b/gcc/config/m68k/linux.h index 0d18e5ae5ac..a01647c6210 100644 --- a/gcc/config/m68k/linux.h +++ b/gcc/config/m68k/linux.h @@ -194,10 +194,10 @@ along with GCC; see the file COPYING3. If not see #undef FINALIZE_TRAMPOLINE #define FINALIZE_TRAMPOLINE(TRAMP) \ - emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"), \ - LCT_NORMAL, VOIDmode, TRAMP, Pmode, \ - plus_constant (Pmode, TRAMP, TRAMPOLINE_SIZE), \ - Pmode); + maybe_emit_call_builtin___clear_cache ((TRAMP), \ + plus_constant (Pmode, \ + (TRAMP), \ + TRAMPOLINE_SIZE)) /* Clear the instruction cache from `beg' to `end'. This makes an inline system call to SYS_cacheflush. The arguments are as diff --git a/gcc/config/tilegx/tilegx.c b/gcc/config/tilegx/tilegx.c index 92a16551ac0..142e3427c2c 100644 --- a/gcc/config/tilegx/tilegx.c +++ b/gcc/config/tilegx/tilegx.c @@ -5049,9 +5049,7 @@ tilegx_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain) end_addr = force_reg (Pmode, plus_constant (Pmode, XEXP (m_tramp, 0), TRAMPOLINE_SIZE)); - emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"), - LCT_NORMAL, VOIDmode, begin_addr, Pmode, - end_addr, Pmode); + maybe_emit_call_builtin___clear_cache (begin_addr, end_addr); } diff --git a/gcc/config/tilepro/tilepro.c b/gcc/config/tilepro/tilepro.c index 540c6356c08..3990194cade 100644 --- a/gcc/config/tilepro/tilepro.c +++ b/gcc/config/tilepro/tilepro.c @@ -4458,9 +4458,7 @@ tilepro_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain) end_addr = force_reg (Pmode, plus_constant (Pmode, XEXP (m_tramp, 0), TRAMPOLINE_SIZE)); - emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"), - LCT_NORMAL, VOIDmode, begin_addr, Pmode, - end_addr, Pmode); + maybe_emit_call_builtin___clear_cache (begin_addr, end_addr); } diff --git a/gcc/config/vxworks.c b/gcc/config/vxworks.c index ca0f5de12a7..b67d21d07c6 100644 --- a/gcc/config/vxworks.c +++ b/gcc/config/vxworks.c @@ -27,6 +27,9 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-core.h" #include "output.h" #include "fold-const.h" +#include "rtl.h" +#include "memmodel.h" +#include "optabs.h" #if !HAVE_INITFINI_ARRAY_SUPPORT /* Like default_named_section_asm_out_constructor, except that even @@ -169,4 +172,25 @@ vxworks_override_options (void) if (!global_options_set.x_dwarf_version) dwarf_version = VXWORKS_DWARF_VERSION_DEFAULT; + +} + +/* We don't want to use library symbol __clear_cache on SR0640. Avoid + it and issue a direct call to cacheTextUpdate. It takes a size_t + length rather than the END address, so we have to compute it. */ + +void +vxworks_emit_call_builtin___clear_cache (rtx begin, rtx end) +{ + /* STATUS cacheTextUpdate (void *, size_t); */ + rtx callee = gen_rtx_SYMBOL_REF (Pmode, "cacheTextUpdate"); + + enum machine_mode size_mode = TYPE_MODE (sizetype); + + rtx len = simplify_gen_binary (MINUS, size_mode, end, begin); + + emit_library_call (callee, + LCT_NORMAL, VOIDmode, + begin, ptr_mode, + len, size_mode); } diff --git a/gcc/config/vxworks.h b/gcc/config/vxworks.h index e2ce22bec8b..cd4313982fa 100644 --- a/gcc/config/vxworks.h +++ b/gcc/config/vxworks.h @@ -282,10 +282,13 @@ extern void vxworks_asm_out_destructor (rtx symbol, int priority); /* The diab linker does not handle .gnu_attribute sections. */ #undef HAVE_AS_GNU_ATTRIBUTE -/* We provide our own version of __clear_cache in libgcc, using a separate C - file to facilitate #inclusion of VxWorks header files. */ -#undef CLEAR_INSN_CACHE -#define CLEAR_INSN_CACHE 1 +/* We call vxworks's cacheTextUpdate instead of CLEAR_INSN_CACHE if + needed. We don't want to force a call on targets that don't define + cache-clearing insns nor CLEAR_INSN_CACHE. */ +#undef TARGET_EMIT_CALL_BUILTIN___CLEAR_CACHE +#define TARGET_EMIT_CALL_BUILTIN___CLEAR_CACHE \ + vxworks_emit_call_builtin___clear_cache +extern void vxworks_emit_call_builtin___clear_cache (rtx begin, rtx end); /* Default dwarf control values, for non-gdb debuggers that come with VxWorks. */ diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 9f700b1c774..f5077655716 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -5457,11 +5457,24 @@ Note that the block move need only cover the constant parts of the trampoline. If the target isolates the variable parts of the trampoline to the end, not all @code{TRAMPOLINE_SIZE} bytes need be copied. -If the target requires any other actions, such as flushing caches or +If the target requires any other actions, such as flushing caches +(possibly calling function maybe_emit_call_builtin___clear_cache) or enabling stack execution, these actions should be performed after initializing the trampoline proper. @end deftypefn +@deftypefn {Target Hook} void TARGET_EMIT_CALL_BUILTIN___CLEAR_CACHE (rtx @var{begin}, rtx @var{end}) +On targets that do not define a @code{clear_cache} insn expander, +but that define the @code{CLEAR_CACHE_INSN} macro, +maybe_emit_call_builtin___clear_cache relies on this target hook +to clear an address range in the instruction cache. + +The default implementation calls the @code{__clear_cache} builtin, +taking the assembler name from the builtin declaration. Overriding +definitions may call alternate functions, with alternate calling +conventions, or emit alternate RTX to perform the job. +@end deftypefn + @deftypefn {Target Hook} rtx TARGET_TRAMPOLINE_ADJUST_ADDRESS (rtx @var{addr}) This hook should perform any machine-specific adjustment in the address of the trampoline. Its argument contains the address of the @@ -5490,7 +5503,7 @@ the following macro. If defined, expands to a C expression clearing the @emph{instruction cache} in the specified interval. The definition of this macro would typically be a series of @code{asm} statements. Both @var{beg} and -@var{end} are both pointer expressions. +@var{end} are pointer expressions. @end defmac To use a standard subroutine, define the following macro. In addition, diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 012cb1c53f0..ad568581fd4 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -3877,6 +3877,8 @@ is used for aligning trampolines. @hook TARGET_TRAMPOLINE_INIT +@hook TARGET_EMIT_CALL_BUILTIN___CLEAR_CACHE + @hook TARGET_TRAMPOLINE_ADJUST_ADDRESS Implementing trampolines is difficult on many machines because they have @@ -3897,7 +3899,7 @@ the following macro. If defined, expands to a C expression clearing the @emph{instruction cache} in the specified interval. The definition of this macro would typically be a series of @code{asm} statements. Both @var{beg} and -@var{end} are both pointer expressions. +@var{end} are pointer expressions. @end defmac To use a standard subroutine, define the following macro. In addition, diff --git a/gcc/target.def b/gcc/target.def index 14f06b6d4f9..a0ea853b75f 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -5166,12 +5166,28 @@ Note that the block move need only cover the constant parts of the\n\ trampoline. If the target isolates the variable parts of the trampoline\n\ to the end, not all @code{TRAMPOLINE_SIZE} bytes need be copied.\n\ \n\ -If the target requires any other actions, such as flushing caches or\n\ +If the target requires any other actions, such as flushing caches\n\ +(possibly calling function maybe_emit_call_builtin___clear_cache) or\n\ enabling stack execution, these actions should be performed after\n\ initializing the trampoline proper.", void, (rtx m_tramp, tree fndecl, rtx static_chain), default_trampoline_init) +/* Emit a call to a function to clear the instruction cache. */ +DEFHOOK +(emit_call_builtin___clear_cache, + "On targets that do not define a @code{clear_cache} insn expander,\n\ +but that define the @code{CLEAR_CACHE_INSN} macro,\n\ +maybe_emit_call_builtin___clear_cache relies on this target hook\n\ +to clear an address range in the instruction cache.\n\ +\n\ +The default implementation calls the @code{__clear_cache} builtin,\n\ +taking the assembler name from the builtin declaration. Overriding\n\ +definitions may call alternate functions, with alternate calling\n\ +conventions, or emit alternate RTX to perform the job.", + void, (rtx begin, rtx end), + default_emit_call_builtin___clear_cache) + /* Adjust the address of the trampoline in a target-specific way. */ DEFHOOK (trampoline_adjust_address, diff --git a/gcc/targhooks.h b/gcc/targhooks.h index 68e8688a32f..4542ba1b22d 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -166,6 +166,7 @@ extern bool default_function_value_regno_p (const unsigned int); extern rtx default_internal_arg_pointer (void); extern rtx default_static_chain (const_tree, bool); extern void default_trampoline_init (rtx, tree, rtx); +extern void default_emit_call_builtin___clear_cache (rtx, rtx); extern poly_int64 default_return_pops_args (tree, tree, poly_int64); extern reg_class_t default_ira_change_pseudo_allocno_class (int, reg_class_t, reg_class_t); diff --git a/gcc/tree.h b/gcc/tree.h index ecdb11efcd1..7faa49d42ba 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -5600,6 +5600,13 @@ is_lang_specific (const_tree t) #define BUILTIN_VALID_P(FNCODE) \ (IN_RANGE ((int)FNCODE, ((int)BUILT_IN_NONE) + 1, ((int) END_BUILTINS) - 1)) +/* Obtain a pointer to the identifier string holding the asm name for + BUILTIN, a BUILT_IN code. This is handy if the target + mangles/overrides the function name that implements the + builtin. */ +#define BUILTIN_ASM_NAME_PTR(BUILTIN) \ + (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (builtin_decl_explicit (BUILTIN)))) + /* Return the tree node for an explicit standard builtin function or NULL. */ static inline tree builtin_decl_explicit (enum built_in_function fncode) diff --git a/libgcc/config/t-vxworks b/libgcc/config/t-vxworks index 02e2efa0eb7..b4bb85bff08 100644 --- a/libgcc/config/t-vxworks +++ b/libgcc/config/t-vxworks @@ -4,7 +4,6 @@ LIBGCC2_DEBUG_CFLAGS = # We provide our own implementation for __clear_cache, using a # VxWorks specific entry point. LIB2FUNCS_EXCLUDE += _clear_cache -LIB2ADD += $(srcdir)/config/vxcache.c # This ensures that the correct target headers are used; some VxWorks # system headers have names that collide with GCC's internal (host) diff --git a/libgcc/config/t-vxworks7 b/libgcc/config/t-vxworks7 index 20c72f490dd..6ddd3e84f33 100644 --- a/libgcc/config/t-vxworks7 +++ b/libgcc/config/t-vxworks7 @@ -4,7 +4,6 @@ LIBGCC2_DEBUG_CFLAGS = # We provide our own implementation for __clear_cache, using a # VxWorks specific entry point. LIB2FUNCS_EXCLUDE += _clear_cache -LIB2ADD += $(srcdir)/config/vxcache.c # This ensures that the correct target headers are used; some VxWorks # system headers have names that collide with GCC's internal (host) diff --git a/libgcc/config/vxcache.c b/libgcc/config/vxcache.c deleted file mode 100644 index e25e0cce0a4..00000000000 --- a/libgcc/config/vxcache.c +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (C) 2018-2020 Free Software Foundation, Inc. - Contributed by Alexandre Oliva - -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. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -. */ - -/* Instruction cache invalidation routine using VxWorks' cacheLib. */ - -#include -#include - -void -__clear_cache (char *beg __attribute__((__unused__)), - char *end __attribute__((__unused__))) -{ - cacheTextUpdate (beg, end - beg); -}