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 ==========