public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] inttypes.h: imaxabs(3): Implement as a macro
@ 2022-09-13 15:18 Alex Colomar
  2022-09-13 15:28 ` Alejandro Colomar
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Alex Colomar @ 2022-09-13 15:18 UTC (permalink / raw)
  To: libc-alpha; +Cc: Alex Colomar, Florian Weimer, JeanHeyd Meneide

Functions using the [u]intmax_t types have a problem: ABI.

The [u]intmax_t types were designed so that users could blindly
use them to work with whatever is the biggest size for a given
architecture.  But this is problematic to implement.  These days,
ABI stability is very important, and programs compiled a specific
version of glibc should continue working with newer glibc
releases.  Of course, that means that future glibc versions can't
change the types of functions, or the functions would be
incompatible.

So, we cannot really change the (linker) signature of functions;
not even of those using [u]intmax_t.

A solution to that problem is to use macros, and not real
functions.  That way, the program really links against whatever
function works with the compile-time maximum width type, be it
long or long long, and the program will be bonded to the ABI of
long or long long, but will know nothing about intmax_t.

We still need a linker symbol with the name imaxabs(), for old
programs linked against old glibc versions, and also for
compatibility with an interpretation of the ISO C standard that
says that imaxabs(3) is a function.  But the standard knows
nothing about ABI or a linker, so a macro that evaluates to a
differently-named function is not a straight violation, but rather
stepping through the line without crossing it, AFAIK.

This implementation with C11 _Generic() is one that I used for the
new _Generic(3) manual page.  It allows treating the macro as a
function, and to take pointers to it.  And it allows to more
easily understand the definition of the macro, without needing
to parse the ifdefs.  It makes it easier to parse with tools like
grepc(1):

$ grepc -k __PRI64_PREFIX inttypes.h
inttypes.h:44:#  define __PRI64_PREFIX	"l"
inttypes.h:47:#  define __PRI64_PREFIX	"ll"
$ grepc -k imaxabs inttypes.h
inttypes.h:290:#define imaxabs  _Generic(INTMAX_C(0), long: labs, long long: llabs)

If glibc can't use C11 features in public headers, then usual
ifdefs could be used.

Cc: Florian Weimer <fweimer@redhat.com>
Cc: JeanHeyd Meneide <wg14@soasis.org>
Signed-off-by: Alex Colomar <alx.manpages@gmail.com>
---

Hi Florian,

What do you think about using this implementation of imaxabs(3) in
glibc?  Is it valid according to ISO C and/or POSIX?

It's been a long time since I last built and tested glibc from
so I haven't tested this patch yet.  I'll try more seriously when
it has some chances of being accepted.

Cheers,

Alex

 stdlib/inttypes.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/stdlib/inttypes.h b/stdlib/inttypes.h
index d550769f2a..eb20e416ac 100644
--- a/stdlib/inttypes.h
+++ b/stdlib/inttypes.h
@@ -287,7 +287,7 @@ typedef struct
 
 
 /* Compute absolute value of N.  */
-extern intmax_t imaxabs (intmax_t __n) __THROW __attribute__ ((__const__));
+#define imaxabs  _Generic(INTMAX_C(0), long: labs, long long: llabs)
 
 /* Return the `imaxdiv_t' representation of the value of NUMER over DENOM. */
 extern imaxdiv_t imaxdiv (intmax_t __numer, intmax_t __denom)
-- 
2.37.2


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] inttypes.h: imaxabs(3): Implement as a macro
  2022-09-13 15:18 [PATCH] inttypes.h: imaxabs(3): Implement as a macro Alex Colomar
@ 2022-09-13 15:28 ` Alejandro Colomar
  2022-09-13 15:34 ` Alejandro Colomar
  2022-09-13 18:27 ` Joseph Myers
  2 siblings, 0 replies; 13+ messages in thread
From: Alejandro Colomar @ 2022-09-13 15:28 UTC (permalink / raw)
  To: libc-alpha; +Cc: Florian Weimer, JeanHeyd Meneide


[-- Attachment #1.1: Type: text/plain, Size: 585 bytes --]

On 9/13/22 17:18, Alex Colomar wrote:
> @@ -287,7 +287,7 @@ typedef struct
>   
>   
>   /* Compute absolute value of N.  */
> -extern intmax_t imaxabs (intmax_t __n) __THROW __attribute__ ((__const__));
> +#define imaxabs  _Generic(INTMAX_C(0), long: labs, long long: llabs)

Maybe we could add the case 'int: abs', in case ILP64 archs would want 
to use int for intmax_t.

>   
>   /* Return the `imaxdiv_t' representation of the value of NUMER over DENOM. */
>   extern imaxdiv_t imaxdiv (intmax_t __numer, intmax_t __denom)

