-
Notifications
You must be signed in to change notification settings - Fork 165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ABI for _BitInt #419
base: master
Are you sure you want to change the base?
ABI for _BitInt #419
Conversation
`_BitInt (N)` is the type defined in C23, allow user to define an arbitrary-sized integer type, where N is a postive integer larger than zero. This proposal defined the size and alignment of _BitInt, and define the unused bits as unspecified which is same as x86-64 and AArch64. For the calling convention part, we keep unused bits as unspecified. Ref: - ISO/IEC WG14 N2763: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2763.pdf - [AArch64] Rationale Document for ABI related to the C23 _BitInt type. https://github.com/ARM-software/abi-aa/tree/main/design-documents/bit-precise-types.rst - AAPCS64 for _BitInt(N) ARM-software/abi-aa@d621417 - x86-64 ABI for _BitInt(N) https://gitlab.com/x86-psABIs/x86-64-ABI/-/commit/8ca45392570e96920f8a15d903d6122f6d263cd0 Fix #300
When passed in registers or on the stack, `__BitInt(N)`, unused bits are | ||
undefined, types narrower than XLEN bits are widened to XLEN bits, with the | ||
upper bits undefined. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The question of what can be done with unused bits is discussed here (incl. consequence for the ARM ABIs): https://github.com/ARM-software/abi-aa/blob/main/design-documents/bit-precise-types.rst#options-and-their-trade-offs-1.
I think it would be reasonable for RISC-V (both, RV32 and RV64) to require sign-extension/zero-extension depending on whether the type is signed
/unsigned
.
Benefits (inspired by the referenced document):
- Operations
==,<,<=,>=,>,>>
, widening conversions, and loading/storing to memory would all naturally work. - Matches the expectation of developers, with a
_BitInt(8)
in a register matching the representation of achar
.
Drawbacks (again inspired by the referenced doc):
- Operations
+,-,*,<<
would all cause the need for masking/extending at an ABI boundary.
The "matches the expectation of developers" is my main motivation for mentioning this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd propose we do whatever is empirically most performant, regardless of intuitiveness. But my sense is that comparisons and conversions to wider types will be more common than basic arithmetic on these types. So maybe we get lucky, and the intuitive design and the performant design are the same one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And performant should necessarily include safety and security as much as one thinks of speed and size.
It's like the distinction between malloc
(or even alloc
) and calloc
. The former is lean and elegant and, thus, fast and small. It fits well in its particular use cases. The latter helps guarantee, for example, arrays of characters (i.e. strings) always are suffixed with terminators. The latter also makes sure yet unused elements of the allocated range don't have any previous information leaking through.
Performance and intuition should thus carefully consider elegance, scope, and use case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In addition, there is an ongoing discussion on x86-64-abi about the unused bits : https://groups.google.com/g/x86-64-abi/c/hO9lHnIf-tU
The unused bits are unspecified, which allows efficient +,-,*,<<
, narrowing, and
atomics when supported.
BTW: "are undefined" is too strong. We should just say "are unspecified".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I favor "undefined" for consistency with the aggregate rules in the standard calling convention.
Consistency with the treatment of other integer types, and following the logic used in aapcs, suggests type-sign extension up to 32 bits and sign extension to XLEN. Ideally, we would have empirical data from at least one real-world application before committing to this decision.
The sizes and alignments look reasonable to me.
Plan to putting more table for the code gen among 3 different options, I was too optimistic that I could have time to doing that...:( anyway will put that once I have one. |
_BitInt (N)
is the type defined in C23, allow user to define an arbitrary-sized integer type, where N is a postive integer larger than zero.This proposal defined the size and alignment of _BitInt, and define the unused bits as unspecified which is same as x86-64 and AArch64.
For the calling convention part, we keep unused bits as unspecified.
Ref:
ISO/IEC WG14 N2763: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2763.pdf
[AArch64] Rationale Document for ABI related to the C23 _BitInt type. https://github.com/ARM-software/abi-aa/tree/main/design-documents/bit-precise-types.rst
AAPCS64 for _BitInt(N) ARM-software/abi-aa@d621417
x86-64 ABI for _BitInt(N) https://gitlab.com/x86-psABIs/x86-64-ABI/-/commit/8ca45392570e96920f8a15d903d6122f6d263cd0
Fix #300