English Amiga Board


Go Back   English Amiga Board > Coders > Coders. Language > Coders. C/C++

 
 
Thread Tools
Old 08 October 2021, 17:47   #1
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
SAS/C Fastcall-ABI (__regargs)

I'm looking for an exact specification of SAS/C's Fastcall ABI.

All I'm sure about is that the first two integer arguments are passed in d0, d1 while the first two pointers are passed in a0, a1. Function names following this ABI are preceded by an '@' instead of an '_'.

Varargs functions will always pass all arguments on the stack, right? And the called function name is still _name.

What about floating point arguments? Without an FPU are the first two float (single precision) arguments passed in d0,d1 (if not already occupied by integer arguments - who has priority)? And double is passed in the register pair d0/d1? Or do floating point arguments always use the stack?

And with FPU? Does it use fp0 and fp1? Or also the stack?
Anything else which I forgot? Passing structures?
Any SAS/C expert here?
phx is offline  
Old 08 October 2021, 18:13   #2
kamelito
Zone Friend
 
kamelito's Avatar
 
Join Date: May 2006
Location: France
Posts: 1,801
Hi PHX I was in contact with a SAS employee who know Steve Krueger, is it a question for him or someone else could answer here?
kamelito is offline  
Old 08 October 2021, 19:03   #3
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,214
Quote:
Originally Posted by phx View Post
All I'm sure about is that the first two integer arguments are passed in d0, d1 while the first two pointers are passed in a0, a1. Function names following this ABI are preceded by an '@' instead of an '_'.
Correct.


Quote:
Originally Posted by phx View Post
Varargs functions will always pass all arguments on the stack, right? And the called function name is still _name.
Correct. varargs functions are implicitly __stdargs, no matter what the configuration says.




Quote:
Originally Posted by phx View Post

What about floating point arguments? Without an FPU are the first two float (single precision) arguments passed in d0,d1 (if not already occupied by integer arguments - who has priority)?
No, double arguments do not qualify for register passing. They are always passed on the stack. Thus, a __regargs function taking a double and an int (in that order) expects the double on the stack, and the int in register d0.


The only exception are function calls to mathieeedoubXXXX, for which SAS/C seems to have extra support. Here doubles are passed correctly. (Though register allocation is broken, d1 is trashed and that is not taken care of. Had to learn this the hard way).



Quote:
Originally Posted by phx View Post



And with FPU? Does it use fp0 and fp1? Or also the stack?
I do not recall by heart, but it was likely fp0 and fp1 as first double arguments. I can probably provide an answer by tomorrow.



Quote:
Originally Posted by phx View Post



Anything else which I forgot? Passing structures?
Any SAS/C expert here?
Ditto, stack-based likely, but let me verify.
Thomas Richter is offline  
Old 08 October 2021, 19:29   #4
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,214
Quote:
Originally Posted by Thomas Richter View Post
I do not recall by heart, but it was likely fp0 and fp1 as first double arguments. I can probably provide an answer by tomorrow.
I remembered correct. fp0 and fp1 as first two arguments, fp0 as result code.


Quote:
Originally Posted by Thomas Richter View Post
Ditto, stack-based likely, but let me verify.

Stack based, I recalled correctly. If you return a structure, SAS/C allocates the returned structure at a stack on the caller, and provides the address of the expected return structure as hidden argument on the stack, even for regargs.
Thomas Richter is offline  
Old 09 October 2021, 12:01   #5
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Thanks a lot! That's all I need to know!

Looks like vbcc's -fastcall option is already very compatible. So I only need some time to add all the Fastcall-ABI functions to vclib.

Quote:
Originally Posted by kamelito View Post
Hi PHX I was in contact with a SAS employee who know Steve Krueger, is it a question for him or someone else could answer here?
You have some really good connections!
Certainly useful to keep in mind for the future.
phx is offline  
Old 19 October 2021, 11:43   #6
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by Thomas Richter View Post
Correct. varargs functions are implicitly __stdargs, no matter what the configuration says.
AFAIK SAS/C can mix Fastcall- and Standard-ABI functions and object files in a single linker library - like clib?

This would lead to another question: Let's take the varargs function printf. It would only occur as _printf in clib, because of varargs.

