For easier review, I broke that patch into two parts:
One for the strlen built-ins, and one to handle built-ins that are only available in C. Delta is the same. Johann Am 30.01.25 um 11:42 schrieb Georg-Johann Lay:
AVR: Provide built-ins for strlen where the string lives in some AS. This patch adds built-in functions __builtin_avr_strlen_flash, __builtin_avr_strlen_flashx and __builtin_avr_strlen_memx. Purpose is that higher-level functions can use __builtin_constant_p on strlen without raising a diagnostic due to -Waddr-space-convert. gcc/ * config/avr/builtins.def (AVR_FIRST_C_ONLY_BUILTIN_ID): New macro. (STRLEN_FLASH, STRLEN_FLASHX, STRLEN_MEMX): New DEF_BUILTIN's. * config/avr/avr-protos.h (avr_builtin_C_only_p): New. * config/avr/avr.cc (avr_builtin_C_only_p): New function. (avr_ftype_strlen): New static function. (avr_init_builtins): Only provide a built-in when it is supported for the compiled language. <strlen_flash_node, strlen_flashx_node, strlen_memx_node>: Provide new fntypes. (avr_fold_builtin) [AVR_BUILTIN_STRLEN_FLASH] [AVR_BUILTIN_STRLEN_FLASHX, AVR_BUILTIN_STRLEN_MEMX]: Fold if possible. * config/avr/avr-c.cc (avr_cpu_cpp_builtins): Only define the __BUILTIN_AVR_<NAME> build-in defines when a built-in function is available for the compiled language. * doc/extend.texi (AVR Built-in Functions): Document __builtin_avr_strlen_flash, __builtin_avr_strlen_flashx, __builtin_avr_strlen_memx. libgcc/ * config/avr/t-avr (LIB1ASMFUNCS): Add _strlen_memx. * config/avr/lib1funcs.S <L_strlen_memx, __strlen_memx>: Implement.
AVR: Only provide a built-in when it is available for the language. Some built-ins are not available for C++ since they are using named address-spaces or fixed-point types. gcc/ * config/avr/builtins.def (AVR_FIRST_C_ONLY_BUILTIN_ID): New macro. * config/avr/avr-protos.h (avr_builtin_C_only_p): New. * config/avr/avr.cc (avr_builtin_C_only_p): New function. (avr_init_builtins): Only provide a built-in when it is supported for the compiled language. * config/avr/avr-c.cc (avr_cpu_cpp_builtins): Only define the __BUILTIN_AVR_<NAME> build-in defines when a built-in function is available for the compiled language. * doc/extend.texi (AVR Built-in Functions): Add a note that following built-ins are supported for only for GNU-C. diff --git a/gcc/config/avr/avr-c.cc b/gcc/config/avr/avr-c.cc index 53f15f2be7b..ced541a9ddc 100644 --- a/gcc/config/avr/avr-c.cc +++ b/gcc/config/avr/avr-c.cc @@ -500,7 +500,9 @@ avr_cpu_cpp_builtins (cpp_reader *pfile) not a specific builtin is available. */ #define DEF_BUILTIN(NAME, N_ARGS, TYPE, CODE, LIBNAME, ATTRS) \ - cpp_define (pfile, "__BUILTIN_AVR_" #NAME); + if (lang_GNU_C () \ + || ! avr_builtin_C_only_p (AVR_BUILTIN_ ## NAME)) \ + cpp_define (pfile, "__BUILTIN_AVR_" #NAME); #include "builtins.def" #undef DEF_BUILTIN diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index 83137c7f6f6..72eb5163cce 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -21,6 +21,7 @@ extern bool avr_function_arg_regno_p (int r); extern void avr_cpu_cpp_builtins (cpp_reader * pfile); +extern bool avr_builtin_C_only_p (unsigned id); extern enum reg_class avr_regno_reg_class (int r); extern void asm_globalize_label (FILE *file, const char *name); extern void avr_adjust_reg_alloc_order (void); diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index 656d3e7389b..de9216e70ce 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -15689,6 +15689,17 @@ avr_bdesc[AVR_BUILTIN_COUNT] = }; +/* Some of our built-in function are available for GNU-C only: + - Built-ins that use named address-spaces. + - Built-ins that use fixed-point types. */ + +bool +avr_builtin_C_only_p (unsigned id) +{ + return id >= AVR_FIRST_C_ONLY_BUILTIN_ID; +} + + /* Implement `TARGET_BUILTIN_DECL'. */ static tree @@ -15885,8 +15896,15 @@ avr_init_builtins (void) tree attr_const = tree_cons (get_identifier ("const"), NULL, NULL); #define DEF_BUILTIN(NAME, N_ARGS, TYPE, CODE, LIBNAME, ATTRS) \ - { \ + do { \ int id = AVR_BUILTIN_ ## NAME; \ + if (! lang_GNU_C () \ + && avr_builtin_C_only_p (id)) \ + { \ + avr_bdesc[id].fndecl = NULL_TREE; \ + break; \ + } \ + \ const char *Name = "__builtin_avr_" #NAME; \ char *name = (char *) alloca (1 + strlen (Name)); \ \ @@ -15894,7 +15912,7 @@ avr_init_builtins (void) avr_bdesc[id].fndecl \ = add_builtin_function (avr_tolower (name, Name), TYPE, id, \ BUILT_IN_MD, LIBNAME, ATTRS); \ - } + } while (0); #include "builtins.def" #undef DEF_BUILTIN diff --git a/gcc/config/avr/builtins.def b/gcc/config/avr/builtins.def index 61dbc3a6c1b..ad75fe9c267 100644 --- a/gcc/config/avr/builtins.def +++ b/gcc/config/avr/builtins.def @@ -34,6 +34,8 @@ ATTRS: Function attributes like "attr_const" for the `const' attribute or "NULL_TREE" for no attribute. */ +#define AVR_FIRST_C_ONLY_BUILTIN_ID AVR_BUILTIN_FLASH_SEGMENT + /* Mapped to respective instruction. */ DEF_BUILTIN (NOP, -1, void_ftype_void, nothing, NULL, NULL_TREE) @@ -56,6 +58,11 @@ DEF_BUILTIN (DELAY_CYCLES, -1, void_ftype_uintSI, nothing, NULL, NULL_TREE) DEF_BUILTIN (NOPS, -1, void_ftype_uintSI, nothing, NULL, NULL_TREE) DEF_BUILTIN (MASK1, 2, uintQI_ftype_uintQI_uintQI, gen_mask1, NULL, attr_const) DEF_BUILTIN (INSERT_BITS, 3, uintQI_ftype_uintSI_uintQI_uintQI, insert_bits, NULL, attr_const) + +/* All following built-ins are C only, see avr.cc::avr_builtin_C_only_p() + * since they are using named address-spaces or fixed-point types, none + * of which are supported for C++. */ + DEF_BUILTIN (FLASH_SEGMENT, 1, intQI_ftype_const_memx_ptr, flash_segment, NULL, attr_const) /* ISO/IEC TR 18037 "Embedded C" diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 2764597a479..c6e7bc37f7d 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -17369,14 +17369,6 @@ might increase delay time. @var{ticks} must be a compile-time integer constant; delays with a variable number of cycles are not supported. @enddefbuiltin -@defbuiltin{int8_t __builtin_avr_flash_segment (const __memx void*)} -This built-in takes a byte address to the 24-bit -@ref{AVR Named Address Spaces,address space} @code{__memx} and returns -the number of the flash segment (the 64 KiB chunk) where the address -points to. Counting starts at @code{0}. -If the address does not point to flash memory, return @code{-1}. -@enddefbuiltin - @defbuiltin{uint8_t __builtin_avr_insert_bits (uint32_t @var{map}, uint8_t @var{bits}, uint8_t @var{val})} Insert bits from @var{bits} into @var{val} and return the resulting value. The nibbles of @var{map} determine how the insertion is @@ -17445,6 +17437,16 @@ Insert @var{count} @code{NOP} instructions. The number of instructions must be a compile-time integer constant. @enddefbuiltin +@b{All of the following built-in functions are only available for GNU-C} + +@defbuiltin{int8_t __builtin_avr_flash_segment (const __memx void*)} +This built-in takes a byte address to the 24-bit +@ref{AVR Named Address Spaces,named address space} @code{__memx} and returns +the number of the flash segment (the 64 KiB chunk) where the address +points to. Counting starts at @code{0}. +If the address does not point to flash memory, return @code{-1}. +@enddefbuiltin + @noindent There are many more AVR-specific built-in functions that are used to implement the ISO/IEC TR 18037 ``Embedded C'' fixed-point functions of
AVR: Provide built-ins for strlen where the string lives in some AS. This patch adds built-in functions __builtin_avr_strlen_flash, __builtin_avr_strlen_flashx and __builtin_avr_strlen_memx. Purpose is that higher-level functions can use __builtin_constant_p on strlen without raising a diagnostic due to -Waddr-space-convert. gcc/ * config/avr/builtins.def (STRLEN_FLASH, STRLEN_FLASHX) (STRLEN_MEMX): New DEF_BUILTIN's. * config/avr/avr.cc (avr_ftype_strlen): New static function. (avr_init_builtins) <strlen_flash_node, strlen_flashx_node, strlen_memx_node>: Provide new fntypes. (avr_fold_builtin) [AVR_BUILTIN_STRLEN_FLASH] [AVR_BUILTIN_STRLEN_FLASHX, AVR_BUILTIN_STRLEN_MEMX]: Fold if possible. * doc/extend.texi (AVR Built-in Functions): Document __builtin_avr_strlen_flash, __builtin_avr_strlen_flashx, __builtin_avr_strlen_memx. libgcc/ * config/avr/t-avr (LIB1ASMFUNCS): Add _strlen_memx. * config/avr/lib1funcs.S <L_strlen_memx, __strlen_memx>: Implement. diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index de9216e70ce..c33beb9b95d 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -15725,6 +15725,25 @@ avr_init_builtin_int24 (void) } +/* Return a function signature type similar to strlen, but where + the address is qualified by named address-space AS. */ + +static tree +avr_ftype_strlen (addr_space_t as) +{ + tree const_AS_char_node + = build_qualified_type (char_type_node, + TYPE_QUAL_CONST | ENCODE_QUAL_ADDR_SPACE (as)); + tree const_AS_ptr_type_node + = build_pointer_type_for_mode (const_AS_char_node, + avr_addr_space_pointer_mode (as), false); + tree size_ftype_const_AS_char_ptr + = build_function_type_list (size_type_node, const_AS_ptr_type_node, NULL); + + return size_ftype_const_AS_char_ptr; +} + + /* Implement `TARGET_INIT_BUILTINS' */ /* Set up all builtin functions for this target. */ @@ -15782,6 +15801,10 @@ avr_init_builtins (void) const_memx_ptr_type_node, NULL); + tree strlen_flash_node = avr_ftype_strlen (ADDR_SPACE_FLASH); + tree strlen_flashx_node = avr_ftype_strlen (ADDR_SPACE_FLASHX); + tree strlen_memx_node = avr_ftype_strlen (ADDR_SPACE_MEMX); + #define ITYP(T) \ lang_hooks.types.type_for_size (TYPE_PRECISION (T), TYPE_UNSIGNED (T)) @@ -16179,6 +16202,13 @@ avr_fold_builtin (tree fndecl, int /*n_args*/, tree *arg, bool /*ignore*/) build_int_cst (val_type, 4)); } + case AVR_BUILTIN_STRLEN_FLASH: + case AVR_BUILTIN_STRLEN_FLASHX: + case AVR_BUILTIN_STRLEN_MEMX: + if (tree len = c_strlen (arg[0], 0)) + return len; + break; + case AVR_BUILTIN_ABSHR: case AVR_BUILTIN_ABSR: case AVR_BUILTIN_ABSLR: diff --git a/gcc/config/avr/builtins.def b/gcc/config/avr/builtins.def index ad75fe9c267..c9610897784 100644 --- a/gcc/config/avr/builtins.def +++ b/gcc/config/avr/builtins.def @@ -65,6 +65,12 @@ DEF_BUILTIN (INSERT_BITS, 3, uintQI_ftype_uintSI_uintQI_uintQI, insert_bits, NUL DEF_BUILTIN (FLASH_SEGMENT, 1, intQI_ftype_const_memx_ptr, flash_segment, NULL, attr_const) +/* strlen for ASes so that __builtin_constant_p can be used wthout raising + a diagnostic from -Waddr-space-convert in some AVR-LibC headers. */ +DEF_BUILTIN (STRLEN_FLASH, 1, strlen_flash_node, nothing, "__strlen_P", attr_const) // AVR-LibC +DEF_BUILTIN (STRLEN_FLASHX, 1, strlen_flashx_node, nothing, "strlen_PF", attr_const) // AVR-LibC +DEF_BUILTIN (STRLEN_MEMX, 1, strlen_memx_node, nothing, "__strlen_memx", NULL_TREE) + /* ISO/IEC TR 18037 "Embedded C" The following builtins are undocumented and used by stdfix.h. */ diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index c6e7bc37f7d..172239216fd 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -17447,6 +17447,15 @@ points to. Counting starts at @code{0}. If the address does not point to flash memory, return @code{-1}. @enddefbuiltin +@defbuiltin{size_t __builtin_avr_strlen_flash (const __flash char*)} +@defbuiltinx{size_t __builtin_avr_strlen_flashx (const __flashx char*)} +@defbuiltinx{size_t __builtin_avr_strlen_memx (const __memx char*)} +These built-ins return the length of a string located in +named address-space @code{__flash}, @code{__flashx} or @code{__memx}, +respectively. They are used to support functions like @code{strlen_F} from +@w{@uref{https://avrdudes.github.io/avr-libc/avr-libc-user-manual/,AVR-LibC}}. +@enddefbuiltin + @noindent There are many more AVR-specific built-in functions that are used to implement the ISO/IEC TR 18037 ``Embedded C'' fixed-point functions of diff --git a/libgcc/config/avr/lib1funcs.S b/libgcc/config/avr/lib1funcs.S index 580f511eb94..96f20ca8e64 100644 --- a/libgcc/config/avr/lib1funcs.S +++ b/libgcc/config/avr/lib1funcs.S @@ -2755,6 +2755,24 @@ DEFUN __fload_4 #endif /* L_fload_{1|2|3|4} */ #endif /* if !defined (__AVR_TINY__) */ + +#if !defined (__AVR_TINY__) +#if defined (L_strlen_memx) +DEFUN __strlen_memx +#ifdef __AVR_ERRATA_SKIP_JMP_CALL__ + tst r24 + brmi 1f +#else + sbrs r24, 7 +#endif + XJMP strlen_PF ; AVR-LibC +1: wmov 24, 22 + XJMP strlen ; AVR-LibC +ENDF __strlen_memx +#endif /* L_strlen_memx */ +#endif /* if !defined (__AVR_TINY__) */ + + #if !defined (__AVR_TINY__) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; memcopy from Address Space __memx to RAM diff --git a/libgcc/config/avr/t-avr b/libgcc/config/avr/t-avr index e9fdb98d776..f98d48fc013 100644 --- a/libgcc/config/avr/t-avr +++ b/libgcc/config/avr/t-avr @@ -33,7 +33,8 @@ LIB1ASMFUNCS = \ _popcountsi2 \ _popcountqi2 \ _bswapsi2 \ - _fmul _fmuls _fmulsu + _fmul _fmuls _fmulsu \ + _strlen_memx # The below functions either use registers that are not present # in tiny core, or use a different register convention (don't save