How do you do a Jump Table in the C backend?

Just starting out? Need help? Post your questions and find answers here.
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: How do you do a Jump Table in the C backend?

Post by skywalk »

Nice!
I've been seeing !"your C code here;".
But thought it was only for some external tool?

If compiling with C backend, do we now get block comments with
!/*
PB regular code here will be ignored
!*/
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
idle
Always Here
Always Here
Posts: 5042
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: How do you do a Jump Table in the C backend?

Post by idle »

Inline c works fine, it's just somewhat limited in scope which is why I wrote the external tools.

No not if you paste it in PB with inline c, you need to put ! on every line

PB will pass this on this to the C compiler which is just regular c block comment
!/*
! PB regular code here will be ignored
!*/
User avatar
mk-soft
Always Here
Always Here
Posts: 5335
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: How do you do a Jump Table in the C backend?

Post by mk-soft »

Off-topic
idle wrote: Fri Jul 01, 2022 10:34 pm thanks, I was aiming for the minimization of inline asm and c but it's better without the peeki
It is good that the function Peek and Poke are available in basic style.
But if you have been working with PureBasic for a while, you can replace all these function calls with a direct access. I know you know it.

Code: Select all

Define *bVal.byte, *iVal.integer, *fltVal.float ; etc
iVal = 100
*iVal = @iVal
Debug *iVal\i
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: How do you do a Jump Table in the C backend?

Post by Olli »

(OffTopic+)

When Peek and Poke are obsolete, it is if we want to modify a memory cell :

Code: Select all

*Address\i + 1
equ to :

Code: Select all

PokeI(*Address, PeekI(*Address) + 1)
Direct pointor syntax is more comfortable.

(/OffTopic)

A point I have in mind is a strange way I use to mangle a call :

Code: Select all

a(0) = @proc0()
a(1) = @proc1()
a(2) = @proc2()
a(3) = @proc3()
; etc...
Assuming a library code contains less than 64K, the higher 48-bits range can be used to mangle the function, 1st by substracting :

Code: Select all

a(0) = @proc0()
a(1) = @proc1() - a(0)
a(2) = @proc2() - a(0)
a(3) = @proc3() - a(0)
And, now, proc1(), proc2(), proc3() and the next functions can be mangled.

A possible convention :

Code: Select all

(variable type codification)
%00 = no variable
%01 = integer variable
%10 = string variable
%11 = double variable
So, we can use the higher 48 bits in a substracted address to store a template :

Code: Select all

bit 62-63 function output type
bits 16-61 function input types (23 arguments available)
bits 0-15 function address offset (referency = a(0) = @proc0()
Example :
a(1) = %01011011 << 56 + (@proc1() - a(0) )
means

Code: Select all

Procedure.i proc1(Arg1.i, Arg2.S, Arg3.D)
User avatar
idle
Always Here
Always Here
Posts: 5042
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: How do you do a Jump Table in the C backend?

Post by idle »

It's a handy trick on x64. x86 you can only use the 2 lower lsb of a pointer.
Cunning way to add reflection thanks olli
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: How do you do a Jump Table in the C backend?

Post by Olli »

idle wrote: Sun Jul 03, 2022 8:49 pm It's a handy trick on x64. x86 you can only use the 2 lower lsb of a pointer.
Cunning way to add reflection thanks olli
I think however nothing prevents us from doing the same on x86.

Code: Select all

Dim a.Q(255)
Whatever the mode, the coder just must insure himself, 1stly, the arguments (and function output) will have 32 bits on x86, and will have 64 bits on x64,
and, 2ndly, the address' memory area between the 1st procedure and the last one, this area must not pass over 64K or 16M (24 bits address mask and a maximum of 19 arguments, in this way).

The bigger problem (imho) is the difference between float and double.
A more consistent convention should be :

Code: Select all

15 arguments set
========================
%000 no variable
%001 integer var
%010 unicode string var
%011 double var
%100 quad var
%101 long var
%110 ascii string var
%111 float var
or

Code: Select all

12 arguments set
========================
%0000 no variable
%0001 integer var
%0010 unicode string var
%0011 double var
%0100 quad var
%0101 long var
%0110 ascii string var
%0111 float var
%1000 byte
%1001 ascii
%1010 word
%1011 unicode
%1100 utf8 string var
%1101 prefixed unicode string var
%1110 prefixed ascii string var
%1111 prefixed utf8 string var
User avatar
Demivec
Addict
Addict
Posts: 4086
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: How do you do a Jump Table in the C backend?

Post by Demivec »

Thank you for the jump table code contributions of idle, mk-soft and any others I may have overlooked.

The sample code works well on its own but during testing I have run into an issue to adapt it to my needs. The test code as last posted by functions by using a procedure parameter as an index. From my original post I mentioned that the index variable(s) would be global and be set outside the procedure to direct the flow within the procedure.

I have tested the code in the Assembler backend and it works fine according to my needs. This is natural as it uses code that has already been verified in previous versions of PureBasic. How can the code under the option for the C Backend be adapted to use a global variable, specifically one also placed in a module named 'YO' for instance? I have tried to apply the naming for the variable myself but I don't think the naming conventions between the two backends is the same. For instance to add prefixes to the variable names like 'p_' or 'p.p_' depending on whether or not the variable is in a procedure or not.

I know that in the Assembler backend that variable names are recognized without any special prefixes if EnableASM is used along with not using '!' at the start of the line. It would be nice if something similar was available for the C backend
User avatar
idle
Always Here
Always Here
Posts: 5042
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: How do you do a Jump Table in the C backend?

Post by idle »

That's a bit tricky. if you had a module named yo with a global variable index, it would be yoXv_index in c backend and
yo.v_index or YO.v_index in the asm backend

compile from command line with -c
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: How do you do a Jump Table in the C backend?

Post by Olli »

Demivec wrote:I have tried to apply the naming for the variable myself but I don't think the naming conventions between the two backends is the same. For instance to add prefixes to the variable names like 'p_' or 'p.p_' depending on whether or not the variable is in a procedure or not.
A little remark, about ASM backend (and certainly C backend), between 'p_' and 'p.p_' :

Start on the idea that what you want is enabled. Simple example (not runable, miss' the macro) :

Code: Select all

Define *myvar
kif(myvar)
Debug *myvar
This code above :
1) will get its macro (named 'kif')
2) will be dupplicated inside and outside a procedure.