Does it mean this is the Standard-ABI printf-object, with references to more Standard-ABI functions? This would effectively make the linker pull in more Standard-ABI objects, which are suboptimal regarding the currently selected ABI. And, even worse, you may have Fastcall-ABI variants for the same functions in parallel (e.g. vfprintf or fputc), increasing the size of your executable.

Or is there a second Standard-ABI printf in clib, which calls Fastcall-ABI functions (as long as they do not take varargs)? Then how does SAS/C differentiate between them?
phx is offline  
Old 19 October 2021, 15:14   #7
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,214
Quote:
Originally Posted by phx View Post
AFAIK SAS/C can mix Fastcall- and Standard-ABI functions and object files in a single linker library - like clib?
Yes, they are distinguished by the underscore or the @ sign, depending on the calling convention. Sometimes even in the same function/module. For example, @NewList and _NewList are in the same module, the only difference being that the second has an entry point 8 bytes above which pulls the argument from the stack, and then runs into @NewList.


Quote:
Originally Posted by phx View Post
This would lead to another question: Let's take the varargs function printf. It would only occur as _printf in clib, because of varargs.
Correct.


Quote:
Originally Posted by phx View Post

Does it mean this is the Standard-ABI printf-object, with references to more Standard-ABI functions?
It's probably vice versa, namely that printf in sc.lib was compiled with registerized arguments, and for that pulls in the registerized functions. As said above, they are in many cases almost identical to the stdargs functions, with just a small difference in the entry code. Quite frankly, I haven't checked which way around it works, but I can check. There is no @printf, that's for sure.


