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

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to