-- 
<http://www.alejandro-colomar.es/>

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] inttypes.h: imaxabs(3): Implement as a macro
  2022-09-13 15:18 [PATCH] inttypes.h: imaxabs(3): Implement as a macro Alex Colomar
  2022-09-13 15:28 ` Alejandro Colomar
@ 2022-09-13 15:34 ` Alejandro Colomar
  2022-09-13 18:27 ` Joseph Myers
  2 siblings, 0 replies; 13+ messages in thread
From: Alejandro Colomar @ 2022-09-13 15:34 UTC (permalink / raw)
  To: libc-alpha; +Cc: Florian Weimer, JeanHeyd Meneide


[-- Attachment #1.1: Type: text/plain, Size: 2567 bytes --]

Hi Florian,

On 9/13/22 17:18, Alex Colomar wrote:
> Functions using the [u]intmax_t types have a problem: ABI.
> 
> The [u]intmax_t types were designed so that users could blindly
> use them to work with whatever is the biggest size for a given
> architecture.  But this is problematic to implement.  These days,
> ABI stability is very important, and programs compiled a specific
> version of glibc should continue working with newer glibc
> releases.  Of course, that means that future glibc versions can't
> change the types of functions, or the functions would be
> incompatible.
> 
> So, we cannot really change the (linker) signature of functions;
> not even of those using [u]intmax_t.
> 
> A solution to that problem is to use macros, and not real
> functions.  That way, the program really links against whatever
> function works with the compile-time maximum width type, be it
> long or long long, and the program will be bonded to the ABI of
> long or long long, but will know nothing about intmax_t.
> 
> We still need a linker symbol with the name imaxabs(), for old
> programs linked against old glibc versions, and also for
> compatibility with an interpretation of the ISO C standard that
> says that imaxabs(3) is a function.  But the standard knows
> nothing about ABI or a linker, so a macro that evaluates to a
> differently-named function is not a straight violation, but rather
> stepping through the line without crossing it, AFAIK.
> 
> This implementation with C11 _Generic() is one that I used for the
> new _Generic(3) manual page.  It allows treating the macro as a
> function, and to take pointers to it.  And it allows to more
> easily understand the definition of the macro, without needing
> to parse the ifdefs.  It makes it easier to parse with tools like
> grepc(1):
> 
> $ grepc -k __PRI64_PREFIX inttypes.h
> inttypes.h:44:#  define __PRI64_PREFIX	"l"
> inttypes.h:47:#  define __PRI64_PREFIX	"ll"
> $ grepc -k imaxabs inttypes.h
> inttypes.h:290:#define imaxabs  _Generic(INTMAX_C(0), long: labs, long long: llabs)
> 
> If glibc can't use C11 features in public headers, then usual
> ifdefs could be used.
> 
> Cc: Florian Weimer <fweimer@redhat.com>
> Cc: JeanHeyd Meneide <wg14@soasis.org>
> Signed-off-by: Alex Colomar <alx.manpages@gmail.com>
> ---

My plan, if this is welcome, is to get rid of most traces of [u]intmax_t 
in the ABI, so I'd continue with similar patches for other functions and 
symbols.

Cheers,

Alex

-- 
<http://www.alejandro-colomar.es/>

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] inttypes.h: imaxabs(3): Implement as a macro
  2022-09-13 15:18 [PATCH] inttypes.h: imaxabs(3): Implement as a macro Alex Colomar
  2022-09-13 15:28 ` Alejandro Colomar
  2022-09-13 15:34 ` Alejandro Colomar
@ 2022-09-13 18:27 ` Joseph Myers
  2022-09-13 18:47   ` Paul Eggert
  2022-09-13 22:43   ` Alejandro Colomar
  2 siblings, 2 replies; 13+ messages in thread
From: Joseph Myers @ 2022-09-13 18:27 UTC (permalink / raw)
  To: Alex Colomar; +Cc: libc-alpha, Florian Weimer, JeanHeyd Meneide

On Tue, 13 Sep 2022, Alex Colomar via Libc-alpha wrote:

> What do you think about using this implementation of imaxabs(3) in
> glibc?  Is it valid according to ISO C and/or POSIX?

No.  There has to be a prototype in the header for when #undef is used on 
the macro definition.

Note that GCC expands imaxabs inline as a built-in function (unless using 
-std=c90 or -fno-builtin etc.).

Note that C2x allows integer types wider than intmax_t in certain cases.  
So there is no standard obstacle to providing int128_t and uint128_t and 
having be fully integer types as defined in C2x, without needing to change 
intmax_t - although appropriate syntax would be needed for INT128_C and 
UINT128_C.  (Changing intmax_t would be a pain because of the very large 
number of printf-like functions in glibc, all of whose ABIs involve 
intmax_t.)

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] inttypes.h: imaxabs(3): Implement as a macro
  2022-09-13 18:27 ` Joseph Myers
@ 2022-09-13 18:47   ` Paul Eggert
  2022-09-13 19:30     ` Joseph Myers
  2022-09-13 22:43   ` Alejandro Colomar
  1 sibling, 1 reply; 13+ messages in thread
