github.com/cloudwego/frugal@v0.1.15/internal/binary/encoder/translator.go (about)

     1  /*
     2   * Copyright 2022 ByteDance Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package encoder
    18  
    19  import (
    20      `fmt`
    21      `os`
    22      `reflect`
    23  
    24      `github.com/cloudwego/frugal/internal/atm/abi`
    25      `github.com/cloudwego/frugal/internal/atm/hir`
    26      `github.com/cloudwego/frugal/internal/binary/defs`
    27      `github.com/cloudwego/frugal/internal/rt`
    28      `github.com/cloudwego/frugal/internal/utils`
    29  )
    30  
    31  /** Function Prototype
    32   *
    33   *      func (
    34   *          buf unsafe.Pointer,
    35   *          len int,
    36   *          mem iov.BufferWriter,
    37   *          p   unsafe.Pointer,
    38   *          rs  *RuntimeState,
    39   *          st  int,
    40   *      ) (
    41   *          pos int,
    42   *          err error,
    43   *      )
    44   */
    45  
    46  const (
    47      ARG_buf      = 0
    48      ARG_len      = 1
    49      ARG_mem_itab = 2
    50      ARG_mem_data = 3
    51      ARG_p        = 4
    52      ARG_rs       = 5
    53      ARG_st       = 6
    54  )
    55  
    56  /** Register Allocations
    57   *
    58   *      P1      Current Working Pointer
    59   *      P2      Output Buffer Pointer
    60   *      P3      Runtime State Pointer
    61   *      P4      Error Type Pointer
    62   *      P5      Error Value Pointer
    63   *
    64   *      R2      Output Buffer Length
    65   *      R3      Output Buffer Capacity
    66   *      R4      State Index
    67   */
    68  
    69  const (
    70      WP = hir.P1
    71      RP = hir.P2
    72      RS = hir.P3
    73      ET = hir.P4 // may also be used as a temporary pointer register
    74      EP = hir.P5 // may also be used as a temporary pointer register
    75  )
    76  
    77  const (
    78      RL = hir.R2
    79      RC = hir.R3
    80      ST = hir.R4
    81  )
    82  
    83  const (
    84      TP = hir.P0
    85      TR = hir.R0
    86      UR = hir.R1
    87  )
    88  
    89  const (
    90      LB_halt       = "_halt"
    91      LB_error      = "_error"
    92      LB_nomem      = "_nomem"
    93      LB_overflow   = "_overflow"
    94      LB_duplicated = "_duplicated"
    95  )
    96  
    97  var (
    98      _N_page       = int64(os.Getpagesize())
    99      _E_nomem      = fmt.Errorf("frugal: buffer is too small")
   100      _E_overflow   = fmt.Errorf("frugal: encoder stack overflow")
   101      _E_duplicated = fmt.Errorf("frugal: duplicated element within sets")
   102  )
   103  
   104  func Translate(s Program) hir.Program {
   105      p := hir.CreateBuilder()
   106      prologue (p)
   107      program  (p, s)
   108      epilogue (p)
   109      errors   (p)
   110      return p.Build()
   111  }
   112  
   113  func errors(p *hir.Builder) {
   114      p.Label (LB_nomem)
   115      p.MOV   (UR, RL)
   116      p.IP    (&_E_nomem, TP)
   117      p.JMP   ("_basic_error")
   118      p.Label (LB_overflow)
   119      p.IP    (&_E_overflow, TP)
   120      p.JMP   ("_basic_error")
   121      p.Label (LB_duplicated)
   122      p.IP    (&_E_duplicated, TP)
   123      p.Label ("_basic_error")
   124      p.LP    (TP, 0, ET)
   125      p.LP    (TP, 8, EP)
   126      p.JMP   (LB_error)
   127  }
   128  
   129  func program(p *hir.Builder, s Program) {
   130      for i, v := range s {
   131          p.Mark(i)
   132          translators[v.Op](p, v)
   133      }
   134  }
   135  
   136  func prologue(p *hir.Builder) {
   137      p.LDAP  (ARG_buf, RP)
   138      p.LDAQ  (ARG_len, RC)
   139      p.LDAP  (ARG_p, WP)
   140      p.LDAP  (ARG_rs, RS)
   141      p.LDAQ  (ARG_st, ST)
   142      p.MOV   (hir.Rz, UR)
   143      p.MOV   (hir.Rz, RL)
   144  }
   145  
   146  func epilogue(p *hir.Builder) {
   147      p.Label (LB_halt)
   148      p.MOVP  (hir.Pn, ET)
   149      p.MOVP  (hir.Pn, EP)
   150      p.Label (LB_error)
   151      p.RET   ().
   152        R0    (RL).
   153        R1    (ET).
   154        R2    (EP)
   155  }
   156  
   157  var translators = [256]func(*hir.Builder, Instr) {
   158      OP_size_check    : translate_OP_size_check,
   159      OP_size_const    : translate_OP_size_const,
   160      OP_size_dyn      : translate_OP_size_dyn,
   161      OP_size_map      : translate_OP_size_map,
   162      OP_size_defer    : translate_OP_size_defer,
   163      OP_byte          : translate_OP_byte,
   164      OP_word          : translate_OP_word,
   165      OP_long          : translate_OP_long,
   166      OP_quad          : translate_OP_quad,
   167      OP_sint          : translate_OP_sint,
   168      OP_length        : translate_OP_length,
   169      OP_memcpy_be     : translate_OP_memcpy_be,
   170      OP_seek          : translate_OP_seek,
   171      OP_deref         : translate_OP_deref,
   172      OP_defer         : translate_OP_defer,
   173      OP_map_len       : translate_OP_map_len,
   174      OP_map_key       : translate_OP_map_key,
   175      OP_map_next      : translate_OP_map_next,
   176      OP_map_value     : translate_OP_map_value,
   177      OP_map_begin     : translate_OP_map_begin,
   178      OP_map_if_next   : translate_OP_map_if_next,
   179      OP_map_if_empty  : translate_OP_map_if_empty,
   180      OP_list_decr     : translate_OP_list_decr,
   181      OP_list_begin    : translate_OP_list_begin,
   182      OP_list_if_next  : translate_OP_list_if_next,
   183      OP_list_if_empty : translate_OP_list_if_empty,
   184      OP_unique        : translate_OP_unique,
   185      OP_goto          : translate_OP_goto,
   186      OP_if_nil        : translate_OP_if_nil,
   187      OP_if_hasbuf     : translate_OP_if_hasbuf,
   188      OP_if_eq_imm     : translate_OP_if_eq_imm,
   189      OP_if_eq_str     : translate_OP_if_eq_str,
   190      OP_make_state    : translate_OP_make_state,
   191      OP_drop_state    : translate_OP_drop_state,
   192      OP_halt          : translate_OP_halt,
   193  }
   194  
   195  func translate_OP_size_check(p *hir.Builder, v Instr) {
   196      p.ADDI  (RL, v.Iv, UR)
   197      p.BLTU  (RC, UR, LB_nomem)
   198  }
   199  
   200  func translate_OP_size_const(p *hir.Builder, v Instr) {
   201      p.ADDI  (RL, v.Iv, RL)
   202  }
   203  
   204  func translate_OP_size_dyn(p *hir.Builder, v Instr) {
   205      p.LQ    (WP, int64(v.Uv), TR)
   206      p.MULI  (TR, v.Iv, TR)
   207      p.ADD   (RL, TR, RL)
   208  }
   209  
   210  func translate_OP_size_map(p *hir.Builder, v Instr) {
   211      p.LP    (WP, 0, TP)
   212      p.LQ    (TP, 0, TR)
   213      p.MULI  (TR, v.Iv, TR)
   214      p.ADD   (RL, TR, RL)
   215  }
   216  
   217  func translate_OP_size_defer(p *hir.Builder, v Instr) {
   218      p.IP    (v.Vt(), TP)
   219      p.GCALL (F_encode).
   220        A0    (TP).
   221        A1    (hir.Pn).
   222        A2    (hir.Rz).
   223        A3    (hir.Pn).
   224        A4    (hir.Pn).
   225        A5    (WP).
   226        A6    (RS).
   227        A7    (ST).
   228        R0    (TR).
   229        R1    (ET).
   230        R2    (EP)
   231      p.BNEP  (ET, hir.Pn, LB_error)
   232      p.ADD   (RL, TR, RL)
   233  }
   234  
   235  func translate_OP_byte(p *hir.Builder, v Instr) {
   236      p.ADDP  (RP, RL, TP)
   237      p.ADDI  (RL, 1, RL)
   238      p.IB    (int8(v.Iv), TR)
   239      p.SB    (TR, TP, 0)
   240  }
   241  
   242  func translate_OP_word(p *hir.Builder, v Instr) {
   243      p.ADDP  (RP, RL, TP)
   244      p.ADDI  (RL, 2, RL)
   245      p.IW    (bswap16(v.Iv), TR)
   246      p.SW    (TR, TP, 0)
   247  }
   248  
   249  func translate_OP_long(p *hir.Builder, v Instr) {
   250      p.ADDP  (RP, RL, TP)
   251      p.ADDI  (RL, 4, RL)
   252      p.IL    (bswap32(v.Iv), TR)
   253      p.SL    (TR, TP, 0)
   254  }
   255  
   256  func translate_OP_quad(p *hir.Builder, v Instr) {
   257      p.ADDP  (RP, RL, TP)
   258      p.ADDI  (RL, 8, RL)
   259      p.IQ    (bswap64(v.Iv), TR)
   260      p.SQ    (TR, TP, 0)
   261  }
   262  
   263  func translate_OP_sint(p *hir.Builder, v Instr) {
   264      p.ADDP  (RP, RL, TP)
   265      p.ADDI  (RL, v.Iv, RL)
   266  
   267      /* check for copy size */
   268      switch v.Iv {
   269          case 1  : p.LB(WP, 0, TR);                  p.SB(TR, TP, 0)
   270          case 2  : p.LW(WP, 0, TR); p.SWAPW(TR, TR); p.SW(TR, TP, 0)
   271          case 4  : p.LL(WP, 0, TR); p.SWAPL(TR, TR); p.SL(TR, TP, 0)
   272          case 8  : p.LQ(WP, 0, TR); p.SWAPQ(TR, TR); p.SQ(TR, TP, 0)
   273          default : panic("can only convert 1, 2, 4 or 8 bytes at a time")
   274      }
   275  }
   276  
   277  func translate_OP_length(p *hir.Builder, v Instr) {
   278      p.LL    (WP, v.Iv, TR)
   279      p.SWAPL (TR, TR)
   280      p.ADDP  (RP, RL, TP)
   281      p.ADDI  (RL, 4, RL)
   282      p.SL    (TR, TP, 0)
   283  }
   284  
   285  func translate_OP_memcpy_1(p *hir.Builder) {
   286      p.IQ    (_N_page, UR)
   287      p.BGEU  (UR, TR, "_do_copy_{n}")
   288      p.LDAP  (ARG_mem_itab, ET)
   289      p.LDAP  (ARG_mem_data, EP)
   290      p.BEQP  (EP, hir.Pn, "_do_copy_{n}")
   291      p.SUB   (RC, RL, UR)
   292      p.ICALL (ET, EP, utils.FnWrite).
   293        A0    (TP).
   294        A1    (TR).
   295        A2    (TR).
   296        A3    (UR).
   297        R0    (ET).
   298        R1    (EP)
   299      p.BNEP  (ET, hir.Pn, LB_error)
   300      p.JMP   ("_done_{n}")
   301      p.Label ("_do_copy_{n}")
   302      p.ADD   (RL, TR, UR)
   303      p.BLTU  (RC, UR, LB_nomem)
   304      p.ADDP  (RP, RL, EP)
   305      p.MOV   (UR, RL)
   306      p.BCOPY (TP, TR, EP)
   307      p.Label ("_done_{n}")
   308  }
   309  
   310  func translate_OP_memcpy_be(p *hir.Builder, v Instr) {
   311      p.LQ    (WP, int64(v.Uv), TR)
   312      p.BEQ   (TR, hir.Rz, "_done_{n}")
   313      p.LP    (WP, 0, TP)
   314  
   315      /* special case: unit of a single byte */
   316      if v.Iv == 1 {
   317          translate_OP_memcpy_1(p)
   318          return
   319      }
   320  
   321      /* adjust the buffer length */
   322      p.MULI  (TR, v.Iv, UR)
   323      p.ADD   (RL, UR, UR)
   324      p.BLTU  (RC, UR, LB_nomem)
   325      p.ADDP  (RP, RL, EP)
   326      p.MOV   (UR, RL)
   327      p.Label ("_loop_{n}")
   328      p.BEQ   (TR, hir.Rz, "_done_{n}")
   329  
   330      /* load-swap-store sequence */
   331      switch v.Iv {
   332          case 2  : p.LW(TP, 0, UR); p.SWAPW(UR, UR); p.SW(UR, EP, 0)
   333          case 4  : p.LL(TP, 0, UR); p.SWAPL(UR, UR); p.SL(UR, EP, 0)
   334          case 8  : p.LQ(TP, 0, UR); p.SWAPQ(UR, UR); p.SQ(UR, EP, 0)
   335          default : panic("can only swap 2, 4 or 8 bytes at a time")
   336      }
   337  
   338      /* update loop counter */
   339      p.SUBI  (TR, 1, TR)
   340      p.ADDPI (TP, v.Iv, TP)
   341      p.ADDPI (EP, v.Iv, EP)
   342      p.JMP   ("_loop_{n}")
   343      p.Label ("_done_{n}")
   344  }
   345  
   346  func translate_OP_seek(p *hir.Builder, v Instr) {
   347      p.ADDPI (WP, v.Iv, WP)
   348  }
   349  
   350  func translate_OP_deref(p *hir.Builder, _ Instr) {
   351      p.LP    (WP, 0, WP)
   352  }
   353  
   354  func translate_OP_defer(p *hir.Builder, v Instr) {
   355      p.IP    (v.Vt(), TP)
   356      p.LDAP  (ARG_mem_itab, ET)
   357      p.LDAP  (ARG_mem_data, EP)
   358      p.SUB   (RC, RL, TR)
   359      p.ADDP  (RP, RL, RP)
   360      p.GCALL (F_encode).
   361        A0    (TP).
   362        A1    (RP).
   363        A2    (TR).
   364        A3    (ET).
   365        A4    (EP).
   366        A5    (WP).
   367        A6    (RS).
   368        A7    (ST).
   369        R0    (TR).
   370        R1    (ET).
   371        R2    (EP)
   372      p.SUBP  (RP, RL, RP)
   373      p.BNEP  (ET, hir.Pn, LB_error)
   374      p.ADD   (RL, TR, RL)
   375  }
   376  
   377  func translate_OP_map_len(p *hir.Builder, _ Instr) {
   378      p.LP    (WP, 0, TP)
   379      p.LQ    (TP, 0, TR)
   380      p.SWAPL (TR, TR)
   381      p.ADDP  (RP, RL, TP)
   382      p.ADDI  (RL, 4, RL)
   383      p.SL    (TR, TP, 0)
   384  }
   385  
   386  func translate_OP_map_key(p *hir.Builder, _ Instr) {
   387      p.ADDP  (RS, ST, TP)
   388      p.LP    (TP, MiOffset + MiKeyOffset, WP)
   389  }
   390  
   391  func translate_OP_map_next(p *hir.Builder, _ Instr) {
   392      p.ADDP  (RS, ST, TP)
   393      p.ADDPI (TP, MiOffset, TP)
   394      p.GCALL (F_mapiternext).A0(TP)
   395  }
   396  
   397  func translate_OP_map_value(p *hir.Builder, _ Instr) {
   398      p.ADDP  (RS, ST, TP)
   399      p.LP    (TP, MiOffset + MiValueOffset, WP)
   400  }
   401  
   402  func translate_OP_map_begin(p *hir.Builder, v Instr) {
   403      p.IP    (v.Vt(), ET)
   404      p.LP    (WP, 0, EP)
   405      p.ADDP  (RS, ST, TP)
   406      p.ADDPI (TP, MiOffset, TP)
   407      p.GCALL (F_mapiterstart).
   408        A0    (ET).
   409        A1    (EP).
   410        A2    (TP)
   411  }
   412  
   413  func translate_OP_map_if_next(p *hir.Builder, v Instr) {
   414      p.ADDP  (RS, ST, TP)
   415      p.LP    (TP, MiOffset + MiKeyOffset, TP)
   416      p.BNEP  (TP, hir.Pn, p.At(v.To))
   417  }
   418  
   419  func translate_OP_map_if_empty(p *hir.Builder, v Instr) {
   420      p.LP    (WP, 0, TP)
   421      p.LQ    (TP, 0, TR)
   422      p.BEQ   (TR, hir.Rz, p.At(v.To))
   423  }
   424  
   425  func translate_OP_list_decr(p *hir.Builder, _ Instr) {
   426      p.ADDP  (RS, ST, TP)
   427      p.LQ    (TP, LnOffset, TR)
   428      p.SUBI  (TR, 1, TR)
   429      p.SQ    (TR, TP, LnOffset)
   430  }
   431  
   432  func translate_OP_list_begin(p *hir.Builder, _ Instr) {
   433      p.LQ    (WP, abi.PtrSize, TR)
   434      p.LP    (WP, 0, WP)
   435      p.ADDP  (RS, ST, TP)
   436      p.SQ    (TR, TP, LnOffset)
   437  }
   438  
   439  func translate_OP_list_if_next(p *hir.Builder, v Instr) {
   440      p.ADDP  (RS, ST, TP)
   441      p.LQ    (TP, LnOffset, TR)
   442      p.BNE   (TR, hir.Rz, p.At(v.To))
   443  }
   444  
   445  func translate_OP_list_if_empty(p *hir.Builder, v Instr) {
   446      p.LQ    (WP, abi.PtrSize, TR)
   447      p.BEQ   (TR, hir.Rz, p.At(v.To))
   448  }
   449  
   450  func translate_OP_unique(p *hir.Builder, v Instr) {
   451      p.IB    (2, UR)
   452      p.LQ    (WP, abi.PtrSize, TR)
   453      p.BLTU  (TR, UR, "_ok_{n}")
   454      translate_OP_unique_type(p, v.Vt())
   455      p.Label ("_ok_{n}")
   456  }
   457  
   458  func translate_OP_unique_type(p *hir.Builder, vt *rt.GoType) {
   459      switch vt.Kind() {
   460          case reflect.Bool    : translate_OP_unique_b(p)
   461          case reflect.Int     : translate_OP_unique_int(p)
   462          case reflect.Int8    : translate_OP_unique_i8(p)
   463          case reflect.Int16   : translate_OP_unique_i16(p)
   464          case reflect.Int32   : translate_OP_unique_i32(p)
   465          case reflect.Int64   : translate_OP_unique_i64(p)
   466          case reflect.Float64 : translate_OP_unique_i64(p)
   467          case reflect.Map     : break
   468          case reflect.Ptr     : break
   469          case reflect.Slice   : break
   470          case reflect.String  : translate_OP_unique_str(p)
   471          case reflect.Struct  : break
   472          default              : panic("unique: invalid type: " + vt.String())
   473      }
   474  }
   475  
   476  func translate_OP_unique_b(p *hir.Builder) {
   477      p.BLTU  (UR, TR, LB_duplicated)
   478      p.LP    (WP, 0, TP)
   479      p.LB    (TP, 0, TR)
   480      p.LB    (TP, 1, UR)
   481      p.BEQ   (TR, UR, LB_duplicated)
   482  }
   483  
   484  func translate_OP_unique_i8(p *hir.Builder) {
   485      p.IQ    (RangeUint8, UR)
   486      p.BLTU  (UR, TR, LB_duplicated)
   487      translate_OP_unique_small(p, RangeUint8 / 8, 1, p.LB)
   488  }
   489  
   490  func translate_OP_unique_i16(p *hir.Builder) {
   491      p.IQ    (RangeUint16, UR)
   492      p.BLTU  (UR, TR, LB_duplicated)
   493      translate_OP_unique_small(p, RangeUint16 / 8, 2, p.LW)
   494  }
   495  
   496  func translate_OP_unique_int(p *hir.Builder) {
   497      switch defs.IntSize {
   498          case 4  : translate_OP_unique_i32(p)
   499          case 8  : translate_OP_unique_i64(p)
   500          default : panic("invalid int size")
   501      }
   502  }
   503  
   504  func translate_OP_unique_small(p *hir.Builder, nb int64, dv int64, ld func(hir.PointerRegister, int64, hir.GenericRegister) *hir.Ir) {
   505      p.ADDPI (RS, BmOffset, ET)
   506      p.BZERO (nb, ET)
   507      p.LP    (WP, 0, EP)
   508      p.JMP   ("_first_{n}")
   509      p.Label ("_loop_{n}")
   510      p.ADDPI (EP, dv, EP)
   511      p.Label ("_first_{n}")
   512      ld      (EP, 0, RC)
   513      p.SHRI  (RC, 3, UR)
   514      p.ANDI  (RC, 0x3f, RC)
   515      p.ANDI  (UR, ^0x07, UR)
   516      p.ADDP  (ET, UR, TP)
   517      p.LQ    (TP, 0, UR)
   518      p.BTS   (RC, UR, RC)
   519      p.SQ    (UR, TP, 0)
   520      p.BNE   (RC, hir.Rz, LB_duplicated)
   521      p.SUBI  (TR, 1, TR)
   522      p.BNE   (TR, hir.Rz, "_loop_{n}")
   523      p.LDAQ  (ARG_len, RC)
   524  }
   525  
   526  func translate_OP_unique_i32(p *hir.Builder) {
   527      p.LP    (WP, 0, TP)
   528      p.GCALL (F_unique32).
   529        A0    (TP).
   530        A1    (TR).
   531        R0    (TR)
   532      p.BNE   (TR, hir.Rz, LB_duplicated)
   533  }
   534  
   535  func translate_OP_unique_i64(p *hir.Builder) {
   536      p.LP    (WP, 0, TP)
   537      p.GCALL (F_unique64).
   538        A0    (TP).
   539        A1    (TR).
   540        R0    (TR)
   541      p.BNE   (TR, hir.Rz, LB_duplicated)
   542  }
   543  
   544  func translate_OP_unique_str(p *hir.Builder) {
   545      p.LP    (WP, 0, TP)
   546      p.GCALL (F_uniquestr).
   547        A0    (TP).
   548        A1    (TR).
   549        R0    (TR)
   550      p.BNE   (TR, hir.Rz, LB_duplicated)
   551  }
   552  
   553  func translate_OP_goto(p *hir.Builder, v Instr) {
   554      p.JMP   (p.At(v.To))
   555  }
   556  
   557  func translate_OP_if_nil(p *hir.Builder, v Instr) {
   558      p.LP    (WP, 0, TP)
   559      p.BEQP  (TP, hir.Pn, p.At(v.To))
   560  }
   561  
   562  func translate_OP_if_hasbuf(p *hir.Builder, v Instr) {
   563      p.BNEP  (RP, hir.Pn, p.At(v.To))
   564  }
   565  
   566  func translate_OP_if_eq_imm(p *hir.Builder, v Instr) {
   567      switch v.Uv {
   568          case 1  : p.LB(WP, 0, TR); p.IB( int8(v.Iv), UR); p.BEQ(TR, UR, p.At(v.To))
   569          case 2  : p.LW(WP, 0, TR); p.IW(int16(v.Iv), UR); p.BEQ(TR, UR, p.At(v.To))
   570          case 4  : p.LL(WP, 0, TR); p.IL(int32(v.Iv), UR); p.BEQ(TR, UR, p.At(v.To))
   571          case 8  : p.LQ(WP, 0, TR); p.IQ(      v.Iv , UR); p.BEQ(TR, UR, p.At(v.To))
   572          default : panic("invalid imm size")
   573      }
   574  }
   575  
   576  func translate_OP_if_eq_str(p *hir.Builder, v Instr) {
   577      nb := v.Iv
   578      to := p.At(v.To)
   579  
   580      /* load the string length */
   581      p.IQ    (v.Iv, TR)
   582      p.LQ    (WP, abi.PtrSize, UR)
   583  
   584      /* empty string */
   585      if v.Iv == 0 {
   586          p.BEQ(TR, UR, to)
   587          return
   588      }
   589  
   590      /* compare the string pointers */
   591      p.BNE   (TR, UR, "_neq_{n}")
   592      p.IP    (v.Pr, TP)
   593      p.LP    (WP, 0, EP)
   594      p.BEQP  (TP, EP, to)
   595  
   596      /* compare the content, 4-byte loop */
   597      for nb >= 4 {
   598          p.LL    (EP, v.Iv - nb, TR)
   599          p.IL    (v.Long(v.Iv - nb), UR)
   600          p.BNE   (TR, UR, "_neq_{n}")
   601          nb -= 4
   602      }
   603  
   604      /* compare the content, 2-byte test */
   605      if nb >= 2 {
   606          p.LW    (EP, v.Iv - nb, TR)
   607          p.IW    (v.Word(v.Iv - nb), UR)
   608          p.BNE   (TR, UR, "_neq_{n}")
   609          nb -= 2
   610      }
   611  
   612      /* compare the content, the last byte */
   613      if nb != 0 {
   614          p.LB    (EP, v.Iv - 1, TR)
   615          p.IB    (v.Byte(v.Iv - 1), UR)
   616          p.BNE   (TR, UR, "_neq_{n}")
   617      }
   618  
   619      /* two string are equal */
   620      p.JMP   (to)
   621      p.Label ("_neq_{n}")
   622  }
   623  
   624  func translate_OP_make_state(p *hir.Builder, _ Instr) {
   625      p.IQ    (StateMax, TR)
   626      p.BGEU  (ST, TR, LB_overflow)
   627      p.ADDP  (RS, ST, TP)
   628      p.SP    (WP, TP, WpOffset)
   629      p.ADDI  (ST, StateSize, ST)
   630  }
   631  
   632  func translate_OP_drop_state(p *hir.Builder, _ Instr) {
   633      p.SUBI  (ST, StateSize, ST)
   634      p.ADDP  (RS, ST, TP)
   635      p.LP    (TP, WpOffset, WP)
   636      p.SP    (hir.Pn, TP, WpOffset)
   637  }
   638  
   639  func translate_OP_halt(p *hir.Builder, _ Instr) {
   640      p.JMP   (LB_halt)
   641  }