Date: Sun, 31 Aug 2025 11:40:00 +0000
In regards to the fact if you provide easy access to non-portable code it will mean that more non-portable code will be written.
Well, that is true. If you miss-use the feature you get more of bad code.
But I want this precisely because I want to write more portable code, not less.
AES is a perfect illustration for this.
You say that we should handle AES like we did with popcount, just define the spec for all and let each figure out what is best in each platform...
Ok, AES has come out in 2001, where is my std::aes?
Should I expect it in C++26? C++29? C++32?
I would prefer it to be in C++never, and here's why.
AES like all encryption standards has not been proven safe. If you were to adopt std::aes, and later found out that this algorithm has a very bad vulnerability I would want to sunset it. But now because it is in the standard you can't just remove it because it's going to be in many people's and you don't want to break it.
And now you would be in the much worse position of providing and supporting a feature that is unsafe.
In my opinion algorithms like AES fall squarely in the domain of third-party implementations, where I can decide when and how to sunset it, and not make it generally available.
Since I made the case that AES should be a third-party feature, what tools do I have available as a third-party developer that would allow me to do this thing?
I could stick only to available C++ standard functions and make it available to the wildest audience possible, but the performance of it would be terrible.
Now imagine that a systems implementer comes along and sees 2 different AES libraries, one runs everywhere but is painfully slow, the other is blazingly fast but only runs on 1 or 2 systems.
A system engineer couldn't care less if your code is portable, what they care about is that they have millions of requests per second that they have to respond to and has to figure out how many servers they have to buy. They don't have a to support a zoo of different systems, they only have to support one that they buy in bulk and the less they have to buy the better.
Until of course the day they have to support a different system, and now their software doesn't run on it and it might take years to re-write the whole thing and that is if they even bother to sink that cost instead of giving up on the effort.
How many times I have seen this?
If I can take advantage of the hardware, and provide my users a better experience to convince them to keep using it, why shouldn't I be allowed to do it?
Why can't I just open an exception in my code test for the system you will be deploying and take advantage of it? And why shouldn't this be made easier?
What standard, other than THE C++ standard, should define this identification?
________________________________
From: David Brown <david.brown_at_[hidden]>
Sent: Sunday, August 31, 2025 11:58:44 AM
To: Tiago Freire <tmiguelf_at_[hidden]>; std-discussion_at_[hidden] <std-discussion_at_[hidden]>
Subject: Re: [std-discussion] Architecture specific library extensions
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.
Well, that is true. If you miss-use the feature you get more of bad code.
But I want this precisely because I want to write more portable code, not less.
AES is a perfect illustration for this.
You say that we should handle AES like we did with popcount, just define the spec for all and let each figure out what is best in each platform...
Ok, AES has come out in 2001, where is my std::aes?
Should I expect it in C++26? C++29? C++32?
I would prefer it to be in C++never, and here's why.
AES like all encryption standards has not been proven safe. If you were to adopt std::aes, and later found out that this algorithm has a very bad vulnerability I would want to sunset it. But now because it is in the standard you can't just remove it because it's going to be in many people's and you don't want to break it.
And now you would be in the much worse position of providing and supporting a feature that is unsafe.
In my opinion algorithms like AES fall squarely in the domain of third-party implementations, where I can decide when and how to sunset it, and not make it generally available.
Since I made the case that AES should be a third-party feature, what tools do I have available as a third-party developer that would allow me to do this thing?
I could stick only to available C++ standard functions and make it available to the wildest audience possible, but the performance of it would be terrible.
Now imagine that a systems implementer comes along and sees 2 different AES libraries, one runs everywhere but is painfully slow, the other is blazingly fast but only runs on 1 or 2 systems.
A system engineer couldn't care less if your code is portable, what they care about is that they have millions of requests per second that they have to respond to and has to figure out how many servers they have to buy. They don't have a to support a zoo of different systems, they only have to support one that they buy in bulk and the less they have to buy the better.
Until of course the day they have to support a different system, and now their software doesn't run on it and it might take years to re-write the whole thing and that is if they even bother to sink that cost instead of giving up on the effort.
How many times I have seen this?
If I can take advantage of the hardware, and provide my users a better experience to convince them to keep using it, why shouldn't I be allowed to do it?
Why can't I just open an exception in my code test for the system you will be deploying and take advantage of it? And why shouldn't this be made easier?
What standard, other than THE C++ standard, should define this identification?
________________________________
From: David Brown <david.brown_at_[hidden]>
Sent: Sunday, August 31, 2025 11:58:44 AM
To: Tiago Freire <tmiguelf_at_[hidden]>; std-discussion_at_[hidden] <std-discussion_at_[hidden]>
Subject: Re: [std-discussion] Architecture specific library extensions
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.
Received on 2025-08-31 11:40:11