[PATCH] D108643: Introduce _BitInt, deprecate _ExtInt

John McCall via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 24 19:25:24 PDT 2021


rjmccall added a comment.

I agree with James; I know you've reached out to the Itanium ABI group about mangling, but ABI involvement needs to mean also reaching out and getting psABI agreement about representation.  I would suggest proposing a generic ABI, getting consensus on that generic ABI with other implementors, and then running that generic ABI past as many platform ABI groups as you can get in touch with.

I think the most logical generic ABI is:

- Let `MaxFundamentalWidth` be the (target-chosen) bit-width of the largest fundamental integer type that can be used to represent a `_BitInt`.  Typically this will be the largest integer type supported by the ABI, but some targets may want to use a smaller limit.  At the very least, this needs to be locked down in the ABI; the ABI for `_BitInt(256)` shouldn't change if the ABI adds new support for  an `int256_t` type.
- Let `chunk_t` be the (target-chosen) fundamental integer type that will be used to store the components of a `_BitInt` that is wider than `MaxFundamentalWidth`.  This should be an integer type that the architecture comfortably supports overflow operations on, and it will typically be the full width of a GPR.
- Let `ChunkWidth` be defined as `CHAR_BITS * sizeof(chunk_t)`.
- If `N < RepWidth(N)`, then signed/unsigned `_BitInt(N)` has the same representation as `_BitInt(RepWidth(N))`, with the value held in the least significant bits and sign/zero-extended to the full width.  Values must be in the proper range of the original type; that is, it is undefined behavior if e.g. a `signed _BitInt(7)` does not hold a value in the range of `-64 ..< 63`.  Hereafter we will assume that `N == RepWidth(N)`.
- If `N <= MaxFundamentalWidth`, then signed/unsigned `_BitInt(N)` has the same representation as the smallest fundamental integer type (least rank, if material) of at least `N` bits and the same signedness.  `_Bool` is not considered in this selection.
- Otherwise, signed/unsigned `_BitInt(N)` has the same representation as a `struct` containing a single field of type `chunk_t[N / sizeof(chunk_t)]`, where the element at index `i` stores bits `i*ChunkWidth ..< (i+1)*ChunkWidth` of the integer.  That is, the array is always stored in little-endian order, which should have better memory-access properties regardless of the endianness of the target.  (The individual elements still have natural host endianness, of course.)

Some targets that don't pass/return small structs efficiently as a matter of course may want to treat smallish (but still non-fundamental) `_BitInt`s specially in their calling convention.

I think using a uniform, GPR-sized chunk makes more sense than trying to use a smaller chunk that might eliminate some padding.  I could imagine that a 64-bit platform that supports 32-bit overflow checking might consider represent `_BitInt(96)` with three 32-bit chunks instead of two 64-bit chunks, and that would indeed make an array of them pack better, but it would also mean that e.g. addition would take three operations instead of two.

You can't have bit-fields of `_BitInt` type, can you?  If people want that, or want a truly packed `_BitInt` where `sizeof(_BitInt(56)) == 7`, it's going to add a lot of complexity.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D108643/new/

https://reviews.llvm.org/D108643



More information about the cfe-commits mailing list