Page 2 of 2

Re: Jump table - faster case selection

Posted: Sat Mar 06, 2021 4:03 am
by Keya
OOOH, now I know why

In my original example you'll see I included the DataSection part WITHIN the Procedure.
In your example you have it external.
Simply move the DataSection part into the Procedure (ie. before EndProcedure) :)
I'll edit my original example to make note of this.

Good (in regards to "local labels"):

Code: Select all

Procedure Example()
  ;code
 
 DataSection
  ;data referencing labels within Example()
 EndDataSection
EndProcedure
Bad (the compiler cannot recognise local labels):

Code: Select all

Procedure Example()
 ;code
EndProcedure
 
DataSection
 ;data referencing labels within Example(), but it can't see it
EndDataSection

Re: Jump table - faster case selection

Posted: Sat Mar 06, 2021 2:11 pm
by mk-soft
@keya

works fine :wink:

Small update

Code: Select all

      CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
        ! jmp qword [p.v_OpFunc]
      CompilerElse
        ! jmp dword [p.v_OpFunc]
      CompilerEndIf
I like an array of pointer

Code: Select all

Enumeration PIXELOPS
  #PIXELOP_REPLACE
  #PIXELOP_ADD
  #PIXELOP_SUB
  #PIXELOP_FILL
  #PIXELOP_INVERT
  #PIXELOPEND
EndEnumeration


Structure ArrayOfPointer
  *index[0]
EndStructure

Procedure ModifyAllPixels(Operation, width, height)
  If Operation < 0 Or Operation => #PIXELOPEND: ProcedureReturn 0: EndIf  ;ensure valid Operation index
  Protected *JumpTable.ArrayOfPointer = ?PIXELOP_JMPTABLE
  Protected OpFunc = *JumpTable\index[Operation]  ;the address of the specified PIXELOP_xxx label
  
  For y = 1 To height
    For x = 1 To width
      
      CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
        ! jmp qword [p.v_OpFunc]
      CompilerElse
        ! jmp dword [p.v_OpFunc]
      CompilerEndIf
      
      ;These can be in any order...
      PIXELOP_FILL:
      ;DoFill
      Debug "Fill"
      Goto PixelOpEnd
      
      PIXELOP_ADD:
      ;DoAdd
      Debug "Add"
      Goto PixelOpEnd
      
      PIXELOP_SUB:
      ;DoSub
      Debug "Sub"
      Goto PixelOpEnd
      
      PIXELOP_INVERT:
      ;DoInvert
      Debug "Invert"
      Goto PixelOpEnd                
      
      PIXELOP_REPLACE:             
      ;DoReplace
      Debug "Replace"
      ;GOTO PixelOpEnd ;not needed on last
      
      PixelOpEnd:
    Next x
  Next y
  
  DataSection          ;the DataSection MUST be WITHIN the Procedure code for labels to be recognised by the compiler
    PIXELOP_JMPTABLE:  ;these MUST be listed in the same order as listed in Enumeration PIXELOPS
    Data.i ?PIXELOP_REPLACE, ?PIXELOP_ADD, ?PIXELOP_SUB, ?PIXELOP_FILL, ?PIXELOP_INVERT ;addresses of labels
  EndDataSection
EndProcedure

