Performance improvements for D / DMD compiler.

janderson askme at me.com
Sat Jan 20 01:09:10 PST 2007


Walter Bright wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> No, and for a good reason:
>>
>> foo(LargeStruct s1, LargeStruct s2)
>> {
>>   ...
>> }
>> ...
>> LargeStruct s;
>> foo(s, s);
>>
>> Nobody would enjoy hidden aliasing of s1 and s2.

I think you mean more like:


foo(LargeStruct s1, LargeStruct inout s2)
{
    ...
}
...
LargeStruct s;
foo(s, s);

In cases where there is an inout, I think the compiler would have to 
fallback on the old one.  The one below that Walter pointed out is more 
troublesome.

> 
> There's another aliasing case:
> 
> LargeStruct s;
> foo(s);
> ... here some other thread modifies s ...
> 
> And foo() suddenly has its argument values change unexpectedly.
> 
> Value and reference type usages mostly overlap, but they are 
> fundamentally different, and having the compiler switch between the two 
> in some implementation-defined manner (as suggested by others more than 
> once) is not going to work.
> 
> If one is needing reference behavior from a struct, seriously consider 
> making it a class instead. Or even just take the address of it and pass 
> the pointer.

I never thought about that one.  Of course your right about this like 
normal.  Humm... what about copy on read/write...

struct A
{
   byte[100] b;
}

//My contrived example

void foo(in A x, in A y)
{
    if (g)
    {
      if (x)
      {
         //...
      }
      else
      {
         if (y)
         {
            //...

	}
      }
    }
}

//Would convert too.

void foo(inout A x, inout A y) //Both treated as in/out
{
    if (g)
    {
      A x2 = x;  //First time x is used
      if (x2)
      {
         //...
      }
      else
      {
         A y2 = y;  //First time y is used
         if (y2)
         {
            //...

	}
      }
    }
}

if (g) was false you would avoid the expensive copy of x2 to the stack. 
   Of course the tricky part is working out when this optimisation is 
worth it.  The function could actually run slower because there are 2 
more values on the stack.

Ok, I spotted a floor in that design also.  A thread event could occur 
  between the copy of x2 and y2 (or at g).  I guess this would mean the 
user would have to somehow indicate that that is ok.

Ok here's yet another idea.

void bar(in A a)
{
   //....
}

void foo(in A a)
{
    bar(a);
    bar(a);
}

In this example we already have an in copy of A, so why copy it again? 
We do not have a reference and foo isn't doing any threading operations. 
  If this was inlined it would be optimized away, however if it can't be 
inlined it should still be possible to optimize it away.

//Here's another example of the some thing

void foo()
{
    A a;
    bar(a);
    //End of function A goes out of scope and A is destroyed.
}

-Joel



More information about the Digitalmars-d mailing list