Date: Sun, 31 Aug 2025 11:58:39 +0200
On 29/08/2025 22:48, Tiago Freire wrote:
> At the “TBAA and extended floating-point types” topic I had hinted I had
> hinted at the possibility of having “standard extensions” that would
> only be available on certain architectures.
>
> The idea being that these would allow to add content that for some
> reason or another is not feasible to implement in a common cross-
> platform way, but still provide important enough functionality that
> would be ice to standardize for different compilers targeting the same
> platform. Mostly low-level stuff.
>
> 1st pre-compiler directives for major cpu architectures should have a
> standard name. I.e. pre-compiler directives that tells you if you are
> emitting instructions for an Arm64, Risc-V, x86_64, etc…
>
> Of course, compilers don’t have to know about directives that they don’t
> target, but if it targets a specific instruction set that the standard
> acknowledges the directive that identifies that is the same on all
> compilers targeting that architecture.
>
> 2nd All supported data types that make sense that makes sense to perform
> operations (or register types) should a well-defined type. No “unsigned
> int” or “float”, more of a “uint16”, “ieee_fp32”, or “AVX_512_fp64”
>
> 3rd All function that make sense on a specific architecture (things that
> the CPU provide specific instructions for) should be put in a library
> collection that is only available on a specific architecture being targeted.
>
> Not necessarily every single instruction but most intrinsics should
> probably end-up there. I’m talking stuff like “cupid” (on arm or x86),
> AVX instructions, AES or CRC instructions.
>
> The intel intrinsics library does a very good job to make this more or
> less portable, but I’m talking a similar thing for all major
> architectures. And if the functions do something deterministic, make it
> constexpr as well.
>
> The point being that if I want to do something very specific, I don’t
> need to figure out how to abstract and implement it to work on every
> single architecture in order to get it into the standard.
>
> A lot of stuff is important but doesn’t make sense everywhere.
>
> Of course, using this feature would make your code not portable C++, and
> that is fine.
>
> You can opt-in to it if that is what you really want, because sometimes
> it is fine that your code is made only to support only specific platforms.
>
> And if there are specific thing that is only available on arm or x86, if
> that is only what you support, you can just pull those from the library
> and not have to re-invent the wheel.
>
> Anything that is possible to do on a specific architecture, developers
> should have access to the building blocks and be allowed to express it
> in C++ (and build upon it).
>
> Thoughts?
>
My thought is that this is completely backwards.
C++ is /not/ assembly. It is a language you can use so that you don't
have to use assembly.
People sometimes, incorrectly, refer to C as a "portable assembly
language". The reality is that one of C's guiding principles was that
it should be efficient enough for low-level programming that it removed
the need to write most assembly. C++ follows that while also covering
significantly higher level abstractions than C.
I fully agree that low-level concrete types are useful in some kinds of
C++ coding - such as uint16_t. And these could be extended towards
fixed-sized vectors for SIMD usage. I fully agree that standard
libraries with low-level functions such as CRC and AES primitives can be
useful. I am not the only one who thinks that - C++ has gained more
bit-manipulation libraries and SIMD standard libraries. It could
benefit from more.
But it is /critical/ to the language that this is as
hardware-independent as practically possible. People should be able to
write their AES (or whatever) algorithm so that it will work correctly
on /all/ hardware, even though it will only be maximally efficient when
you have an optimising compiler and a target processor that has suitable
specialised instructions. We do not want a balkanisation of source code
where there are different standard library functions available depending
on whether you are compiling for AMD's chips or Intel's chips - but can
accept a balkanisation of speed on the results. Compiler implementers
will do with "crc" functions as they have done for "popcount" and all
other functions and operators from the dawn of compiled languages - if
the target processor has appropriate hardware instructions, use them,
and if not, use software routines to get the same effect.
What might be reasonable is to define a type of "normal" target. Just
as the standard today supports "freestanding" and "hosted" environments
with different requirements about what libraries are supported, you
could have "niche" and "normal" targets (these names would need a lot of
bikeshedding). "normal" targets would have 32-bit int, 8-bit char,
support [u]intN_t 8, 16, 32, and 64, and have IEEE floating point types.
A library with AES and CRC routines and the like would be for "normal"
targets only - then the interfaces for them could perhaps be simpler
because sizes can be fixed and regular.
It might also be nice to have some fixed formats for #define'd constants
for architecture types, or other ways to inspect or restrict target
architectures or details. For example, the C++ standard could define a
way to write the equivalent of gcc's "__attribute__((target__("see3")))"
to specify a function version to be used when compiling for a target
that supports "see3". But the details of the targets should be in the
hands of the implementers - the C++ standard must be completely hardware
independent.
I do not, however, see the slightest benefit of the C++ standard having
anything hardware or target specific in the standard or standard libraries.
> At the “TBAA and extended floating-point types” topic I had hinted I had
> hinted at the possibility of having “standard extensions” that would
> only be available on certain architectures.
>
> The idea being that these would allow to add content that for some
> reason or another is not feasible to implement in a common cross-
> platform way, but still provide important enough functionality that
> would be ice to standardize for different compilers targeting the same
> platform. Mostly low-level stuff.
>
> 1st pre-compiler directives for major cpu architectures should have a
> standard name. I.e. pre-compiler directives that tells you if you are
> emitting instructions for an Arm64, Risc-V, x86_64, etc…
>
> Of course, compilers don’t have to know about directives that they don’t
> target, but if it targets a specific instruction set that the standard
> acknowledges the directive that identifies that is the same on all
> compilers targeting that architecture.
>
> 2nd All supported data types that make sense that makes sense to perform
> operations (or register types) should a well-defined type. No “unsigned
> int” or “float”, more of a “uint16”, “ieee_fp32”, or “AVX_512_fp64”
>
> 3rd All function that make sense on a specific architecture (things that
> the CPU provide specific instructions for) should be put in a library
> collection that is only available on a specific architecture being targeted.
>
> Not necessarily every single instruction but most intrinsics should
> probably end-up there. I’m talking stuff like “cupid” (on arm or x86),
> AVX instructions, AES or CRC instructions.
>
> The intel intrinsics library does a very good job to make this more or
> less portable, but I’m talking a similar thing for all major
> architectures. And if the functions do something deterministic, make it
> constexpr as well.
>
> The point being that if I want to do something very specific, I don’t
> need to figure out how to abstract and implement it to work on every
> single architecture in order to get it into the standard.
>
> A lot of stuff is important but doesn’t make sense everywhere.
>
> Of course, using this feature would make your code not portable C++, and
> that is fine.
>
> You can opt-in to it if that is what you really want, because sometimes
> it is fine that your code is made only to support only specific platforms.
>
> And if there are specific thing that is only available on arm or x86, if
> that is only what you support, you can just pull those from the library
> and not have to re-invent the wheel.
>
> Anything that is possible to do on a specific architecture, developers
> should have access to the building blocks and be allowed to express it
> in C++ (and build upon it).
>
> Thoughts?
>
My thought is that this is completely backwards.
C++ is /not/ assembly. It is a language you can use so that you don't
have to use assembly.
People sometimes, incorrectly, refer to C as a "portable assembly
language". The reality is that one of C's guiding principles was that
it should be efficient enough for low-level programming that it removed
the need to write most assembly. C++ follows that while also covering
significantly higher level abstractions than C.
I fully agree that low-level concrete types are useful in some kinds of
C++ coding - such as uint16_t. And these could be extended towards
fixed-sized vectors for SIMD usage. I fully agree that standard
libraries with low-level functions such as CRC and AES primitives can be
useful. I am not the only one who thinks that - C++ has gained more
bit-manipulation libraries and SIMD standard libraries. It could
benefit from more.
But it is /critical/ to the language that this is as
hardware-independent as practically possible. People should be able to
write their AES (or whatever) algorithm so that it will work correctly
on /all/ hardware, even though it will only be maximally efficient when
you have an optimising compiler and a target processor that has suitable
specialised instructions. We do not want a balkanisation of source code
where there are different standard library functions available depending
on whether you are compiling for AMD's chips or Intel's chips - but can
accept a balkanisation of speed on the results. Compiler implementers
will do with "crc" functions as they have done for "popcount" and all
other functions and operators from the dawn of compiled languages - if
the target processor has appropriate hardware instructions, use them,
and if not, use software routines to get the same effect.
What might be reasonable is to define a type of "normal" target. Just
as the standard today supports "freestanding" and "hosted" environments
with different requirements about what libraries are supported, you
could have "niche" and "normal" targets (these names would need a lot of
bikeshedding). "normal" targets would have 32-bit int, 8-bit char,
support [u]intN_t 8, 16, 32, and 64, and have IEEE floating point types.
A library with AES and CRC routines and the like would be for "normal"
targets only - then the interfaces for them could perhaps be simpler
because sizes can be fixed and regular.
It might also be nice to have some fixed formats for #define'd constants
for architecture types, or other ways to inspect or restrict target
architectures or details. For example, the C++ standard could define a
way to write the equivalent of gcc's "__attribute__((target__("see3")))"
to specify a function version to be used when compiling for a target
that supports "see3". But the details of the targets should be in the
hands of the implementers - the C++ standard must be completely hardware
independent.
I do not, however, see the slightest benefit of the C++ standard having
anything hardware or target specific in the standard or standard libraries.
Received on 2025-08-31 09:58:44