ModifyAllPixels(#PIXELOP_FILL, 1, 1)
ModifyAllPixels(#PIXELOP_REPLACE, 1, 1)

Re: Jump table - faster case selection

Posted: Sat Mar 06, 2021 2:48 pm
by Keya
mk-soft, yep I was just trying to keep the code minimal with the dword/qword x86/x64 for example purpose :)

but in regards to your pointer array, is there any benefit? it just seems to do the same thing but requires a little bit more code? (always good to have multiple ways though!)

Re: Jump table - faster case selection

Posted: Sat Mar 06, 2021 3:11 pm
by mk-soft
I work a lot with virtual tables and accessing the function table is very easy. So you don't have to pay attention to the processor type and the index always starts with zero.
The ASM effort is not greater. You don't need to call PeekI because the address is taken directly from the table.

Offtopic
For example, when using gadgets with constants with an enumeration start with zero. This way you can call the event procedure directly with a virtual table.
For this purpose, the event procedures are stored in the DataSection and called up in the gadget event.

Update Example

Code: Select all

;-TOP

Enumeration Windows
  #Main
EndEnumeration

Enumeration Gadgets
  #Button_Start
  #Button_Stop
  #Button_End
EndEnumeration

Enumeration Status
  #MainStatusBar
EndEnumeration

Prototype MyPrototypeInvoke()

Structure MyEventInvoke
  Invoke.MyPrototypeInvoke[0]
EndStructure

Global *vTableMyEventGadget.MyEventInvoke = ?vTableMyEventGadget

Procedure MyEventGadget()
  Protected Gadget = EventGadget()
  If Gadget >= 0 And Gadget <= #Button_End
    *vTableMyEventGadget\Invoke[Gadget]()
  EndIf
EndProcedure

BindEvent(#PB_Event_Gadget, @MyEventGadget())

Procedure Main()
  
  #MainStyle = #PB_Window_SystemMenu | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget
  
  If OpenWindow(#Main, #PB_Ignore, #PB_Ignore, 500, 150, "Window - Virtuell Table Example" , #MainStyle)
    ButtonGadget(#Button_Start, 10, 10, 120, 25, "Start")
    ButtonGadget(#Button_Stop, 140, 10, 120, 25, "Stop")
    ButtonGadget(#Button_End, 270, 10, 120, 25, "End")
    
    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_CloseWindow
          Break
      EndSelect
    ForEver
    
  EndIf
  
EndProcedure : Main()

End

Procedure Event_Button_Start()
  Select EventType()
    Case #PB_EventType_LeftClick
      Debug "Button Start"
  EndSelect
EndProcedure

Procedure Event_Button_Stop()
  Select EventType()
    Case #PB_EventType_LeftClick
      Debug "Button Stop"
  EndSelect
EndProcedure

Procedure Event_Button_End()
  Select EventType()
    Case #PB_EventType_LeftClick
      Debug "Button End"
  EndSelect
EndProcedure

DataSection
  vTableMyEventGadget: ; Same order as enumeration
  Data.i @Event_Button_Start()
  Data.i @Event_Button_Stop()
  Data.i @Event_Button_End()
EndDataSection
[/size]

Re: Jump table - faster case selection

Posted: Sat Mar 06, 2021 11:01 pm
by idle
I tried making a jmp table macro in this thread viewtopic.php?f=35&t=62304
Though it's still a bit clunky and needs a bounds check

Code: Select all

Macro JumpTable(table)
  DataSection
    ! table :
EndMacro     

CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
  Macro JumpTableData
  !dd
  EndMacro   
CompilerElse
  Macro JumpTableData
  !dq
  EndMacro   
CompilerEndIf

Macro Switch(table,switch)
  EndDataSection
  EnableASM
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    mov eax, switch
    jmp dword [ table + eax * 4]
  CompilerElse
   lea rdx, [ table ]
   mov rax,  switch
   jmp qword [rdx + rax * 8]
  CompilerEndIf
  DisableASM
EndMacro   

Macro caseJT(label,endlabel)
  !jmp endlabel
  ! label :
EndMacro   

Macro EndJumpTable(label)
  ! label :
EndMacro   


Procedure foo(a.i)
  Protected result
 
  JumpTable(jmp_table_foo)    ;define a jumptable
  JumpTableData le,l1,l2,l3   ;set the labels 0 offset 
 
  Switch(jmp_table_foo,a)     ;switch the table with the index 
    caseJT(l1,le)
      result = a * 10
    caseJT(l2,le)
      result = a * 20
    casejt(l3,le)
     result = a * 30
  EndJumpTable(le)
 
  ProcedureReturn result
 
EndProcedure   

Debug foo(2)  ;should return 40