From: Paul Eggert @ 2022-09-13 18:47 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Florian Weimer, libc-alpha, JeanHeyd Meneide, Alex Colomar

On 9/13/22 13:27, Joseph Myers wrote:

> C2x allows integer types wider than intmax_t in certain cases....
> (Changing intmax_t would be a pain because of the very large
> number of printf-like functions in glibc, all of whose ABIs involve
> intmax_t.)

It would indeed be a pain. However, the possibility of 
wider-than-intmax_t types is potentially even a much greater pain for 
user code. It's common, for example, for user code to have functions 
like this:

   int
   print_offset (off_t offset)
   {
     intmax_t off = offset;
     return printf ("%jd", off);
   }

Unfortunately, code like this would not work if off_t were wider than 
intmax_t. This is fresh in my mind as I recently added code like the 
above to paxutils, replacing older, pre-C99 code that converted off_t to 
strings by hand. Was I mistaken? 
<https://git.savannah.gnu.org/cgit/paxutils.git/commit/?id=2bf63fcba72c4f4bc54a4caf53d7923c1f9f174f>

Is it safe to assume that standard types like off_t are no wider than 
intmax_t? If so, this should be documented explicitly somewhere in the 
glibc manual. If not, user code would be in so much hurt that it really 
ought to be glibc's job to widen intmax_t to be at least as wide as 
standard types, as painful as that widening might be.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] inttypes.h: imaxabs(3): Implement as a macro
  2022-09-13 18:47   ` Paul Eggert
@ 2022-09-13 19:30     ` Joseph Myers
  2022-09-13 20:59       ` Paul Eggert
  0 siblings, 1 reply; 13+ messages in thread
From: Joseph Myers @ 2022-09-13 19:30 UTC (permalink / raw)
  To: Paul Eggert; +Cc: Florian Weimer, Alex Colomar, libc-alpha, JeanHeyd Meneide

On Tue, 13 Sep 2022, Paul Eggert via Libc-alpha wrote:

> Is it safe to assume that standard types like off_t are no wider than
> intmax_t?

Standard C doesn't discuss off_t at all.  Maybe whatever version of POSIX 
gets based on C2x should address that question.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] inttypes.h: imaxabs(3): Implement as a macro
  2022-09-13 19:30     ` Joseph Myers
