[M3devel] gcc 4.5.0?

Rodney M. Bates rodney_bates at lcwb.coop
Fri May 21 21:45:32 CEST 2010


I have no quarrels with you there, Jay.  I'm not advocating it, just
reporting what I know about how gcc does it.

Jay K wrote:
> Wierd. To me the model to follow is almost obvious. It should be obvious to everyone and implemented the way I have in mind. :)
>  
>  
> The static link is an extra parameter.
> And, as such, also an extra local variable.
> You only need one.
> Each nesting level would follow another chain.
> Or you can pass each nesting level as an extra parameter.
> Or you can optimize and pass locals/parameters separately.
> But there is an obvious straightforward non-optimized form. ?
>  
>  
> Here, I worked it through:
>  
>  
>  
> Why doesn't it just look something like this:
>  
>  
> nested:
>  
> void F1(int a, int b)
> {
>   int c = a + b;
>  
>   int f2()
>   {
>     int d = a + b;
>  
>     int f3()
>     {
>        return d + a + c;
>     }
>  
>     return a + c + f3();
>   }
>  
>   return f2();
> }
>  
> not nested:
>  
> 
> typedef struct {
>   /* locals */
>   int d;
>   void* x86_frame_pointer;
>   void* x86_return_address;
>   /* parameters */
>   f1_frame_t* f1;
> } f2_frame_t;
>  
> 
> typedef struct {
>   /* locals */
>   int c;
>   void* x86_frame_pointer;
>   void* x86_return_address;
>   /* parameters */
>   int a;
>   int b;
> } f1_frame_t;
>  
>  
> int f3(f2_frame_t* f2)
> {
>     return f2->d + f2->f1->a + f2->f1->c;
> }
>  
> 
> int f2(f1_frame_t* f1)
> {
>   int d = f1->a + f1->b;
>   return f1->a + f1->c + f3((f2_frame_t*)&d);
> }
>  
> 
> int F1(int a, int b)
> {
>   int c = a + b;
>   return f2((f1_frame_t*)&c);
> }
> 
>  
> or, alernatively, almost the same, pass each chain as another parameter:
>  
> 
> typedef struct {
>   /* locals */
>   int d;
>   void* x86_frame_pointer;
>   void* x86_return_address;
>   /* parameters */
> } f2_frame_t;
>  
> 
> typedef struct {
>   /* locals */
>   int c;
>   void* x86_frame_pointer;
>   void* x86_return_address;
>   /* parameters */
>   int a;
>   int b;
> } f1_frame_t;
>  
>  
> int f3(f2_frame_t* f2, f1_frame_t* f1)
> {
>     return f2->d + f1->a + f1->c;
> }
>  
>  
> 
> int f2(f1_frame_t* f1)
> {
>   int d = f1->a + f1->b;
>   return f1->a + f1->c + f3((f2_frame_t*)&d, f1);
> }
>  
> 
> int F1(int a, int b)
> {
>   int c = a + b;
>   return f2((f1_frame_t*)&c);
> }
>  
>  
> This should be easily adapted to any function call convention/sequence.
> e.g. even if parameters are passed in registers.
>  
>  
> And for that matter, why don't we just transform it to be like this?
>   With the goal of reducing/eliminating gcc patches?
>  
>  
> Am I missing something?
>  
> 
> This form doesn't work?
>  
> 
> Isn't reasonably simple?
>  
> 
> Granted it might not be optimal. But it depends.
>   You know, you can copy in the local/parameter values, but then you have
>    to copy them out too. You can do analysis to show they aren't changed,
>    in which case no need to copy them out.
>   Similarly you can pass the parameters as separate parameters, by address
>    if they are ever changed.
> 
>  
> A portable transform couldn't depend on adjacency of locals and parameters.
> It would have to either copy the parameters into the frame_t, or their addresses.
>  
>  
> A portable form couldn't get the frame by taking the address of a "individual" local.
>  
>  
> Here is portable form:
>  
>  
> typedef struct {
>   int d;
>   f1_frame_t* f1;
> } f2_frame_t;
>  
> typedef struct {
>   int a;
>   int b;
>   int c;
> } f1_frame_t;
>  
> 
> int f3(f2_frame_t* f2)
> {
>     return f2->d + f2->f1->a + f2->f1->c;
> }
>  
> int f2(f1_frame_t* f1)
> {
>   f2_frame_t f;
>   f.f1 = f1;
>   f.d = f1->a + f1->b;
>   return f1->a + f1->c + f3(&f);
> }
>  
>  
> int F1(int a, int b)
> {
>   f1_frame_t f;
>   f.a = a;
>   f.b = b;
>   f.c = a + b;
>   return f2(&f);
> }
>  
>  
> or:
>  
>  
> typedef struct {
>   int d;
> } f2_frame_t;
>  
>  
> typedef struct {
>   int a;
>   int b;
>   int c;
> } f1_frame_t;
>  
>  
> int f3(f2_frame_t* f2, f1_frame_t* f1)
> {
>     return f2->d + f1->a + f1->c;
> }
>  
>  
> int f2(f1_frame_t* f1)
> {
>   f2_frame_t f;
>   f.d = f1->a + f1->b;
>   return f1->a + f1->c + f3(&f, f1);
> }
> 
>  
> int F1(int a, int b)
> {
>   f1_frame_t f;
>   f.a = a;
>   f.b = b;
>   f.c = a + b;
>   return f2(&f);
> }
> 
>  
>  
>  
>  - Jay
> 
> 
> 
> ----------------------------------------
>> Date: Thu, 20 May 2010 12:12:00 -0500
>> From: rodney_bates at lcwb.coop
>> To: m3devel at elegosoft.com
>> Subject: Re: [M3devel] gcc 4.5.0?
>>
>> gcc even extends C with nested functions, and the support is there for that. We use it too.
>>
>> Beware: The runtime model is, IMO, bizarre. Definitely counterintuitive and unlike anything
>> you will ever see elsewhere. There are two static links. One is used for the first step
>> in following a static chain and points to the expected place in the target frame. The other
>> is used of subsequent steps in chain-following, and points to somewhere inside the target
>> frame that is dependent on the target procedure. It's the beginning of a subrecord where
>> all the nonlocally-referenced variables are collected. The second static link is also
>> located in there. All the nonlocally-referenced variables and parameters are duplicated
>> in there too.
>>
>> I'm not sure I remembered these details exactly right. Maybe both links point to the
>> subrecord, but one is located at a traditional procedure-independent, fixed location
>> in the frame, while the second is located in the subrecord. Also, sometimes the first
>> static link value is kept in a register and never stored.
>>
>> What this all apparently accomplishes is simplifying an "insanely complicated" _compile-time_
>> scheme that, I believe came from interaction between nested procedures and inlining them.
>>
>> But it's at the cost of what I would call an insanely complicated _runtime_ scheme.
>>
>> It undermined m3gdb's handling of static links, and I don't think it's possible to fix
>> with the current design of emitting debug info very early. The locations and target
>> offsets of these things aren't know until later, and m3gdb really needs to know them.
>>
>>
>> Jay K wrote:
>>> What I meant regarding "static chain" was more like "does gcc already have support that we can use".
>>> Don't any of the other languages need it already?
>>> Ada? Pascal? Maybe the nested C function support?
>>>
>>> - Jay
>>> 		 	   		  



More information about the M3devel mailing list