flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > fasmx - .switch .case - jmp tab & cmp/je & Pascal C

Author
Thread Post new topic Reply to topic
Mike Gonta



Joined: 26 Dec 2010
Posts: 238
Location: the-ideom
Mike Gonta
Here is a .switch macro that uses cmp/je instead of a jump table.
Each .case will jmp to .endswitch unless .continue is used.
.default is optional.
Code:
use32
.switch [counter]
  .case 1
  .case 2
    mov eax, 2
    .continue
  .case 5
    mov eax, 3
    .switch ebx
      .case 4
        mov eax, 4
      .case 5
        mov eax, 5
      .default
        nop
    .endswitch
    nop
  .default
    nop
.endswitch    
Here is the macro based on this one
Code:
macro .switch variable {
local continue, this, c_style, var
local stat, default, exit
local top, count, here, x, val, location
local save_eax

  continue=0
  this=0
  c_style=0
  save_eax=0
  
  match =c x, variable \{
    var equ x
    c_style=1
    stat equ
  \}
  match =stat x, stat variable \{
    var equ x
  \}
  restore stat

  if ~var eq eax
    save_eax=1
    push eax
    if var in <al, ah, ax, bl, bh, bx, cl, ch, cx, dl, dh, dx, bp, di, si>
      movzx eax, var
    else
      match x y, var \{
        movzx eax, var
        stat equ
      \}
      match =stat, stat \{
        mov eax, var
      \}
      restore stat
    end if
  end if
  label top DWORD
  repeat count
    cmp eax, DWORD 0
    je NEAR $
  end repeat
  if defined default
    jmp default
  else
    if save_eax
      jmp exit-1
    else
      jmp exit
    end if
  end if

  macro .case [value] \{
  \common
    if this
      if c_style | continue
        continue=0
        if save_eax
          jmp $+3
        end if
      else
        jmp exit
        align 16
      end if
    end if
    continue=0
  virtual
    dd $
    load here DWORD from $$
  end virtual
    if save_eax
      pop eax
    end if
  \forward
    this=this+1
    match =stat a-b, stat value \\{
      x equ a
      val equ b
      stat equ
    \\}
    match =stat b, stat value \\{
      x equ
      val equ b
    \\}
    restore stat
    location=top+(11*this)
    if ~x eq
      if x<>0
        store DWORD x at location-10           ;  cmp eax, DWORD x
        store DWORD 11 at location-4
        store BYTE 82h at location-5           ;  jb .1
        this=this+1
        location=location+size
      end if
      store DWORD val at location-10           ;  cmp eax, DWORD val
      store DWORD here-location at location-4
      store BYTE 86h at location-5             ;  jbe here
    else                                       ;.1:
      store DWORD val at location-10           ;  cmp eax, DWORD val
      store DWORD here-location at location-4  ;  je here
    end if
  \}
  
  macro .break arg \{
    match =.if x, arg \\{
      JCOND exit, x
      stat equ
    \\}
    match =stat, stat \\{
      jmp exit
    \\}
    restore stat
  \}
  
  macro .continue \{
    continue=1
  \}
  
  macro .default \{
    if c_style | continue
      continue=0
      if save_eax
        jmp $+3
      end if
    else
      jmp exit
      align 16
    end if
  default:
    if save_eax
      pop eax
    end if
  \}

  macro finish@switch \{
    count=this
    if save_eax
      jmp $+3
      pop eax
    end if
  exit:
  \}

  macro .table \{
  local cmin, cmax
  local min, max, switch_table
  local counter
  local start, next, tab
  tab=1
  cmin=0FFFFFFFFh
  cmax=0
    if this
      if c_style
        if save_eax
          jmp next+1
        else
          jmp next
        end if
      else
        if continue
          continue=0
          if save_eax
            jmp next+1
          else
            jmp next
          end if
        else
          jmp exit
        end if
      end if
    else
      continue=0
    end if
    this=this+1
    location=top+(11*this)
    if min
      store DWORD min at location-10           ;  cmp eax, DWORD min
      store DWORD 11 at location-4
      store BYTE 82h at location-5             ;  jb .1
      this=this+1
      location=location+11
    end if
    store DWORD max at location-10             ;  cmp eax, DWORD max
    store DWORD start-location at location-4
    store BYTE 86h at location-5               ;  jbe start
  start:                                       ;.1:
    jmp [switch_table+(eax-min)*4]
    align 4
    label switch_table DWORD
    times max+1-min dd exit
  next:
  
    macro .case [value] \\{
    \\common
      if ~tab
        if c_style | continue
          continue=0
          if save_eax
            jmp $+3
          end if
        else
          jmp exit
          align 16
        end if
      end if
      tab=0
      continue=0
    virtual
      dd $
      load here DWORD from $$
    end virtual
      if save_eax
        pop eax
      end if
    \\forward
      match =stat a-b, stat value \\\{
        x equ a
        val equ b
        stat equ
      \\\}
      match =stat b, stat value \\\{
        x equ
        val equ b
      \\\}
      restore stat
      if val>cmax
        cmax=val
      end if
      if ~x eq
        if x<cmin
          cmin=x
        end if
        if x<>0
          counter=val-x+1
        else
          counter=val+1
        end if
      else
        if val<cmin
          cmin=val
        end if
        counter=1
      end if
      location=switch_table+(val-min)*4
      repeat counter
        store DWORD here at location
        location=location-4
      end repeat
    \\}
     
    macro finish@table \\{
      max=cmax
      min=cmin
    \\}
  \}
}
  
