# -*-whitespace-*-
# SYNTAX: (keyword: opcode (tree $substitutions))

# include 'standard' macros
(include: "src/jit/macro.expr")

# Number with dollar-signs stand for the arguments of the opcode.  The
# opcode preprocessor inserts loads, and immediate nodes for arguments
# automatically.

# Add templates where you wish and then once you are done run
# tools/sort-expr-templates-by-oplist-order.raku to sort it in the same order as
# the oplist.

(template: const_i16 (copy $1))
(template: const_i64 (copy $1))
# Disabled for the time being
(template: const_n64 (copy $1))
(template: const_s (^cu_string $1))

(template: set (copy $1))

(template: trunc_u8 (ucast $1 int_sz 1))
(template: trunc_u16 (ucast $1 int_sz 2))
(template: trunc_u32 (ucast $1 int_sz 4))

(template: trunc_i8 (ucast $1 int_sz 1))
(template: trunc_i16 (ucast $1 int_sz 2))
(template: trunc_i32 (ucast $1 int_sz 4))

(template: extend_u8  (ucast $1 int_sz 1))
(template: extend_u16 (ucast $1 int_sz 2))
(template: extend_u32 (ucast $1 int_sz 4))

(template: extend_i8  (scast $1 int_sz 1))
(template: extend_i16 (scast $1 int_sz 2))
(template: extend_i32 (scast $1 int_sz 4))


(template: goto (branch $0))

(template: if_i
  (when (nz $0)
    (branch $1)))

(template: unless_i
  (when (zr $0)
    (branch $1)))

(template: if_n
  (when (nz $0)
    (branch $1)))

(template: unless_n
  (when (zr $0)
    (branch $1)))

(template: sp_getarg_o
  (load
    (^source_arg_addr $1)
    ptr_sz
  )
)
(template: sp_getarg_i
  (load
    (^source_arg_addr $1)
    int_sz
  )
)
(template: sp_getarg_s
  (load
    (^source_arg_addr $1)
    ptr_sz
  )
)
(template: sp_getarg_n
  (load_num
    (^source_arg_addr $1)
    num_sz
  )
)

(template: getlex (copy $1))
(template: bindlex! (store \$0 $1 reg_sz))

(template: getlex_ni
  (load
    (call (^func &MVM_frame_find_lexical_by_name)
      (arglist
        (carg (tc) ptr)
        (carg (^cu_string $1) ptr)
        (carg (^reg_int) int)) int_sz)
    int_sz))

(template: getlex_nn
  (load_num
    (call (^func &MVM_frame_find_lexical_by_name)
      (arglist
        (carg (tc) ptr)
        (carg (^cu_string $1) ptr)
        (carg (^reg_num) int)) int_sz)
    num_sz))

(template: getlex_ns
  (load
    (call (^func &MVM_frame_find_lexical_by_name)
      (arglist
        (carg (tc) ptr)
        (carg (^cu_string $1) ptr)
        (carg (^reg_str) int)) int_sz)
    ptr_sz))

(template: getlex_no
  (let: (($found (call (^func &MVM_frame_find_lexical_by_name)
                   (arglist
                     (carg (tc) ptr)
                     (carg (^cu_string $1) ptr)
                     (carg (^reg_obj) int)) ptr_sz)))
    (if (nz $found) (load $found ptr_sz) (^vmnull))))

(template: bindlex_ni
  (callv (^func &MVM_frame_bind_lexical_by_name)
    (arglist
      (carg (tc) ptr)
      (carg (^cu_string $0) ptr)
      (carg (^reg_int) int)
      (carg $1 ptr))))

(template: bindlex_nn
  (callv (^func &MVM_frame_bind_lexical_by_name)
    (arglist
      (carg (tc) ptr)
      (carg (^cu_string $0) ptr)
      (carg (^reg_num) int)
      (carg $1 ptr))))

(template: bindlex_ns
  (callv (^func &MVM_frame_bind_lexical_by_name)
    (arglist
      (carg (tc) ptr)
      (carg (^cu_string $0) ptr)
      (carg (^reg_str) int)
      (carg $1 ptr))))

(template: bindlex_no
  (callv (^func &MVM_frame_bind_lexical_by_name)
    (arglist
      (carg (tc) ptr)
      (carg (^cu_string $0) ptr)
      (carg (^reg_obj) int)
      (carg $1 ptr))))

(template: getdynlex
  (call (^func &MVM_frame_getdynlex)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg (^caller) ptr)) ptr_sz))

(template: binddynlex
  (callv (^func &MVM_frame_binddynlex)
    (arglist
      (carg (tc) ptr)
      (carg $0   ptr)
      (carg $1   ptr)
      (carg (^caller) ptr))))

(template: return_i
  (dov
    (callv (^func &MVM_args_set_result_int)
      (arglist
        (carg (tc) ptr)
        (carg $0 int)
        (carg (^zero) int)))
    (callv (^func &MVM_frame_try_return)
      (arglist
        (carg (tc) ptr)))
    (^exit)))

(template: return_n
  (dov
    (callv (^func &MVM_args_set_result_num)
      (arglist
        (carg (tc) ptr)
        (carg $0 num)
        (carg (^zero) int)))
    (callv (^func &MVM_frame_try_return)
      (arglist
        (carg (tc) ptr)))
    (^exit)))

(template: return_s
  (dov
    (callv (^func &MVM_args_set_result_str)
      (arglist
        (carg (tc) ptr)
        (carg $0 ptr)
        (carg (^zero) int)))
    (callv (^func &MVM_frame_try_return)
      (arglist
        (carg (tc) ptr)))
    (^exit)))

(template: return_o
  (dov
    (callv (^func &MVM_args_set_result_obj)
      (arglist
        (carg (tc) ptr)
        (carg $0 ptr)
        (carg (^zero) int)))
    (callv (^func &MVM_frame_try_return)
      (arglist
        (carg (tc) ptr)))
    (^exit)))

(template: eq_i (flagval (eq $1 $2)))
(template: ne_i (flagval (ne $1 $2)))
(template: lt_i (flagval (lt $1 $2)))
(template: le_i (flagval (le $1 $2)))
(template: gt_i (flagval (gt $1 $2)))
(template: ge_i (flagval (ge $1 $2)))
(template: cmp_i (sub (flagval (gt $1 $2)) (flagval (lt $1 $2))))

(template: eq_u (flagval (eq $1 $2)))
(template: ne_u (flagval (ne $1 $2)))
(template: lt_u (flagval (lt $1 $2)))
(template: le_u (flagval (le $1 $2)))
(template: gt_u (flagval (gt $1 $2)))
(template: ge_u (flagval (ge $1 $2)))
(template: cmp_u (sub (flagval (gt $1 $2)) (flagval (lt $1 $2))))

(template: eq_n (flagval (eq $1 $2)))
(template: ne_n (flagval (ne $1 $2)))
(template: lt_n (flagval (lt $1 $2)))
(template: le_n (flagval (le $1 $2)))
(template: gt_n (flagval (gt $1 $2)))
(template: ge_n (flagval (ge $1 $2)))
(template: cmp_n (sub (flagval (gt $1 $2)) (flagval (lt $1 $2))))

(template: add_i (add $1 $2))
(template: sub_i (sub $1 $2))
(template: mul_i (mul $1 $2))

(template: add_n (add $1 $2))
(template: sub_n (sub $1 $2))
(template: mul_n (mul $1 $2))

(template: inc_i (add $1 (^one)))
(template: dec_i (sub $1 (^one)))

(template: band_i (and $1 $2))
(template: bor_i  (or  $1 $2))
(template: bxor_i (xor $1 $2))
(template: bnot_i (not $1))

(template: not_i (flagval (zr $1)))

(template: coerce_is
  (call (^func &MVM_coerce_i_s)
    (arglist
      (carg (tc) ptr)
      (carg $1   int)) ptr_sz))

(template: coerce_ns
  (call (^func &MVM_coerce_n_s)
    (arglist
      (carg (tc) ptr)
      (carg $1 num)) ptr_sz))

(template: coerce_si
  (call (^func &MVM_coerce_s_i)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) int_sz))

(template: coerce_sn
  (calln (^func &MVM_coerce_s_n)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr))))

(template: checkarity
  (callv (^func &MVM_args_checkarity)
    (arglist
      (carg (tc) ptr)
      (carg (^params) ptr)
      (carg $0 int)
      (carg $1 int))))

(template: param_rp_i
  (call (^func &MVM_args_get_required_pos_int)
    (arglist
      (carg (tc)      ptr)
      (carg (^params) ptr)
      (carg $1        ptr)) int_sz))

(template: param_rp_s
  (call (^func &MVM_args_get_required_pos_str)
    (arglist
      (carg (tc) ptr)
      (carg (^params) ptr)
      (carg $1 int)) ptr_sz))

(template: param_rp_o
  (call (^func &MVM_args_get_required_pos_obj)
    (arglist
      (carg (tc) ptr)
      (carg (^params) ptr)
      (carg $1 int)) ptr_sz))

(template: param_sp
  (call (^func &MVM_args_slurpy_positional)
    (arglist
      (carg (tc) ptr)
      (carg (const 0 ptr_sz) ptr)
      (carg $1 int)) ptr_sz))

