Page 1 of 1

jmp tables

Posted: Sun May 24, 2015 1:00 am
by idle
I'm curious to see if we can implement a jump table macro for PB as an alternative to using select / case
which results in a chain of if's that aren't particularly optimal if there's a lot of cases to wade through.
If the cases are serialized eg 0 to n, a jump table is a better option with O(1) worst case vs O(n) for selects worse case.
though any performance increase will likely be negligible in general useage.

This works on linux x64 and probably on x86 with fasm but I don't know if it'll work on OSX or Windows x64

Edit: changed to using lea and using a datasection

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


Re: jmp tables

Posted: Sun May 24, 2015 8:17 pm
by davido
I tried it on Windows 7 x64 compiled with PureBasic 5.31 x64.

Gave this error:
POLINK: error: Relocation type ADDR32 is invalid without /LARGEADDRESSAWARE:NO, for symbol '.code'.

Clever idea: I do hope you get it working.

Re: jmp tables

Posted: Sun May 24, 2015 10:58 pm
by idle
thanks for that Davido

I've had another go at it, and rearranged it based on a solution wilbert sent me
it's a little messy but I don't think there's an easier alternative in PB 5.22
since it can't resolve pb labels in the procedure and datasection .

it looks like

Code: Select all

Procedure foo(a.i)
  Protected result 
  
  JumpTable(jmp_table_foo)    ;define a jumptable
  JumpTableData le,l1,l2,l3      ;set the jump labels 0 offset  
  
  Switch(jmp_table_foo,a)        ;switch the table to index  
    caseJT(l1,le)                        :switch case 
      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

Re: jmp tables

Posted: Mon May 25, 2015 6:04 am
by wilbert
Works fine now :)

Re: jmp tables

Posted: Mon May 25, 2015 6:29 am
by idle
wilbert wrote:Works fine now :)
Thanks, it'll only be marginally faster than a select, though it depends on what's being done.
If you had 20 cases you could expect at most a 20% speed up on average but otherwise it'd be negligible
unless it was constantly selects worst case, then it'd be 2 to 3 times faster.

Re: jmp tables

Posted: Tue May 26, 2015 1:58 am
by jack
idle
jump tables were popular in the 8-bit and 16-bit world, but I don't think they are a good idea in todays CPU's, have a look at this blog http://lolengine.net/blog/2011/9/17/pla ... u-pipeline

Re: jmp tables

Posted: Tue May 26, 2015 7:12 am
by idle
I'd still think an optimizing compiler would produce a branch table over an if else switch if the boot fits.
it's just a case of consistency and quantity and a switch in it's worst case is slower than
a binary search which is slower than a jump table, even if it incurs a cache hit.
if you know it's quicker and the boot fits why wouldn't you use one?

Re: jmp tables

Posted: Fri May 29, 2015 1:51 am
by DoubleDutch
jmp tables will be faster than the case statements if you call procedures or any commands in the case statements - as they would also break the pipeline too on a mondern day cpu.