macro .endtable {
  finish@table
  purge .case, finish@table
}

macro .endswitch {
  finish@switch
  purge .case, .break, .continue, .default, finish@switch
}    

_________________
Mike Gonta
the-ideom - now you know how to compile

https://mikegonta.com


Last edited by Mike Gonta on 14 Oct 2013, 09:27; edited 11 times in total
Post 27 Dec 2011, 21:42
View user's profile Send private message Visit poster's website Reply with quote
typedef



Joined: 25 Jul 2010
Posts: 2913
Location: 0x77760000
typedef
isn't this enough though ?

Code:
cmp [mem32], imm32
jne  @F

@@:
cmp reg32, xxx
jne  @F

@@:

...
    


Rolling Eyes
Post 27 Dec 2011, 22:10
View user's profile Send private message Reply with quote
Mike Gonta



Joined: 26 Dec 2010
Posts: 238
Location: the-ideom
Mike Gonta
Added options to the basic .switch macro:
    .switch <variable> - cmp/je method , .case ends with jmp to .endswitch unless .continue is used
    .switch c <variable> - cmp/je method , .case falls through to next .case unless .break is used
.default is optional
.break .if is supported
.case accepts a comma separated list if values, the values can also be a range:
    .case 2-5, 7, 9-11, 15

_________________
Mike Gonta
the-ideom - now you know how to compile

https://mikegonta.com


Last edited by Mike Gonta on 14 Oct 2013, 09:27; edited 3 times in total
Post 02 Jan 2012, 11:09
View user's profile Send private message Visit poster's website Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc
Mike Gonta
Could you write a version, that optimally combines jump tables and comparisons? That was my intention for some time, just didn't get to it.
Post 02 Jan 2012, 23:01
View user's profile Send private message Reply with quote
Mike Gonta



Joined: 26 Dec 2010
Posts: 238
Location: the-ideom
Mike Gonta
l_inc wrote:
Could you write a version, that optimally combines jump tables and comparisons?
That's doable.
The total number of cases vs the total number of jump table slots.
What would be the optimal criterion? For example:
Code:
  if cases>3 & slots<(cases*2)
    jump_table
  else
    comparisons
  end if    
Or how about mixing jump tables and comparisons in the same switch block?
Code:
  .switch <variable>
    .case 1
    .case 5
    .table
      .case 10
      .case 11
      .case 12
      .case 13
    .endtable
    .case 20
  .endswitch    

_________________
Mike Gonta
the-ideom - now you know how to compile

https://mikegonta.com


Last edited by Mike Gonta on 14 Oct 2013, 09:28; edited 2 times in total
Post 03 Jan 2012, 00:51
View user's profile Send private message Visit poster's website Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc
Mike Gonta
Quote:
Or how about mixing jump tables and comparisons in the same switch block?

That's exactly what I meant: to build a binary decision tree, where the leafs are either the jump tables with continuous ranges, so that the highest inter-case difference is 2 (the condition "slots<(cases*2)" is then automatically satisfied), or single values.
Post 03 Jan 2012, 11:48
View user's profile Send private message Reply with quote
Mike Gonta



Joined: 26 Dec 2010
Posts: 238
Location: the-ideom
Mike Gonta
I've updated the .switch macro with .table / .endtable.
.case blocks within will use the jump table method. This allows the mixing of both methods in the same .switch block to provide a fully programmer controlled optimization.
Code:
use32
  .switch
    .case 1
    .case 2
    .table
      .case 3
      .case 4
    .endtable
    .case 5
    .default
  .endswitch    

_________________
Mike Gonta
the-ideom - now you know how to compile

https://mikegonta.com


Last edited by Mike Gonta on 14 Oct 2013, 09:28; edited 2 times in total
Post 05 Jan 2012, 00:13
View user's profile Send private message Visit poster's website Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc
Mike Gonta
Thank you. The macro seems to be pretty complicated now.
Post 05 Jan 2012, 16:53
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar. Also on YouTube, Twitter.

Website powered by rwasa.