(template: param_sn
  (call (^func &MVM_args_slurpy_named)
    (arglist
      (carg (tc) ptr)
      (carg (^zero) ptr)) ptr_sz))

(template: getcode
  (load (idx (^getf (cu) MVMCompUnit body.coderefs) $1 ptr_sz) ptr_sz))

(template: capturelex
  (callv (^func MVM_frame_capturelex)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr))))

(template: takeclosure
  (call (^func MVM_frame_takeclosure)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: exception
  (let: (($ah (^getf (tc) MVMThreadContext active_handlers)))
    (if
      (nz $ah)
      (^getf $ah MVMActiveHandler ex_obj)
      (^vmnull))))

# Does not require the destructive ! postfix, since $0 is a read-only register
(template: bindexpayload
  (callv (^func &MVM_bind_exception_payload)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 ptr))))

(template: bindexcategory
  (callv (^func &MVM_bind_exception_category)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 int))))

(template: bindexmessage
  (callv (^func &MVM_bind_exception_message)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 ptr))))

(template: getexpayload
  (call (^func &MVM_get_exception_payload)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: getexcategory
  (call (^func &MVM_get_exception_category)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) int_sz))

(template: getexmessage
  (call (^func &MVM_get_exception_message)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: die!
  (callv (^func &MVM_exception_die)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg \$0 ptr))))

(template: resume
  (callv (^func &MVM_exception_resume)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr))))

(template: backtracestrings
  (call (^func &MVM_exception_backtrace_strings)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: usecapture
  (call (^func &MVM_args_use_capture)
    (arglist
      (carg (tc)     ptr)
      (carg (^frame) ptr)) ptr_sz))

(template: savecapture
  (call (^func &MVM_args_save_capture)
    (arglist
      (carg (tc)     ptr)
      (carg (^frame) ptr)) ptr_sz))

(template: captureposelems
  (call (^func &MVM_capture_num_pos_args)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) int_sz))

(template: captureposarg
  (call (^func &MVM_capture_arg_pos_o)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg (ucast $2 int_sz 4) int)) ptr_sz))

(template: captureposarg_i
  (call (^func &MVM_capture_arg_pos_i)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg (ucast $2 int_sz 4) int)) int_sz))

(template: captureposarg_n
  (calln (^func &MVM_capture_arg_pos_n)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg (ucast $2 int_sz 4) int))))

(template: captureposarg_s
  (call (^func &MVM_capture_arg_pos_s)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg (ucast $2 int_sz 4) int)) ptr_sz))

(template: captureposprimspec
  (call (^func &MVM_capture_arg_pos_primspec)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg (ucast $2 int_sz 4) int)) int_sz))

(template: captureexistsnamed
  (call (^func &MVM_capture_has_named_arg)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)) int_sz))

(template: capturehasnameds
  (call (^func &MVM_capture_has_nameds)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) int_sz))

(template: null_s (^nullptr))

(template: isnull_s (flagval (zr $1)))

(template: eq_s
  (call (^func &MVM_string_equal)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)) int_sz))

(template: ne_s
  (flagval
    (zr (call (^func &MVM_string_equal)
      (arglist
        (carg (tc) ptr)
        (carg $1 ptr)
        (carg $2 ptr)) int_sz))))

(template: gt_s
  (flagval
    (gt
      (call (^func &MVM_string_compare)
        (arglist
          (carg (tc) ptr)
          (carg $1 ptr)
          (carg $2 ptr)) int_sz)
      (^zero))))

(template: ge_s
  (flagval
    (ge
      (call (^func &MVM_string_compare)
        (arglist
          (carg (tc) ptr)
          (carg $1 ptr)
          (carg $2 ptr)) int_sz)
      (^zero))))

(template: lt_s
  (flagval
    (lt
      (call (^func &MVM_string_compare)
        (arglist
          (carg (tc) ptr)
          (carg $1 ptr)
          (carg $2 ptr)) int_sz)
      (^zero))))

(template: le_s
  (flagval
    (le
      (call (^func &MVM_string_compare)
        (arglist
          (carg (tc) ptr)
          (carg $1 ptr)
          (carg $2 ptr)) int_sz)
      (^zero))))

(template: cmp_s
  (call (^func &MVM_string_compare)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)) int_sz))

(template: eqat_s
  (call (^func &MVM_string_equal_at)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 int)) int_sz))

(template: eqatic_s
  (call (^func &MVM_string_equal_at_ignore_case)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 int)) int_sz))

(template: haveat_s
  (call (^func &MVM_string_have_at)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 int)
      (carg $3 int)
      (carg $4 ptr)
      (carg $5 int)) int_sz))

(template: concat_s
  (call (^func &MVM_string_concatenate)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)) ptr_sz))

(template: repeat_s
  (call (^func &MVM_string_repeat)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 int)) ptr_sz))

(template: substr_s
  (call (^func &MVM_string_substring)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 int)
      (carg $3 int)) ptr_sz))

(template: index_s
  (call (^func &MVM_string_index)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 int)) int_sz))

(template: codes_s
  (call (^func &MVM_string_codes)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) int_sz))

(template: getcp_s
  (call (^func &MVM_string_get_grapheme_at)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 int)) int_sz))

(template: indexcp_s
  (call (^func &MVM_string_index_of_grapheme)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 int)) int_sz))

(template: uc
  (call (^func &MVM_string_uc)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: lc
  (call (^func &MVM_string_lc)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: tc
  (call (^func &MVM_string_tc)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: split
  (call (^func &MVM_string_split)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)) ptr_sz))

(template: join
  (call (^func &MVM_string_join)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)) ptr_sz))

(template: getcpbyname
  (scast
    (call (^func &MVM_unicode_lookup_by_name)
      (arglist
        (carg (tc) ptr)
        (carg $1 ptr)) int_sz) int_sz 4))

(template: unipropcode
  (call (^func &MVM_unicode_name_to_property_code)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) int_sz))

(template: unipvalcode
  (call (^func &MVM_unicode_name_to_property_value_code)
    (arglist
      (carg (tc) ptr)
      (carg $1 int)
      (carg $2 ptr)) int_sz))

(template: hasuniprop
  (call (^func &MVM_string_offset_has_unicode_property_value)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 int)
      (carg $3 int)
      (carg $4 int)) int_sz))

(template: hasunipropc
  (call (^func &MVM_string_offset_has_unicode_property_value)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 int)
      (carg $3 int)
      (carg $4 int)) int_sz))

(template: chars
  (call (^func &MVM_string_graphs)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) int_sz))

(template: chr
  (call (^func &MVM_string_chr)
    (arglist
      (carg (tc) ptr)
      (carg $1 int)) ptr_sz))

(template: ordfirst
  (scast
    (call (^func &MVM_string_ord_at)
      (arglist
        (carg (tc) ptr)
        (carg $1 ptr)
        (carg (^zero) int)) int_sz) int_sz 4))

(template: ordat
  (scast
    (call (^func &MVM_string_ord_at)
      (arglist
        (carg (tc) ptr)
        (carg $1 ptr)
        (carg $2 int)) int_sz) int_sz 4))

(template: rindexfrom
  (call (^func &MVM_string_index_from_end)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 int)) int_sz))

(template: escape
  (call (^func &MVM_string_escape)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: flip
  (call (^func &MVM_string_flip)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: setbuffersize_fh
  (callv (^func &MVM_io_set_buffer_size)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 int))))

(template: iscclass
  (call (^func &MVM_string_is_cclass)
    (arglist
      (carg (tc) ptr)
      (carg $1 int)
      (carg $2 ptr)
      (carg $3 int)) int_sz))

(template: findcclass
  (call (^func &MVM_string_find_cclass)
    (arglist
      (carg (tc) ptr)
      (carg $1 int)
      (carg $2 ptr)
      (carg $3 int)
      (carg $4 int)) int_sz))

(template: findnotcclass
  (call (^func &MVM_string_find_not_cclass)
    (arglist
      (carg (tc) ptr)
      (carg $1 int)
      (carg $2 ptr)
      (carg $3 int)
      (carg $4 int)) int_sz))

(template: nfafromstatelist
  (call (^func &MVM_nfa_from_statelist)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)) ptr_sz))

(template: nfarunproto
  (call (^func &MVM_nfa_run_proto)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 int)) ptr_sz))

(template: nfarunalt
  (callv (^func &MVM_nfa_run_alt)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 ptr)
      (carg $2 int)
      (carg $3 ptr)
      (carg $4 ptr)
      (carg $5 ptr))))

(template: radix
  (call (^func &MVM_radix)
    (arglist
      (carg (tc) ptr)
      (carg $1 int)
      (carg $2 ptr)
      (carg $3 int)
      (carg $4 int)) ptr_sz))

(template: encode
  (call (^func &MVM_string_encode_to_buf)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 ptr)
      (carg (^nullptr) ptr)) ptr_sz))

(template: decode
  (call (^func &MVM_string_decode_from_buf)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)) ptr_sz))

(template: istrue_s
  (call (^func &MVM_coerce_istrue_s)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) int_sz))

(template: isfalse_s
  (flagval
    (zr
      (call (^func &MVM_coerce_istrue_s)
        (arglist
          (carg (tc) ptr)
          (carg $1 ptr)) int_sz))))

(template: null (^vmnull))
(template: sp_resumption (^vmnull))

(template: isnull
  (or
    (flagval (zr $1))
    (flagval (eq $1 (^vmnull)))))

