123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- ; vim:ft=fasm:
- ;include 'align.inc'
- include 'inline.inc'
- if ~ defined utils
- restore utils
- define utils yes
- struc static_string str&
- . db str
- .len = $ - .
- end struc
- namespace mov_args
- ;;; 8 ;;;
- reg8_1 = rdi
- reg8_2 = rsi
- reg8_3 = rdx
- reg8_4 = r10
- reg8_5 = r9
- reg8_6 = r8
- ;;; 4 ;;;
- reg4_1 = edi
- reg4_2 = esi
- reg4_3 = edx
- reg4_4 = r10d
- reg4_5 = r9d
- reg4_6 = r8d
- ;;; 2 ;;;
- reg2_1 = di
- reg2_2 = si
- reg2_3 = dx
- reg2_4 = r10w
- reg2_5 = r9w
- reg2_6 = r8w
- ;;; 1 ;;;
- reg1_1 = dil
- reg1_2 = sil
- reg1_3 = dl
- reg1_4 = r10b
- reg1_5 = r9b
- reg1_6 = r8b
- max_args = 6
- end namespace
- macro mov_args args&
- match any, args
- iterate arg, args
- if % > mov_args.max_args
- err 'too many args: maximum is ', '0' + mov_args.max_args
- end if
- local skip, size
- skip = 0
- x86.parse_operand@src arg
- if @src.size = 0
- size = 8
- else
- size = @src.size
- end if
- local current_arg
- repeat 1, _i:(%)
- repeat 1, _size:(size)
- current_arg = mov_args.reg#_size#_#_i
- end repeat
- end repeat
- if @src.type = 'reg'
- if arg eq current_arg
- skip = 1
- end if
- end if
- if skip = 0
- mov current_arg, arg
- end if
- end iterate
- end match
- end macro
- macro do_syscall sys*,args&
- mov_args args
- mov rax, sys
- syscall
- end macro
- macro call_args fn*, args&
- mov_args args
- call fn
- end macro
- ; TODO: automatically define macro for proc (`proc func ...` should define `func` macro and `func_impl` function)
- macro proc name*
- macro end?.proc!
- .end:
- ret
- end if
- purge end?.proc
- end macro
- name:
- if used name
- end macro
- macro using_regs regs&
- macro end?.using_regs!
- calminstruction reverse_pop reg&
- local tmp, stack, cmd
- collect:
- match tmp=,reg, reg
- take stack, tmp
- jyes collect
- execute:
- arrange cmd, =pop reg
- assemble cmd
- take reg, stack
- jyes execute
- end calminstruction
- match any, regs
- reverse_pop regs
- end match
- purge reverse_pop
- purge end?.using_regs
- end macro
- match any, regs
- iterate reg, regs
- x86.parse_operand@src reg
- if ~ @src.type = 'reg'
- err '"', `reg, '" is not register'
- end if
- push reg
- end iterate
- end match
- end macro
- inlinemacro sum_irpv arr
- local res
- res = 0
- irpv i, arr
- res = res + i
- end irpv
- return = res
- end inlinemacro
- macro stack_frame size*
- local aligned_size
- local _stack_frame
- virtual at 0
- _stack_frame rb size
- align 16
- aligned_size = $
- end virtual
- local used_stack_arr, used_stack, stack_start
- stack_start = rbp
- define used_stack stack_start
- inlinemacro stack_frame.use use_size*
- local sz, _stack_frame
- virtual at 0
- _stack_frame rb use_size
- align 8
- sz = $
- end virtual
- used_stack_arr equ (sz)
- local sum
- sum = sum_irpv(used_stack_arr)
- if sum > (aligned_size)
- repeat 1, _sum:(sum)
- repeat 1, _size:(aligned_size)
- err 'used more than frame size (wanted: ', `_sum, ', frame size: ', `_size, ')'
- end repeat
- end repeat
- end if
- define used_stack used_stack - (sz)
- return = (used_stack)
- end inlinemacro
-
- macro end?.stack_frame!
- lea rsp, [rsp + aligned_size]
- pop rbp
-
- purge end?.stack_frame
- ; FIXME: `stack_frame.use` still defined after `end stack_frame`
- purge stack_frame.use
- end macro
- push rbp
- mov rbp, rsp
- lea rsp, [rsp - aligned_size]
- end macro
- ; macro struct? name
- ; macro end?.struct?!
- ; end namespace
- ; esc end struc
- ; virtual at 0
- ; name name
- ; align16 sizeof.name, $
- ; end virtual
- ; purge end?.struct?
- ; end macro
- ; esc struc name
- ; label . : sizeof.name
- ; namespace .
- ; end macro
- inlinemacro align_comptime n*, to*
- return = ((n + to - 1) and (not (to - 1)))
- end inlinemacro
- macro mov2mem dst*, src*, tmp_reg:rax
- mov tmp_reg, src
- mov dst, tmp_reg
- end macro
- macro enum name
- local counter
- counter = 0
- namespace name
- macro ? line&
- match =end =enum, line
- end namespace
- purge ?
- else match name==n, line
- name := n
- counter = n + 1
- else match name, line
- name := counter
- counter = counter + 1
- else match any, line
- err "syntax error"
- end match
- end macro
- end macro
- ;end namespace
- end if
|