| Deutsch English Français Italiano |
|
<v6k13q$1g7uk$1@dont-email.me> View for Bookmarking (what is this?) Look up another Usenet article |
Path: ...!news.mixmin.net!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: =?UTF-8?Q?Re=3A_technology_discussion_=E2=86=92_does_the_world_need?=
=?UTF-8?B?IGEgIm5ldyIgQyA/?=
Date: Tue, 9 Jul 2024 13:55:51 -0500
Organization: A noiseless patient Spider
Lines: 151
Message-ID: <v6k13q$1g7uk$1@dont-email.me>
References: <v66eci$2qeee$1@dont-email.me> <v67gt1$2vq6a$2@dont-email.me>
<v687h2$36i6p$1@dont-email.me> <871q48w98e.fsf@nosuchdomain.example.com>
<v68dsm$37sg2$1@dont-email.me> <87wmlzvfqp.fsf@nosuchdomain.example.com>
<v6ard1$3ngh6$4@dont-email.me> <v6b0jv$3nnt6$1@dont-email.me>
<87h6d2uox5.fsf@nosuchdomain.example.com> <v6d779$6rk5$2@dont-email.me>
<v6e76u$c0i9$1@dont-email.me> <v6esqm$fian$2@dont-email.me>
<v6f7vg$hgam$1@dont-email.me> <20240707164747.258@kylheku.com>
<v6gl83$s72a$1@dont-email.me> <v6h8ao$ur1v$1@dont-email.me>
<v6jhk3$1drd6$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
Injection-Date: Tue, 09 Jul 2024 20:55:55 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="05b7ca2b320d2b6fc0402746ff5c99a9";
logging-data="1581012"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19LKerfOHzGk2nI2pXqOnluwZmypgS3F7Q="
User-Agent: Mozilla Thunderbird
Cancel-Lock: sha1:rlkfor+d/JoP6vYdYdigHjglRYs=
In-Reply-To: <v6jhk3$1drd6$1@dont-email.me>
Content-Language: en-US
Bytes: 7538
On 7/9/2024 9:31 AM, David Brown wrote:
> On 08/07/2024 19:39, BGB wrote:
>> On 7/7/2024 11:28 PM, James Kuyper wrote:
>>> On 7/7/24 20:02, Kaz Kylheku wrote:
>>> ...
>
>>
>>> I see no point in having implicit pointers, but I don't believe that
>>> they are prohibited.
>>>
>>
>> They mostly exist in a "sort of simpler to implement the compiler this
>> way" sense.
>>
>> In the implicit pointer case, the compiler just treats it as-if it
>> were an explicit pointer. In this case, both are basically treated as
>> being roughly equivalent at the IR levels.
>>
>> And, most of the code-generation stage doesn't need separate handling
>> for arrays and pointers, but can use combined "ArrayOrPointer"
>> handling or similar.
>>
>> It had all seemed "obvious enough".
>>
>>
>>
>>
>> Similar reasoning for passing structs by-reference in the ABI:
>> Pass by reference is easy to implement;
>> In place copying and decomposing into registers, kinda bad.
>>
>> Though, this one seems to be a common point of divergence between
>> "SysV" and "Microsoft" ABIs. Sometimes a target will have an ABI
>> defined, and the MS version was almost the same, just typically
>> differing in that it passes structs by reference and provides a spill
>> space for register arguments.
>>
>
> I don't think it is helpful that you keep mixing /logical/ terms with
> /implementation/ terms.
>
> In C, there is no "pass by reference" or "return by reference". It is
> all done by value. Even when you use pointer arguments or return types,
> you are passing or returning pointer values. C programmers use pointers
> to get the effect of passing by reference, but in C you use pointers to
> be explicit about references.
>
The pass by reference, in this context, was referring to the ABI, not to
C itself.
It looks from C's POV as-if it were by-value.
Which it is, depends on if one is looking at things at the language
level, ABI level, or IR level, ...
> Structs in C are passed by value, and returned by value. Not by reference.
>
Granted, by-value is how it looks from within the language.
But, saying that it is by-value in the ABI inaccurate if it is
implemented by passing the address of the structure to the called
function (and then making local copies as needed).
> The C standards don't say how passing structs around by value is to be
> implemented - that is hidden from the programmer. Usually ABI's (which
> are also hidden from the programmer) specify the implementation details,
> but some ABI's are weak in that area. Generally, structs up to a
> certain size or complexity are passed in registers while bigger or more
> advanced types are passed via addresses (pointing to stack areas) in
> registers or the stack, just like any other bigger types. This is not
> "pass by reference" as far as the C programming is concerned - but you
> could well call it that at the assembly level. Where the line between
> "passing in registers" and "passing via addresses to space on the stack"
> is drawn, is entirely up to the compiler implementation and any ABI
> requirements. Some simpler compilers will pass all structs via
> addresses, no matter how simple they are, while others will aim to use
> registers whenever possible.
>
>
> So if you have these structs and declarations :
>
> struct small { uint16_t a; uint16_t b; };
> struct big { uint32_t xs[10]; };
>
> struct small foos(struct small y);
> struct big foob(struct big y);
>
> Then compilers will typically implement "x = foos(y)" as though it were:
>
> extern uint32_t foos(uint32_t ab);
> uint32_t _1 = foos(y.a << 16) | (y.b);
> struct small x = { _1 >> 16, _1 & 0xffff };
>
> And they will typically implement "x = foosb(y)" as though it were:
>
> extern void foob(struct big * ret, const struct big * xs);
> struct big x;
> foob(&x, &y);
>
>
> This is not, as you wrote somewhere, something peculiar to MSVC - it is
> the technique used by virtually every C compiler, except perhaps for
> outdated brain-dead 8-bit microcontrollers that have difficulty handling
> data on a stack.
>
> And it is not really "pass by reference" or "implicit pointers", it is
> just passing addresses around behind the scenes in the implementation.
>
In the SysV AMD64 ABI, and original SuperH ABI, struct passing is done as:
Decompose each struct member into registers as-if each field were passed
as its own function argument, putting the whole rest of the struct on
the stack if it doesn't fit in registers;
Returning a structure was done using the same area as used for passing
memory arguments.
This is both needlessly complicated and inefficient (as well as
requiring that the stack be big enough to accommodate any struct which
may be conceivably passed or returned by-value).
The RISC-V ABI is similar, except that IIRC the idea is that the struct
is passed and returned by copying it as a chunk of memory (without
otherwise decomposing or repacking it to match argument-list layout).
Contrast, Win64 ABI and the WinCE SH4 ABI:
Pass in a register if it fits, else pass a reference;
On a function call, a pointer is passed to the callee to accept the
returned structure on function return (may need to point to a dummy area
if no return location was given in the function call), if the structure
is too big to fit in a register.
On GCC for SH-4, IIRC it would use either a modified form of the Hitachi
ABI or WinCE ABI depending on whether it was configured for ELF or PE/COFF.
My ABI generally also works in this way, though uses register pairs (for
passing/returning 128-bit types and 16-byte structures).
So:
1-8 bytes: 1 register
9-16 byes: 2 registers
17+ bytes: Reference