erichkeane added a comment.

In D108643#3057417 <https://reviews.llvm.org/D108643#3057417>, @rjmccall wrote:

> In D108643#3055244 <https://reviews.llvm.org/D108643#3055244>, @erichkeane 
> wrote:
>
>>>> ! In D108643#3054443 <https://reviews.llvm.org/D108643#3054443>, @rjmccall 
>>>> wrote:
>>>>
>>>>> ! In D108643#3027473 <https://reviews.llvm.org/D108643#3027473>, 
>>>>> @erichkeane wrote:
>>>>>
>>>>>> ! In D108643#3026550 <https://reviews.llvm.org/D108643#3026550>, 
>>>>>> @rjmccall wrote:
>>>>>
>>>>> I think it would be better to provide a generic ABI specification that is 
>>>>> designed to "lower" `_BitInt` types into more basic concepts that ABIs 
>>>>> typically already have rules for.  It would be appropriate to note at the 
>>>>> top that this is only a generic specification and that the rules for any 
>>>>> particular platform should be codified in a platform-specific ABI.  But 
>>>>> we should make that easy so that platform owners who don't have strong 
>>>>> opinions about the ABI can just say "as described in version 1.4 of the 
>>>>> generic ABI at https://clang.llvm.org/...";
>>>>>
>>>>> Now, that is all independent of what we actually decide the ABI should 
>>>>> be.  But I do think that if we're going to make this available on all 
>>>>> targets, we should strongly consider doing a "legalizing" lowering in the 
>>>>> frontend: at ABI-exposed points (call arguments/parameters and memory 
>>>>> accesses), `_BitInt` types should be translated into types that a naive 
>>>>> backend can be trusted to handle in a way that matches the documented 
>>>>> ABI.  Individual targets can then opt in to using the natural lowerings 
>>>>> if they promise to match the ABI, but that becomes a decision that they 
>>>>> make to enable better optimization and code generation, not something 
>>>>> that's necessary for correctness.
>>>>
>>>> Don't we already have that?  We work the same way a 'bool' does, that is, 
>>>> we zero/sign extend for parameters and return values?  The backends then 
>>>> reliably up-scale these to the power-of-two/multiple-of-pointer.
>>>
>>> There's two levels of a "legalizing" lowering.
>>>
>>> On the specification level, we'd be formally saying that the ABI matches 
>>> the ABI of some other C construct.  For example, we might say that a 
>>> `signed _BitInt(14)` argument is treated exactly as if the argument type 
>>> was instead `signed short` (with whatever restriction we do or do not 
>>> impose on the range).  This is very nice on this level because, first, it's 
>>> a rule that works generically for all targets without needing to care about 
>>> the details of how arguments are assigned to registers or stack slots or 
>>> whatever; and second, it means you're never adding new cases to the ABI 
>>> that e.g. libffi would need to care about; and third, you can reliably 
>>> match the ABI with manually-lowered C code from a compiler that doesn't 
>>> even support `_BitInt`s.
>>>
>>> On the implementation level, we'd have to actually emit IR which will turn 
>>> into code which matches that ABI.  I think you are right that small 
>>> integers already reliably work that way in LLVM, so that if you pass an 
>>> `i11 sext` it'll get sign-extended to some width — what width exactly, I 
>>> don't know, but probably the same width that `i16 sext` would be.  Larger 
>>> integers, I'm not sure.  A legalizing lowering of big `_BitInt` argument 
>>> would presumably say either that it's exactly the same as a struct 
>>> containing all the chunks or that it's exactly the same as a series of 
>>> arguments for each of the chunks.  Those are two very different rules!  
>>> Most ABIs won't "straddle" a single argument between registers and the 
>>> stack, so e.g. if you'd need two registers and you only have one left then 
>>> you exhaust the registers and go fully on the stack; but obviously you can 
>>> get straddling if the lowering expands the sequence.  Similarly, some ABIs 
>>> will go indirect if the struct gets big enough, but you won't get that if 
>>> the lowering expands.  But on the other hand, if the rule is really that 
>>> it's like a struct, well, some ABIs don't pass small structs in registers.  
>>> Anyway, my point is that what exactly LLVM targets do if you give them an 
>>> `i117` might not match either of these possibilities reliably across 
>>> targets.  In any case, since we currently have to count registers in the 
>>> frontend for the register-passing ABIs, we'll need to actually know what 
>>> the targets do.
>>
>> Hmm... now that I think I understand the concern, I'm not sure we're able to 
>> take on this level of commitment. The Clang ABI code is a bit of a mess in 
>> general, plus each target has its own code, right (In 
>> CodeGen/TargetInfo.cpp)?
>
> Ideally we would have a generic handling of it that most ABI code would 
> simply trigger.
>
>> Additionally, that would require breaking the Microsoft ABI again, and I 
>> thought we'd discussed trying not to make changes until Microsoft defined 
>> that ABI, right?
>
> I didn't realize we were matching any other compilers at the moment.  Or is 
> that not what you mean?