@ 2022-09-13 20:59       ` Paul Eggert
  0 siblings, 0 replies; 13+ messages in thread
From: Paul Eggert @ 2022-09-13 20:59 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Florian Weimer, Alex Colomar, libc-alpha, JeanHeyd Meneide

[-- Attachment #1: Type: text/plain, Size: 330 bytes --]

On 9/13/22 14:30, Joseph Myers wrote:
> Standard C doesn't discuss off_t at all.  Maybe whatever version of POSIX
> gets based on C2x should address that question.

That would be a good idea. However, the glibc manual should discuss this 
regardless of whether POSIX addresses it. For now, how about the 
attached proposed patch?

[-- Attachment #2: 0001-Document-ISO-C23-s-types-wider-than-intmax_t.patch --]
[-- Type: text/x-patch, Size: 1998 bytes --]

From 4acf0090cf31cbde99bb64d8024f5f4bc90a6296 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Tue, 13 Sep 2022 15:56:38 -0500
Subject: [PATCH] =?UTF-8?q?Document=20ISO=20C23=E2=80=99s=20types=20wider?=
 =?UTF-8?q?=20than=20intmax=5Ft?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 manual/arith.texi | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/manual/arith.texi b/manual/arith.texi
index edb9cfdafb..83f3e7607b 100644
--- a/manual/arith.texi
+++ b/manual/arith.texi
@@ -96,7 +96,8 @@ one of these:
 @item uint_fast64_t
 @end itemize
 
-If you want an integer with the widest range possible on the platform on
+If you want an integer that ordinarily has the widest range possible
+on the platform on
 which it is being used, use one of the following.  If you use these,
 you should write code that takes into account the variable size and range
 of the integer.
@@ -106,6 +107,18 @@ of the integer.
 @item uintmax_t
 @end itemize
 
+Draft @w{ISO C23} allows for signed integer types wider than @code{intmax_t}.
+These include signed bit-precise integer types and extended integer
+types that are wider than @code{long long} and that are referred by the
+type definition for an exact width integer type.  For example, if
+@code{intmax_t} is equivalent to @code{long long} and is 64 bits,
+the signed bit-precise integer type @code{_BitInt (128)} and the
+typedef @code{int128_t}, if they exist, are wider than @code{intmax_t}.
+However, @theglibc{} avoids wider-than-@code{intmax_t} types
+and it is safe to convert to @code{intmax_t} any signed integer value
+documented as being generated or used by @theglibc{}, and similarly
+for @code{uintmax_t} and unsigned integer values.
+
 @Theglibc{} also provides macros that tell you the maximum and
 minimum possible values for each integer data type.  The macro names
 follow these examples: @code{INT32_MAX}, @code{UINT8_MAX},
-- 
2.37.2


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] inttypes.h: imaxabs(3): Implement as a macro
  2022-09-13 18:27 ` Joseph Myers
  2022-09-13 18:47   ` Paul Eggert
@ 2022-09-13 22:43   ` Alejandro Colomar
  2022-09-13 22:56     ` Joseph Myers
  1 sibling, 1 reply; 13+ messages in thread
From: Alejandro Colomar @ 2022-09-13 22:43 UTC (permalink / raw)
  To: Joseph Myers, Paul Eggert; +Cc: libc-alpha, Florian Weimer, JeanHeyd Meneide


[-- Attachment #1.1: Type: text/plain, Size: 6042 bytes --]

Hi Joseph, Paul,

On 9/13/22 20:27, Joseph Myers wrote:
> On Tue, 13 Sep 2022, Alex Colomar via Libc-alpha wrote:
> 
>> What do you think about using this implementation of imaxabs(3) in
>> glibc?  Is it valid according to ISO C and/or POSIX?
> 
> No.  There has to be a prototype in the header for when #undef is used on
> the macro definition.

Ahh, yes, C23::7.1.4/1 says that

"Any function declared in a header may be *additionally* implemented as 
a function-like macro defined in the header"

That additionally is what requires pedantically to provide a real function.

Let me suggest that the standard is defective in its definition of 
imaxabs_t (and in general about any functions using intmax_t).  It 
should note that they "can be implemented as macros", as it does with 
getc(3).

Providing a prototype (and the corresponding function definition) for 
functions with intmax_t is the issue (or one of them; see below).

> 
> Note that GCC expands imaxabs inline as a built-in function (unless using
> -std=c90 or -fno-builtin etc.).

I don't understand the process by which gcc expands builtins.  How does 
exactly the suggested macro interfere with it?  Is it because of the 
macro?  Or because of _Generic()?

> 
> Note that C2x allows integer types wider than intmax_t in certain cases.

That is a workaround to the type being broken.  The type can't widen, 
due to ABI issues; for some time, the compiler provided __int128 as a 
limbo extension that wouldn't be covered by intmax_t, and later ISO C 
just acknowledged the fact and reworded the definition of intmax_t to be 
less of "the widest type" and more or "a wide but not really widest 
type, so don't really trust it very much".

Since the standard (and implementations) is kind of broken in this 
regard, my intention is to deviate from the standard the bare minimum to 
make this type what it really was meant to be from the beginning.

> So there is no standard obstacle to providing int128_t and uint128_t and
> having be fully integer types as defined in C2x, without needing to change
> intmax_t

Yeah, there may not be, but then, what good is intmax_t?
The name suggests that it is what it is not.  After acknowledging that, 
it's not better than some random type widest_ish_t.  long long, for 
historic reasons, is guaranteed to be exactly as wide as intmax_t, with 
less issues.  If there's no hope in intmax_t, we should just mark the 
type as obsolescent, and discard any idea of having a "widest" type at all.

Working around it to keep it there, but keeping it useless is not 
something I'd be happy with.

I think this would be enough reason to deviate from the standard, and 
let's call it a non-conforming extension that improves usability.  Let's 
keep a linker definition for old code; but don't allow new code to link 
to anything with intmax_t in it.

> - although appropriate syntax would be needed for INT128_C and
> UINT128_C.

Yes, that's an issue that we could easily fix if intmax_t disappears 
from the ABI completely.  Then we could grow it arbitrarily without any 
concerns.

>  (Changing intmax_t would be a pain because of the very large
> number of printf-like functions in glibc, all of whose ABIs involve
> intmax_t.)

Ahh, you anticipated part 2 of my plan.  Deprecate "j", and add a new 
set of macros PRIdMAX and the like.  This type has it deserved.  But I 
know those macros aren't very well received, so it is just part 2.

I'd justify macros here for the same reason that I justified defining 
the functions as macros: ABI.  I don't see a way of doing this without 
macros.

On 9/13/22 20:47, Paul Eggert wrote:
 > On 9/13/22 13:27, Joseph Myers wrote:
 >
 >> C2x allows integer types wider than intmax_t in certain cases....
 >> (Changing intmax_t would be a pain because of the very large
 >> number of printf-like functions in glibc, all of whose ABIs involve
 >> intmax_t.)
 >
 > It would indeed be a pain. However, the possibility of
 > wider-than-intmax_t types is potentially even a much greater pain for
 > user code.

Indeed.  intmax_t is just broken as it is right now.

 > It's common, for example, for user code to have functions
 > like this:
 >
 >    int
 >    print_offset (off_t offset)
 >    {
 >      intmax_t off = offset;
 >      return printf ("%jd", off);
 >    }
 >
 > Unfortunately, code like this would not work if off_t were wider than
 > intmax_t. This is fresh in my mind as I recently added code like the
 > above to paxutils, replacing older, pre-C99 code that converted off_t to
 > strings by hand. Was I mistaken?

Not so broken.  It's good enough for that.  intmax_t is (with some 
caveat) wide enough to work with all current system data types; that is, 
intmax_t is always 64 bits, AFAIK, since long long is 64 bits in all 
existing systems that I know, and intmax_t must be at least as wide as 
long long.  And I don't know of any system data types longer than long 
long (that would be __int128, but no system data types use that 
underlying type).


 > 
<https://git.savannah.gnu.org/cgit/paxutils.git/commit/?id=2bf63fcba72c4f4bc54a4caf53d7923c1f9f174f>
 >
 > Is it safe to assume that standard types like off_t are no wider than
 > intmax_t? If so, this should be documented explicitly somewhere in the
 > glibc manual. If not, user code would be in so much hurt that it really
 > ought to be glibc's job to widen intmax_t to be at least as wide as
 > standard types, as painful as that widening might be.

It is safe.  But so is long long, which is easier to use.  intmax_t is 
dead, if it must be defined to be exactly as wide as long long (except 
of course, for fresh architectures that can define it to be exactly 
__int128, but then have to write that in stone, and will have the same 
problem with a hypothetical __int256.  intmax_t is to be wide-able, or 
it becomes DOA, IMO.


Cheers,

Alex

-- 
<http://www.alejandro-colomar.es/>

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] inttypes.h: imaxabs(3): Implement as a macro
  2022-09-13 22:43   ` Alejandro Colomar
