How to call repetitive code within a Proc using the proc variables?

Started by trastikata, Jul 16, 2023, 10:59 AM

Previous topic - Next topic

trastikata

Hello all,

I am a bit stuck in optimizing some code I've written. Any advise would be appreciated.

The code is in a procedure with 6 parameters and depending on which combinations of parameters occur a code is being executed that uses the rest of the parameters passed to some other math procedures.

However the code is long math and has several repeating variations in some of the combinations of parameters in different places. However if I create a new procedure for each code snippet, then I'll have to re-pass the parameters and this will make it very difficult to follow at the end.

The resultant code I was hoping to achieve is something like using a subroutines within a procedure (which is not possible) and call the subs without re-passing all the parameters from the procedure.


TimB


From what you have said the issue just seems to be the use of variables.

When I need to pass variables I just Dim them outside the proc. You can specify a variable as the parameter

I may have what your looking to do wrong thought :-[

    DIm bTemp as byte

    Proc TestProc(pValue1 as bTemp), byte
        Inc pValue1

        MathProc(pValue1)

        result = pValue1
    EndProc



    Proc MathProc(pvalue2 as bTemp)

        Inc pvalue2

    EndProc


    Dim bTemp2 as Byte


    While 1 = 1

        bTemp2 = TestProc(bTemp2)


    Wend

trastikata

Quote from: TimB on Jul 16, 2023, 02:33 PMFrom what you have said the issue just seems to be the use of variables.

Thank you TimB, indeed the variables is the hinder, but what I am looking to achieve is a bit different. Note in the following simplified example code:

- in Statement 1 and in Statement 2 this portion of the code is repetitive:
        wTemp = MyProc1(a, b, c) + MyProc2(b, d, f) + e
        wTemp = wTemp * 10

- in Statement 2 and in Statement 3 this portion of the code is repetitive:

        wTemp1 = c + d
        wTemp1 = wTemp1 * MyProc3(c, d, e)

So I was looking for a way to replace those repetitive parts with "something like Subs inside the Procedure" where I can place those repetitive code parts without the need of creating new procedures and re-passing initial parameters to them.


MyProc(1,2,3,4,5,6)
End

Proc MyProc(a As Byte, b As Byte, c As Byte, d As Byte, e As Byte, f As Byte), Word
    Dim wTemp As Word
    Dim wTemp1 As Word
   
    If a + b = c Then       'Statement 1
        wTemp1 = c + d
        wTemp1 = wTemp1 * MyProc3(c, d, e)
       
        wTemp = MyProc1(a, b, c) + MyProc2(b, d, f) + e
        wTemp = wTemp * 10
       
        Result = wTemp1 + wTemp
    ElseIf a + a = 5 Then   'Statement 2
        wTemp1 = c + d
        wTemp1 = wTemp1 * MyProc3(c, d, e)
       
        wTemp = MyProc1(a, b, c) + MyProc2(b, d, f) + e
        wTemp = wTemp * 10
       
        Result = wTemp1 + wTemp
    ElseIf e * f = 8 Then   'Statement 3
        wTemp1 = c + d
        wTemp1 = wTemp1 * MyProc3(c, d, e)
       
        wTemp = MyProc1(a, b, c) * MyProc2(b, d, f)
       
        Result = wTemp - wTemp1
    EndIf
EndProc


Proc MyProc1(a1 As Byte, b1 As Byte, c1 As Byte), Word
    Result = a1 + b1 + c1
EndProc

Proc MyProc2(a2 As Byte, b2 As Byte, c2 As Byte), Word
    Result = b2 * b2 + a2 - c2
EndProc

Proc MyProc3(a3 As Byte, b3 As Byte, c3 As Byte), Word
    Result = (c3 - b3) * a3
EndProc

tumbleweed

It looks like you're always evaluating the same set of procs for each case, so can't you get rid of the proc calls and pre-compute the three results instead...
Proc MyProc(a As Byte, b As Byte, c As Byte, d As Byte, e As Byte, f As Byte), Word
    Dim wTemp As Word
    Dim wTemp1 As Word

    dim Result1 as word
    dim Result2 as word
    dim Result3 as word
   
    Result1 = a + b + c
    Result2 = d * d + b - f
    Result3 = (f - d) * c

    If a + b = c Then       'Statement 1
        wTemp1 = c + d
        wTemp1 = wTemp1 * Result3        'MyProc3(c, d, e)
      
        wTemp = Result1 + Result2 + e    ' MyProc1(a, b, c) + MyProc2(b, d, f) + e
        wTemp = wTemp * 10
      
        Result = wTemp1 + wTemp
    ElseIf a + a = 5 Then   'Statement 2
        wTemp1 = c + d
        wTemp1 = wTemp1 * Result3        'MyProc3(c, d, e)
      
        wTemp = Result1 + Result2 + e    'MyProc1(a, b, c) + MyProc2(b, d, f) + e
        wTemp = wTemp * 10
      
        Result = wTemp1 + wTemp
    ElseIf e * f = 8 Then   'Statement 3
        wTemp1 = c + d
        wTemp1 = wTemp1 * Result3        'MyProc3(c, d, e)
      
        wTemp = Result1 * Result2        'MyProc1(a, b, c) * MyProc2(b, d, f)
      
        Result = wTemp - wTemp1
    EndIf
EndProc

I think I got that right...


trastikata

Quote from: tumbleweed on Jul 16, 2023, 04:45 PMIt looks like you're always evaluating the same set of procs for each case, so can't you get rid of the proc calls and pre-compute the three results instead...

Thank you tumbleweed, this was just a simplified example, in reality the code is much more complicated and diverse.

I was thinking of placing Labels within the Procedure and use the GoTo and then return to the previous assembler label address instead of Subs, but I don't know how the Procedure's parameters will be evaluated in this case. I guess I'd have to test this option.

TimB

A system I have used in the past when I ran out of stack was to use gotos and flag where to return/goto after use

bReturnAddress as byte


Proc MyProc()

bReturnAddress = 1

Goto MySubEntry1
MySubReturnAddress1:


MySubEntry1:

code
code

MySubEntry2
code
code
code

Select bReturnAddress
Case 1
    Goto MySubReturnAddress1
Case 2
    Goto MySubReturnAddress2

...
...










End Proc

Stephen Moss

As yo uonly provided a simplified code example it could get a bit messy depending on how many terms need to access the same function but could you not restructure your If-Then statments as follows...
Proc MyProc(a As Byte, b As Byte, c As Byte, d As Byte, e As Byte, f As Byte), Word
    Dim wTemp As Word
    Dim wTemp1 As Word
 
If a + b = c or A + A = 5 Then      'Statement 1/2 shared code
        wTemp = MyProc1(a, b, c) + MyProc2(b, d, f) + e
        wTemp = wTemp * 10
End If

If a + b = c then    'Statement 1 Code only
    wTemp1 = c + d
    wTemp1 = wTemp1 * MyProc3(c, d, e)
End If

If a + a = 5 or e * f = 8 Then  'Statement 2/3 Shared Code
        wTemp1 = c + d
        wTemp1 = wTemp1 * MyProc3(c, d, e)
End If

If e * f = 8 Then  'Statement 3 Only Code 
        wTemp = MyProc1(a, b, c) * MyProc2(b, d, f)
EndIf


        Result = wTemp - wTemp1
EndProc

top204

One of the features of the procedure mechanism I created for the compilers is also something that was not intentional, but it is very useful for global variable re-use. It also allows procedures to use the same variables as parameters when appropriate to do so. So if they are called, the parameter variables do not have to be re-filled, or an indirect address to be filled every time (very wasteful).

See what you think of the code snippet below, based upon your example:

Proc MyProc(pParam1 As MyProc_bPm1, pParam2 As MyProc_bPm2, pParam3 As MyProc_bPm3, pParam4 As MyProc_bPm4, pParam5 As MyProc_bPm5, pParam6 As MyProc_bPm6), MyProc_wRes
'
' Create some global variables that are also used as parameters, but only if the MyProc procedure is called in a program's listing
'
Global Dim MyProc_bPm1 As Byte
Global Dim MyProc_bPm2 As Byte
Global Dim MyProc_bPm3 As Byte
Global Dim MyProc_bPm4 As Byte
Global Dim MyProc_bPm5 As Byte
Global Dim MyProc_bPm6 As Byte
Global Dim MyProc_wRes As Word

    Dim wTemp As Word
    Dim wTemp1 As Word
  
    If (pParam1 + pParam2) = pParam3 Then       'Statement 1
        wTemp1 = pParam3 + pParam4
        wTemp1 = wTemp1 * MyProc3(pParam3, pParam4, pParam5)
      
        wTemp = MyProc1(pParam1, pParam2, pParam3) + MyProc2(pParam2, pParam4, pParam6) + pParam5
        wTemp = wTemp * 10
      
        Result = wTemp1 + wTemp
    ElseIf (pParam1 + pParam1) = 5 Then   'Statement 2
        wTemp1 = pParam3 + pParam4
        wTemp1 = wTemp1 * MyProc3(pParam3, pParam4, pParam5)
      
        wTemp = MyProc1(pParam1, pParam2, pParam3) + MyProc2(pParam2, pParam4, pParam6) + pParam5
        wTemp = wTemp * 10
      
        Result = wTemp1 + wTemp
    ElseIf (pParam5 * pParam6) = 8 Then   'Statement 3
        wTemp1 = pParam3 + pParam4
        wTemp1 = wTemp1 * MyProc3(pParam3, pParam4, pParam5)
      
        wTemp = MyProc1(pParam1, pParam2, pParam3) * MyProc2(pParam2, pParam4, pParam6)
      
        Result = wTemp - wTemp1
    EndIf
EndProc

'-------------------------------------------------------------------
Proc MyProc1(pParam1 As MyProc_bPm1, pParam2 As MyProc_bPm2, pParam3 As MyProc_bPm3), MyProc_wRes
    Result = pParam1 + pParam2 + pParam3
EndProc

'-------------------------------------------------------------------
Proc MyProc2(pParam2 As MyProc_bPm2, pParam4 As MyProc_bPm4, pParam6 As MyProc_bPm6), MyProc_wRes
    Result = (pParam4 * pParam4) + pParam2 - pParam6
EndProc

'-------------------------------------------------------------------
Proc MyProc3(pParam3 As MyProc_bPm3, pParam4 As MyProc_bPm4, pParam5 As MyProc_bPm5), MyProc_wRes
    Result = (pParam5 - pParam4) * pParam3
EndProc

It is based on Tim's suggestion above, but with a bit of an unexpected twist to it for re-using global variables. :-)

It is a "not fully tested", mechanism, and certainly not going to go in the manual, but whenever I have used it in a program it has worked flawlessly, and the underlying compiler C++ code looks sound. Also, if it fails, an error message will be created to state that a variable does not exist that is trying to be used, so it cannot give unexpected problems in the code's running. It was something I never intented to happen when I made the flat language into a procedural language as well. :-)

Remember, the procedure that creates the global variables, "must" be called at least once, so the variables are created for others to see.

In your code snippet, it does add complexity, but it should work. I have used the mechanism for standard parameters and returns in procedures that do similar things and use the same variable. i.e. X position, Y position, colour etc...

If you look at the assembler code, you will see just a few user variables created and lots of aliases:

; STANDARD VARIABLES
MyProc_bPm1 equ 0x11
MyProc_bPm2 equ 0x12
MyProc_bPm3 equ 0x13
MyProc_bPm4 equ 0x14
MyProc_bPm5 equ 0x15
MyProc_bPm6 equ 0x16
MyProc_wRes equ 0x17
MyProc_wResH equ 0x18
MyProcwTemp equ 0x19
MyProcwTempH equ 0x1A
MyProcwTemp1 equ 0x1B
MyProcwTemp1H equ 0x1C
; ALIAS VARIABLES
#define __HRSOUT1_PORT PORTC
#define __HRSOUT_PORT PORTC
#define __HRSOUT1_PORT_PIN PORTC,6
#define __HRSOUT_PORT_PIN PORTC,6
#define MyProcpParam1 MyProc_bPm1
#define MyProcpParam2 MyProc_bPm2
#define MyProcpParam3 MyProc_bPm3
#define MyProcpParam4 MyProc_bPm4
#define MyProcpParam5 MyProc_bPm5
#define MyProcpParam6 MyProc_bPm6
#define MyProcResult MyProc_wRes
#define MyProcResultH MyProc_wResH
#define MyProc1pParam1 MyProc_bPm1
#define MyProc1pParam2 MyProc_bPm2
#define MyProc1pParam3 MyProc_bPm3
#define MyProc1Result MyProc_wRes
#define MyProc1ResultH MyProc_wResH
#define MyProc2pParam2 MyProc_bPm2
#define MyProc2pParam4 MyProc_bPm4
#define MyProc2pParam6 MyProc_bPm6
#define MyProc2Result MyProc_wRes
#define MyProc2ResultH MyProc_wResH
#define MyProc3pParam3 MyProc_bPm3
#define MyProc3pParam4 MyProc_bPm4
#define MyProc3pParam5 MyProc_bPm5
#define MyProc3Result MyProc_wRes
#define MyProc3ResultH MyProc_wResH

trastikata

Thank you all for the help.

I can continue now with my code optimization.

top204

In your code snippet, it also looks as though you can use Result instead of wTemp. Remember, Result is a standard variable of the size required, so using Result instead of wTemp will save time and code space because they are both 16-bit unsigned Word types.