https://gcc.gnu.org/g:e347e2b81ac7daa7382c611a62d54ec0b761bee8
commit r16-4379-ge347e2b81ac7daa7382c611a62d54ec0b761bee8 Author: Georg-Johann Lay <[email protected]> Date: Wed Dec 11 11:57:46 2024 +0100 Allow target to chose address-space for artificial rodata. This patch adds a new target hook TARGET_ADDR_SPACE_FOR_ARTIFICIAL_RODATA that allows the backend to chose an address space other than the generic one. This hook is only invoked when the compiler can make sure that: - The object for which the hooks is being invoked will be located in the desired address space, and - All accesses to that object will be accesses appropriate for that address space, and - The object is read-only and is initialized at load time, and - The hook invokations are independent of each other. This means that this hook can be used to optimize code / data consumption. (Rather than introducing an ABI change, which would be the case when C++'s vtables were put in a different AS). To date, there are only two candidates for such compiler generated lookup tables: CSWTCH tables as generated by tree-switch-conversion.cc, and CRC lookup tables generated by gimple-crc-optimization.cc. gcc/ * coretypes.h (enum artificial_rodata): New enum type. * doc/tm.texi: Rebuild. * doc/tm.texi.in (TARGET_ADDR_SPACE_FOR_ARTIFICIAL_RODATA): New hook. * target.def (addr_sapce.for_artificial_rodata): New DEFHOOK. * targhooks.cc (default_addr_space_convert): New function. * targhooks.h (default_addr_space_convert): New prototype. * tree-switch-conversion.cc (build_one_array) <value_type>: Set type_quals address-space according to targetm.addr_space.for_artificial_rodata(). * config/avr/avr.cc (avr_rodata_in_flash_p): Move up. (TARGET_ADDR_SPACE_FOR_ARTIFICIAL_RODATA): Define to... (avr_addr_space_for_artificial_rodata): ...this new function. * common/config/avr/avr-common.cc (avr_option_optimization_table): Adjust -ftree-switch-conversion comment. Diff: --- gcc/common/config/avr/avr-common.cc | 11 ++-- gcc/config/avr/avr.cc | 108 ++++++++++++++++++++++-------------- gcc/coretypes.h | 13 +++++ gcc/doc/tm.texi | 25 +++++++++ gcc/doc/tm.texi.in | 2 + gcc/target.def | 29 ++++++++++ gcc/targhooks.cc | 10 ++++ gcc/targhooks.h | 2 + gcc/tree-switch-conversion.cc | 10 ++++ 9 files changed, 161 insertions(+), 49 deletions(-) diff --git a/gcc/common/config/avr/avr-common.cc b/gcc/common/config/avr/avr-common.cc index 914b7417fdad..5b642345a0aa 100644 --- a/gcc/common/config/avr/avr-common.cc +++ b/gcc/common/config/avr/avr-common.cc @@ -29,12 +29,11 @@ /* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */ static const struct default_options avr_option_optimization_table[] = { - // The lookup table from tree-swicth-conversion.cc lives in .rodata - // and hence consumes RAM on almost all devices. As PR49857 has - // been rejected several times for non-technical reasons, just - // disable -ftree-switch-conversion by default. But even with PR49857 - // in place there remains PR81540, which cannot be filtered out since - // the pass has no way to hook in. + // There is no way to filter out unwanted cswtch transformations: + // - Code bload as mentioned in PR81540. + // - When tree-switch-conversion.cc::build_one_array() finds a + // linear function, it will use a formula that involves a + // multiplication without even trying to work out the costs. { OPT_LEVELS_ALL, OPT_ftree_switch_conversion, NULL, 0 }, // The only effect of -fcaller-saves might be that it triggers // a frame without need when it tries to be smart around calls. diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index 033bd09e7bfc..0cee92565777 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -120,6 +120,25 @@ const avr_addrspace_t avr_addrspace[ADDR_SPACE_COUNT] = }; +#ifdef HAVE_LD_AVR_AVRXMEGA2_FLMAP +static const bool have_avrxmega2_flmap = true; +#else +static const bool have_avrxmega2_flmap = false; +#endif + +#ifdef HAVE_LD_AVR_AVRXMEGA4_FLMAP +static const bool have_avrxmega4_flmap = true; +#else +static const bool have_avrxmega4_flmap = false; +#endif + +#ifdef HAVE_LD_AVR_AVRXMEGA3_RODATA_IN_FLASH +static const bool have_avrxmega3_rodata_in_flash = true; +#else +static const bool have_avrxmega3_rodata_in_flash = false; +#endif + + /* Holding RAM addresses of some SFRs used by the compiler and that are unique over all devices in an architecture like 'avr4'. */ @@ -287,6 +306,36 @@ avr_tolower (char *lo, const char *up) } +/* Return TRUE when the .rodata sections are located in program memory (flash). + Otherwise, the .rodata input sections are located in RAM and FALSE is + returned. Note that the FLMAP cases are a bit wonky since the libs are + compiled with the default but -mrodata-in-ram is not a multilib option. */ + +static bool +avr_rodata_in_flash_p () +{ + switch (avr_arch_index) + { + default: + break; + + case ARCH_AVRTINY: + return true; + + case ARCH_AVRXMEGA3: + return have_avrxmega3_rodata_in_flash; + + case ARCH_AVRXMEGA2: + return avropt_flmap && have_avrxmega2_flmap && avropt_rodata_in_ram != 1; + + case ARCH_AVRXMEGA4: + return avropt_flmap && have_avrxmega4_flmap && avropt_rodata_in_ram != 1; + } + + return false; +} + + /* Return chunk of mode MODE of X as an rtx. N specifies the subreg byte at which the chunk starts. N must be an integral multiple of the mode size. */ @@ -11482,6 +11531,18 @@ avr_addr_space_diagnose_usage (addr_space_t as, location_t loc) } +/* Implement `TARGET_ADDR_SPACE_FOR_ARTIFICIAL_RODATA'. */ + +static addr_space_t +avr_addr_space_for_artificial_rodata (tree /*type*/, + artificial_rodata /*kind*/) +{ + return avr_rodata_in_flash_p () + ? ADDR_SPACE_GENERIC + : avropt_n_flash > 1 ? ADDR_SPACE_FLASHX : ADDR_SPACE_FLASH; +} + + /* Implement `TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID'. Zero is a valid address in all address spaces. Even in ADDR_SPACE_FLASH1 etc.., a zero address is valid and means 0x<RAMPZ val>0000, where RAMPZ is @@ -11823,49 +11884,6 @@ avr_insert_attributes (tree node, tree *attributes) } } -#ifdef HAVE_LD_AVR_AVRXMEGA2_FLMAP -static const bool have_avrxmega2_flmap = true; -#else -static const bool have_avrxmega2_flmap = false; -#endif - -#ifdef HAVE_LD_AVR_AVRXMEGA4_FLMAP -static const bool have_avrxmega4_flmap = true; -#else -static const bool have_avrxmega4_flmap = false; -#endif - -#ifdef HAVE_LD_AVR_AVRXMEGA3_RODATA_IN_FLASH -static const bool have_avrxmega3_rodata_in_flash = true; -#else -static const bool have_avrxmega3_rodata_in_flash = false; -#endif - - -static bool -avr_rodata_in_flash_p () -{ - switch (avr_arch_index) - { - default: - break; - - case ARCH_AVRTINY: - return true; - - case ARCH_AVRXMEGA3: - return have_avrxmega3_rodata_in_flash; - - case ARCH_AVRXMEGA2: - return avropt_flmap && have_avrxmega2_flmap && avropt_rodata_in_ram != 1; - - case ARCH_AVRXMEGA4: - return avropt_flmap && have_avrxmega4_flmap && avropt_rodata_in_ram != 1; - } - - return false; -} - /* Implement `ASM_OUTPUT_ALIGNED_DECL_LOCAL'. */ /* Implement `ASM_OUTPUT_ALIGNED_DECL_COMMON'. */ @@ -16811,6 +16829,10 @@ avr_unwind_word_mode () #undef TARGET_ADDR_SPACE_DIAGNOSE_USAGE #define TARGET_ADDR_SPACE_DIAGNOSE_USAGE avr_addr_space_diagnose_usage +#undef TARGET_ADDR_SPACE_FOR_ARTIFICIAL_RODATA +#define TARGET_ADDR_SPACE_FOR_ARTIFICIAL_RODATA \ + avr_addr_space_for_artificial_rodata + #undef TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID #define TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID avr_addr_space_zero_address_valid diff --git a/gcc/coretypes.h b/gcc/coretypes.h index b6a922a506c3..8c3633b96771 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -342,6 +342,19 @@ enum warn_strict_overflow_code WARN_STRICT_OVERFLOW_MAGNITUDE = 5 }; +/* Kind of artificial, compiler-generated lookup table. Type of the + second argument of TARGET_ADDR_SPACE_FOR_ARTIFICIAL_RODATA resp. + targetm.addr_space.for_artificial_rodata. */ +enum artificial_rodata +{ + /* Generated by tree-switch-conversion.cc: Lowered GIMPLE_SWITCH expressions + to something more efficient than a jump table. */ + ARTIFICIAL_RODATA_CSWITCH, + + /* Generated by gimple-crc-optimization.cc: CRC optimization. */ + ARTIFICIAL_RODATA_CRC +}; + /* The type of an alias set. Code currently assumes that variables of this type can take the values 0 (the alias set which aliases everything) and -1 (sometimes indicating that the alias set is diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 930003725378..fd208f53844a 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -11532,6 +11532,31 @@ the address space as registered with @code{c_register_addr_space}. The default implementation does nothing. @end deftypefn +@deftypefn {Target Hook} addr_space_t TARGET_ADDR_SPACE_FOR_ARTIFICIAL_RODATA (tree @var{type}, enum artificial_rodata @var{purpose}) +Define this hook to return a named address space to be used for +@var{type}, usually the type of an artificial lookup-table that would +reside in @code{.rodata} and in the generic address space. + +The hook can be used to put compiler-generated, artificial lookup tables in +static storage into a non-generic address space when it is better suited +than the generic address space. +The compiler will generate all accesses to the respective data +so that all associated accesses will also use the specified address space +and pointer mode. + +@var{type} is the type of the lookup table. @var{purpose} specifies +the purpose of the lookup table. It is one of: +@table @code +@item ARTIFICIAL_RODATA_CSWITCH +@file{tree-switch-conversion.cc} lowered a GIMPLE_SWITCH expressions +to something more efficient than a jump table. +@item ARTIFICIAL_RODATA_CRC +@file{gimple-crc-optimization.cc} optimized a CRC computation by +using a polynomial lookup table. +@end table +The default implementation of the hook returns @code{ADDR_SPACE_GENERIC}. +@end deftypefn + @node Misc @section Miscellaneous Parameters @cindex parameters, miscellaneous diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 4838af8c0da9..14315dd50805 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -7375,6 +7375,8 @@ c_register_addr_space ("__ea", ADDR_SPACE_EA); @hook TARGET_ADDR_SPACE_DIAGNOSE_USAGE +@hook TARGET_ADDR_SPACE_FOR_ARTIFICIAL_RODATA + @node Misc @section Miscellaneous Parameters @cindex parameters, miscellaneous diff --git a/gcc/target.def b/gcc/target.def index 31c7af1f8bcc..f288329ffcab 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -3540,6 +3540,35 @@ The default implementation does nothing.", void, (addr_space_t as, location_t loc), default_addr_space_diagnose_usage) +/* Function to patch the address space of some compiler-generated + read-only data. Used for optimization purposes only. */ +DEFHOOK +(for_artificial_rodata, + "Define this hook to return a named address space to be used for\n\ +@var{type}, usually the type of an artificial lookup-table that would\n\ +reside in @code{.rodata} and in the generic address space.\n\ +\n\ +The hook can be used to put compiler-generated, artificial lookup tables in\n\ +static storage into a non-generic address space when it is better suited\n\ +than the generic address space.\n\ +The compiler will generate all accesses to the respective data\n\ +so that all associated accesses will also use the specified address space\n\ +and pointer mode.\n\ +\n\ +@var{type} is the type of the lookup table. @var{purpose} specifies\n\ +the purpose of the lookup table. It is one of:\n\ +@table @code\n\ +@item ARTIFICIAL_RODATA_CSWITCH\n\ +@file{tree-switch-conversion.cc} lowered a GIMPLE_SWITCH expressions\n\ +to something more efficient than a jump table.\n\ +@item ARTIFICIAL_RODATA_CRC\n\ +@file{gimple-crc-optimization.cc} optimized a CRC computation by\n\ +using a polynomial lookup table.\n\ +@end table\n\ +The default implementation of the hook returns @code{ADDR_SPACE_GENERIC}.", + addr_space_t, (tree type, enum artificial_rodata purpose), + default_addr_space_for_artificial_rodata) + HOOK_VECTOR_END (addr_space) #undef HOOK_PREFIX diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc index dfd46eeb8af8..1873d572ba3f 100644 --- a/gcc/targhooks.cc +++ b/gcc/targhooks.cc @@ -1791,6 +1791,16 @@ default_addr_space_convert (rtx op ATTRIBUTE_UNUSED, gcc_unreachable (); } + +/* The default hook for TARGET_ADDR_SPACE_FOR_ARTIFICIAL_RODATA. */ + +addr_space_t +default_addr_space_for_artificial_rodata (tree, artificial_rodata) +{ + return ADDR_SPACE_GENERIC; +} + + /* The defualt implementation of TARGET_HARD_REGNO_NREGS. */ unsigned int diff --git a/gcc/targhooks.h b/gcc/targhooks.h index 441206763451..92e7a4cb10f1 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -214,6 +214,8 @@ extern bool default_addr_space_subset_p (addr_space_t, addr_space_t); extern bool default_addr_space_zero_address_valid (addr_space_t); extern int default_addr_space_debug (addr_space_t); extern void default_addr_space_diagnose_usage (addr_space_t, location_t); +extern addr_space_t default_addr_space_for_artificial_rodata (tree, + artificial_rodata); extern rtx default_addr_space_convert (rtx, tree, tree); extern unsigned int default_case_values_threshold (void); extern bool default_have_conditional_execution (void); diff --git a/gcc/tree-switch-conversion.cc b/gcc/tree-switch-conversion.cc index 62eddcd95d31..4bd8ed750511 100644 --- a/gcc/tree-switch-conversion.cc +++ b/gcc/tree-switch-conversion.cc @@ -1008,6 +1008,16 @@ switch_conversion::build_one_array (int num, tree arr_index_type, default_type = TREE_TYPE (m_default_values[num]); value_type = array_value_type (default_type, num); array_type = build_array_type (value_type, arr_index_type); + addr_space_t as + = targetm.addr_space.for_artificial_rodata (array_type, + ARTIFICIAL_RODATA_CSWITCH); + if (!ADDR_SPACE_GENERIC_P (as)) + { + int quals = (TYPE_QUALS_NO_ADDR_SPACE (value_type) + | ENCODE_QUAL_ADDR_SPACE (as)); + value_type = build_qualified_type (value_type, quals); + array_type = build_array_type (value_type, arr_index_type); + } if (default_type != value_type) { unsigned int i;
