Deutsch   English   Français   Italiano  
<vk3jbp$3dldp$1@dont-email.me>

View for Bookmarking (what is this?)
Look up another Usenet article

Path: ...!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: BGB <cr88192@gmail.com>
Newsgroups: comp.lang.c
Subject: Re: transpiling to low level C
Date: Fri, 20 Dec 2024 05:10:44 -0600
Organization: A noiseless patient Spider
Lines: 490
Message-ID: <vk3jbp$3dldp$1@dont-email.me>
References: <vjlh19$8j4k$1@dont-email.me>
 <vjn9g5$n0vl$1@raubtier-asyl.eternal-september.org>
 <vjnhsq$oh1f$1@dont-email.me> <vjnq5s$pubt$1@dont-email.me>
 <vjp2f3$13k4m$2@dont-email.me> <vjr7np$1j57r$2@dont-email.me>
 <vjsdum$1rfp2$1@dont-email.me> <vjse6l$1rfp2$2@dont-email.me>
 <vjsf6g$1rlkq$1@dont-email.me> <vjsgdr$1rrvs$1@dont-email.me>
 <vjsi61$1rlkq$2@dont-email.me> <vjsk7q$1rrvs$2@dont-email.me>
 <vjv5ir$2ds8r$2@dont-email.me> <vjv8lv$2edrv$1@dont-email.me>
 <vjvp9g$2h6ck$1@dont-email.me> <vjvpos$2gsil$3@dont-email.me>
 <vk0bvf$2nn4a$1@dont-email.me> <vk0vu7$2qr2c$1@dont-email.me>
 <vk204q$310pu$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
Injection-Date: Fri, 20 Dec 2024 12:10:50 +0100 (CET)
Injection-Info: dont-email.me; posting-host="cf4714a0858564e052c1456b9080839f";
	logging-data="3593657"; mail-complaints-to="abuse@eternal-september.org";	posting-account="U2FsdGVkX18pAFsuyrDD4MZaeYM36FZxcoLNPzakjdw="
User-Agent: Mozilla Thunderbird
Cancel-Lock: sha1:0MAJO3nWfgbqyQCX5wiTVdjZSiI=
Content-Language: en-US
In-Reply-To: <vk204q$310pu$1@dont-email.me>
Bytes: 20255

