www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Call Conventions

reply Dan <murpsoft hotmail.com> writes:
While I must admit it's most probably a very rare thing to need to specify a
calling convention; when you do need to it's excrutiating.

For Walnut, I'm currently doing this:

struct Value.sizeof = 16;

Value x(Value self, Value cc, Value[] arguments ...){
bla bla bla
}

Now, the way that's getting done by D is absolutely horrid compared to the way
I'd like to do it - by taking advantage of XMM registers, using the functions
to mutate self, cc, and a third variable which keeps getting returned, while
arguments get copied.

I don't understand how I can do that in D without declaring every single
function naked, templating in raw assembler, and then processing the function
using raw assembler because the variables aren't where D expects.

*sigh*

How about a way to specify call convention and use it via 

extern(MyCallConvention)

Would be fabulous.

Regards,
Dan
Jan 03 2008
next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Dan wrote:

 
 While I must admit it's most probably a very rare thing to need to specify
 a calling convention; when you do need to it's excrutiating.
 
 For Walnut, I'm currently doing this:
 
 struct Value.sizeof = 16;
 
 Value x(Value self, Value cc, Value[] arguments ...){
 bla bla bla
 }
 
 Now, the way that's getting done by D is absolutely horrid compared to the
 way I'd like to do it - by taking advantage of XMM registers, using the
 functions to mutate self, cc, and a third variable which keeps getting
 returned, while arguments get copied.
 
 I don't understand how I can do that in D without declaring every single
 function naked, templating in raw assembler, and then processing the
 function using raw assembler because the variables aren't where D expects.
 
 *sigh*
 
 How about a way to specify call convention and use it via
 
 extern(MyCallConvention)
 
 Would be fabulous.
 
 Regards,
 Dan
That sounds like a coll feature that D should have. I have no idea how it'd get implemented under the hood.
Jan 03 2008
parent Dan <murpsoft hotmail.com> writes:
Jason House Wrote:
 Dan Wrote:
...
 Now, the way that's getting done by D is absolutely horrid compared to the
 way I'd like to do it - by taking advantage of XMM registers, using the
 functions to mutate self, cc, and a third variable which keeps getting
 returned, while arguments get copied.
 
 I don't understand how I can do that in D without declaring every single
 function naked, templating in raw assembler, and then processing the
 function using raw assembler because the variables aren't where D expects.
 
 *sigh*
 
 How about a way to specify call convention and use it via
 
 extern(MyCallConvention)
...
 
 That sounds like a coll feature that D should have.  I have no idea how it'd
 get implemented under the hood.