@ 2022-09-13 22:56     ` Joseph Myers
  2022-09-13 23:43       ` Alejandro Colomar
  0 siblings, 1 reply; 13+ messages in thread
From: Joseph Myers @ 2022-09-13 22:56 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Paul Eggert, libc-alpha, Florian Weimer, JeanHeyd Meneide

On Tue, 13 Sep 2022, Alejandro Colomar wrote:

> I don't understand the process by which gcc expands builtins.  How does
> exactly the suggested macro interfere with it?  Is it because of the macro?
> Or because of _Generic()?

My point is that you already have to go out of your way to get a link-time 
reference to imaxabs - it will almost always have been expanded inline 
instead.  Given that, your patch is adding extra complexity to address an 
issue that doesn't actually exist.

> That is a workaround to the type being broken.  The type can't widen, due to
> ABI issues; for some time, the compiler provided __int128 as a limbo extension
> that wouldn't be covered by intmax_t, and later ISO C just acknowledged the
> fact and reworded the definition of intmax_t to be less of "the widest type"
> and more or "a wide but not really widest type, so don't really trust it very
> much".

It is the type used for preprocessor arithmetic, for example.

intmax_t was discussed at length in WG14, and while there was agreement on 
reducing its uses (hence the change to floating-point return types for 
fromfp functions, for example, see bug 28327), there was not agreement on 
any particular form of obsolescence.  And it *is* useful in practice for 
printing types such as off_t or mode_t with no corresponding printf 
formats; those could just do with appropriate constraints to be no wider 
than intmax_t when a future POSIX revision is based on C2x.

> If there's no hope in intmax_t, we should just mark the type as obsolescent,
> and discard any idea of having a "widest" type at all.

I don't think it's useful to try to rehash here discussions that were had 
at length in WG14.

> Ahh, you anticipated part 2 of my plan.  Deprecate "j", and add a new set of
> macros PRIdMAX and the like.  This type has it deserved.  But I know those
> macros aren't very well received, so it is just part 2.

