Hi! As detailed in the PR, unlike most other targets, on ARM EABI the floating point registers are saved lazily, when EH personality routine calls __gnu_unwind_frame (usually in the CONTINUE_UNWINDING macro). That means the unwinder itself and the personality routines (and whatever other functions those call in the path to CONTINUE_UNWINDING) must be compiled so that it doesn't use floating point registers. Calling some function that saves those on entry and restores on exit is fine, but calling some function which saves those on entry and then calls __gnu_unwind_frame and then restores on exit is not fine. In 8.x and earlier we were just lucky that the RA when compiling those didn't decide to use any of those registers, but starting with the combiner hard register changes we are no longer so lucky.
The following patch introduces -mgeneral-regs-only option and general-regs-only target attribute for ARM (similarly to how other targets like AArch64 and x86), changes the ARM unwinder to be compiled with that and changes the personality routines of all languages so that either just the personality routine, or whatever other routines called by personality routines that call directly or indirectly __gnu_unwind_frame to be compiled that way. Bootstrapped/regtested on armv7hl-linux-gnueabi (and x86_64-linux to make sure it compiles on other targets too). Ok for trunk? While the libgo changes are included in the patch, I think those need to go through go upstream and will likely need some changes if that code can be compiled by earlier GCC versions or other compilers. Not sure about libphobos D stuff, does it need to go through upstream and is libdruntime/gcc/deh.d compiled by compilers other than GDC? The Ada changes need those guards because the file is compiled by both the system compiler and by the newly built compilers; when compiled by system compiler, as the FE is built with -fno-exceptions I'd hope the EH stuff isn't really used there and at least until GCC 9.1 is released we have the issue that the system compiler could be some earlier GCC 9.0.1 snapshot which doesn't support general-regs-only. 2019-04-22 Ramana Radhakrishnan <ramana.radhakrish...@arm.com> Bernd Edlinger <bernd.edlin...@hotmail.de> Jakub Jelinek <ja...@redhat.com> PR target/89093 * config/arm/arm.c (aapcs_vfp_is_call_or_return_candidate): Diagnose if used with general-regs-only. (arm_conditional_register_usage): Don't add non-general regs if general-regs-only. (arm_valid_target_attribute_rec): Handle general-regs-only. * config/arm/arm.h (TARGET_HARD_FLOAT): Return false if general-regs-only. (TARGET_HARD_FLOAT_SUB): Define. (TARGET_SOFT_FLOAT): Define as negation of TARGET_HARD_FLOAT_SUB. (TARGET_REALLY_IWMMXT): Add && !TARGET_GENERAL_REGS_ONLY. (TARGET_REALLY_IWMMXT2): Likewise. * config/arm/arm.opt: Add -mgeneral-regs-only. * doc/extend.texi: Document ARM general-regs-only target. * doc/invoke.texi: Document ARM -mgeneral-regs-only. gcc/ada/ * raise-gcc.c (TARGET_ATTRIBUTE): Define. (continue_unwind, personality_body, PERSONALITY_FUNCTION): Add TARGET_ATTRIBUTE. libgcc/ * config/arm/pr-support.c: Add #pragma GCC target("general-regs-only"). * config/arm/unwind-arm.c: Likewise. * unwind-c.c (PERSONALITY_FUNCTION): Add general-regs-only target attribute for ARM. libobjc/ * exception.c (PERSONALITY_FUNCTION): Add general-regs-only target attribute for ARM. libphobos/ * libdruntime/gcc/deh.d: Import gcc.attribute. (personality_fn_attributes): New enum. (scanLSDA, CONTINUE_UNWINDING, gdc_personality, __gdc_personality): Add @personality_fn_attributes. libstdc++-v3/ * libsupc++/eh_personality.cc (PERSONALITY_FUNCTION): Add general-regs-only target attribute for ARM. libgo/ * runtime/go-unwind.c (PERSONALITY_FUNCTION, __gccgo_personality_dummy): Add general-regs-only target attribute for ARM. --- gcc/config/arm/arm.c (revision 270444) +++ gcc/config/arm/arm.c (working copy) @@ -6112,6 +6112,11 @@ aapcs_vfp_is_call_or_return_candidate (enum arm_pc return false; *base_mode = new_mode; + + if (TARGET_GENERAL_REGS_ONLY) + error ("argument of type %qT not permitted with -mgeneral-regs-only", + type); + return true; } @@ -28404,7 +28409,7 @@ arm_conditional_register_usage (void) } } - if (TARGET_REALLY_IWMMXT) + if (TARGET_REALLY_IWMMXT && !TARGET_GENERAL_REGS_ONLY) { regno = FIRST_IWMMXT_GR_REGNUM; /* The 2002/10/09 revision of the XScale ABI has wCG0 @@ -30878,6 +30883,9 @@ arm_valid_target_attribute_rec (tree args, struct else if (!strcmp (q, "arm")) opts->x_target_flags &= ~MASK_THUMB; + else if (!strcmp (q, "general-regs-only")) + opts->x_target_flags |= MASK_GENERAL_REGS_ONLY; + else if (!strncmp (q, "fpu=", 4)) { int fpu_index; --- gcc/config/arm/arm.h (revision 270444) +++ gcc/config/arm/arm.h (working copy) @@ -122,12 +122,18 @@ extern tree arm_fp16_type_node; #define TARGET_32BIT_P(flags) (TARGET_ARM_P (flags) || TARGET_THUMB2_P (flags)) /* Run-time Target Specification. */ -/* Use hardware floating point instructions. */ -#define TARGET_HARD_FLOAT (arm_float_abi != ARM_FLOAT_ABI_SOFT \ +/* Use hardware floating point instructions. -mgeneral-regs-only prevents +the use of floating point instructions and registers but does not prevent +emission of floating point pcs attributes. */ +#define TARGET_HARD_FLOAT_SUB (arm_float_abi != ARM_FLOAT_ABI_SOFT \ && bitmap_bit_p (arm_active_target.isa, \ isa_bit_vfpv2) \ && TARGET_32BIT) -#define TARGET_SOFT_FLOAT (!TARGET_HARD_FLOAT) + +#define TARGET_HARD_FLOAT (TARGET_HARD_FLOAT_SUB \ + && !TARGET_GENERAL_REGS_ONLY) + +#define TARGET_SOFT_FLOAT (!TARGET_HARD_FLOAT_SUB) /* User has permitted use of FP instructions, if they exist for this target. */ #define TARGET_MAYBE_HARD_FLOAT (arm_float_abi != ARM_FLOAT_ABI_SOFT) @@ -135,8 +141,10 @@ extern tree arm_fp16_type_node; #define TARGET_HARD_FLOAT_ABI (arm_float_abi == ARM_FLOAT_ABI_HARD) #define TARGET_IWMMXT (arm_arch_iwmmxt) #define TARGET_IWMMXT2 (arm_arch_iwmmxt2) -#define TARGET_REALLY_IWMMXT (TARGET_IWMMXT && TARGET_32BIT) -#define TARGET_REALLY_IWMMXT2 (TARGET_IWMMXT2 && TARGET_32BIT) +#define TARGET_REALLY_IWMMXT (TARGET_IWMMXT && TARGET_32BIT \ + && !TARGET_GENERAL_REGS_ONLY) +#define TARGET_REALLY_IWMMXT2 (TARGET_IWMMXT2 && TARGET_32BIT \ + && !TARGET_GENERAL_REGS_ONLY) #define TARGET_IWMMXT_ABI (TARGET_32BIT && arm_abi == ARM_ABI_IWMMXT) #define TARGET_ARM (! TARGET_THUMB) #define TARGET_EITHER 1 /* (TARGET_ARM | TARGET_THUMB) */ --- gcc/config/arm/arm.opt (revision 270444) +++ gcc/config/arm/arm.opt (working copy) @@ -302,3 +302,7 @@ When linking for big-endian targets, generate a le mbranch-cost= Target RejectNegative Joined UInteger Var(arm_branch_cost) Init(-1) Cost to assume for a branch insn. + +mgeneral-regs-only +Target Report RejectNegative Mask(GENERAL_REGS_ONLY) Save +Generate code which uses the core registers only (r0-r14). --- gcc/doc/extend.texi (revision 270444) +++ gcc/doc/extend.texi (working copy) @@ -4190,6 +4190,15 @@ into the @code{sjli} table needs to be passed as a These function attributes are supported for ARM targets: @table @code + +@item general-regs-only +@cindex @code{general-regs-only} function attribute, ARM +Indicates that no floating-point or Advanced SIMD registers should be +used when generating code for this function. If the function explicitly +uses floating-point code, then the compiler gives an error. This is +the same behavior as that of the command-line option +@option{-mgeneral-regs-only}. + @item interrupt @cindex @code{interrupt} function attribute, ARM Use this attribute to indicate --- gcc/doc/invoke.texi (revision 270444) +++ gcc/doc/invoke.texi (working copy) @@ -674,6 +674,7 @@ Objective-C and Objective-C++ Dialects}. -mabi=@var{name} @gol -mapcs-stack-check -mno-apcs-stack-check @gol -mapcs-reentrant -mno-apcs-reentrant @gol +-mgeneral-regs-only @gol -msched-prolog -mno-sched-prolog @gol -mlittle-endian -mbig-endian @gol -mbe8 -mbe32 @gol @@ -17068,6 +17069,12 @@ the hard-float and soft-float ABIs are not link-co compile your entire program with the same ABI, and link with a compatible set of libraries. +@item -mgeneral-regs-only +@opindex mgeneral-regs-only +Generate code which uses only the general-purpose registers. This will prevent +the compiler from using floating-point and Advanced SIMD registers but will not +impose any restrictions on the assembler. + @item -mlittle-endian @opindex mlittle-endian Generate code for a processor running in little-endian mode. This is --- gcc/ada/raise-gcc.c (revision 270444) +++ gcc/ada/raise-gcc.c (working copy) @@ -1154,10 +1154,18 @@ extern void __gnat_notify_unhandled_exce #define PERSONALITY_FUNCTION __gnat_personality_v0 #endif +#if defined (__ARM_EABI_UNWINDER__) \ + && (defined (IN_RTS) || GCC_VERSION > 9000) +#define TARGET_ATTRIBUTE __attribute__((target ("general-regs-only"))) +#else +#define TARGET_ATTRIBUTE +#endif + /* Code executed to continue unwinding. With the ARM unwinder, the personality routine must unwind one frame (per EHABI 7.3 4.). */ static _Unwind_Reason_Code +TARGET_ATTRIBUTE continue_unwind (struct _Unwind_Exception* ue_header ATTRIBUTE_UNUSED, struct _Unwind_Context* uw_context ATTRIBUTE_UNUSED) { @@ -1172,6 +1180,7 @@ continue_unwind (struct _Unwind_Exceptio between all unwinders. */ static _Unwind_Reason_Code +TARGET_ATTRIBUTE personality_body (_Unwind_Action uw_phases, _Unwind_Exception *uw_exception, _Unwind_Context *uw_context) @@ -1342,6 +1351,7 @@ PERSONALITY_FUNCTION (_Unwind_State stat struct _Unwind_Context* uw_context); PERSONALITY_STORAGE _Unwind_Reason_Code +TARGET_ATTRIBUTE PERSONALITY_FUNCTION (_Unwind_State state, struct _Unwind_Exception* uw_exception, struct _Unwind_Context* uw_context) --- libgcc/config/arm/pr-support.c (revision 270444) +++ libgcc/config/arm/pr-support.c (working copy) @@ -21,6 +21,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see <http://www.gnu.org/licenses/>. */ +#pragma GCC target ("general-regs-only") #include "unwind.h" /* We add a prototype for abort here to avoid creating a dependency on --- libgcc/config/arm/unwind-arm.c (revision 270444) +++ libgcc/config/arm/unwind-arm.c (working copy) @@ -21,6 +21,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see <http://www.gnu.org/licenses/>. */ +#pragma GCC target ("general-regs-only") #include "unwind.h" /* Misc constants. */ --- libgcc/unwind-c.c (revision 270444) +++ libgcc/unwind-c.c (working copy) @@ -106,6 +106,7 @@ PERSONALITY_FUNCTION (_Unwind_State, struct _Unwin struct _Unwind_Context *); _Unwind_Reason_Code +__attribute__((target ("general-regs-only"))) PERSONALITY_FUNCTION (_Unwind_State state, struct _Unwind_Exception * ue_header, struct _Unwind_Context * context) --- libgo/runtime/go-unwind.c (revision 270444) +++ libgo/runtime/go-unwind.c (working copy) @@ -411,7 +411,7 @@ parse_lsda_header (struct _Unwind_Contex _Unwind_Reason_Code PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *) - __attribute__ ((no_split_stack, flatten)); + __attribute__ ((no_split_stack, flatten, target ("general-regs-only"))); _Unwind_Reason_Code PERSONALITY_FUNCTION (_Unwind_State state, @@ -604,6 +604,9 @@ __gccgo_personality_dummy (int, _Unwind_ __attribute__ ((no_split_stack)); _Unwind_Reason_Code +#ifdef __ARM_EABI_UNWINDER__ +__attribute__ ((target ("general-regs-only"))) +#endif __gccgo_personality_dummy (int version __attribute__ ((unused)), _Unwind_Action actions __attribute__ ((unused)), _Unwind_Exception_Class exception_class __attribute__ ((unused)), --- libobjc/exception.c (revision 270444) +++ libobjc/exception.c (working copy) @@ -220,6 +220,7 @@ get_ttype_entry (struct lsda_header_info *info, _U while (0) _Unwind_Reason_Code +__attribute__((target ("general-regs-only"))) PERSONALITY_FUNCTION (_Unwind_State state, struct _Unwind_Exception *ue_header, struct _Unwind_Context *context) --- libphobos/libdruntime/gcc/deh.d (revision 270444) +++ libphobos/libdruntime/gcc/deh.d (working copy) @@ -28,6 +28,7 @@ import gcc.unwind; import gcc.unwind.pe; import gcc.builtins; import gcc.config; +import gcc.attribute; extern(C) { @@ -519,10 +520,19 @@ extern(C) void _d_throw(Throwable object) terminate("unwind error", __LINE__); } +static if (GNU_ARM_EABI_Unwinder) +{ + enum personality_fn_attributes = attribute("target", ("general-regs-only")); +} +else +{ + enum personality_fn_attributes = ""; +} /** * Read and extract information from the LSDA (.gcc_except_table section). */ +@personality_fn_attributes _Unwind_Reason_Code scanLSDA(const(ubyte)* lsda, _Unwind_Exception_Class exceptionClass, _Unwind_Action actions, _Unwind_Exception* unwindHeader, _Unwind_Context* context, _Unwind_Word cfa, @@ -772,6 +782,7 @@ int actionTableLookup(_Unwind_Action actions, _Unw * Called when the personality function has found neither a cleanup or handler. * To support ARM EABI personality routines, that must also unwind the stack. */ +@personality_fn_attributes _Unwind_Reason_Code CONTINUE_UNWINDING(_Unwind_Exception* unwindHeader, _Unwind_Context* context) { static if (GNU_ARM_EABI_Unwinder) @@ -814,6 +825,7 @@ else static if (GNU_ARM_EABI_Unwinder) { pragma(mangle, PERSONALITY_FUNCTION) + @personality_fn_attributes extern(C) _Unwind_Reason_Code gdc_personality(_Unwind_State state, _Unwind_Exception* unwindHeader, _Unwind_Context* context) @@ -873,6 +885,7 @@ else } } +@personality_fn_attributes private _Unwind_Reason_Code __gdc_personality(_Unwind_Action actions, _Unwind_Exception_Class exceptionClass, _Unwind_Exception* unwindHeader, --- libstdc++-v3/libsupc++/eh_personality.cc (revision 270444) +++ libstdc++-v3/libsupc++/eh_personality.cc (working copy) @@ -343,6 +343,7 @@ extern "C" #endif _Unwind_Reason_Code #ifdef __ARM_EABI_UNWINDER__ +__attribute__((target ("general-regs-only"))) PERSONALITY_FUNCTION (_Unwind_State state, struct _Unwind_Exception* ue_header, struct _Unwind_Context* context) Jakub