www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Structs, Speed and refs.

reply "Jakob Bornecrantz" <wallbraker gmail.com> writes:
Hey everybody!

A bit of background; I'm porting some code over from D1 to D2 and 
I ran into a bit of a problem. I have a bunch of code that looks 
something like this:

class Bar : Other {
   override void func(ref LargeStruct st) {}
}

Bar bar;
LargeStruct foo, too;
bar.func(foo - too);

This compiles just fine in D1 but no longer in D2. Because the 
temp created by "foo - too" is not a lvalue apparently. I don't 
want to remove the "ref" storage type because i still want it to 
be fast. And I rather have neater looking code vs:

LargeStruct foo, too, temp;
temp = foo - too;
bar.func(temp);

One solution is to turn "in" structs into pass by reference, eg 
const ref, but not require lvalue semantics at the call site?

Cheers, Jakob.
Oct 23 2012
next sibling parent reply "Daniel =?UTF-8?B?S296w6FrIg==?= <kozzi11 gmail.com> writes:
Hi,

First of all, I think there is no difference in speed between

LargeStruct foo, too, temp;
temp = foo - too;
bar.func(temp);

and with func without ref.

How looks your opBinary(Right) method?

For eg. this works for me:

struct LargeStruct {
	int x;
	
	auto ref opBinary(string op)(LargeStruct rhs) if (op == "-") {		
		this.x = this.x - rhs.x;
		return this;
	}
}

class Bar {
   void func(ref LargeStruct st) {}
}


void main(string[] args)
{
	Bar bar = new Bar();
	LargeStruct foo, too;
	bar.func(foo - too);
}

However this will modify foo struct.


On Tuesday, 23 October 2012 at 09:44:06 UTC, Jakob Bornecrantz 
wrote:
 Hey everybody!

 A bit of background; I'm porting some code over from D1 to D2 
 and I ran into a bit of a problem. I have a bunch of code that 
 looks something like this:

 class Bar : Other {
   override void func(ref LargeStruct st) {}
 }

 Bar bar;
 LargeStruct foo, too;
 bar.func(foo - too);

 This compiles just fine in D1 but no longer in D2. Because the 
 temp created by "foo - too" is not a lvalue apparently. I don't 
 want to remove the "ref" storage type because i still want it 
 to be fast. And I rather have neater looking code vs:

 LargeStruct foo, too, temp;
 temp = foo - too;
 bar.func(temp);

 One solution is to turn "in" structs into pass by reference, eg 
 const ref, but not require lvalue semantics at the call site?

 Cheers, Jakob.
Oct 23 2012
parent "Jakob Bornecrantz" <wallbraker gmail.com> writes:
On Tuesday, 23 October 2012 at 10:36:11 UTC, Daniel Kozák wrote:
 Hi,

 First of all, I think there is no difference in speed between

 LargeStruct foo, too, temp;
 temp = foo - too;
 bar.func(temp);

 and with func without ref.
That doesn't seem to be the case, as at least DMD always copies to the stack. Even if I change the function to have the struct as a unused local variable it still copies. void example(LargeStruct t, Bar bar) { bar.func(t); } with ref: Dump of assembler code for function _D7example4testFS7example11LargeStructC7example3BarZv: 0x0000000000425ee0 <+0>: push %rbp 0x0000000000425ee1 <+1>: mov %rsp,%rbp 0x0000000000425ee4 <+4>: sub $0x10,%rsp 0x0000000000425ee8 <+8>: lea 0x10(%rbp),%rsi 0x0000000000425eec <+12>: mov (%rdi),%rax 0x0000000000425eef <+15>: rex.W callq *0x30(%rax) 0x0000000000425ef3 <+19>: mov %rbp,%rsp 0x0000000000425ef6 <+22>: pop %rbp 0x0000000000425ef7 <+23>: retq without ref: Dump of assembler code for function _D7example4testFS7example11LargeStructC7example3BarZv: 0x0000000000425ee0 <+0>: push %rbp 0x0000000000425ee1 <+1>: mov %rsp,%rbp 0x0000000000425ee4 <+4>: sub $0x10,%rsp 0x0000000000425ee8 <+8>: lea 0x208(%rbp),%rsi 0x0000000000425eef <+15>: mov $0x40,%ecx 0x0000000000425ef4 <+20>: pushq (%rsi) 0x0000000000425ef6 <+22>: sub $0x8,%rsi 0x0000000000425efa <+26>: loop 0x425ef4 <_D7example4testFS7example11LargeStructC7example3BarZv+20> 0x0000000000425efc <+28>: mov (%rdi),%rax 0x0000000000425eff <+31>: rex.W callq *0x30(%rax) 0x0000000000425f03 <+35>: add $0x200,%rsp 0x0000000000425f0a <+42>: mov %rbp,%rsp 0x0000000000425f0d <+45>: pop %rbp 0x0000000000425f0e <+46>: retq
 How looks your opBinary(Right) method?

 For eg. this works for me:

 struct LargeStruct {
 	int x;
 	
 	auto ref opBinary(string op)(LargeStruct rhs) if (op == "-") 
 {		
 		this.x = this.x - rhs.x;
 		return this;
 	}
 }

 class Bar {
   void func(ref LargeStruct st) {}
 }


 void main(string[] args)
 {
 	Bar bar = new Bar();
 	LargeStruct foo, too;
 	bar.func(foo - too);
 }

 However this will modify foo struct.
Since this is D1 code being ported I'm currently using opSub. I tried changing your code to opSub and I got the same error as with mine. Your example should probably be an error. I'm not saying I was right in doing what I did. The point of the post was to improve D. Cheers, Jakob.
Oct 23 2012
prev sibling parent "martin" <kinke libero.it> writes:
On Tuesday, 23 October 2012 at 09:44:06 UTC, Jakob Bornecrantz 
wrote:
 One solution is to turn "in" structs into pass by reference, eg 
 const ref, but not require lvalue semantics at the call site?
And here we go again - missing rvalue-to-const-ref propagation. Check out http://forum.dlang.org/thread/yhnbcocwxnbutylfeoxi forum.dlang.org
Oct 23 2012