The actual direction is to move away from those macros (adding length 
modifiers for printing intN_t / int_leastN_t / int_fastN_t without needing 
to use such macros any more).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] inttypes.h: imaxabs(3): Implement as a macro
  2022-09-13 22:56     ` Joseph Myers
@ 2022-09-13 23:43       ` Alejandro Colomar
  2022-09-14 16:41         ` Joseph Myers
  0 siblings, 1 reply; 13+ messages in thread
From: Alejandro Colomar @ 2022-09-13 23:43 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Paul Eggert, libc-alpha, Florian Weimer, JeanHeyd Meneide


[-- Attachment #1.1: Type: text/plain, Size: 3769 bytes --]

Hi Joseph,

On 9/14/22 00:56, Joseph Myers wrote:
> On Tue, 13 Sep 2022, Alejandro Colomar wrote:
> 
>> I don't understand the process by which gcc expands builtins.  How does
>> exactly the suggested macro interfere with it?  Is it because of the macro?
>> Or because of _Generic()?
> 
> My point is that you already have to go out of your way to get a link-time
> reference to imaxabs - it will almost always have been expanded inline
> instead.  Given that, your patch is adding extra complexity to address an
> issue that doesn't actually exist.

Ahh, now I understand.  So, kind of the situation with bzero(3) which is 
implemented in the compiler, and glibc doesn't support it because the 
compiler always transforms it to memcpy(3).

Then, if there are still any references, glibc still needs to fix that, 
or if there are no references, glibc could just remove the function 
completely.

However, imaxabs(3) was just the starting point, because it happened to 
be the function I chose to use at random.  Other functions using the 
type may not be so commonly inlined.

> 
>> That is a workaround to the type being broken.  The type can't widen, due to
>> ABI issues; for some time, the compiler provided __int128 as a limbo extension
>> that wouldn't be covered by intmax_t, and later ISO C just acknowledged the
>> fact and reworded the definition of intmax_t to be less of "the widest type"
>> and more or "a wide but not really widest type, so don't really trust it very
>> much".
> 
> It is the type used for preprocessor arithmetic, for example.

Yep.  Happens to always coincide with long long though (not in rank, but 
in width), so not much would be lost by using long long.

> 
> intmax_t was discussed at length in WG14, and while there was agreement on
> reducing its uses (hence the change to floating-point return types for
> fromfp functions, for example, see bug 28327), there was not agreement on
> any particular form of obsolescence.  And it *is* useful in practice for
> printing types such as off_t or mode_t with no corresponding printf
> formats; those could just do with appropriate constraints to be no wider
> than intmax_t when a future POSIX revision is based on C2x.

Yes, and yet the same can be said about long long.  intmax_t is one less 
character (both in the type name, and in "j"), but apart from that, no 
much benefit.

Do we really need a typedef for a type that is guaranteed to be as wide 
as any system data type (effectively that is long long)?  It wasn't the 
original intention for intmax_t, AFAIK, and neither is necessary.  I 
considered changing to long long in the man pages to keep it simple.

> 
>> If there's no hope in intmax_t, we should just mark the type as obsolescent,
>> and discard any idea of having a "widest" type at all.
> 
> I don't think it's useful to try to rehash here discussions that were had
> at length in WG14.

Okay.

> 
>> Ahh, you anticipated part 2 of my plan.  Deprecate "j", and add a new set of
>> macros PRIdMAX and the like.  This type has it deserved.  But I know those
>> macros aren't very well received, so it is just part 2.
> 
> The actual direction is to move away from those macros (adding length
> modifiers for printing intN_t / int_leastN_t / int_fastN_t without needing
> to use such macros any more).

While for fixed-width types it makes sense to use fixed strings "w<N>", 
for variable-width types, it doesn't so much.  Otherwise, the types are 
really fixed-width, as far as the ABI is concerned, even if they are not 
explicit-width.  I think having a macro PRIdMAX could make sense.  But 
of course it depends on the meaning of intmax_t.

-- 
<http://www.alejandro-colomar.es/>

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] inttypes.h: imaxabs(3): Implement as a macro
  2022-09-13 23:43       ` Alejandro Colomar
@ 2022-09-14 16:41         ` Joseph Myers
  2022-09-14 19:03           ` JeanHeyd Meneide
  0 siblings, 1 reply; 13+ messages in thread
From: Joseph Myers @ 2022-09-14 16:41 UTC (permalink / raw)
  To: Alejandro Colomar; +Cc: Florian Weimer, libc-alpha, JeanHeyd Meneide

On Wed, 14 Sep 2022, Alejandro Colomar via Libc-alpha wrote:

> > intmax_t was discussed at length in WG14, and while there was agreement on
> > reducing its uses (hence the change to floating-point return types for
> > fromfp functions, for example, see bug 28327), there was not agreement on
> > any particular form of obsolescence.  And it *is* useful in practice for
> > printing types such as off_t or mode_t with no corresponding printf
> > formats; those could just do with appropriate constraints to be no wider
> > than intmax_t when a future POSIX revision is based on C2x.
> 
> Yes, and yet the same can be said about long long.  intmax_t is one less
> character (both in the type name, and in "j"), but apart from that, no much
> benefit.

It provides a clearer statement of intent to readers of the code than long 
long does.

