Proc - Local variables with the same name in different Procedures - RAM question

Started by trastikata, May 04, 2021, 09:34 AM

Previous topic - Next topic

trastikata

Hello,

I couldn't find information on how the compiler deals with local variables using the same name within different procedures?

My question is pertaining to how much of the RAM is being used, let's say if I want to use the same name for temporary variables within different procedures?

Sins they are local to the procedure, my thinking is that it shouldn't be a problem if they occupy the same space and being reset at the beginning of each procedure, on other hands if they aren't occupying the same space, then it's better to declare them as global variables and reset them myself?

Any thoughts would be appreciated.

Regards

trastikata

I just realized if local variable shares the same space in memory it will cause troubles if procedure is used within procedure, disregard my question.

JohnB

What I tend to do with local variables which do not have to be persistent do is to declare the max number of variables to be used in any of your procedures then, in the procedure, alias them to the variable names for that procedure:

e.g.
first set up the general purpose variables - these can be whatever type you need for your app.  I write mostly for 16 bit pics so I rarely use anything smaller than words.

   
    Dim OSPW0 As Word        ' General purpose variables used internally
    Dim OSPW1 As Word
    Dim OSPW2 As Word
    Dim OSPW3 As Word
Then in my Procedure I alias the general purpose variables to meaningful names for that procedure.
You can similarly do that with Registers e.g. Dim myProcVaraiible as WREG4
    Proc GetEventID(), Word                        ' Returns the first vacant ECB EventID
        Dim EventPtr As OSPW0
        Dim EventID As OSPW1
        EventPtr = 0
        EventID = 0
        If LastEvent = OSNO_EVENT Then                ' If no Event yet assigned
          LastEvent = EventID                        ' Set last event to 0
          Result = LastEvent                          ' and return with EventID in result
        Else
          Result = OSNO_EVENT                        ' defualt to No Event
          Do                                          ' scan through the TCBs for empty TCB
          If ECBs[EventPtr] = OSECB_EVENT_NOEVENT Then' if empty slot found
            If EventID > LastEvent Then LastEvent = EventID' Update lastEvent
            Result = EventID                          ' set return with taskID of TCB
            Break                                    ' and break as we have finished
          Else
            Inc EventID                              ' ECB occupied so inc EventID and step
            EventPtr = EventPtr + ECBSize            ' on to next ECB
          EndIf
          Loop Until EventID >= OSEVENTS_COUNT        ' loop until end of Tasks List
        EndIf
      EndProc   

If you have a lot of procedures which don't need persistence it can save quite a bit of memory.  Hope that helps.
JohnB

TimB

Quote from: trastikata on May 04, 2021, 10:49 AMI just realized if local variable shares the same space in memory it will cause troubles if procedure is used within procedure, disregard my question.

In the long past before there were procedures I just used

wTemp1
wTemp2
wTemp3

etc
When I followed a call to a sub I just checked what temp vars they were using. If they it was already using say wTemp1 and wTemp then I made my calling sub use wTemp3 etc

I like Johns aliasing though neat solution to making the code clear.

Tim

John Drew

Trastikata,
When a 'local' variable is declared in a procedure it generates a global variable called 'procedurename.local'.

For example create a byte variable 'dim mylocal as byte' inside a procedure called 'John' then the variable's full name is: 'john.mylocal'
Inside the procedure the 'John' is assumed so you can assign 'mylocal=3'

Interestingly you can access the variable outside the procedure by using its full name 'John.mylocal'
Like this 'John.mylocal =5'
Not that you should do this as it defeats the idea. But it does work.

So this why you can use 'mylocal' in another procedure because its real name might be 'Fred.mylocal'

Get the idea?

This is why JohnGB's solution is so interesting because it saves space. Very clever.

True local variables are not very practical in a PIC because local variables in e.g. PCs, are normally stored on the stack so they can be created and destroyed. Pics have very small stacks (perhaps 8 or 16 bytes) but reasonable RAM for variables. That's probably why Les used the approach I described above.

John

trastikata


tumbleweed

QuoteTrue local variables are not very practical in a PIC...
Statically allocating them (effectively making them global, but with a different name) is the easiest way,
but some other compilers can share allocations between routines automatically, radically reducing ram usage.

That gets complicated since the compiler needs to track the call graph of which routines call which and what local allocations they make.

TimB


There is a pic compiler "Swordfish" That has automatic variable reuse. It works well, very well if you use it right.
Eg you can and may be able to in Positron allocate a system reg as the local variable. Thus almost negating the usage of variables at all for the sub.

However it only seemed to look like it was saving vars until you had a large program. If you have the variables then who cares right?

I say if you get to the point where your running out of vars its not hard to start using reusable global vars Like John showed.

tumbleweed

I have large programs in Swordfish using well over 600 bytes of shared variable space. With 120K+ of code, there's no way I'm doing that by hand!
Plus ram is very tight, pretty much maxing out the 4K available in most 18F parts. Without variable reuse I couldn't do what I do.

But you're right... if you have the ram who cares.

top204

I wrote the backend Asm code generator for the Swordfish compiler, and that is why it produces quite tight code. However, the Swordfish compiler was not able to produce code for any of the 12-bit core or 14-bit core devices because it was generated by a "Compiler Generator" program that cannot handle fragmented RAM or page handling for flash memory, as Proton can.

I had to create a lot of new functions within the code generator to handle the RAM as a large array that was addressed, and the Swordfish variables were addressed to elements within the array as aliases, so the Swordfish compiler, essentially, produced Proton BASIC code and the extra functions I created within the backend produced signed variable handling etc... So all the RAM handling and comparisons, and everything else, was performed by the Proton backend. :-) And with the original 12-bit and 14-bit core devices, large linear arrays are not possible because they only have an 8-bit indirect register (FSR), and a bit within the STATUS register as its 9th bit. They also have, extremely, fragmented RAM blocks, so I had to create a set of unique subroutines to get large arrays with standard 14-bit core devices for Proton, so they cannot be used as a large linear RAM block. That's why the standard 14-bit core devices do not support String variables with Proton8, but the enhanced 14-bit core devices do because they have 16-bit indirect registers. i.e. FSR0L\H and FSR1L\H and new mnemonics for accessing indirect linear RAM, as long as the RAM address has a high bit set. i.e. Moviw and Movwi.

Since then, the Proton8 compiler's code generation has improved significantly, so it produces a lot smaller, and faster, Asm code than it used to do.

RAM re-use was something I was working on for the 16-bit devices before my brain hemorage happened, and all the bits and pieces are in the compiler's source code, contained in the Tlist structures I created for procedures and variables, and where the variable is, and what procedure call's what other procedure, and what RAM each procedure uses etc, but I simply cannot find the many months of time to make it happen for so little benefit. :-(

Also, the newer 8-bit and 16-bit devices have more and more RAM so it serves little purpose anymore. The compiler uses as little RAM as it possibly can for its internal compiling mechanisms, and re-uses what it can of its system variables. Re-use of RAM in a high level language can actually, sometimes, take more RAM because it needs to make large internal variables to cover a certain variable type, even if it is only used once.

tumbleweed

I wouldn't wish trying to write a compiler for the 12-bit or 14-bit cores on my worst enemy!

I'm always amazed at the folks who manage to pull it off and what they must have to go through. My hats off to you!