Sorry, no, not what I meant, but I see how it is misleading.  We currently have 
an ABI for _ExtInt (admittedly experimental as you said) on Windows that we 
will have to break at least 1 more time (when MS decides on the ABI).  I 
thought at one point in this discussion we'd decided to keep us from breaking 
OUR experimental MS ABI as much as possible, so we only broke it 1x.

> I think we need to consider the ABI for this experimental and unstable on all 
> platforms.
>
>> I would like us to be able to find a way forward, and hope you can help make 
>> a suggestion on how to do so.  We'd love to get Clang to support this C23 
>> feature at least on some targets as there are a good amount of users of this 
>> feature already as `_ExtInt`, and we would really want to get them to the 
>> standards version ASAP.  Do you have any suggestions on how we can move 
>> forward?
>
> I think the immediate way forward is that we can continue to document this as 
> an experimental feature with an unstable ABI, just with a new name.  We do 
> not need to tie these things together as long as we agree that the feature is 
> experimental and the ABI might change.  Perhaps it should be enabled by an 
> experimental flag until the ABI is official?

I don't know if we should continue to document this as experimental.  This is a 
language-standardized type that we'd ultimately like to be able to claim 
support for. I'm not sure on the progress of the ABI going 'official', but I 
think it has already been published, or nearly so?  We've been engaging with 
HJ, who owns the Itanium ABI.

>> PS: The current state of the things for the 4 platforms I deal with (and of 
>> course the most complicated ones) is:
>
> Ah, thank you for this.
>
>> |                                                 | <32 bit    | < 64 bit    
>>                  | < 128 bit                                                 
>>           | >128 bit          |
>> | Linux x86_64                                    | s/zext     | always pass 
>> as a coerced i64 | Pass as 2 i64s 'coerced' while in registers, then Ptr to 
>> iN (byval) | Ptr to iN (Byval) |
>> | Windows x86_64                                  | pass as iN | pass as iN  
>>                  | Ptr to iN                                                 
>>           | Ptr to iN         |
>> | Linux i386                                      | s/zext     | pass as iN  
>>                  | Ptr to iN                                                 
>>           | Ptr to iN         |
>> | Windows i386                                    | s/zext     | pass as iN  
>>                  | Ptr to iN                                                 
>>           | Ptr to iN         |
>> | + Your suggestion for ?all? as I understand it? | s/zext     | s/zext      
>>                  | Split into i64s?                                          
>>           | Split into i64s?  |
>> |
>
> Lowering semantics would use the platform's normal ABI rules for the lowered 
> type.  For example, if we lowered larger-than-fundamental `_BitInt`s to a 
> struct containing the chunks, then `unsigned _BitInt(192)` would become 
> `struct { uint32_t a, b, c, d, e, f; }` on 32-bit (which IIUC on both Linux 
> and Windows x86 would be passed directly on the stack, not by reference) and 
> `struct { uint64_t a, b, c; }` on 64-bit (which IIUC on both Linux and 
> Windows  x86_64 would be passed by reference).  The target lowering code 
> would recognize `_BitInt` types and ask the normal code to handle the lowered 
> type instead.

I think I have a better understanding of this? I perhaps need to ruminate 
further.  I don't know if we'd be able to have a single place where we can do 
all of this, but it seems like this is a fairly non-trivial task.  Aaron and I 
will discuss it further.

> What you're describing above are completely custom target-specific rules, and 
> in some cases they're novel rules that the ABIs don't normally use for other 
> types.  The standard i386 CCs basically never pass arguments by reference 
> unless they have a non-trivially-copyable C++ type — the only exception is 
> over-aligned types on Windows.  Unless you don't really mean they're passed 
> by pointer; if you're looking at IR, it can be misleading because of `byval`.

For the windows types, they are currently passed directly as iN*.  The only 
platform that did the 'byval' was the linux 64 bit ABI. This is perhaps novel, 
but it IS what we do currently for '_ExtInt'.


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