(template: ifnonnull
  (when (all
          (nz $0)
          (ne $0 (^vmnull)))
    (branch $1)))

(template: create!
  (letv: (($obj (call (^getf (^repr $1) MVMREPROps allocate)
                 (arglist
                   (carg (tc) ptr)
                   (carg (^stable $1) ptr)) ptr_sz))
         ($initialize (^getf (^repr $1) MVMREPROps initialize)))
    (dov
      (store \$0 $obj ptr_sz)
      (when (nz $initialize)
        (callv $initialize
          (arglist
            (carg (tc) ptr)
            (carg (^stable $obj) ptr)
            (carg $obj ptr)
            (carg (^body $obj) ptr)))))))

(template: clone
  (call (^func &MVM_repr_clone)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) ptr_sz))

(template: isconcrete
  (if (all
        (nz $1)
        (^is_conc_obj $1))
    (^one)
    (^zero)))

(template: objprimspec
  (if
    (nz $1)
    (^getf_ucast (^storage_spec $1) MVMStorageSpec boxed_primitive int_sz)
    (^zero)))

(template: gethow
  (let: (($how (^getf (^stable $1) MVMSTable HOW)))
  (if (nz $how)
    $how
    (call (^func MVM_6model_get_how)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $1) ptr)) ptr_sz))))

(template: getwhat
  (^getf (^stable $1) MVMSTable WHAT))

(template: getwho
  (let: (($who (^getf (^stable $1) MVMSTable WHO)))
  (if (nz $who) $who (^vmnull))))

(template: setwho
  (do
    (^store_write_barrier! (^stable $1) (^addrf (^stable $1) MVMSTable WHO) $2)
    $1))

(template: reprname
  (load (idx (^get_instance_field repr_names) (^repr_id $1) ptr_sz) ptr_sz))

(template: eqaddr (flagval (eq $1 $2)))

(template: bindattr_i
  (callv (^func &MVM_repr_bind_attr_inso)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 ptr)
      (carg (^cu_string $2) ptr)
      (carg $4 int)
      (carg $3 ptr)
      (carg (^reg_int) int))))

(template: bindattr_u
  (callv (^func &MVM_repr_bind_attr_inso)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 ptr)
      (carg (^cu_string $2) ptr)
      (carg $4 int)
      (carg $3 ptr)
      (carg (^reg_uint) int))))

(template: bindattr_n
  (callv (^func &MVM_repr_bind_attr_inso)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 ptr)
      (carg (^cu_string $2) ptr)
      (carg $4 int)
      (carg $3 ptr)
      (carg (^reg_num) int))))

(template: bindattr_s
  (callv (^func &MVM_repr_bind_attr_inso)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 ptr)
      (carg (^cu_string $2) ptr)
      (carg $4 int)
      (carg $3 ptr)
      (carg (^reg_str) int))))

(template: bindattr_o
  (callv (^func &MVM_repr_bind_attr_inso)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 ptr)
      (carg (^cu_string $2) ptr)
      (carg $4 int)
      (carg $3 ptr)
      (carg (^reg_obj) int))))

(template: bindattrs_i
  (callv (^func &MVM_repr_bind_attr_inso)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg (const -1 int_sz) int)
      (carg $3 ptr)
      (carg (^reg_int) int))))

(template: bindattrs_n
  (callv (^func &MVM_repr_bind_attr_inso)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg (const -1 int_sz) int)
      (carg $3 ptr)
      (carg (^reg_num) int))))

(template: bindattrs_s
  (callv (^func &MVM_repr_bind_attr_inso)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg (const -1 int_sz) int)
      (carg $3 ptr)
      (carg (^reg_str) int))))

(template: bindattrs_o
  (callv (^func &MVM_repr_bind_attr_inso)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg (const -1 int_sz) int)
      (carg $3 ptr)
      (carg (^reg_obj) int))))

(template: getattr_i
  (call (^func &MVM_repr_get_attr_i)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg (^cu_string $3) ptr)
      (carg $4 int)) int_sz))

(template: getattr_u
  (call (^func &MVM_repr_get_attr_u)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg (^cu_string $3) ptr)
      (carg $4 int)) int_sz))

(template: getattr_n
  (calln (^func &MVM_repr_get_attr_n)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg (^cu_string $3) ptr)
      (carg $4 int))))

(template: getattr_s
  (call (^func &MVM_repr_get_attr_s)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg (^cu_string $3) ptr)
      (carg $4 int)) ptr_sz))

(template: getattr_o
  (call (^func &MVM_repr_get_attr_o)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg (^cu_string $3) ptr)
      (carg $4 int)) ptr_sz))

(template: getattrs_i
  (call (^func &MVM_repr_get_attr_i)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 ptr)
      (carg (const -1 int_sz) int)) int_sz))

(template: getattrs_u
  (call (^func &MVM_repr_get_attr_u)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 ptr)
      (carg (const -1 int_sz) int)) int_sz))

(template: getattrs_n
  (calln (^func &MVM_repr_get_attr_n)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 ptr)
      (carg (const -1 int_sz) int))))

(template: getattrs_s
  (call (^func &MVM_repr_get_attr_s)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 ptr)
      (carg (const -1 int_sz) int)) ptr_sz))

(template: getattrs_o
  (call (^func &MVM_repr_get_attr_o)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 ptr)
      (carg (const -1 int_sz) int)) ptr_sz))

(template: attrinited
  (call (^func &MVM_repr_attribute_inited)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 ptr)) ptr_sz))

(template: box_i
  (call (^func &MVM_repr_box_int)
    (arglist
      (carg (tc) ptr)
      (carg $2 ptr)
      (carg $1 int)) ptr_sz))

(template: box_u
  (call (^func &MVM_repr_box_uint)
    (arglist
      (carg (tc) ptr)
      (carg $2 ptr)
      (carg $1 int)) ptr_sz))

(template: box_s
  (call (^func &MVM_repr_box_str)
    (arglist
      (carg (tc) ptr)
      (carg $2 ptr)
      (carg $1 ptr)) ptr_sz))

(template: unbox_s
  (call (^func &MVM_repr_get_str)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: unbox_i
  (call (^getf (^repr $1) MVMREPROps box_funcs.get_int)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)) int_sz))

(template: unbox_u
  (call (^getf (^repr $1) MVMREPROps box_funcs.get_uint)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)) int_sz))

(template: atpos_i!
  (callv (^getf (^repr $1) MVMREPROps pos_funcs.at_pos)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg $2 int)
      (carg \$0 ptr)
      (carg (^reg_int) int))))

(template: atpos_u!
  (callv (^getf (^repr $1) MVMREPROps pos_funcs.at_pos)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg $2 int)
      (carg \$0 ptr)
      (carg (^reg_uint) int))))

(template: atpos_n!
  (callv (^getf (^repr $1) MVMREPROps pos_funcs.at_pos)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg $2 int)
      (carg \$0 ptr)
      (carg (^reg_num) int))))

(template: atpos_s!
  (callv (^getf (^repr $1) MVMREPROps pos_funcs.at_pos)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg $2 int)
      (carg \$0 ptr)
      (carg (^reg_str) int))))

#  REPR(obj)->pos_funcs.at_pos(tc, STABLE(obj), obj,
#       OBJECT_BODY(obj), GET_REG(cur_op, 4).i64,
#       &GET_REG(cur_op, 0), MVM_reg_obj);
(template: atpos_o!
  (ifv (^is_type_obj $1)
    (store \$0 (^vmnull) ptr_sz)
    (callv (^getf (^repr $1) MVMREPROps pos_funcs.at_pos)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $1) ptr)
        (carg $1 ptr)
        (carg (^body $1) ptr)
        (carg $2 int)
        (carg \$0 ptr)
        (carg (^reg_obj) int)))))

(template: bindpos_i
  (dov
    (callv (^getf (^repr $0) MVMREPROps pos_funcs.bind_pos)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $0) ptr)
        (carg $0 ptr)
        (carg (^body $0) ptr)
        (carg $1 ptr)
        (carg $2 ptr)
        (carg (^reg_int) int)))
    (callv (^func &MVM_SC_WB_OBJ)
      (arglist
        (carg (tc) ptr)
        (carg $0 ptr)))))

(template: bindpos_u
  (dov
    (callv (^getf (^repr $0) MVMREPROps pos_funcs.bind_pos)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $0) ptr)
        (carg $0 ptr)
        (carg (^body $0) ptr)
        (carg $1 ptr)
        (carg $2 ptr)
        (carg (^reg_uint) int)))
    (callv (^func &MVM_SC_WB_OBJ)
      (arglist
        (carg (tc) ptr)
        (carg $0 ptr)))))

(template: bindpos_n
  (dov
    (callv (^getf (^repr $0) MVMREPROps pos_funcs.bind_pos)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $0) ptr)
        (carg $0 ptr)
        (carg (^body $0) ptr)
        (carg $1 ptr)
        (carg $2 ptr)
        (carg (^reg_num) int)))
    (callv (^func &MVM_SC_WB_OBJ)
      (arglist
        (carg (tc) ptr)
        (carg $0 ptr)))))

