github.com/cloudwego/frugal@v0.1.15/internal/atm/hir/ir.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 hir
    18  
    19  import (
    20      `fmt`
    21      `strings`
    22      `unsafe`
    23  
    24      `github.com/cloudwego/frugal/internal/rt`
    25  )
    26  
    27  type (
    28  	OpCode     byte
    29      Constness  byte
    30      Likeliness byte
    31  )
    32  
    33  const (
    34      OP_nop OpCode = iota    // no operation
    35      OP_ip                   // ptr(Pr) -> Pd
    36      OP_lb                   // u64(*(* u8)(Ps + Iv)) -> Rx
    37      OP_lw                   // u64(*(*u16)(Ps + Iv)) -> Rx
    38      OP_ll                   // u64(*(*u32)(Ps + Iv)) -> Rx
    39      OP_lq                   //     *(*u64)(Ps + Iv)  -> Rx
    40      OP_lp                   //     *(*ptr)(Ps + Iv)  -> Pd
    41      OP_sb                   //  u8(Rx) -> *(*u8)(Pd + Iv)
    42      OP_sw                   // u16(Rx) -> *(*u16)(Pd + Iv)
    43      OP_sl                   // u32(Rx) -> *(*u32)(Pd + Iv)
    44      OP_sq                   //     Rx  -> *(*u64)(Pd + Iv)
    45      OP_sp                   //     Ps  -> *(*ptr)(Pd + Iv)
    46      OP_ldaq                 // arg[Iv] -> Rx
    47      OP_ldap                 // arg[Iv] -> Pd
    48      OP_addp                 // Ps + Rx -> Pd
    49      OP_subp                 // Ps - Rx -> Pd
    50      OP_addpi                // Ps + Iv -> Pd
    51      OP_add                  // Rx + Ry -> Rz
    52      OP_sub                  // Rx - Ry -> Rz
    53      OP_bts                  // Ry & (1 << (Rx % PTR_BITS)) != 0 -> Rz, Ry |= 1 << (Rx % PTR_BITS)
    54      OP_addi                 // Rx + Iv -> Ry
    55      OP_muli                 // Rx * Iv -> Ry
    56      OP_andi                 // Rx & Iv -> Ry
    57      OP_xori                 // Rx ^ Iv -> Ry
    58      OP_shri                 // Rx >> Iv -> Ry
    59      OP_bsi                  // Rx | (1 << Iv) -> Ry
    60      OP_swapw                // bswap16(Rx) -> Ry
    61      OP_swapl                // bswap32(Rx) -> Ry
    62      OP_swapq                // bswap64(Rx) -> Ry
    63      OP_sxlq                 // sign_extend_32_to_64(Rx) -> Ry
    64      OP_beq                  // if (Rx == Ry) Br.PC -> PC
    65      OP_bne                  // if (Rx != Ry) Br.PC -> PC
    66      OP_blt                  // if (Rx <  Ry) Br.PC -> PC
    67      OP_bltu                 // if (u(Rx) <  u(Ry)) Br.PC -> PC
    68      OP_bgeu                 // if (u(Rx) >= u(Ry)) Br.PC -> PC
    69      OP_beqp                 // if (Ps == Pd) Br.PC -> PC
    70      OP_bnep                 // if (Ps == Pd) Br.PC -> PC
    71      OP_bsw                  // if (u(Rx) <  u(An)) Sw[u(Rx)].PC -> PC
    72      OP_jmp                  // Br.PC -> PC
    73      OP_bzero                // memset(Pd, 0, Iv)
    74      OP_bcopy                // memcpy(Pd, Ps, Rx)
    75      OP_ccall                // call external C functions
    76      OP_gcall                // call external Go functions
    77      OP_icall                // call external Go iface methods
    78      OP_ret                  // return from function
    79      OP_break                // trigger a debugger breakpoint
    80  )
    81  
    82  const (
    83      Const Constness = iota
    84      Volatile
    85  )
    86  
    87  const (
    88      Likely Likeliness = iota
    89      Unlikely
    90  )
    91  
    92  type Ir struct {
    93      Op OpCode
    94      Rx GenericRegister
    95      Ry GenericRegister
    96      Rz GenericRegister
    97      Ps PointerRegister
    98      Pd PointerRegister
    99      An uint8
   100      Rn uint8
   101      Ar [8]uint8
   102      Rr [8]uint8
   103      Iv int64
   104      Pr unsafe.Pointer
   105      Br *Ir
   106      Ln *Ir
   107  }
   108  
   109  func (self *Ir) iv(v int64)           *Ir { self.Iv = v; return self }
   110  func (self *Ir) pr(v unsafe.Pointer)  *Ir { self.Pr = v; return self }
   111  func (self *Ir) rx(v GenericRegister) *Ir { self.Rx = v; return self }
   112  func (self *Ir) ry(v GenericRegister) *Ir { self.Ry = v; return self }
   113  func (self *Ir) rz(v GenericRegister) *Ir { self.Rz = v; return self }
   114  func (self *Ir) ps(v PointerRegister) *Ir { self.Ps = v; return self }
   115  func (self *Ir) pd(v PointerRegister) *Ir { self.Pd = v; return self }
   116  
   117  func (self *Ir) constness(c Constness) *Ir {
   118      if self.Op != OP_ip {
   119          panic("constness only applicable to `OP_ip` instruction")
   120      } else {
   121          self.An = uint8(c)
   122          return self
   123      }
   124  }
   125  
   126  func (self *Ir) likeliness(p Likeliness) *Ir {
   127      if !self.IsBranch() {
   128          panic("likeliness only applicable to branch instructions")
   129      } else if self.Op == OP_bsw {
   130          panic("cannot specify likeliness for `OP_bsw`")
   131      } else {
   132          self.An = uint8(p)
   133          return self
   134      }
   135  }
   136  
   137  func (self *Ir) A0(v Register) *Ir { self.An, self.Ar[0] = 1, v.A(); return self }
   138  func (self *Ir) A1(v Register) *Ir { self.An, self.Ar[1] = 2, v.A(); return self }
   139  func (self *Ir) A2(v Register) *Ir { self.An, self.Ar[2] = 3, v.A(); return self }
   140  func (self *Ir) A3(v Register) *Ir { self.An, self.Ar[3] = 4, v.A(); return self }
   141  func (self *Ir) A4(v Register) *Ir { self.An, self.Ar[4] = 5, v.A(); return self }
   142  func (self *Ir) A5(v Register) *Ir { self.An, self.Ar[5] = 6, v.A(); return self }
   143  func (self *Ir) A6(v Register) *Ir { self.An, self.Ar[6] = 7, v.A(); return self }
   144  func (self *Ir) A7(v Register) *Ir { self.An, self.Ar[7] = 8, v.A(); return self }
   145  
   146  func (self *Ir) R0(v Register) *Ir { self.Rn, self.Rr[0] = 1, v.A(); return self }
   147  func (self *Ir) R1(v Register) *Ir { self.Rn, self.Rr[1] = 2, v.A(); return self }
   148  func (self *Ir) R2(v Register) *Ir { self.Rn, self.Rr[2] = 3, v.A(); return self }
   149  func (self *Ir) R3(v Register) *Ir { self.Rn, self.Rr[3] = 4, v.A(); return self }
   150  func (self *Ir) R4(v Register) *Ir { self.Rn, self.Rr[4] = 5, v.A(); return self }
   151  func (self *Ir) R5(v Register) *Ir { self.Rn, self.Rr[5] = 6, v.A(); return self }
   152  func (self *Ir) R6(v Register) *Ir { self.Rn, self.Rr[6] = 7, v.A(); return self }
   153  func (self *Ir) R7(v Register) *Ir { self.Rn, self.Rr[7] = 8, v.A(); return self }
   154  
   155  func (self *Ir) Const()    *Ir { return self.constness(Const) }
   156  func (self *Ir) Volatile() *Ir { return self.constness(Volatile) }
   157  
   158  func (self *Ir) Likely()   *Ir { return self.likeliness(Likely) }
   159  func (self *Ir) Unlikely() *Ir { return self.likeliness(Unlikely) }
   160  
   161  func (self *Ir) Free() {
   162      freeInstr(self)
   163  }
   164  
   165  func (self *Ir) Switch() (p []*Ir) {
   166      (*rt.GoSlice)(unsafe.Pointer(&p)).Ptr = self.Pr
   167      (*rt.GoSlice)(unsafe.Pointer(&p)).Len = int(self.Iv)
   168      (*rt.GoSlice)(unsafe.Pointer(&p)).Cap = int(self.Iv)
   169      return
   170  }
   171  
   172  func (self *Ir) IsBranch() bool {
   173      return self.Op >= OP_beq && self.Op <= OP_jmp
   174  }
   175  
   176  func (self *Ir) Constness() Constness {
   177      if self.Op != OP_ip {
   178          panic("constness only applicable to `OP_ip` instruction")
   179      } else {
   180          return Constness(self.An)
   181      }
   182  }
   183  
   184  func (self *Ir) Likeliness() Likeliness {
   185      if !self.IsBranch() {
   186          panic("likeliness only applicable to branch instructions")
   187      } else if self.Op == OP_bsw {
   188          panic("`OP_bsw` does not have likeliness assigned")
   189      } else {
   190          return Likeliness(self.An)
   191      }
   192  }
   193  
   194  func (self *Ir) formatCall() string {
   195      return fmt.Sprintf(
   196          "%s, %s",
   197          self.formatArgs(&self.Ar, self.An),
   198          self.formatArgs(&self.Rr, self.Rn),
   199      )
   200  }
   201  
   202  func (self *Ir) formatArgs(vv *[8]uint8, nb uint8) string {
   203      i := uint8(0)
   204      ret := make([]string, nb)
   205  
   206      /* add each register */
   207      for i = 0; i < nb; i++ {
   208          if v := vv[i]; (v & ArgPointer) == 0 {
   209              ret[i] = "%" + GenericRegister(v & ArgMask).String()
   210          } else {
   211              ret[i] = "%" + PointerRegister(v & ArgMask).String()
   212          }
   213      }
   214  
   215      /* compose the result */
   216      return fmt.Sprintf(
   217          "{%s}",
   218          strings.Join(ret, ", "),
   219      )
   220  }
   221  
   222  func (self *Ir) formatRefs(refs map[*Ir]string, v *Ir) string {
   223      if vv, ok := refs[v]; ok {
   224          return vv
   225      } else {
   226          return fmt.Sprintf("@%p", v)
   227      }
   228  }
   229  
   230  func (self *Ir) formatTable(refs map[*Ir]string) string {
   231      tab := self.Switch()
   232      ret := make([]string, 0, self.Iv)
   233  
   234      /* empty table */
   235      if self.Iv == 0 {
   236          return "{}"
   237      }
   238  
   239      /* format every label */
   240      for i, lb := range tab {
   241          if lb != nil {
   242              ret = append(ret, fmt.Sprintf("%4ccase $%d: %s,\n", ' ', i, self.formatRefs(refs, lb)))
   243          }
   244      }
   245  
   246      /* join them together */
   247      return fmt.Sprintf(
   248          "{\n%s}",
   249          strings.Join(ret, ""),
   250      )
   251  }
   252  
   253  func (self *Ir) Disassemble(refs map[*Ir]string) string {
   254      switch self.Op {
   255          case OP_nop   : return "nop"
   256          case OP_ip    : return fmt.Sprintf("ip      $%p, %%%s", self.Pr, self.Pd)
   257          case OP_lb    : return fmt.Sprintf("lb      %d(%%%s), %%%s", self.Iv, self.Ps, self.Rx)
   258          case OP_lw    : return fmt.Sprintf("lw      %d(%%%s), %%%s", self.Iv, self.Ps, self.Rx)
   259          case OP_ll    : return fmt.Sprintf("ll      %d(%%%s), %%%s", self.Iv, self.Ps, self.Rx)
   260          case OP_lq    : return fmt.Sprintf("lq      %d(%%%s), %%%s", self.Iv, self.Ps, self.Rx)
   261          case OP_lp    : return fmt.Sprintf("lp      %d(%%%s), %%%s", self.Iv, self.Ps, self.Pd)
   262          case OP_sb    : return fmt.Sprintf("sb      %%%s, %d(%%%s)", self.Rx, self.Iv, self.Pd)
   263          case OP_sw    : return fmt.Sprintf("sw      %%%s, %d(%%%s)", self.Rx, self.Iv, self.Pd)
   264          case OP_sl    : return fmt.Sprintf("sl      %%%s, %d(%%%s)", self.Rx, self.Iv, self.Pd)
   265          case OP_sq    : return fmt.Sprintf("sq      %%%s, %d(%%%s)", self.Rx, self.Iv, self.Pd)
   266          case OP_sp    : return fmt.Sprintf("sp      %%%s, %d(%%%s)", self.Ps, self.Iv, self.Pd)
   267          case OP_ldaq  : return fmt.Sprintf("ldaq    $%d, %%%s", self.Iv, self.Rx)
   268          case OP_ldap  : return fmt.Sprintf("ldap    $%d, %%%s", self.Iv, self.Pd)
   269          case OP_addp  : return fmt.Sprintf("addp    %%%s, %%%s, %%%s", self.Ps, self.Rx, self.Pd)
   270          case OP_subp  : return fmt.Sprintf("subp    %%%s, %%%s, %%%s", self.Ps, self.Rx, self.Pd)
   271          case OP_addpi : return fmt.Sprintf("addpi   %%%s, $%d, %%%s", self.Ps, self.Iv, self.Pd)
   272          case OP_add   : return fmt.Sprintf("add     %%%s, %%%s, %%%s", self.Rx, self.Ry, self.Rz)
   273          case OP_sub   : return fmt.Sprintf("sub     %%%s, %%%s, %%%s", self.Rx, self.Ry, self.Rz)
   274          case OP_bts   : return fmt.Sprintf("bts     %%%s, %%%s, %%%s", self.Rx, self.Ry, self.Rz)
   275          case OP_addi  : return fmt.Sprintf("addi    %%%s, $%d, %%%s", self.Rx, self.Iv, self.Ry)
   276          case OP_muli  : return fmt.Sprintf("muli    %%%s, $%d, %%%s", self.Rx, self.Iv, self.Ry)
   277          case OP_andi  : return fmt.Sprintf("andi    %%%s, $%d, %%%s", self.Rx, self.Iv, self.Ry)
   278          case OP_xori  : return fmt.Sprintf("xori    %%%s, $%d, %%%s", self.Rx, self.Iv, self.Ry)
   279          case OP_shri  : return fmt.Sprintf("shri    %%%s, $%d, %%%s", self.Rx, self.Iv, self.Ry)
   280          case OP_bsi   : return fmt.Sprintf("bsi     %%%s, $%d, %%%s", self.Rx, self.Iv, self.Ry)
   281          case OP_swapw : return fmt.Sprintf("swapw   %%%s, %%%s", self.Rx, self.Ry)
   282          case OP_swapl : return fmt.Sprintf("swapl   %%%s, %%%s", self.Rx, self.Ry)
   283          case OP_swapq : return fmt.Sprintf("swapq   %%%s, %%%s", self.Rx, self.Ry)
   284          case OP_sxlq  : return fmt.Sprintf("sxlq    %%%s, %%%s", self.Rx, self.Ry)
   285          case OP_beq   : return fmt.Sprintf("beq     %%%s, %%%s, %s", self.Rx, self.Ry, self.formatRefs(refs, self.Br))
   286          case OP_bne   : return fmt.Sprintf("bne     %%%s, %%%s, %s", self.Rx, self.Ry, self.formatRefs(refs, self.Br))
   287          case OP_blt   : return fmt.Sprintf("blt     %%%s, %%%s, %s", self.Rx, self.Ry, self.formatRefs(refs, self.Br))
   288          case OP_bltu  : return fmt.Sprintf("bltu    %%%s, %%%s, %s", self.Rx, self.Ry, self.formatRefs(refs, self.Br))
   289          case OP_bgeu  : return fmt.Sprintf("bgeu    %%%s, %%%s, %s", self.Rx, self.Ry, self.formatRefs(refs, self.Br))
   290          case OP_beqp  : return fmt.Sprintf("beq     %%%s, %%%s, %s", self.Ps, self.Pd, self.formatRefs(refs, self.Br))
   291          case OP_bnep  : return fmt.Sprintf("bne     %%%s, %%%s, %s", self.Ps, self.Pd, self.formatRefs(refs, self.Br))
   292          case OP_bsw   : return fmt.Sprintf("bsw     %%%s, %s", self.Rx, self.formatTable(refs))
   293          case OP_jmp   : return fmt.Sprintf("jmp     %s", self.formatRefs(refs, self.Br))
   294          case OP_bzero : return fmt.Sprintf("bzero   $%d, %s", self.Iv, self.Pd)
   295          case OP_bcopy : return fmt.Sprintf("bcopy   %%%s, %%%s, %%%s", self.Ps, self.Rx, self.Pd)
   296          case OP_ccall : return fmt.Sprintf("ccall   %s, %s", LookupCall(self.Iv), self.formatCall())
   297          case OP_gcall : return fmt.Sprintf("gcall   %s, %s", LookupCall(self.Iv), self.formatCall())
   298          case OP_icall : return fmt.Sprintf("icall   $%d, {%%%s, %%%s}, %s", LookupCall(self.Iv).Slot, self.Ps, self.Pd, self.formatCall())
   299          case OP_ret   : return fmt.Sprintf("ret     %s", self.formatArgs(&self.Rr, self.Rn))
   300          case OP_break : return "break"
   301          default       : panic(fmt.Sprintf("invalid OpCode: 0x%02x", self.Op))
   302      }
   303  }