Well, I would suggest utilizing opCall for the caller side... The idea is that if you inline opCall(), then essentially the code being generated is the contents of it (which could be inline assembler, or whatever works) The real problem comes in the callee side, because you need to run arbitrary code before what you see (typically the ebp/esp stuff), bind registers and/or stack variables to names correctly, and then run arbitrary code after what you see (closing the context by add ebp or whatever) My first suggestion would be that one could probably declare a given function to be a convention, at which point, any functions declared with that convention are passed as delegates to it. extern(MyConvention) = MyConventionFunction; void MyConventionFunction(lazy function f, *whatever*) { bla bla bla f(); bla bla bla } extern(MyConvention) void bob() { bla bla bla // this gets wrapped according to MyConventionFunction } Beyond that, using inline assembler correctly should handle the rest; and anyone who can't do that probably shouldn't be writing a call convention. Is that correct enough? How hard would it be to do that? Is it possible to achieve this with mixins/templates without needing to butcher the "void bob(){}" functions? (there'll be hundreds, and they *should* be legible) Regards, Dan
Jan 03 2008
prev sibling next sibling parent reply Alan Knowles <alan akbkhome.com> writes:
While it's not going to solve that issue, I think this should achieve 
what you are trying to do, although not quite as clean...


import std.string;
import std.stdio;

class Value {
	static Value[] emptyAr;
	int type = 0;
	int ival;
	this(int v) {
		this.type = 1;
		this.ival = v;
	}
	char[] cval;
	this(char[] v) {
		this.type = 2;
		this.cval = v;
	}
	char[] asString() {
		if (this.type == 2){
			return cval;
		}
		return std.string.toString(ival);
	}
}



void testArgs(char[] x, Value[] somevals) {
	foreach (v; somevals) {
		writefln("got vals %s", v.asString());
	}
}


void main ()
{
	
	testArgs("fred",
		Value.emptyAr
		~ (new Value(3))
		~ (new Value("dog"))
		~ (new Value(6)));
	
}






Dan wrote:
 While I must admit it's most probably a very rare thing to need to
 specify a calling convention; when you do need to it's excrutiating.
 
 For Walnut, I'm currently doing this:
 
 struct Value.sizeof = 16;
 
 Value x(Value self, Value cc, Value[] arguments ...){ bla bla bla }
 
 Now, the way that's getting done by D is absolutely horrid compared
 to the way I'd like to do it - by taking advantage of XMM registers,
 using the functions to mutate self, cc, and a third variable which
 keeps getting returned, while arguments get copied.
 
 I don't understand how I can do that in D without declaring every
 single function naked, templating in raw assembler, and then
 processing the function using raw assembler because the variables
 aren't where D expects.
 
 *sigh*
 
 How about a way to specify call convention and use it via
 
 extern(MyCallConvention)
 
 Would be fabulous.
 
 Regards, Dan
Jan 04 2008
parent reply Dan <murpsoft hotmail.com> writes:
Alan Knowles Wrote:

 While it's not going to solve that issue, I think this should achieve 
 what you are trying to do, although not quite as clean...
Unfortunately, no, that's quite a ways off the mark from what I'm trying to do. I was hoping to change how the program internally handles function calls. For example; if we use "extern(C)", - all the arguments are pushed onto the stack from right to left - return value is in eax or fp0 - cleanup is by the caller. So when we go: extern(C) int main(char[][] arguments), the caller knows to get the result from eax, and to push twice to make a D array, and to add 4 to esp afterwards to clean up. the callee knows that if there are any local variables, it needs to wiggle ebp and esp to cause the local variables to get wiped when the function returns. That's _cdecl. There's also syscall, optlink, pascal, fastcall, stdcall, safecall, and thiscall amongst the ones listed on wikipedia: http://en.wikipedia.org/wiki/X86_calling_conventions I was hoping to roll my own which allowed me to pass Value structs by SSE2 registers. Perhaps that's a little optimistic, but that's what got me thinking about this.
Jan 04 2008
parent Dan <murpsoft hotmail.com> writes:
PS:  This is how Watcom C/C++ did it:

http://www.openwatcom.org/index.php/Calling_Conventions#Specifying_Calling_Conventions_the_Watcom_Way
Jan 04 2008
prev sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
Dan <murpsoft hotmail.com> wrote:
 While I must admit it's most probably a very rare thing to need to  =
 specify a calling convention; when you do need to it's excrutiating.

 For Walnut, I'm currently doing this:

 struct Value.sizeof =3D 16;

 Value x(Value self, Value cc, Value[] arguments ...){
 bla bla bla
 }

 Now, the way that's getting done by D is absolutely horrid compared to=
=
 the way I'd like to do it - by taking advantage of XMM registers, usin=
g =
 the functions to mutate self, cc, and a third variable which keeps  =
 getting returned, while arguments get copied.

 I don't understand how I can do that in D without declaring every sing=
le =
 function naked, templating in raw assembler, and then processing the  =
 function using raw assembler because the variables aren't where D  =
 expects.

 *sigh*

 How about a way to specify call convention and use it via

 extern(MyCallConvention)

 Would be fabulous.

 Regards,
 Dan
I'm sure if we could get downs or Don to work on this, it could be done = = via some funky template mixin - possibly with absurd syntax (downs). Simen Kjaeraas
Jan 13 2008
parent Daniel Lewis <murpsoft hotmail.com> writes:
Simen Kjaeraas Wrote:

 Dan <murpsoft hotmail.com> wrote:
 How about a way to specify call convention and use it via

 extern(MyCallConvention)

 Would be fabulous.

 Regards,
 Dan
I'm sure if we could get downs or Don to work on this, it could be done via some funky template mixin - possibly with absurd syntax (downs). Simen Kjaeraas
Yeah, I'm absolutely horrible with templates, and I have no idea what the final executable is actually like inside; there are 80kb of "library/gc crap" that come with every executable that I can't see past enough to be able to profile. I tried extracting the GC out to a DLL, but nobody seems to know how to, apart from "it's possible" and "you can make DLL's use the EXE's GC doing this and this and this." Consider I can't just do it, maybe I'm not all the programmer I like to make myself out to be.
Jan 13 2008