As I noted in the WG14 discussions of a few proposed obsoletions, just 
because some language feature is not useful for *all* the things some 
people might like to be able to use it for isn't a reason for obsoletion 
when it's still useful for *some* of those things.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] inttypes.h: imaxabs(3): Implement as a macro
  2022-09-14 16:41         ` Joseph Myers
@ 2022-09-14 19:03           ` JeanHeyd Meneide
  2022-09-15 12:33             ` Alejandro (Alex) Colomar
  0 siblings, 1 reply; 13+ messages in thread
From: JeanHeyd Meneide @ 2022-09-14 19:03 UTC (permalink / raw)
  To: Joseph Myers
  Cc: Alejandro Colomar, Florian Weimer, libc-alpha, JeanHeyd Meneide

Dear Alejandro, Joseph,

On Wed, Sep 14, 2022 at 12:41 PM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Wed, 14 Sep 2022, Alejandro Colomar via Libc-alpha wrote:
>
> > > intmax_t was discussed at length in WG14, and while there was agreement on
> > > reducing its uses (hence the change to floating-point return types for
> > > fromfp functions, for example, see bug 28327), there was not agreement on
> > > any particular form of obsolescence.  And it *is* useful in practice for
> > > printing types such as off_t or mode_t with no corresponding printf
> > > formats; those could just do with appropriate constraints to be no wider
> > > than intmax_t when a future POSIX revision is based on C2x.
> >
> > Yes, and yet the same can be said about long long.  intmax_t is one less
> > character (both in the type name, and in "j"), but apart from that, no much
> > benefit.
>
> It provides a clearer statement of intent to readers of the code than long
> long does.
>
> As I noted in the WG14 discussions of a few proposed obsoletions, just
> because some language feature is not useful for *all* the things some
> people might like to be able to use it for isn't a reason for obsoletion
> when it's still useful for *some* of those things.


     I agree here. I have a proposal to fix this, based on the
assembly labels and similar existing practice found on a lot of
compilers, and based on what BSDs such as NetBSD have been using for
25+ years to provide ABI stability despite shifting architectures and
types: https://thephd.dev/_vendor/future_cxx/papers/C%20-%20Transparent%20Aliases.html

     I would rather we not fall back to macros for all the reasons
Joseph and others mentioned (the standard library #undef macro reason
is also listed in the above-linked paper). I personally view the
exemptions we made for the upcoming C2x (C23) standard as stop-gaps to
allow important evolution and implementation work from, but not
general-purpose solutions. I think transparent aliases is a generic
solution to the problem and would achieve much of what we need to do,
but it will not be in until C2y/C3a (the next revision of the C
standard) if I work hard at it and polish the wording while surfacing
implementations. I also found a few embedded folks who similarly
suffered drawbacks because their platform's compiler could not deal
with the asm("") labels for ABIs, and broke the entire build on their
machine. So even for non-large systems, there's a real need for a
language-level indirection mechanism that has all the same properties
as normal functions.

     I hope that we can still make do with implementation extensions
while I (and others?) work to make proper strides in implementation.
And I apologize it took me this long to come up with these things; I
certainly do wish I was "faster on the draw" to solving these
problems, so to speak.

Best Wishes,
JeanHeyd

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] inttypes.h: imaxabs(3): Implement as a macro
  2022-09-14 19:03           ` JeanHeyd Meneide
