Passing A Const As A Parameter

Coding and general discussion relating to the compiler

Moderators: David Barker, Jerry Messina

Post Reply
DannyScott
Posts: 22
Joined: Thu Sep 05, 2013 4:45 pm
Location: United Kingdom

Passing A Const As A Parameter

Post by DannyScott » Wed Apr 02, 2014 11:34 am

Does anyone have any suggestions as to how to pass a constant as a parameter?

I realise that passing a parameter 'As Const' doesn't exist, and ByRefConst passes the whole array, where ideally I would only like to pass the index of a single element within the constant array, or ideally the constant itself.

I could pass the constant Byval of course, and this works perfectly, however RAM copies are produced, and as I am using this type of call a great deal, I could probably save some RAM as I am getting close to the limit with still more code to write!

I use As TABLEPTR for passing string constants elsewhere which saves me bucketloads of RAM (thanks again Jerry), is there anything similar I can do?

I am attempting to run the project in parallel, using Firewing (a beta 8 bit version interfaced to the Swordfish compiler), as there is support for Enums (thanks David!), and although it works well, I am attempting to defer my decision to make the transition to Firewing at present as there are other factors I have to consider. Perhaps I should just take a 'brave pill' ? !

Any suggestions would be gratefully appreciated.

Code: Select all

Const MYCONST_A = 0
Const MYCONST_B = 1
Const MYCONST_C = 2

' I know 'As Const' doesn't exist!
MyFunction(MYCONST As Const, ByRef MyByte As Byte) As Byte

  'Do something here...

End Function


Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: Passing A Const As A Parameter

Post by Jerry Messina » Wed Apr 02, 2014 1:43 pm

You might be overthinking this one.

Most languages pass parameters "byval" by making a copy of the object and passing that copy to the routine. This is good since the called routine isn't working on the original, so it can't make changes to it that would effect the original variable itself.

"ByRef" passes a pointer to the original object. For small simple objects this can take more code than just using byval since the object has to be dereferenced, and it's dangerous in the sense that the called routine now has access to the original object itself, so any changes made to it modify the original memory locations. This is useful however since when you use structures, arrays or strings you might not want to pass a copy of the whole darn thing, esp. if you know you aren't going to be changing it.

Either way, in Swordfish the passed parameters are placed in the shared stack frame area, so unless you have a lot of nested calls you won't normally see the actual ram usage increase. It's pretty good at allocating/using this shared memory.

For example, something like

Code: Select all

const MyConst() as byte = (1, 2, 3, 4, 5)

function MyFunction(ArrayElement as byte, MyByte as byte) as byte

' do stuff
end function

dim b as byte

Myfunction(MyConst(2), b)
is pretty efficient. The code for loading 'ArrayElement' is about as good as you can get since the compiler knows the const value at compile time. It'll take a bit more code if the index is a variable (ie MyConst(i)), but it won't really use more ram. Calling MyFunction multiple times won't increase RAM usage since the parameters will reuse the same areas.
Note: if you pass MyByte byref, the code will be larger.

A general rule of thumb might be - If the passed object is small, use pass by val. If it's big, then you might want to consider pass byref,
but general rules are just that.

The best thing to do is to try a few different scenarios and look at the resulting asm produced. It can be very educational.

DannyScott
Posts: 22
Joined: Thu Sep 05, 2013 4:45 pm
Location: United Kingdom

Re: Passing A Const As A Parameter

Post by DannyScott » Wed Apr 02, 2014 3:33 pm

Thanks Jerry,

Apologies as I don't think I explained myself very well.

I should have said, is there an undocumented 'neat trick' to pass a single constant essentially 'ByRef' so that no local copy is made within the function being called?

I agree if you are only passing a byte by value, the local copy only consumes another byte, however if there are several constant LongInt's passed as parameters and functions are nested, it becomes more expensive in terms of RAM. I suppose subsequent calls below the initial function call could be passed ByRef of course.

What I was really trying to find out is if there are any more 'neat tricks', (as there seem to be quite a few!) similar to the way you showed me how to pass string constants (effectively passing strings ByRef using As TABLEPTR) to eliminate copies of the strings in RAM, but with regular constants instead of strings.

My RAM has not reached the critical point yet, but thanks for the detailed response anyway!

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: Passing A Const As A Parameter

Post by Jerry Messina » Wed Apr 02, 2014 5:36 pm

Oh, the devil's in the details!

You might be asking a lot for the pic18 and those specifics (nested calls with multiple longints). You could try passing the data using specific registers, but when you do this you have to be really, really careful they don't get trampled on.

You need 4 bytes for a longint, and the pic18 has precious few "general purpose" registers... one in fact. Using the PRODL/H, TBLPTRU/H/L, and FSRnH/L come to mind but you'd have to make sure that the compiler didn't use them, so that limits what you could do in code.

I think what you'd end up with would be a very limited, hand-crafted set of code that could end up being a maintenance headache. Sounds like you might be better off looking for a different way of coding the thing... if they're really const longints do you actually need to be passing them around? Sometimes I find in the end it's easier to use a few dedicated subs to access particular things instead of a single generic routine. Even on the biggest PIC18, you only get 4K of ram to play around with, so I end up trading code space for RAM or vice-versa.

Maybe there are some other suggestions out there?

User avatar
David Barker
Swordfish Developer
Posts: 1214
Joined: Tue Oct 03, 2006 7:01 pm
Location: Saltburn by the Sea, UK
Contact:

Re: Passing A Const As A Parameter

Post by David Barker » Wed Apr 02, 2014 6:17 pm

Anyone who has used Swordfish from any length of time will have probably spotted that RAM initially "bloats" after a few subs and functions have been written (especially when using strings) but as the program size increases, RAM will stabilize at some point at not increase at all - even if you eventually run out of ROM! I doubt you will run out of RAM using a PIC18, unless you have some very large or huge numbers of variables declared at the module level. Swordfish works really hard to recycle RAM and ensure there are no collisions with data use. If you insist on fixing a RAM location, you could use something like this:

Code: Select all

dim param as byte

' only works if last value is alias - won't work if
' proceeding values are alias...
sub mySub(a as byte, b as param)
end sub

mysub(10, 20)
...but personally I would always use standard byval or byref for production code unless I understood 100% what the impact of deviating from this would be.

Post Reply