]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Allow target to chose address-space for artificial rodata.
authorGeorg-Johann Lay <avr@gjlay.de>
Wed, 11 Dec 2024 10:57:46 +0000 (11:57 +0100)
committerGeorg-Johann Lay <avr@gjlay.de>
Sat, 11 Oct 2025 13:36:34 +0000 (15:36 +0200)
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.

gcc/common/config/avr/avr-common.cc
gcc/config/avr/avr.cc
gcc/coretypes.h
gcc/doc/tm.texi
gcc/doc/tm.texi.in
gcc/target.def
gcc/targhooks.cc
gcc/targhooks.h
gcc/tree-switch-conversion.cc

index 914b7417fdad4262b90842ea433a9502a861b153..5b642345a0aa37f73a18a0de92d7a32ba5c70d4e 100644 (file)
 /* 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.
index 033bd09e7bfc01876098cba2c921247fdbf71e3d..0cee92565777e67efa3eb626b21aaff6a588d083 100644 (file)
@@ -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
 
index b6a922a506c3b12b98f3b2a9b1c3aab00ab4cf40..8c3633b96771d5543638b656eb14371e24e8898e 100644 (file)
@@ -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
index 93000372537822ac784310af27928e079a24909f..fd208f53844a157721dd8a0282f283da64cf5d93 100644 (file)
@@ -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
index 4838af8c0da9f734171ce763689e8266c3e32d98..14315dd508051037b7936c89638c05f07b6d3d6f 100644 (file)
@@ -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
index 31c7af1f8bcc10ba22c74d816eaba96afcff8b55..f288329ffcab81e2773c2066e60a470611f29e23 100644 (file)
@@ -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
index dfd46eeb8af8fb3d41f0779cb75f0ad05429de6f..1873d572ba3fb59c4713e10b5c5b14afb029b953 100644 (file)
@@ -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
index 441206763451cc5b09ff1a5f7f7e4aed9792afe3..92e7a4cb10f109978301d8c10f69b4c5a3952f56 100644 (file)
@@ -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);
index 62eddcd95d312019d8b03ff75d8afa07b6745d67..4bd8ed750511ba450561a830047a063750323e31 100644 (file)
@@ -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;