@ 2022-09-15 12:33             ` Alejandro (Alex) Colomar
  0 siblings, 0 replies; 13+ messages in thread
From: Alejandro (Alex) Colomar @ 2022-09-15 12:33 UTC (permalink / raw)
  To: JeanHeyd Meneide, Joseph Myers; +Cc: Florian Weimer, libc-alpha


[-- Attachment #1.1: Type: text/plain, Size: 6205 bytes --]

Dear JeanHeyd, Joseph,

On 9/14/22 21:03, JeanHeyd Meneide wrote:
> Dear Alejandro, Joseph,
> 
> On Wed, Sep 14, 2022 at 12:41 PM Joseph Myers <joseph@codesourcery.com> wrote:
>>
>> On Wed, 14 Sep 2022, Alejandro Colomar via Libc-alpha wrote:
>>
>>>> intmax_t was discussed at length in WG14, and while there was agreement on
>>>> reducing its uses (hence the change to floating-point return types for
>>>> fromfp functions, for example, see bug 28327), there was not agreement on
>>>> any particular form of obsolescence.  And it *is* useful in practice for
>>>> printing types such as off_t or mode_t with no corresponding printf
>>>> formats; those could just do with appropriate constraints to be no wider
>>>> than intmax_t when a future POSIX revision is based on C2x.
>>>
>>> Yes, and yet the same can be said about long long.  intmax_t is one less
>>> character (both in the type name, and in "j"), but apart from that, no much
>>> benefit.
>>
>> It provides a clearer statement of intent to readers of the code than long
>> long does.
>>
>> As I noted in the WG14 discussions of a few proposed obsoletions, just
>> because some language feature is not useful for *all* the things some
>> people might like to be able to use it for isn't a reason for obsoletion
>> when it's still useful for *some* of those things.

Hmm, I guess that makes sense.

> 
> 
>       I agree here. I have a proposal to fix this, based on the
> assembly labels and similar existing practice found on a lot of
> compilers, and based on what BSDs such as NetBSD have been using for
> 25+ years to provide ABI stability despite shifting architectures and
> types: https://thephd.dev/_vendor/future_cxx/papers/C%20-%20Transparent%20Aliases.html

It was a good read!  Let me share some thoughts on it.

> 
>       I would rather we not fall back to macros for all the reasons
> Joseph and others mentioned (the standard library #undef macro reason
> is also listed in the above-linked paper). I personally view the
> exemptions we made for the upcoming C2x (C23) standard as stop-gaps to
> allow important evolution and implementation work from, but not
> general-purpose solutions. I think transparent aliases is a generic
> solution to the problem and would achieve much of what we need to do,
> but it will not be in until C2y/C3a (the next revision of the C
> standard) if I work hard at it and polish the wording while surfacing
> implementations. I also found a few embedded folks who similarly
> suffered drawbacks because their platform's compiler could not deal
> with the asm("") labels for ABIs, and broke the entire build on their
> machine. So even for non-large systems, there's a real need for a
> language-level indirection mechanism that has all the same properties
> as normal functions.

I think macros can be used for this same purpose (but don't cry so fast; 
please continue reading ;).  They effectively achieve the aliasing 
objective, with an already existing feature.

The objection seems to be 7.1.4.  As your N2970 paper says, 7.1.4 is 
there to make sure that users can "remove" the aliasing that macros may 
be doing, so that they make sure they call the exact function they are 
trying to call by using #undef.  That's not really true, since compilers 
don't care how much you #undef things, but they'll use builtins whether 
you like it or not, unless you work hard enough on your compiler flags 
and maybe even asm() statements to work around that.  But let's ignore 
compiler builtins.  The objective of 7.1.4 was that users can avoid 
macros and make sure they call a function called foo() if they want. 
Keeping 7.1.4, but then adding _Alias is a bit of lying.  _Alias, like a 
macro, will make user code call a function different from what they 
think: in neither case will the generated assembly code have traces of 
foo(), if it was defined or _Aliased to something else; and you cannot 
#undef an _Alias, so 7.1.4 becomes a bit irrelevant.

Nevertheless, and even if macros can achieve what _Alias does in the 
same way, given that the 7.1.4 restrictions were lifted, either for all 
functions, or for specific ones, I do like _Alias.  In the end, macros 
can achieve what typedef does, and we still have it, and I like it.  It 
provides a bit more safety, by being a C feature, and not a cpp(1) one; 
we get more warnings and more restrictions, which are nice.

In general I like the paper very much.  I'd say that the part of the 
rationale that talks about 7.1.4 is a bit of a lie in the sense that I 
stated above, but that's not a big issue to me.  The feature makes 
sense, and seems an improvement over the GNU attribute.  The GNU C issue 
could be overcome through macros (again), so it wasn't as painful to 
use, but still those macros make clear the the interface was less than 
ideal.  See what I used:

#define ALX_ALIAS_DECLARATION(aka, original)  \
         [[gnu::copy(original)]] extern typeof(original)  aka

#define ALX_ALIAS_DEFINITION(aka, original)  \
         [[gnu::alias(#original)]] ALX_ALIAS_DECLARATION(aka, original)

#define ALX_ALIAS_WEAK_DEF(aka, original)  \
         [[gnu::weak]] ALX_ALIAS_DEFINITION(aka, original)

So, yeah, your paper makes a lot of sense to standardize this.  About 
the naming, if I may give my opinion, _Alias (and the alias macro) seem 
quite nice.  'using' would also be nice if the feature is a strict 
subset of the C++ one, so that programmers know they are the same exact 
feature, just that C++ obviously can apply it to more contexts.


> 
>       I hope that we can still make do with implementation extensions
> while I (and others?) work to make proper strides in implementation.
> And I apologize it took me this long to come up with these things; I
> certainly do wish I was "faster on the draw" to solving these
> problems, so to speak.
Time gives the opportunity to think it very well, so I don't see it as 
bad.  Just knowing that it is in the process of being fixed makes me 
happy enough.  :-)

Cheers,

Alex

> 
> Best Wishes,
> JeanHeyd


-- 
<http://www.alejandro-colomar.es/>

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2022-09-15 12:33 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-13 15:18 [PATCH] inttypes.h: imaxabs(3): Implement as a macro Alex Colomar
2022-09-13 15:28 ` Alejandro Colomar
2022-09-13 15:34 ` Alejandro Colomar
2022-09-13 18:27 ` Joseph Myers
2022-09-13 18:47   ` Paul Eggert
2022-09-13 19:30     ` Joseph Myers
2022-09-13 20:59       ` Paul Eggert
2022-09-13 22:43   ` Alejandro Colomar
2022-09-13 22:56     ` Joseph Myers
2022-09-13 23:43       ` Alejandro Colomar
2022-09-14 16:41         ` Joseph Myers
2022-09-14 19:03           ` JeanHeyd Meneide
2022-09-15 12:33             ` Alejandro (Alex) Colomar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).