(template: bindpos_s
  (dov
    (callv (^getf (^repr $0) MVMREPROps pos_funcs.bind_pos)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $0) ptr)
        (carg $0 ptr)
        (carg (^body $0) ptr)
        (carg $1 ptr)
        (carg $2 ptr)
        (carg (^reg_str) int)))
    (callv (^func &MVM_SC_WB_OBJ)
      (arglist
        (carg (tc) ptr)
        (carg $0 ptr)))))

(template: bindpos_o
  (dov
    (callv (^getf (^repr $0) MVMREPROps pos_funcs.bind_pos)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $0) ptr)
        (carg $0 ptr)
        (carg (^body $0) ptr)
        (carg $1 ptr)
        (carg $2 ptr)
        (carg (^reg_obj) int)))
    (callv (^func &MVM_SC_WB_OBJ)
      (arglist
        (carg (tc) ptr)
        (carg $0 ptr)))))

(template: push_i
  (dov
    (callv (^getf (^repr $0) MVMREPROps pos_funcs.push)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $0) ptr)
        (carg $0 ptr)
        (carg (^body $0) ptr)
        (carg $1 ptr)
        (carg (^reg_int) int)))
    (callv (^func &MVM_SC_WB_OBJ)
      (arglist
        (carg (tc) ptr)
        (carg $0 ptr)))))

(template: push_n
  (dov
    (callv (^getf (^repr $0) MVMREPROps pos_funcs.push)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $0) ptr)
        (carg $0 ptr)
        (carg (^body $0) ptr)
        (carg $1 ptr)
        (carg (^reg_num) int)))
    (callv (^func &MVM_SC_WB_OBJ)
      (arglist
        (carg (tc) ptr)
        (carg $0 ptr)))))

(template: push_s
  (dov
    (callv (^getf (^repr $0) MVMREPROps pos_funcs.push)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $0) ptr)
        (carg $0 ptr)
        (carg (^body $0) ptr)
        (carg $1 ptr)
        (carg (^reg_str) int)))
    (callv (^func &MVM_SC_WB_OBJ)
      (arglist
        (carg (tc) ptr)
        (carg $0 ptr)))))

(template: push_o
  (dov
    (callv (^getf (^repr $0) MVMREPROps pos_funcs.push)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $0) ptr)
        (carg $0 ptr)
        (carg (^body $0) ptr)
        (carg $1 ptr)
        (carg (^reg_obj) int)))
    (callv (^func &MVM_SC_WB_OBJ)
      (arglist
        (carg (tc) ptr)
        (carg $0 ptr)))))

(template: pop_i!
  (callv (^getf (^repr $1) MVMREPROps pos_funcs.pop)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg \$0 ptr)
      (carg (^reg_int) int))))

(template: pop_n!
  (callv (^getf (^repr $1) MVMREPROps pos_funcs.pop)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg \$0 ptr)
      (carg (^reg_num) int))))

(template: pop_s!
  (callv (^getf (^repr $1) MVMREPROps pos_funcs.pop)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg \$0 ptr)
      (carg (^reg_str) int))))

(template: pop_o!
  (callv (^getf (^repr $1) MVMREPROps pos_funcs.pop)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg \$0 ptr)
      (carg (^reg_obj) int))))

(template: shift_i!
  (callv (^getf (^repr $1) MVMREPROps pos_funcs.shift)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg \$0 ptr)
      (carg (^reg_int) int))))

(template: shift_n!
  (callv (^getf (^repr $1) MVMREPROps pos_funcs.shift)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg \$0 ptr)
      (carg (^reg_num) int))))

(template: shift_s!
  (callv (^getf (^repr $1) MVMREPROps pos_funcs.shift)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg \$0 ptr)
      (carg (^reg_str) int))))

(template: shift_o!
  (callv (^getf (^repr $1) MVMREPROps pos_funcs.shift)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg \$0 ptr)
      (carg (^reg_obj) int))))

(template: unshift_i
  (callv (^getf (^repr $0) MVMREPROps pos_funcs.unshift)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $0) ptr)
      (carg $0 ptr)
      (carg (^body $0) ptr)
      (carg $1 ptr)
      (carg (^reg_int) int))))

(template: unshift_n
  (callv (^getf (^repr $0) MVMREPROps pos_funcs.unshift)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $0) ptr)
      (carg $0 ptr)
      (carg (^body $0) ptr)
      (carg $1 ptr)
      (carg (^reg_num) int))))

(template: unshift_s
  (callv (^getf (^repr $0) MVMREPROps pos_funcs.unshift)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $0) ptr)
      (carg $0 ptr)
      (carg (^body $0) ptr)
      (carg $1 ptr)
      (carg (^reg_str) int))))

(template: unshift_o
  (callv (^getf (^repr $0) MVMREPROps pos_funcs.unshift)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $0) ptr)
      (carg $0 ptr)
      (carg (^body $0) ptr)
      (carg $1 ptr)
      (carg (^reg_obj) int))))


(template: splice
  (callv (^getf (^repr $0) MVMREPROps pos_funcs.splice)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $0) ptr)
      (carg $0 ptr)
      (carg (^body $0) ptr)
      (carg $1 ptr)
      (carg $2 int)
      (carg $3 int))))

(template: setelemspos
  (callv (^getf (^repr $0) MVMREPROps pos_funcs.set_elems)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $0) ptr)
      (carg $0 ptr)
      (carg (^body $0) ptr)
      (carg $1 int))))

(template: existspos
  (call (^func &MVM_repr_exists_pos)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   int)) int_sz))

(template: atkey_i!
  (callv (^getf (^repr $1) MVMREPROps ass_funcs.at_key)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg $2 ptr)
      (carg \$0 ptr)
      (carg (^reg_int) int))))


(template: atkey_n!
  (callv (^getf (^repr $1) MVMREPROps ass_funcs.at_key)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg $2 ptr)
      (carg \$0 ptr)
      (carg (^reg_num) int))))

(template: atkey_s!
  (callv (^getf (^repr $1) MVMREPROps ass_funcs.at_key)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg $2 ptr)
      (carg \$0 ptr)
      (carg (^reg_str) int))))

#  REPR(obj)->ass_funcs.at_key(tc, STABLE(obj), obj, OBJECT_BODY(obj),
#       (MVMObject *)GET_REG(cur_op, 4).s, &GET_REG(cur_op, 0), MVM_reg_obj);
(template: atkey_o!
  (ifv (^is_type_obj $1)
    (store \$0 (^vmnull) ptr_sz)
    (callv (^getf (^repr $1) MVMREPROps ass_funcs.at_key)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $1) ptr)
        (carg $1 ptr)
        (carg (^body $1) ptr)
        (carg $2 ptr)
        (carg \$0 ptr)
        (carg (^reg_obj) int)))))

(template: bindkey_i
  (dov
    (callv (^getf (^repr $0) MVMREPROps ass_funcs.bind_key)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $0) ptr)
        (carg $0 ptr)
        (carg (^body $0) ptr)
        (carg $1 ptr)
        (carg $2 ptr)
        (carg (^reg_int) int)))
    (callv (^func &MVM_SC_WB_OBJ)
      (arglist
        (carg (tc) ptr)
        (carg $0 ptr)))))

(template: bindkey_n
  (dov
    (callv (^getf (^repr $0) MVMREPROps ass_funcs.bind_key)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $0) ptr)
        (carg $0 ptr)
        (carg (^body $0) ptr)
        (carg $1 ptr)
        (carg $2 ptr)
        (carg (^reg_num) int)))
    (callv (^func &MVM_SC_WB_OBJ)
      (arglist
        (carg (tc) ptr)
        (carg $0 ptr)))))

(template: bindkey_s
  (dov
    (callv (^getf (^repr $0) MVMREPROps ass_funcs.bind_key)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $0) ptr)
        (carg $0 ptr)
        (carg (^body $0) ptr)
        (carg $1 ptr)
        (carg $2 ptr)
        (carg (^reg_str) int)))
    (callv (^func &MVM_SC_WB_OBJ)
      (arglist
        (carg (tc) ptr)
        (carg $0 ptr)))))

(template: bindkey_o
  (dov
    (callv (^getf (^repr $0) MVMREPROps ass_funcs.bind_key)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $0) ptr)
        (carg $0 ptr)
        (carg (^body $0) ptr)
        (carg $1 ptr)
        (carg $2 ptr)
        (carg (^reg_obj) int)))
    (callv (^func &MVM_SC_WB_OBJ)
      (arglist
        (carg (tc) ptr)
        (carg $0 ptr)))))

(template: existskey
  (call (^getf (^repr $1) MVMREPROps ass_funcs.exists_key)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg $2 ptr)) int_sz))

#  GET_REG(cur_op, 0).i64 = (MVMint64)REPR(obj)->elems(tc, STABLE(obj), obj, OBJECT_BODY(obj));
(template: elems
  (call (^getf (^repr $1) MVMREPROps elems)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)) int_sz))

(template: knowhow     (^get_instance_field KnowHOW))
(template: knowhowattr (^get_instance_field KnowHOWAttribute))

(template: newtype
  (let: (($repr (call (^func &MVM_repr_get_by_name)
                  (arglist
                    (carg (tc) ptr)
                    (carg $2   ptr)) ptr_sz)))
    (call (^getf $repr MVMREPROps type_object_for)
      (arglist
        (carg (tc) ptr)
        (carg $1   ptr)) ptr_sz)))