The macro added will
1) take a value from the compiler, value which is the count of 'calls' of this macro (example of a value).
2) store this value in the lowlevel (ASM register) RAX
3) then copy this value in the highlevel pointor you want (defined in the macro argument)

Code: Select all

Macro kif(paf)
! mov rax, macroexpandedcount
compilerif #pb_compiler_procedure = #null$
! mov [p_#paf], rax
compilerelse
! mov [p.p_#paf], rax
compilerendif
endmacro

procedure test()
define *myvar
kif(myvar)          ; note I removed the '*' star
debug *myvar
endprocedure

test()
define *myvar
kif(myvar)          ; note I removed the '*' star
debug *myvar
As you can observe, it is exactly the same code (before preprocessing compilation) inside and outside the procedure. And I think this is the enable with the modules, and in C backend too (I trust to idle !!)

The unique problem I imagine is ASM cannot copy from a variable to another variable without using a CPU register, so we must create two macros to separate the flows (memory read and memory write) versus only one macros on C backend (it is not really a true problem indeed). My example code above treats only a memory write flow, because I code it on ASM backend which forbides me to blend read and write flows in the same instruction.

Code: Select all

! mov [x], [y] ; forbidden on ASM
User avatar
idle
Always Here
Always Here
Posts: 5042
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: How do you do a Jump Table in the C backend?

Post by idle »

Never realized we had #pb_compiler_procedure to test like that. :shock: Thanks good tip
Olli
Addict
Addict
Posts: 1071
Joined: Wed May 27, 2020 12:26 pm

Re: How do you do a Jump Table in the C backend?

Post by Olli »

It would be better if I tell you the doc page about this :
https://www.purebasic.com/documentation ... tives.html
I just tried modules and I find, missing informations (errors or warnings) : #PB_Compiler_Module allows us to bypass this miss.
User avatar
useful
Enthusiast
Enthusiast
Posts: 367
Joined: Fri Jul 19, 2013 7:36 am

Re: How do you do a Jump Table in the C backend?

Post by useful »

mk-soft wrote: Fri Jul 01, 2022 10:10 am Small optimation with ArrayOfPointer

Code: Select all

Structure ArrayOfPointer
  *Index[0]
EndStructure

Procedure test(index)
  Protected *addr.ArrayOfPointer = ?jt 
  Protected result 
  
  DataSection : jt:
    Data.i ?l0 , ?l1 , ?l2 , ?l3 , ?l4
  EndDataSection 
  
  If index < 5 
    
    CompilerIf #PB_Compiler_Backend = #PB_Backend_C    
      !goto *p_addr->f_index[v_index];
    CompilerElse 
      EnableASM  
      jmp *addr\Index[index]
      DisableASM 
    CompilerEndIf 
    
  Else 
    Goto le 
  EndIf  
  
  
  l0: 
  result =  0
  Goto lE 
  l1: 
  result = 1  
  Goto lE
  l2:
  result =  2  
  Goto lE 
  l3:
  result = 3 
  Goto lE 
  l4:
  result =  4  
  lE:
  
  ProcedureReturn result 
EndProcedure    


Debug test(3)
Something has changed and the line gives an error.
!goto *p_addr->f_index[v_index];
Dawn will come inevitably.
User avatar
mk-soft
Always Here
Always Here
Posts: 5335
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: How do you do a Jump Table in the C backend?

Post by mk-soft »

Update
- Fix goto pointer

Link: Small optimation with ArrayOfPointer ...
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
useful
Enthusiast
Enthusiast
Posts: 367
Joined: Fri Jul 19, 2013 7:36 am

Re: How do you do a Jump Table in the C backend?

Post by useful »

Thank you.
Dawn will come inevitably.
Post Reply