[M3devel] front end function about a "virtual stack"

Jay K jay.krell at cornell.edu
Sun Feb 7 08:02:24 CET 2010


I think I have this aspect dealt with now.

 

Convert.m3:

 

     -----LINE 129  -----
 load              tv.25[_nDigits] 0 Int.32 Int.32
 check_range       0 n:8,x:0,0,0,0,0,0,0,0 64 n:4,x:40,0,0,0,0,0,0,0 2
 00000435: 8B5DFC              MOV EBX tv.25[_nDigits]
 00000438: 83FB40              CMP EBX $64
 0000043B: 7600                JBE rel8 L.68
 0000043D: B822100000          MOV EAX $4130
 00000442: E800000000          CALL L.0
 loophole          Int.32 Int.32
 load_address      tv.31[_result] 0
 00000447: 8D75AE              LEA ESI tv.31[_result]
 swap              Int.32 Addr
 index_address     Int.32 1
 0000044A: 03F3                ADD ESI EBX            ** result location in ESI *
 load              tv.35[_base] 0 Word.8 Int.32
 loophole          Int.32 Int.64
 0000044C: 33D2                XOR EDX EDX
 0000044E: 8A5514              MOV EDX tv.35[_base]:Word.8
 00000451: 33FF                XOR EDI EDI
 load              tv.34[_value] 0 Int.64 Int.64
 swap              Int.64 Int.64
 mod               Int.64 X P
 call_64          m3_mod64 2
 import_procedure   m3_mod64 2 Int.64 "__stdcall" p.31[m3_mod64]
 declare_param     * 8 8 Word.64 0 F F 100 tv.201[T$201] 8
 declare_param     * 8 8 Word.64 0 F F 100 tv.202[T$202] 16
 start_call_direct   p.31[_m3_mod64 at 16] 0 Int.64
 load_stack_param   Word.64 1
 00000453: 8B4D0C              MOV ECX tv.34[_value]
 00000456: 8B4510              MOV EAX tv.34[_value]+4
 00000459: 50                  PUSH EAX
 0000045A: 51                  PUSH ECX
 load_stack_param   Word.64 0
 0000045B: 57                  PUSH EDI
 0000045C: 52                  PUSH EDX
 declare_temp      4 4 Addr F tv.203[T$203] -92
 0000045D: 8975A4              MOV tv.203[T$203] ESI         ** ESI saved unnecessarily in temporary to satisfy us **
 call_direct       p.31[_m3_mod64 at 16] Int.64
 00000460: FF1500000000        CALL p.31[_m3_mod64 at 16]
 loophole          Int.64 Int.32
 loophole          Int.32 Int.32
 load_address      gv.2[_MM_Convert] 52
 00000466: 8D3534000000        LEA ESI gv.2[_MM_Convert]+52
 swap              Int.32 Addr
 index_address     Int.32 1
 0000046C: 03F0                ADD ESI EAX
 load_indirect     0 Word.8 Int.32
 0000046E: 33DB                XOR EBX EBX
 00000470: 8A5E00              MOV EBX ESI^[0:Word.8]
 store_indirect    0 Int.32 Word.8
 00000473: 8B75A4              MOV ESI tv.203[T$203]:Addr   ** ESI refetched from temporary **
 free_temp         tv.203[T$203]
 00000476: 885E00              MOV ESI^[0:Word.8] EBX
     -----LINE 130  -----


 

Pretty wasteful.

Instead it should just compute the destination when it does the store.

 

 

 - Jay

 


From: jay.krell at cornell.edu
To: hosking at cs.purdue.edu
CC: m3devel at elegosoft.com
Subject: RE: front end function about a "virtual stack"
Date: Sun, 7 Feb 2010 06:49:11 +0000



 > But, there have always been calls for mod/div

Not on NT386.
 
 - Jay
 


Subject: Re: front end function about a "virtual stack"
From: hosking at cs.purdue.edu
Date: Sat, 6 Feb 2010 13:07:23 -0500
CC: m3devel at elegosoft.com
To: jay.krell at cornell.edu


The front-end does do that for known calls.  But not for arithmetic ops.  You will need to cope in the backend.  But, there have always been calls for mod/div, so I think it really comes down to the back-end needing to do the right thing.



On 6 Feb 2010, at 07:29, Jay K wrote:

Tony, can you confirm something?
It's hard to explain.
 

The NT36 backend of course maintains
a bunch of information as to which registers are in use.

 
For example, at the start of the function, it
marks all registers as not in use.
  (It always preserves all volatile registers I believe.
  Obviously it could do better. It should only
  mark non-volatile registers as in use, see
  which registers it uses in the function, and
  then only preserve/restore the nonvolatile ones
  that it uses.)

 
As well when it generates a function call it
marks them as all not in use too.
But in that case, it checks itself.
Again, it is a bit dumb -- nonvolatile registers
 would be ok to still be in use.
 

Now, all is ok.
But then, I've introduced function calls where
they weren't before -- multiply, divide, mod etc.
 

Upon generating the call to mod (for example),
I get an assertion failure, because registers
are still in use. In this case it is a nonvolatile
register, but I think that's largely luck.
 

In particular I think the location that
will be stored to after the mod is in a register.
That is reasonable.
You know..as a compiler, given:
 *(a + b) = f();

 
you might generate code to evaluate a + b first,
put it in a (non volatile) register, then call f(),
or you might call f() first.
 

A simpler approach is to call all the functions first,
so you have more easy use of registers.
 

But then imagine
 *(a + b) = (c % d);

 
is there a function call in there or not?
It depends.

 
So then my question is, like, when does the
frontend assume a "stack based code generator"'s
stack can/should/will be empty?
Does it endeavor to make it so?
 

That is, is it very reasonable to for the NT386
backend to assume its stack is empty when
it calls a function, because the front end
colludes to make it so, but then
the front end doesn't do similar for things
like multiply/divide?
 

I can deal with this pretty easily either way.
Around function calls I introduce that weren't
previously there I can save whatever volatile
registers are in use.
 

But I'd like to understand.
 

Thanks,
 - Jay

 		 	   		  
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://m3lists.elegosoft.com/pipermail/m3devel/attachments/20100207/ab5b328f/attachment-0002.html>


More information about the M3devel mailing list