(template: composetype
  (do
    (callv (^getf (^repr $1) MVMREPROps compose)
      (arglist
        (carg (tc)         ptr)
        (carg (^stable $1) ptr)
        (carg $2           ptr)))
    (copy $1)))

(template: bootint      (^get_instance_field boot_types.BOOTInt))
(template: bootnum      (^get_instance_field boot_types.BOOTNum))
(template: bootstr      (^get_instance_field boot_types.BOOTStr))
(template: bootarray    (^get_instance_field boot_types.BOOTArray))
(template: bootintarray (^get_instance_field boot_types.BOOTIntArray))
(template: bootnumarray (^get_instance_field boot_types.BOOTNumArray))
(template: bootstrarray (^get_instance_field boot_types.BOOTStrArray))
(template: boothash     (^get_instance_field boot_types.BOOTHash))

(template: isint
  (if (all
        (nz $1)
        (^is_repr_id $1 MVM_REPR_ID_P6int))
    (^one)
    (^zero)))

(template: isnum
  (if (all
        (nz $1)
        (^is_repr_id $1 MVM_REPR_ID_P6num))
    (^one)
    (^zero)))

(template: isstr
  (if (all
        (nz $1)
        (^is_repr_id $1 MVM_REPR_ID_P6str))
    (^one)
    (^zero)))

(template: islist
  (if (all
        (nz $1)
        (^is_repr_id $1 MVM_REPR_ID_VMArray))
    (^one)
    (^zero)))

(template: ishash
  (if (all
        (nz $1)
        (^is_repr_id $1 MVM_REPR_ID_MVMHash))
    (^one)
    (^zero)))

(template: hllboxtype_i
  (^getf (^hllconfig) MVMHLLConfig int_box_type))

(template: hllboxtype_n
  (^getf (^hllconfig) MVMHLLConfig num_box_type))

(template: hllboxtype_s
  (^getf (^hllconfig) MVMHLLConfig str_box_type))

(template: hlllist
  (^getf (^hllconfig) MVMHLLConfig slurpy_array_type))

(template: hllhash
  (^getf (^hllconfig) MVMHLLConfig slurpy_hash_type))

(template: getcomp!
  (dov
    (callv (^func &uv_mutex_lock)
      (arglist
        (carg (^addrf (^getf (tc) MVMThreadContext instance) MVMInstance mutex_compiler_registry) ptr)))
    (store \$0 (call (^func &MVM_repr_at_key_o)
                 (arglist
                   (carg (tc) ptr)
                   (carg (^get_instance_field compiler_registry) ptr)
                   (carg $1 ptr)) ptr_sz) ptr_sz)
    (callv (^func &uv_mutex_unlock)
      (arglist
        (carg (^addrf (^getf (tc) MVMThreadContext instance) MVMInstance mutex_compiler_registry) ptr)))))

(template: gethllsym
  (call (^func &MVM_hll_sym_get)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)) ptr_sz))

(template: settypehll
  (^setf (^stable $0) MVMSTable hll_owner
    (call (^func &MVM_hll_get_config_for)
      (arglist
        (carg (tc) ptr)
        (carg $1 ptr)) ptr_sz)))

(template: settypehllrole
  (^setf (^stable $0) MVMSTable hll_role $1))

(template: iter
  (call (^func &MVM_iter)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: iterkey_s
  (call (^func &MVM_iterkey_s)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: iterval
  (call (^func &MVM_iterval)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: getcodename
  (do
    (when (any
           (^is_type_obj $1)
           (^not_repr_id $1 MVM_REPR_ID_MVMCode))
      (^throw_adhoc "getcodename requires a concrete code object"))
    (^getf $1 MVMCode body.name)))

(template: iscoderef
  (call (^func &MVM_code_iscode)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) int_sz))

(template: getcodeobj
  (call (^func &MVM_frame_get_code_object)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: markcodestatic
  (ifv (all
         (^is_conc_obj $0)
         (^is_repr_id $0 MVM_REPR_ID_MVMCode))
    (^setf $0 MVMCode body.is_static (const 1 int_sz))
    (^throw_adhoc "markcodestatic requires a concrete coderef")))

(template: markcodestub
  (ifv (all
         (^is_conc_obj $0)
         (^is_repr_id $0 MVM_REPR_ID_MVMCode))
    (^setf $0 MVMCode body.is_compiler_stub (const 1 int_sz))
    (^throw_adhoc "markcodestub requires a concrete coderef")))

(template: iscont
  (if
    (any (^is_vmnull $1) (zr (^getf (^stable $1) MVMSTable container_spec)))
    (^zero)
    (^one)))

(template: decont!
  (ifv (any
         (^is_type_obj $1)
         (zr (^getf (^stable $1) MVMSTable container_spec)))
    (store \$0 $1 ptr_sz)
    (callv (^stable_cont_func $1 fetch)
      (arglist
        (carg (tc) ptr)
        (carg $1 ptr)
        (carg \$0 ptr)))))

(template: sha1
  (call (^func &MVM_sha1)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) ptr_sz))

(template: createsc
  (call (^func &MVM_sc_create)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) ptr_sz))

(template: scsetobj
  (callv (^func &MVM_sc_set_object_op)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 int)
      (carg $2 ptr))))

(template: scsetcode
  (callv (^func &MVM_sc_set_code_op)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 int)
      (carg $2 ptr))))

(template: getobjsc
  (call (^func &MVM_sc_get_obj_sc)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) ptr_sz))

(template: wval
  (call (^func MVM_sc_get_sc_object)
    (arglist
      (carg (tc) ptr)
      (carg (cu) ptr)
      (carg $1 int)
      (carg $2 int)) ptr_sz))

(template: newmixintype
  (let: (($repr (call (^func &MVM_repr_get_by_name)
                  (arglist
                    (carg (tc) ptr)
                    (carg $2   ptr)) ptr_sz)))
    (let: (($type (call (^getf $repr MVMREPROps type_object_for)
                    (arglist
                      (carg (tc) ptr)
                      (carg $1   ptr)) ptr_sz)))
      (do
        (^setf $type MVMSTable is_mixin_type (const 1 int_sz))
        (load $type ptr_sz)))))

(template: iscompunit
  (flagval
    (^is_repr_id $1 MVM_REPR_ID_MVMCompUnit)))

(template: ctx
  (call (^func &MVM_context_from_frame)
    (arglist
      (carg (tc)     ptr)
      (carg (^frame) ptr)) ptr_sz))

(template: curcode
  (^getf (^frame) MVMFrame code_ref))

(template: callercode
  (call (^func &MVM_frame_caller_code)
    (arglist
      (carg (tc) ptr)) ptr_sz))

(template: add_I
  (call (^func &MVM_bigint_add)
    (arglist
      (carg (tc) ptr)
      (carg $3   ptr)
      (carg $1   ptr)
      (carg $2   ptr)) ptr_sz))

(template: sub_I
  (call (^func &MVM_bigint_sub)
    (arglist
      (carg (tc) ptr)
      (carg $3   ptr)
      (carg $1   ptr)
      (carg $2   ptr)) ptr_sz))

(template: mul_I
  (call (^func &MVM_bigint_mul)
    (arglist
      (carg (tc) ptr)
      (carg $3   ptr)
      (carg $1   ptr)
      (carg $2   ptr)) ptr_sz))

(template: div_I
  (call (^func &MVM_bigint_div)
    (arglist
      (carg (tc) ptr)
      (carg $3   ptr)
      (carg $1   ptr)
      (carg $2   ptr)) ptr_sz))

(template: mod_I
  (call (^func &MVM_bigint_mod)
    (arglist
      (carg (tc) ptr)
      (carg $3   ptr)
      (carg $1   ptr)
      (carg $2   ptr)) ptr_sz))

(template: neg_I
  (call (^func &MVM_bigint_neg)
    (arglist
      (carg (tc) ptr)
      (carg $2   ptr)
      (carg $1   ptr)) ptr_sz))

(template: abs_I
  (call (^func &MVM_bigint_abs)
    (arglist
      (carg (tc) ptr)
      (carg $2   ptr)
      (carg $1   ptr)) ptr_sz))

(template: cmp_I
  (call (^func &MVM_bigint_cmp)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)) int_sz))

(template: eq_I
  (flagval
    (zr
      (call (^func &MVM_bigint_cmp)
        (arglist
          (carg (tc) ptr)
          (carg $1   ptr)
          (carg $2   ptr)) int_sz))))

(template: ne_I
  (flagval
    (nz
      (call (^func &MVM_bigint_cmp)
        (arglist
          (carg (tc) ptr)
          (carg $1   ptr)
          (carg $2   ptr)) int_sz))))

(template: lt_I
  (flagval
    (eq
      (const (&QUOTE MP_LT) int_sz)
      (call (^func &MVM_bigint_cmp)
        (arglist
          (carg (tc) ptr)
          (carg $1   ptr)
          (carg $2   ptr)) int_sz))))

(template: le_I
  (flagval
    (ne
      (const (&QUOTE MP_GT) int_sz)
      (call (^func &MVM_bigint_cmp)
        (arglist
          (carg (tc) ptr)
          (carg $1   ptr)
          (carg $2   ptr)) int_sz))))

(template: gt_I
  (flagval
    (eq
      (const (&QUOTE MP_GT) int_sz)
      (call (^func &MVM_bigint_cmp)
        (arglist
          (carg (tc) ptr)
          (carg $1   ptr)
          (carg $2   ptr)) int_sz))))