On 12/19/2024 2:36 PM, BGB wrote:
> On 12/19/2024 5:27 AM, bart wrote:
>> On 19/12/2024 05:46, BGB wrote:
>>> On 12/18/2024 6:35 PM, bart wrote:
>>>> On 19/12/2024 00:27, BGB wrote:
>>
>>>>> By-Value Structs smaller than 16 bytes are passed as-if they were a 
>>>>> 64 or 128 bit integer type (as a single register or as a register 
>>>>> pair, with a layout matching their in-memory representation).
>>>>>
>>>>> ...
>>>>>
>>>>>
>>>>> But, yeah, at the IL level, one could potentially eliminate structs 
>>>>> and arrays as a separate construct, and instead have bare pointers 
>>>>> and a generic "reserve a blob of bytes in the frame and initialize 
>>>>> this pointer to point to it" operator (with the business end of 
>>>>> this operator happening in the function prolog).
>>>>
>>>> The problem with this, that I mentioned elsewhere, is how well it 
>>>> would work with SYS V ABI, since the rules for structs are complex, 
>>>> and apparently recursive.
>>>>
>>>> Having just a block of bytes might not be enough.
>>>
>>> In my case, I am not bothering with the SysV style ABI's (well, along 
>>> with there not being any x86 or x86-64 target...).
>>
>> I'd imagine it's worse with ARM targets as there are so many more 
>> registers to try and deconstruct structs into.
>>
> 
> Not messed much with the ARM64 ABI or similar, but I will draw the line 
> in the sand somewhere.
> 
> Struct passing/return is enough of an edge case that one can just sort 
> of declare it "no go" between compilers with "mostly but not strictly 
> compatible" ABIs.
> 
> 
>>>
>>> For my ISA, it is a custom ABI, but follows mostly similar rules to 
>>> some of the other "Microsoft style" ABIs (where, I have noted that 
>>> across multiple targets, MS tools have tended to use similar ABI 
>>> designs).
>>
>> When you do your own thing, it's easy.
>>
>> In the 1980s, I didn't need to worry about call conventions used for 
>> other software, since there /was/ no other software! I had to write 
>> everything, save for the odd calls to DOS which used some form of 
>> SYSCALL.
>>
>> Then, arrays and structs were actually passed and returned by value 
>> (not via hidden references), by copying the data to and from the stack.
>>
>> However, I don't recall ever using the feature, as I considered it 
>> efficient. I always used explicit references in my code.
>>
> 
> Most of the time, one is passing/returning structures as pointers, and 
> not by value.
> 
> By value structures are usually small.
> 
> 
> When a structure is not small, it is both simpler to implement, and 
> usually faster, to internally pass it by reference.
> 
> If you pass a large structure to a function by value, via an on-stack 
> copy, and the function assigns it to another location (say, a global 
> variable):
>    Pass by reference: Only a single copy operation is needed;
>    Pass by value on-stack: At least two copy operations are needed.
> 
> One also needs to reserve enough space in the function arguments list to 
> hold any structures passed, which could be bad if they are potentially 
> large.
> 
> 
> 
> But, on my ISA, ABI is sort of like:
>    R4 ..R7 : Arg0 ..Arg3
>    R20..R23: Arg4 ..Arg7
>    R36..R39: Arg8 ..Arg11 (optional)
>    R52..R55: Arg12..Arg15 (optional)
> Return Value:
>    R2, R3:R2 (128 bit)
>    R2 is also used to pass in the return value pointer.
> 
> 'this':
>    Generally passed in either R3 or R18, depending on ABI variant.
> 
> Where, callee-save:
>    R8 ..R14,  R24..R31,
>    R40..R47,  R56..R63
>    R15=SP
> 
> Non-saved scratch:
>    R2 ..R7 ,  R16..R23,
>    R32..R39,  R48..R55
> 
> 
> Arguments beyond the first 8/16 register arguments are passed on stack. 
> In this case, a spill space for the first 8/16 arguments (64 or 128 
> bytes) is provided on stack before the first non-register argument.
> 
> If the function accepts a fixed number of arguments and the number of 
> argument registers is 8 or less, spill space need only be provided for 
> the first 8 arguments (calling vararg functions will always reserve 
> space for 16 registers in the 16-register ABI). This spill space 
> effectively belongs to the callee rather than the caller.
> 
> 
> Structures (by value):
>    1.. 8 bytes: Passed in a single register
>    9..16 bytes: Passed in a pair, padded to the next even pair
>    17+: Pass as a reference.
> 
> Things like 128-bit types are also passed/returned in register pairs.
> 
> 
> 
> Contrast, RV ABI:
>    X10..X17 are used for arguments;
>    No spill space is provided;
>    ...
> 
> My variant uses similar rules to my own ABI for passing/returning 
> structures, with:
>    X28, structure return pointer
>    X29, 'this'
> Normal return values go into X10 or X11:X10.
> 
> 
> 
> Note that in both ABI's, passing 'this' in a register would mean that 
> class instances and COM objects are not equivalent (COM object methods 
> always pass 'this' as the first argument).
> 
> The 'this' register is implicitly also used by lambdas to pass in the 
> pointer to the captured bindings area (which mostly resembles a 
> structure containing each variable captured by the lambda).
> 
> Can note though that in this case, capturing a binding by reference 
> means the lambda is limited to automatic lifetime (non-automatic lambdas 
> may only capture by value). In this case, capture by value is the default.
> 
> 
>>> For my compiler targeting RISC-V, it uses a variation of RV's ABI rules.
>>> Argument passing is basically similar, but struct pass/return is 
>>> different; and it passes floating-point values in GPRs (and, in my 
>>> own ISA, all floating-point values use GPRs, as there are no FPU 
>>> registers; though FPU registers do exist for RISC-V).
>>
>> Supporting C's variadic functions, which is needed for many languages 
>> when calling C across an FFI, usually requires different rules. On 
>> Win64 ABI for example, by passing low variadic arguments in both GPRs 
>> and FPU registers.
>>
> 
> I simplified things by assuming only GPRs are used.
> 
> 
>> /Implementing/ variadic functions (which only occurs if implementing 
>> C) is another headache if it has to work with the ABI (which can be 
>> assumed for a non-static function).
>>
>> I barely have a working solution for Win64 ABI, which needs to be done 
========== REMAINDER OF ARTICLE TRUNCATED ==========