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
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