(template: ge_I
  (flagval
    (ne
      (const (&QUOTE MP_LT) int_sz)
      (call (^func &MVM_bigint_cmp)
        (arglist
          (carg (tc) ptr)
          (carg $1   ptr)
          (carg $2   ptr)) int_sz))))

(template: bor_I
  (call (^func &MVM_bigint_or)
    (arglist
      (carg (tc) ptr)
      (carg $3   ptr)
      (carg $1   ptr)
      (carg $2   ptr)) ptr_sz))

(template: bxor_I
  (call (^func &MVM_bigint_xor)
    (arglist
      (carg (tc) ptr)
      (carg $3   ptr)
      (carg $1   ptr)
      (carg $2   ptr)) ptr_sz))

(template: band_I
  (call (^func &MVM_bigint_and)
    (arglist
      (carg (tc) ptr)
      (carg $3   ptr)
      (carg $1   ptr)
      (carg $2   ptr)) ptr_sz))

(template: bnot_I
  (call (^func &MVM_bigint_not)
    (arglist
      (carg (tc) ptr)
      (carg $2   ptr)
      (carg $1   ptr)) ptr_sz))

(template: blshift_I
  (call (^func &MVM_bigint_shl)
    (arglist
      (carg (tc) ptr)
      (carg $3   ptr)
      (carg $1   ptr)
      (carg $2   int)) ptr_sz))

(template: brshift_I
  (call (^func &MVM_bigint_shr)
    (arglist
      (carg (tc) ptr)
      (carg $3   ptr)
      (carg $1   ptr)
      (carg $2   int)) ptr_sz))

(template: pow_I
  (call (^func &MVM_bigint_pow)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)
      (carg $3   ptr)
      (carg $4   ptr)) ptr_sz))

(template: gcd_I
  (call (^func &MVM_bigint_gcd)
    (arglist
      (carg (tc) ptr)
      (carg $3   ptr)
      (carg $1   ptr)
      (carg $2   ptr)) ptr_sz))

(template: lcm_I
  (call (^func &MVM_bigint_lcm)
    (arglist
      (carg (tc) ptr)
      (carg $3   ptr)
      (carg $1   ptr)
      (carg $2   ptr)) ptr_sz))

(template: expmod_I
  (call (^func &MVM_bigint_expmod)
    (arglist
      (carg (tc) ptr)
      (carg $4   ptr)
      (carg $1   ptr)
      (carg $2   ptr)
      (carg $3   ptr)) ptr_sz))

(template: isprime_I
  (call (^func &MVM_bigint_is_prime)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) int_sz))

(template: rand_I
  (call (^func &MVM_bigint_rand)
    (arglist
      (carg (tc) ptr)
      (carg $2   ptr)
      (carg $1   ptr)) ptr_sz))

(template: coerce_In
  (calln (^func &MVM_bigint_to_num)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr))))

(template: coerce_Is
  (call (^func &MVM_bigint_to_str)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg (const 10 int_sz) int)) ptr_sz))

(template: coerce_sI
  (call (^func &MVM_coerce_sI)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)) ptr_sz))

(template: isbig_I
  (call (^func &MVM_bigint_is_big)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) int_sz))

(template: bool_I
  (call (^func &MVM_bigint_bool)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) int_sz))

(template: base_I
  (call (^func &MVM_bigint_to_str)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   int)) ptr_sz))

(template: radix_I
  (call (^func &MVM_bigint_radix)
    (arglist
      (carg (tc) ptr)
      (carg $1   int)
      (carg $2   ptr)
      (carg $3   int)
      (carg $4   int)
      (carg $5   ptr)) ptr_sz))

(template: connect_sk
  (callv (^func &MVM_io_connect)
    (arglist
      (carg (tc) ptr)
      (carg $0   ptr)
      (carg $1   ptr)
      (carg $2   int)
      (carg $3   int))))

(template: seek_fh
  (callv (^func &MVM_io_seek)
    (arglist
      (carg (tc) ptr)
      (carg $0   ptr)
      (carg $1   int)
      (carg $2   int))))

(template: socket
  (call (^func &MVM_io_socket_create)
    (arglist
      (carg (tc) ptr)
      (carg $1   int)) ptr_sz))

(template: bind_sk
  (callv (^func &MVM_io_bind)
    (arglist
      (carg (tc) ptr)
      (carg $0   ptr)
      (carg $1   ptr)
      (carg $2   int)
      (carg $3   int)
      (carg $4   int))))

(template: accept_sk
  (call (^func &MVM_io_accept)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) ptr_sz))

(template: print
  (callv (^func &MVM_string_print)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr))))

(template: say
  (callv (^func &MVM_string_say)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr))))

(template: tell_fh
  (call (^func &MVM_io_tell)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) int_sz))

(template: stat
  (call (^func &MVM_file_stat)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   int)
      (carg (^zero) int)) int_sz))

(template: rand_i
  (call (^func &MVM_proc_rand_i)
    (arglist
      (carg (tc) ptr)) int_sz))

(template: rand_n
  (calln (^func &MVM_proc_rand_n)
    (arglist
      (carg (tc) ptr))))

(template: getenvhash
  (call (^func &MVM_proc_getenvhash)
    (arglist
      (carg (tc) ptr)) ptr_sz))

(template: loadlib
  (callv (^func &MVM_dll_load)
    (arglist
      (carg (tc) ptr)
      (carg $0   ptr)
      (carg $1   ptr))))

(template: loadext
  (callv (^func &MVM_ext_load)
    (arglist
      (carg (tc) ptr)
      (carg $0   ptr)
      (carg $1   ptr))))

(template: backendconfig
  (call (^func &MVM_backend_config)
    (arglist
      (carg (tc) ptr)) ptr_sz))

(template: getlexouter
  (call (^func &MVM_frame_find_lexical_by_name_outer)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) ptr_sz))

(template: getlexcaller
  (let: (($res (call (^func &MVM_frame_find_lexical_by_name_rel_caller)
                 (arglist
                   (carg (tc) ptr)
                   (carg $1   ptr)
                   (carg (^getf (^frame) MVMFrame caller) ptr)) ptr_sz)))
    (if (nz $res)
      (load $res ptr_sz)
      (^vmnull))))

(template: bitand_s
  (call (^func &MVM_string_bitand)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)) ptr_sz))

(template: bitor_s
  (call (^func &MVM_string_bitor)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)) ptr_sz))

(template: bitxor_s
  (call (^func &MVM_string_bitxor)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)) ptr_sz))

(template: getpid
  (call (^func &MVM_proc_getpid)
    (arglist
      (carg (tc) ptr)) int_sz))

(template: replace
  (call (^func &MVM_string_replace)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   int)
      (carg $3   int)
      (carg $4   ptr)) ptr_sz))

(template: backtrace
  (call (^func &MVM_exception_backtrace)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: hintfor
  (call (^getf (^repr $1) MVMREPROps attr_funcs.hint_for)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg $2 ptr)) int_sz))

#(template: paramnamesused
#  (letv: (($ctx   (^addrf (^frame) MVMFrame params))
#         ($csite (^getf  $ctx MVMArgProcContext legacy.callsite)))
#    (when (ne (^getf $csite MVMCallsite num_pos) (^getf $csite MVMCallsite arg_count))
#      (callv (^func &MVM_args_assert_nameds_used)
#        (arglist
#          (carg (tc) ptr)
#          (carg $ctx ptr))))))

(template: getuniname
  (call (^func &MVM_unicode_get_name)
    (arglist
      (carg (tc) ptr)
      (carg $1 int)) ptr_sz))

(template: getuniprop_int
  (call (^func &MVM_unicode_codepoint_get_property_int)
    (arglist
      (carg (tc) ptr)
      (carg $1 int)
      (carg $2 int)) int_sz))

(template: getuniprop_bool
  (call (^func &MVM_unicode_codepoint_get_property_bool)
    (arglist
      (carg (tc) ptr)
      (carg $1 int)
      (carg $2 int)) int_sz))

(template: getuniprop_str
  (call (^func &MVM_unicode_codepoint_get_property_str)
    (arglist
      (carg (tc) ptr)
      (carg $1 int)
      (carg $2 int)) ptr_sz))

(template: matchuniprop
  (call (^func &MVM_unicode_codepoint_has_property_value)
    (arglist
      (carg (tc) ptr)
      (carg $1 int)
      (carg $2 int)
      (carg $3 int)) ptr_sz))

(template: nativecallbuild
  (call (^func &MVM_nativecall_build)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 ptr)
      (carg $4 ptr)
      (carg $5 ptr)
      (carg $6 ptr)) int_sz))

(template: nativecallinvoke
  (call (^func &MVM_nativecall_invoke)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 ptr)) ptr_sz))

# XXX check this
(template: nativecallrefresh
  (callv (^func &MVM_nativecall_refresh)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr))))

# XXX check this
(template: threadrun
  (callv (^func &MVM_thread_run)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr))))

(template: threadid
  (call (^func &MVM_thread_id)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) int_sz))

(template: threadyield
  (callv (^func &MVM_thread_yield)
    (arglist
      (carg (tc) ptr))))