This being said, I personally avoid printf() (it's rather fat anyhow). There is Printf() from dos, or go through RawDoFmt() to get the dirty work done.
Thomas Richter is offline  
Old 19 October 2021, 18:40   #8
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,214
So, apparently, the sc.lib was compiled with the option PARMS=BOTH, which creates for each module exactly the structure I described above for NewList: Two entry points per functions, one for regargs as @name, and one with stack-based arguments that takes the stack values, and puts them into the registers for the regargs function. The stack-based function is then of course _name.

To make this more precise: It's not that every function is compiled twice, but each function has two entry points, with the stack-based entry point loading the registers for the registerized entry point a couple of bits later.
Thomas Richter is offline  
Old 19 October 2021, 19:09   #9
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by Thomas Richter View Post
Sometimes even in the same function/module. For example, @NewList and _NewList are in the same module, the only difference being that the second has an entry point 8 bytes above which pulls the argument from the stack, and then runs into @NewList.
Indeed, that's a nice trick, which I also used for some functions. But it can only be done when all arguments fit into the __regargs registers. Otherwise the stack-offsets differ. And there shouldn't be too much function calls in it - because they must either use regargs or stdargs. NewList is a "leaf"-routine with few args, so it is fine.

Quote:
It's probably vice versa, namely that printf in sc.lib was compiled with registerized arguments, and for that pulls in the registerized functions.
Hmm...

Quote:
As said above, they are in many cases almost identical to the stdargs functions, with just a small difference in the entry code.
These implementations with small differences probably cannot be done for all functions (see above). printf will most likely call vfprintf, which has three arguments. Assuming va_list is a pointer, it passes three pointers (FILE *, const char *, va_list) - bad luck.
So you may get a separate @vfprintf and _vfprintf, which is a quite complex routine. Assuming printf calls @vfprintf you will bloat your Standard-ABI program when calling vfprintf() from your own source, as the linker has to include both.
Same problem for the other functions which vfprintf() calls. At least fputc(). Maybe also isdigit() and floating point arithmetics.

EDIT: Just saw your new post. Still my questions/confusion remains.

Last edited by phx; 19 October 2021 at 19:11. Reason: New post
phx is offline  
Old 20 October 2021, 19:41   #10
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,214
Quote:
Originally Posted by phx View Post
Indeed, that's a nice trick, which I also used for some functions. But it can only be done when all arguments fit into the __regargs registers.
Actually, it works for all functions. The function "preamble", in case not all parameters fit into registers, reorganizes the stack frame. That is, it moves the stack arguments to a new location on the stack with additonal moves.



Quote:
Originally Posted by phx View Post
Otherwise the stack-offsets differ. And there shouldn't be too much function calls in it - because they must either use regargs or stdargs.
Sorry, I don't understand this... Functions with parameters=both create an additional preamble, and if you call them yourself, the regargs version is used.




Quote:
Originally Posted by phx View Post


So you may get a separate @vfprintf and _vfprintf, which is a quite complex routine. Assuming printf calls @vfprintf you will bloat your Standard-ABI program when calling vfprintf() from your own source, as the linker has to include both.
The sc.lib will (likely) include both _vprintf and @vprintf, and the former contains just of a preample that picks arguments from the stack and runs into @vprintf. This does not extend the function by a lot (8 bytes or so).
Thomas Richter is offline  
Old 21 October 2021, 11:08   #11
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by Thomas Richter View Post
Actually, it works for all functions. The function "preamble", in case not all parameters fit into registers, reorganizes the stack frame. That is, it moves the stack arguments to a new location on the stack with additonal moves.
Oh. I see. (Does ANSI/ISO-C allow moving arguments on the stack?)

I don't really like that, though. As far as I understand now, sc.lib is probably build with PARMS=both for all functions to keep them compatible with mixed ABIs. This puts Standard-ABI programs generally at a disadvantage, because of the preamble-overhead, which becomes bigger as more registers you pass.

On the other hand you could argue that this overhead becomes insignificant when functions with many arguments are sufficiently complex. And internal sc.lib calls are using regargs anyway.

Hmm...
phx is offline  
Old 21 October 2021, 11:44   #12
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,214
Quote:
Originally Posted by phx View Post
Oh. I see. (Does ANSI/ISO-C allow moving arguments on the stack?)
ISO C always allows the compiler to operate on an AS-IF basis, that is, if the observable behavior isn't any different, the compiler can do what it wants. In this case, it doesn't really make any difference, it just creates overhead by moving bytes around. Note that most sc.lib functions do not create this overhead as it requires more than two ints or more than two pointers to run into this issue.



Quote:
Originally Posted by phx View Post
This puts Standard-ABI programs generally at a disadvantage, because of the preamble-overhead, which becomes bigger as more registers you pass.
Well, two arguments: First, the standard ABI is already not ideal as registerized calls are more efficient anyhow, so the standard ABI should be better deprecated. The other argument would be that you could always supply call-convention specific libraries (i.e. have a sc_rr.lib and a sc_std.lib) if that would be necessary, just that SAS/C did not follow this route. So it's not exactly a compiler choice, but a compiler-deployment choice.
Thomas Richter is offline  
Old 21 October 2021, 15:46   #13
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by Thomas Richter View Post
ISO C always allows the compiler to operate on an AS-IF basis, that is, if the observable behavior isn't any different, the compiler can do what it wants.
You are certainly right. As long as the code generator does not rely on the stack arguments (for optimizing subsequent calls) it is probably ok.

Quote:
First, the standard ABI is already not ideal as registerized calls are more efficient anyhow, so the standard ABI should be better deprecated.
I agree that an ABI using two or three data and address registers to pass arguments is better. Ideally all m68k compiler vendors should come together and agree on a new ABI. But I doubt this will happen, and it would exclude all compilers which are no longer maintained. So we have to stick with the standard ABI for best compatibility.

Quote:
The other argument would be that you could always supply call-convention specific libraries
True. But that's what I wanted to avoid. My idea was that when I offer an optional Fastcall-ABI for vbccm68k it must be compatible with SAS/C, and must not require any new libraries, startup-codes or config files. Just object files, which can be compiled with -fastcall or not.
phx is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
AROS ABI-v1 68k AMiGA Version AMIGASYSTEM News 12 20 June 2019 01:29
Labykill (Fastcall BBS Game) Darksun777 request.Apps 1 12 February 2018 11:20
SAS C 6.58 (again) nyteshade request.Other 2 15 December 2016 17:18
[Found: Death Trap] Game with protagonist called Abi? Justice Looking for a game name ? 2 08 February 2010 22:15
Sas C V 6.0 Jherek Carnelia request.Apps 1 20 March 2007 10:13

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 09:54.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.15006 seconds with 13 queries