www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Possilbe stub func backend related optimization

for stub funcs:

void error(char[] string)
{
     realerror(1,string);
}

void realerror(int errortype, char[] string);
{
     // do some thing
}

while this case inline realerror introduce size bloat.

the best optimization is binding these two functions together

func_error:
             push 1;
func_realerror:

func "error" only pushes the args missing, and it doesn't get any ret  
code, it returns directly by func_realerror.

how semantic analyze work and detect this kind of things?

I propose a possible algo.

if func.complicateness < MAX_BIND_COMPLICATE then
for each callee in func
try bind callee with func

the try bind callee works in the way of trying nest the callee in the  
caller.


that is it trying to do the following
void error(char[] string)
{
     void realerror(int errortype, char[] string);
     {
        // do some thing
     }
     realerror(1,string);
}


now we notice the realerror in nested func can be rewritten as
void error(char[] stirng)
{
     void realerror(int errortype)
     {
     }
     realerror(1);
}

there we go, we get the optimized func "error", all we need to do is  
exposing the nested func as normal func "realerror".

why the "realerror" func in such rewritten form is still working?

there the realerror accesses parent char[]string in the stack, and it  
requires the parent func to push errortype to call it, the sequence of  
pushing params is right in the right-to-left form.

So, calling directly to realerror address with original "realerror" params.
//psuedo asm code:
push string
push 3
call realerror

it gets the same effect as calling inside the func of "error"

Now the algo is almost clear.
1. we try to figure out right-to-left common params with callee and caller.
2. rewrite them in nested func syntax.
3. caller would be naturally optimized by the original flow optimizer

the compiler would analyze the flow of func "error". compilers finds out  
realerror would be called and directly exit after calling realerror(1);

so the optimal flow optimizer would optimize the nested func to the  
optimal assembly.

for a more complicated case, error func works in the way like:

void error(char[]string)
{
     if (string == "abc")
         realerror(1, string);
     else
         realerror(2, string);
     another_func();
}

if we rewrite it then something goes clearer, and it's possible to reuse  
current exist optimizer:


void error(char[]string)
{
     void realerror(int errortype)
     {
     }
     if (string == "abc")
         realerror(1);    // from code flow analyze we know we can exit  
directly at this point. so inlining realerror here would optimize out  
call/retn instructions.
     else
         realerror(2);
}


there the optimal solution is inlining the realerror func in the place of  
first realerror(1)

psuedo codegen would be:

if (string == "abc")
    push 1
realerror_func_entry_point:
    inlined realerror native code    // this inlining doesn't consider any  
cost. because realerror func would always require some place to store it.
else
    push 2
    call realerror_func_entry_point
retn


 From this case, we see in the rewriten nested func form , we get the  
chance of inlining the "realerror" freely for the very first time. This  
optimization still applies for real nested func optimization. so if we  
really gets the nested func, this optimization applies to the real nested  
func case.



-- 
使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/
Mar 13 2008