(template: currentthread
  (call (^func &MVM_thread_current)
    (arglist
      (carg (tc) ptr)) ptr_sz))

(template: lock
  (callv (^func &MVM_reentrantmutex_lock_checked)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr))))

(template: unlock
  (callv (^func &MVM_reentrantmutex_unlock_checked)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr))))

(template: timer
  (call (^func &MVM_io_timer_create)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 int)
      (carg $4 int)
      (carg $5 ptr)) ptr_sz))

(template: cancel
  (callv (^func &MVM_io_eventloop_cancel_work)
    (arglist
      (carg (tc) ptr)
      (carg $0   ptr)
      (carg (^nullptr) ptr)
      (carg (^nullptr) ptr))))

(template: signal
  (call (^func &MVM_io_signal_handle)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)
      (carg $3   int)
      (carg $4   ptr)) ptr_sz))

(template: watchfile
  (call (^func &MVM_io_file_watch)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)
      (carg $3   ptr)
      (carg $4   ptr)) ptr_sz))

(template: asyncconnect
  (call (^func &MVM_io_socket_connect_async)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)
      (carg $3   ptr)
      (carg $4   int)
      (carg $5   ptr)) ptr_sz))

(template: asynclisten
  (call (^func &MVM_io_socket_listen_async)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)
      (carg $3   ptr)
      (carg $4   int)
      (carg $5   int)
      (carg $6   ptr)) ptr_sz))

(template: asyncwritebytes
  (call (^func &MVM_io_write_bytes_async)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)
      (carg $3   ptr)
      (carg $4   ptr)
      (carg $5   ptr)) ptr_sz))

(template: asyncreadbytes
  (call (^func &MVM_io_read_bytes_async)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)
      (carg $3   ptr)
      (carg $4   ptr)
      (carg $5   ptr)) ptr_sz))

(template: getlexperinvtype_o
  (let: (($found (call (^func &MVM_frame_find_lexical_by_name)
                   (arglist
                     (carg (tc) ptr)
                     (carg $1   ptr)
                     (carg (^reg_obj) int)) ptr_sz)))
    (if (nz $found) (load $found ptr_sz) (^vmnull))))

(template: execname
  (call (^func &MVM_executable_name)
    (arglist
      (carg (tc) ptr)) ptr_sz))

(template: const_i64_16 (copy $1))
(template: const_i64_32 (copy $1))

(template: isnonnull
  (and
    (flagval (nz $1))
    (flagval (ne $1 (^vmnull)))))

(template: settypefinalize
  (callv (^func &MVM_gc_finalize_set)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 int))))

(template: setparameterizer
  (callv (^func &MVM_6model_parametric_setup)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 ptr))))

(template: parameterizetype!
  (callv (^func &MVM_6model_parametric_parameterize)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg \$0 ptr))))

(template: typeparameterized
  (call (^func &MVM_6model_parametric_type_parameterized)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: typeparameterat
  (call (^func &MVM_6model_parametric_type_parameter_at)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 int)) ptr_sz))

(template: lstat
  (call (^func &MVM_file_stat)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   int)
      (carg (^one) int)) int_sz))

(template: iscont_i
  (call (^func MVM_6model_container_iscont_i)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) int_sz))

(template: iscont_n
  (call (^func MVM_6model_container_iscont_n)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) int_sz))

(template: iscont_s
  (call (^func MVM_6model_container_iscont_s)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) int_sz))

(template: iscont_u
  (call (^func MVM_6model_container_iscont_u)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) int_sz))

(template: decont_s!
  (callv (^func &MVM_6model_container_decont_s)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg \$0 ptr))))

(template: getrusage
  (callv (^func &MVM_proc_getrusage)
    (arglist
      (carg (tc) ptr)
      (carg $0   ptr))))

(template: threadlockcount
  (call (^func &MVM_thread_lock_count)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) int_sz))

(template: strfromcodes
  (call (^func &MVM_unicode_codepoints_to_nfg_string)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: eqatim_s
  (call (^func &MVM_string_equal_at_ignore_mark)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 int)) int_sz))

(template: ordbaseat
  (scast
    (call (^func &MVM_string_ord_basechar_at)
      (arglist
        (carg (tc) ptr)
        (carg $1 ptr)
        (carg $2 int)) int_sz) int_sz 4))

(template: isrwcont
  (if
    (^is_vmnull $1)
    (^zero)
    (let: (($cs (^getf (^stable $1) MVMSTable container_spec)))
      (if
        (nz $cs)
        (call (^getf $cs MVMContainerSpec can_store)
          (arglist
            (carg (tc) ptr)
            (carg $1 ptr)) int_sz)
        (^zero)))))

(template: fc
  (call (^func &MVM_string_fc)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) ptr_sz))

(template: encoderep
  (call (^func &MVM_string_encode_to_buf)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $4 ptr)
      (carg $3 ptr)) ptr_sz))

(template: istty_fh
  (call (^func &MVM_io_is_tty)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) int_sz))

(template: fileno_fh
  (call (^func &MVM_io_fileno)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) int_sz))

(template: objprimbits
  (if
    (nz $1)
    (let: (($ss (^storage_spec $1)))
      (if
        (nz (^getf $ss MVMStorageSpec boxed_primitive))
        (^getf_ucast $ss MVMStorageSpec bits int_sz)
        (^zero)))
    (^zero)))

(template: objprimunsigned
  (if
    (nz $1)
    (let: (($ss (^storage_spec $1)))
      (if
        (nz (^getf $ss MVMStorageSpec boxed_primitive))
        (^getf_ucast $ss MVMStorageSpec is_unsigned int_sz)
        (^zero)))
    (^zero)))

(template: coerce_iu  (copy $1))

(template: coerce_ui  (copy $1))

(template: decont_u!
  (callv (^func &MVM_6model_container_decont_u)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg \$0 ptr))))

(template: setdebugtypename
  (callv (^func &MVM_6model_set_debug_name)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr)
      (carg $1 ptr))))

(template: lastexpayload
  (^getf (tc) MVMThreadContext last_payload))

(template: decoderaddbytes
  (dov
    (^decoder_ensure_decoder $0 "decoderaddbytes")
    (callv (^func &MVM_decoder_add_bytes)
      (arglist
        (carg (tc) ptr)
        (carg $0 ptr)
        (carg $1 ptr)))))

(template: decodertakeline
  (do
    (^decoder_ensure_decoder $1 "decodertakeline")
    (call (^func &MVM_decoder_take_line)
      (arglist
        (carg (tc) ptr)
        (carg $1 ptr)
        (carg $2 int)
        (carg $3 int)) ptr_sz)))

(template: decodertakeallchars
  (do
    (^decoder_ensure_decoder $1 "decodertakeallchars")
    (call (^func &MVM_decoder_take_all_chars)
      (arglist
        (carg (tc) ptr)
        (carg $1 ptr)) ptr_sz)))

(template: decodertakebytes
  (do
    (^decoder_ensure_decoder $1 "decodertakebytes")
    (call (^func &MVM_decoder_take_bytes)
      (arglist
        (carg (tc) ptr)
        (carg $1 ptr)
        (carg $2 ptr)
        (carg $3 int)) ptr_sz)))

(template: decoderempty
  (do
    (^decoder_ensure_decoder $1 "decoderempty")
    (call (^func &MVM_decoder_empty)
      (arglist
        (carg (tc) ptr)
        (carg $1 ptr)) int_sz)))

(template: indexingoptimized
  (call (^func &MVM_string_indexing_optimized)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: unicmp_s
  (call (^func &MVM_unicode_string_compare)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 int)
      (carg $4 int)
      (carg $5 int)) int_sz))

(template: strfromname
  (call (^func &MVM_unicode_string_from_name)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)) ptr_sz))

(template: indexic_s
  (call (^func &MVM_string_index_ignore_case)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 int)) int_sz))

(template: getport_sk
  (call (^func &MVM_io_getport)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)) int_sz))

(template: eqaticim_s
  (call (^func &MVM_string_equal_at_ignore_case_ignore_mark)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 int)) int_sz))

(template: indexicim_s
  (call (^func &MVM_string_index_ignore_case_ignore_mark)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $3 int)) int_sz))

(template: encoderepconf
  (call (^func &MVM_string_encode_to_buf_config)
    (arglist
      (carg (tc) ptr)
      (carg $1 ptr)
      (carg $2 ptr)
      (carg $4 ptr)
      (carg $3 ptr)
      (carg $5 int_sz)) ptr_sz))

(template: encodeconf
  (call (^func &MVM_string_encode_to_buf_config)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)
      (carg $3   ptr)
      (carg (^nullptr) ptr)
      (carg $4   int)) ptr_sz))

(template: decodeconf
  (call (^func &MVM_string_decode_from_buf_config)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)
      (carg (^nullptr) ptr)
      (carg $3   int)) ptr_sz))

(template: decoderepconf
  (call (^func &MVM_string_decode_from_buf_config)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)
      (carg $3   ptr)
      (carg $4   int)) ptr_sz))

(template: getppid
  (call (^func &MVM_proc_getppid)
    (arglist
      (carg (tc) ptr)) int_sz))

(template: getsignals
  (call (^func &MVM_io_get_signals)
    (arglist
      (carg (tc) ptr)) ptr_sz))

(template: slice!
  (letv: (
    ($dest (call (^getf (^repr $1) MVMREPROps allocate)
      (arglist
        (carg (tc) ptr)
        (carg (^stable $1) ptr))
      ptr_sz))
    ($initialize (^getf (^repr $1) MVMREPROps initialize)))
    (dov
      (store \$0 $dest ptr_sz)
      (when (nz $initialize)
        (callv $initialize
          (arglist
            (carg (tc) ptr)
            (carg (^stable $dest) ptr)
            (carg $dest ptr)
            (carg (^body $dest) ptr))))
      (callv (^getf (^repr $1) MVMREPROps pos_funcs.slice)
        (arglist
          (carg (tc)         ptr)
          (carg (^stable $1) ptr)
          (carg $1           ptr)
          (carg (^body $1)   ptr)
          (carg $dest        ptr)
          (carg $2           int)
          (carg $3           int))))))

(template: atkey_u!
  (callv (^getf (^repr $1) MVMREPROps ass_funcs.at_key)
    (arglist
      (carg (tc) ptr)
      (carg (^stable $1) ptr)
      (carg $1 ptr)
      (carg (^body $1) ptr)
      (carg $2 ptr)
      (carg \$0 ptr)
      (carg (^reg_uint) int))))

(template: coerce_us
  (call (^func &MVM_coerce_u_s)
    (arglist
      (carg (tc) ptr)
      (carg $1   int)) ptr_sz))

(template: hllbool
  (let: (($hllconfig (^getf (cu) MVMCompUnit body.hll_config)))
  (if (nz $1)
    (^getf $hllconfig MVMHLLConfig true_value)
    (^getf $hllconfig MVMHLLConfig false_value))))

(template: hllboolfor
  (let: (($hllconfig (call (^func &MVM_hll_get_config_for)
                       (arglist
                         (carg (tc) ptr)
                         (carg $2   ptr)) ptr_sz)))
    (if (nz $1)
      (^getf $hllconfig MVMHLLConfig true_value)
      (^getf $hllconfig MVMHLLConfig false_value))))

(template: serializetobuf
  (call (^func &MVM_serialization_serialize)
    (arglist
      (carg (tc) ptr)
      (carg $1   ptr)
      (carg $2   ptr)
      (carg $3   ptr)) ptr_sz))

(template: sp_decont!
  (ifv (all
         (^is_conc_obj $1)
         (nz (^getf (^stable $1) MVMSTable container_spec)))
    (callv (^getf (^getf (^stable $1) MVMSTable container_spec) MVMContainerSpec fetch)
      (arglist
        (carg (tc) ptr)
        (carg $1 ptr)
        (carg \$0 ptr)))
    (store \$0 $1 ptr_sz)))

(template: sp_getspeshslot (^spesh_slot_value $1))

(template: sp_fastcreate!
  (letv: (($block (call (^func &MVM_gc_allocate_nursery)
                   (arglist
                     (carg (tc) ptr)
                     (carg $1 int)) ptr_sz)))
    (^setf $block MVMObject st (^spesh_slot_value $2))
    (^setf $block MVMObject header.size $1)
    (^setf $block MVMObject header.owner (^getf (tc) MVMThreadContext thread_id))
    (store \$0 $block ptr_sz)))

(template: sp_p6oget_o
  (let: (($val (load (add (^p6obody $1) $2) ptr_sz)))
    (if (nz $val)
      $val
      (^vmnull))))

(template: sp_p6ogetvt_o
  (let: (($addr (add (^p6obody $1) $2))
         ($val (load $addr ptr_sz)))
    (if (nz $val)
      $val
      (let: (($type (^spesh_slot_value $3)))
        (^store_write_barrier! $1 $addr $type)
        (copy $type)))))

(template: sp_p6oget_bi
  (let: (($bibody (add (^p6obody $1) $2) ptr_sz))
    (if (^bigint_is_smallint $bibody)
      (scast (^getf $bibody MVMP6bigintBody u.smallint.value) int_sz 4)
      (call (^func MVM_p6bigint_get_int64)
        (arglist
          (carg (tc) ptr)
          (carg $bibody ptr)) int_sz))))

(template: sp_p6oget_i (load (add (^p6obody $1) $2) int_sz))
(template: sp_p6oget_n (load_num (add (^p6obody $1) $2) num_sz))
(template: sp_p6oget_s (load (add (^p6obody $1) $2) ptr_sz))

(template: sp_p6obind_o
  (^store_write_barrier! $0 (add (^p6obody $0) $1) $2))

(template: sp_p6obind_i (store (add (^p6obody $0) $1) $2 int_sz))
(template: sp_p6obind_n (store (add (^p6obody $0) $1) $2 num_sz))
(template: sp_p6obind_s
  (^store_write_barrier! $0 (add (^p6obody $0) $1) $2))

(template: sp_get_o
  (let: (($obj (load (add $1 $2) ptr_sz)))
    (if (nz $obj)
      $obj
      (^vmnull))))

#(template: sp_get_i64 (load (add $1 $2) int_sz))
#(template: sp_get_i32 (load (add $1 $2) 4))
#(template: sp_get_i16 (load (add $1 $2) 2))
#(template: sp_get_i8  (load (add $1 $2) 1))

(template: sp_bind_o
  (^store_write_barrier! $0 (add $0 $1) $2))

(macro: ^deopt_one (,deopt_idx)
  (dov (callv (^func MVM_spesh_deopt_one) (arglist (carg (tc) ptr) (carg ,deopt_idx int))) (^exit)))

# Optimization guards
(template: sp_guard
  (let: (($check (copy $1)))
    (when (any (zr $check) (ne (^stable $check) (^spesh_slot_value $2)))
       (^deopt_one $3))
    (copy $check)))

(template: sp_guardconc
  (let: (($check (copy $1)))
    (when (any (zr $check) (^is_type_obj $check) (ne (^stable $check) (^spesh_slot_value $2)))
       (^deopt_one $3))
    (copy $check)))

(template: sp_guardtype
  (let: (($check (copy $1)))
     (when (any (zr $check) (^is_conc_obj $check) (ne (^stable $check) (^spesh_slot_value $2)))
       (^deopt_one $3))
     (copy $check)))

(template: sp_guardsf
  (letv: (($check (copy $0)))
    (when (ne (^getf $check MVMCode body.sf) (^spesh_slot_value $1))
         (^deopt_one $2))))

(template: sp_guardsfouter
  (letv: (($check (copy $0)))
    (when (any (ne (^getf $check MVMCode body.sf) (^spesh_slot_value $1))
               (ne (^getf $check MVMCode body.outer) (^frame)))
         (^deopt_one $2))))

(template: sp_guardobj
  (let: (($check (copy $1)))
     (when (ne $check (^spesh_slot_value $2))
       (^deopt_one $3))
     (copy $check)))

(template: sp_guardnotobj
  (let: (($check (copy $1)))
     (when (eq $check (^spesh_slot_value $2))
       (^deopt_one $3))
     (copy $check)))

(template: sp_guardjustconc
  (let: (($check (copy $1)))
    (when (^is_type_obj $check)
      (^deopt_one $2))
    (copy $check)))

(template: sp_guardjusttype
  (let: (($check (copy $1)))
    (when (^is_conc_obj $check)
      (^deopt_one $2))
    (copy $check)))


# MVMCompUnit *dep = (MVMCompUnit *)tc->cur_frame->effective_spesh_slots[GET_UI16(cur_op, 2)];
# MVMuint16 idx = GET_UI32(cur_op, 4);
# GET_REG(cur_op, 0).s = MVM_cu_string(tc, dep, idx);
(template: sp_getstringfrom
  (^indirect_cu_string (^spesh_slot_value $1) $2))

# MVMSerializationContext *dep = (MVMSerializationContext *)tc->cur_frame->effective_spesh_slots[GET_UI16(cur_op, 2)];
# MVMuint64 idx = MVM_BC_get_I64(cur_op, 4);
# GET_REG(cur_op, 0).o = MVM_sc_get_object(tc, dep, idx);
(template: sp_getwvalfrom
  (call (^func MVM_sc_get_object)
    (arglist
      (carg (tc) ptr)
      (carg (^spesh_slot_value $1) ptr)
      (carg $2 int)) ptr_sz))

(template: prof_enterspesh
  (callv (^func MVM_profile_log_enter)
    (arglist
      (carg (tc) ptr)
      (carg (^getf (^frame) MVMFrame static_info) ptr)
      (carg (const (&QUOTE MVM_PROFILE_ENTER_JIT) int_sz) int))))

(template: prof_enterinline
  (callv (^func MVM_profile_log_enter)
    (arglist
      (carg (tc) ptr)
      (carg (^spesh_slot_value $0) ptr)
      (carg (const (&QUOTE MVM_PROFILE_ENTER_JIT_INLINE) int_sz) int))))

(template: prof_enternative
  (callv (^func MVM_profile_log_enter_native)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr))))

(template: prof_exit
  (callv (^func MVM_profile_log_exit)
    (arglist
      (carg (tc) ptr))))

(template: prof_allocated
  (callv (^func MVM_profile_log_allocated)
    (arglist
      (carg (tc) ptr)
      (carg $0 ptr))))

(template: prof_replaced
  (callv (^func MVM_profile_log_scalar_replaced)
    (arglist
      (carg (tc) ptr)
      (carg (^spesh_slot_value $0) ptr))))
