github.com/cloudwego/frugal@v0.1.15/internal/atm/pgen/pgen_amd64.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 pgen
    18  
    19  import (
    20      `fmt`
    21      `math`
    22      `math/bits`
    23      `reflect`
    24      `sort`
    25      `sync/atomic`
    26  
    27      `github.com/cloudwego/iasm/expr`
    28      `github.com/cloudwego/iasm/x86_64`
    29      `github.com/cloudwego/frugal/internal/atm/abi`
    30      `github.com/cloudwego/frugal/internal/atm/hir`
    31      `github.com/cloudwego/frugal/internal/rt`
    32  )
    33  
    34  type _SwitchTable struct {
    35      ref *x86_64.Label
    36      tab []*x86_64.Label
    37  }
    38  
    39  var (
    40      stabCount uint64
    41  )
    42  
    43  func newSwitchTable(n int) (v _SwitchTable) {
    44      return _SwitchTable {
    45          tab: make([]*x86_64.Label, n),
    46          ref: x86_64.CreateLabel(fmt.Sprintf("_table_%d", atomic.AddUint64(&stabCount, 1))),
    47      }
    48  }
    49  
    50  func (self *_SwitchTable) link(p *x86_64.Program) {
    51      p.Link(self.ref)
    52      self.refs(p, self.ref)
    53  }
    54  
    55  func (self *_SwitchTable) mark(i int, to *x86_64.Label) {
    56      if i >= len(self.tab) {
    57          panic("pgen: stab: index out of bound")
    58      } else {
    59          self.tab[i] = to
    60      }
    61  }
    62  
    63  func (self *_SwitchTable) refs(p *x86_64.Program, to *x86_64.Label) {
    64      for _, v := range self.tab {
    65          p.Long(expr.Ref(v).Sub(expr.Ref(to)))
    66      }
    67  }
    68  
    69  type _DeferBlock struct {
    70      ref *x86_64.Label
    71      def func(p *x86_64.Program)
    72  }
    73  
    74  type _RegSeq []hir.Register
    75  func (self _RegSeq) Len() int               { return len(self) }
    76  func (self _RegSeq) Swap(i int, j int)      { self[i], self[j] = self[j], self[i] }
    77  func (self _RegSeq) Less(i int, j int) bool { return self[i].A() < self[j].A() }
    78  
    79  /** Frame Structure of the Generated Function
    80   *
    81   *                 (Previous Frame)
    82   *      prev() ------------------------
    83   *                    Return PC
    84   *      size() ------------------------
    85   *                    Saved RBP             |
    86   *      offs() ------------------------     |
    87   *                Reserved Registers        | (decrease)
    88   *      rsvd() ------------------------     |
    89   *                   Spill Slots            ↓
    90   *      save() ------------------------
    91   *                Outgoing Arguments
    92   *         RSP ------------------------
    93   */
    94  
    95  type _FrameInfo struct {
    96      alen int
    97      regs _RegSeq
    98      desc *abi.FunctionLayout
    99      regi map[hir.Register]int32
   100      regr map[x86_64.Register64]int32
   101  }
   102  
   103  func (self *_FrameInfo) regc() int {
   104      return len(self.regs)
   105  }
   106  
   107  func (self *_FrameInfo) argc() int {
   108      return len(self.desc.Args)
   109  }
   110  
   111  func (self *_FrameInfo) retc() int {
   112      return len(self.desc.Rets)
   113  }
   114  
   115  func (self *_FrameInfo) save() int32 {
   116      return int32(self.alen)
   117  }
   118  
   119  func (self *_FrameInfo) prev() int32 {
   120      return self.size() + abi.PtrSize
   121  }
   122  
   123  func (self *_FrameInfo) size() int32 {
   124      return self.offs() + abi.PtrSize
   125  }
   126  
   127  func (self *_FrameInfo) offs() int32 {
   128      return self.rsvd() + int32(len(self.regr)) *abi.PtrSize
   129  }
   130  
   131  func (self *_FrameInfo) rsvd() int32 {
   132      return self.save() + int32(len(self.regs)) *abi.PtrSize
   133  }
   134  
   135  func (self *_FrameInfo) argv(i int) *x86_64.MemoryOperand {
   136      return Ptr(RSP, self.prev() + int32(self.desc.Args[i].Mem))
   137  }
   138  
   139  func (self *_FrameInfo) retv(i int) *x86_64.MemoryOperand {
   140      return Ptr(RSP, self.prev() + int32(self.desc.Rets[i].Mem))
   141  }
   142  
   143  func (self *_FrameInfo) slot(r hir.Register) *x86_64.MemoryOperand {
   144      return Ptr(RSP, self.save() + self.regi[r] *abi.PtrSize)
   145  }
   146  
   147  func (self *_FrameInfo) rslot(r x86_64.Register64) *x86_64.MemoryOperand {
   148      return Ptr(RSP, self.rsvd() + self.regr[r] *abi.PtrSize)
   149  }
   150  
   151  func (self *_FrameInfo) ralloc(r hir.Register) {
   152      self.regs = append(self.regs, r)
   153      sort.Sort(self.regs)
   154  
   155      /* assign slots in ascending order */
   156      for i, v := range self.regs {
   157          self.regi[v] = int32(i)
   158      }
   159  }
   160  
   161  func (self *_FrameInfo) require(n uintptr) {
   162      if self.alen < int(n) {
   163          self.alen = int(n)
   164      }
   165  }
   166  
   167  func (self *_FrameInfo) ArgPtrs() *rt.StackMap {
   168      return self.desc.StackMap()
   169  }
   170  
   171  func (self *_FrameInfo) LocalPtrs() *rt.StackMap {
   172      var v hir.Register
   173      var m rt.StackMapBuilder
   174  
   175      /* register spill slots */
   176      for _, v = range self.regs {
   177          m.AddField(v.A() & hir.ArgPointer != 0)
   178      }
   179  
   180      /* reserved registers */
   181      m.AddFields(len(self.regr), false)
   182      return m.Build()
   183  }
   184  
   185  func newContext(proto interface{}) (ret _FrameInfo) {
   186      vt := reflect.TypeOf(proto)
   187      vk := vt.Kind()
   188  
   189      /* must be a function */
   190      if vk != reflect.Func {
   191          panic("pgen: proto must be a function")
   192      }
   193  
   194      /* layout the function */
   195      ret.regr = abi.ABI.Reserved()
   196      ret.desc = abi.ABI.LayoutFunc(-1, vt)
   197      ret.regi = make(map[hir.Register]int32)
   198      return
   199  }
   200  
   201  type (
   202      Operands uint16
   203  )
   204  
   205  const (
   206      Orx Operands = 1 << iota    // read Rx register
   207      Ory                         // read Ry register
   208      Owx                         // write Rx register
   209      Owy                         // write Ry register
   210      Owz                         // write ir.Rz register
   211      Ops                         // read Ps register
   212      Opd                         // write Pd register
   213      Ojmp                        // unconditional jumps
   214      Oret                        // function returns
   215      Ocall                       // function calls
   216      Octrl                       // control OpCodes
   217  )
   218  
   219  var _OperandMask = [256]Operands {
   220      hir.OP_nop   : Octrl,
   221      hir.OP_ip    : Opd,
   222      hir.OP_lb    : Owx | Ops,
   223      hir.OP_lw    : Owx | Ops,
   224      hir.OP_ll    : Owx | Ops,
   225      hir.OP_lq    : Owx | Ops,
   226      hir.OP_lp    : Ops | Opd,
   227      hir.OP_sb    : Orx | Opd,
   228      hir.OP_sw    : Orx | Opd,
   229      hir.OP_sl    : Orx | Opd,
   230      hir.OP_sq    : Orx | Opd,
   231      hir.OP_sp    : Ops | Opd,
   232      hir.OP_ldaq  : Owx,
   233      hir.OP_ldap  : Opd,
   234      hir.OP_addp  : Orx | Ops | Opd,
   235      hir.OP_subp  : Orx | Ops | Opd,
   236      hir.OP_addpi : Ops | Opd,
   237      hir.OP_add   : Orx | Ory | Owz,
   238      hir.OP_sub   : Orx | Ory | Owz,
   239      hir.OP_bts   : Orx | Ory | Owy | Owz,
   240      hir.OP_addi  : Orx | Owy,
   241      hir.OP_muli  : Orx | Owy,
   242      hir.OP_andi  : Orx | Owy,
   243      hir.OP_xori  : Orx | Owy,
   244      hir.OP_shri  : Orx | Owy,
   245      hir.OP_bsi   : Orx | Owy,
   246      hir.OP_swapw : Orx | Owy,
   247      hir.OP_swapl : Orx | Owy,
   248      hir.OP_swapq : Orx | Owy,
   249      hir.OP_sxlq  : Orx | Owy,
   250      hir.OP_beq   : Orx | Ory,
   251      hir.OP_bne   : Orx | Ory,
   252      hir.OP_blt   : Orx | Ory,
   253      hir.OP_bltu  : Orx | Ory,
   254      hir.OP_bgeu  : Orx | Ory,
   255      hir.OP_beqp  : Ops | Opd,
   256      hir.OP_bnep  : Ops | Opd,
   257      hir.OP_bsw   : Orx,
   258      hir.OP_jmp   : Ojmp,
   259      hir.OP_bzero : Opd,
   260      hir.OP_bcopy : Orx | Ops | Opd,
   261      hir.OP_ccall : Ocall,
   262      hir.OP_gcall : Ocall,
   263      hir.OP_icall : Ocall,
   264      hir.OP_ret   : Oret,
   265      hir.OP_break : Octrl,
   266  }
   267  
   268  type Func struct {
   269      Code  []byte
   270      Frame rt.Frame
   271  }
   272  
   273  type CodeGen struct {
   274      regi int
   275      ctxt _FrameInfo
   276      arch *x86_64.Arch
   277      head *x86_64.Label
   278      tail *x86_64.Label
   279      halt *x86_64.Label
   280      defs []_DeferBlock
   281      stab []_SwitchTable
   282      abix _CodeGenExtension
   283      jmps map[string]*x86_64.Label
   284      regs map[hir.Register]x86_64.Register64
   285  }
   286  
   287  func CreateCodeGen(proto interface{}) *CodeGen {
   288      return &CodeGen {
   289          ctxt: newContext(proto),
   290          arch: x86_64.DefaultArch,
   291          jmps: make(map[string]*x86_64.Label),
   292          regs: make(map[hir.Register]x86_64.Register64),
   293      }
   294  }
   295  
   296  func (self *CodeGen) Generate(s hir.Program, sp uintptr) *Func {
   297      h := 0
   298      p := self.arch.CreateProgram()
   299  
   300      /* find the halting points */
   301      for v := s.Head; h < 2 && v != nil; v = v.Ln {
   302          if v.Op == hir.OP_ret {
   303              h++
   304          }
   305      }
   306  
   307      /* program must halt exactly once */
   308      switch h {
   309          case 1  : break
   310          case 0  : panic("pgen: program does not halt")
   311          default : panic("pgen: program halts more than once")
   312      }
   313  
   314      /* static register allocation */
   315      for v := s.Head; v != nil; v = v.Ln {
   316          self.rcheck(v, _OperandMask[v.Op])
   317          self.walloc(v, _OperandMask[v.Op])
   318      }
   319  
   320      /* argument space calculation */
   321      for v := s.Head; v != nil; v = v.Ln {
   322          switch v.Op {
   323              case hir.OP_gcall: fallthrough
   324              case hir.OP_icall: self.ctxt.require(abi.ABI.GetLayout(hir.LookupCall(v.Iv).Id).Sp)
   325              case hir.OP_bcopy: self.ctxt.require(_M_memcpyargs)
   326          }
   327      }
   328  
   329      /* create the labels for stack management */
   330      entry := x86_64.CreateLabel("_entry")
   331      stack := x86_64.CreateLabel("_stack_grow")
   332  
   333      /* create key anchor points */
   334      self.head = x86_64.CreateLabel("_head")
   335      self.tail = x86_64.CreateLabel("_tail")
   336      self.halt = x86_64.CreateLabel("_halt")
   337  
   338      /* stack checking */
   339      p.Link(entry)
   340      self.abiStackCheck(p, stack, sp)
   341  
   342      /* program prologue */
   343      p.SUBQ(self.ctxt.size(), RSP)
   344      p.Link(self.head)
   345      p.MOVQ(RBP, Ptr(RSP, self.ctxt.offs()))
   346      p.LEAQ(Ptr(RSP, self.ctxt.offs()), RBP)
   347  
   348      /* ABI-specific prologue */
   349      self.abiSaveReserved(p)
   350      self.abiPrologue(p)
   351  
   352      /* clear all the pointer registers */
   353      for lr := range self.regs {
   354          if lr.A() & hir.ArgPointer != 0 {
   355              self.clr(p, lr)
   356          }
   357      }
   358  
   359      /* clear all the spill slots, if any */
   360      if i, n := 0, self.ctxt.regc(); n != 0 {
   361          if  n >= 2 { p.PXOR   (XMM15, XMM15) }
   362          for n >= 2 { p.MOVDQU (XMM15, Ptr(RSP, self.ctxt.save() + int32(i) *abi.PtrSize)); i += 2; n -= 2 }
   363          if  n != 0 { p.MOVQ   (0, Ptr(RSP, self.ctxt.save() + int32(i) *abi.PtrSize)) }
   364      }
   365  
   366      /* translate the entire program */
   367      for v := s.Head; v != nil; v = v.Ln {
   368          self.translate(p, v)
   369      }
   370  
   371      /* generate all defered blocks */
   372      for _, fp := range self.defs {
   373          p.Link(fp.ref)
   374          fp.def(p)
   375      }
   376  
   377      /* ABI-specific epilogue */
   378      p.Link(self.halt)
   379      self.abiEpilogue(p)
   380      self.abiLoadReserved(p)
   381  
   382      /* program epilogue */
   383      p.MOVQ(Ptr(RSP, self.ctxt.offs()), RBP)
   384      p.ADDQ(self.ctxt.size(), RSP)
   385      p.Link(self.tail)
   386      p.RET()
   387  
   388      /* stack grow */
   389      p.Link(stack)
   390      self.abiStackGrow(p)
   391      p.JMP(entry)
   392  
   393      /* link all the lookup tables */
   394      for _, v := range self.stab {
   395          v.link(p)
   396      }
   397  
   398      /* stack ranges */
   399      code := p.Assemble(0)
   400      head := toAddress(self.head)
   401      tail := toAddress(self.tail)
   402      args := uintptr(self.ctxt.save())
   403      size := uintptr(self.ctxt.size())
   404  
   405      /* build the PC-SP tab */
   406      tab := []rt.Stack {
   407          { Sp:    0, Nb: head },
   408          { Sp: size, Nb: tail - head },
   409          { Sp:    0, Nb: 0 },
   410      }
   411  
   412      /* assemble the function */
   413      ret := &Func {
   414          Code  : code,
   415          Frame : rt.Frame {
   416              SpTab     : tab,
   417              ArgSize   : args,
   418              ArgPtrs   : self.ctxt.ArgPtrs(),
   419              LocalPtrs : self.ctxt.LocalPtrs(),
   420          },
   421      }
   422  
   423      /* free the assembler */
   424      p.Free()
   425      return ret
   426  }
   427  
   428  func (self *CodeGen) later(ref *x86_64.Label, def func(*x86_64.Program)) {
   429      self.defs = append(self.defs, _DeferBlock {
   430          ref: ref,
   431          def: def,
   432      })
   433  }
   434  
   435  func (self *CodeGen) translate(p *x86_64.Program, v *hir.Ir) {
   436      if p.Link(self.to(v)); v.Op != hir.OP_nop {
   437          if fp := translators[v.Op]; fp != nil {
   438              fp(self, p, v)
   439          } else {
   440              panic("pgen: invalid instruction: " + v.Disassemble(nil))
   441          }
   442      }
   443  }
   444  
   445  /** Register Allocation **/
   446  
   447  type _Check struct {
   448      bv Operands
   449      fn func(*hir.Ir) hir.Register
   450  }
   451  
   452  var _readChecks = [...]_Check {
   453      { bv: Orx, fn: func(p *hir.Ir) hir.Register { return p.Rx } },
   454      { bv: Ory, fn: func(p *hir.Ir) hir.Register { return p.Ry } },
   455      { bv: Ops, fn: func(p *hir.Ir) hir.Register { return p.Ps } },
   456  }
   457  
   458  var _writeAllocs = [...]_Check {
   459      { bv: Owx, fn: func(p *hir.Ir) hir.Register { return p.Rx } },
   460      { bv: Owy, fn: func(p *hir.Ir) hir.Register { return p.Ry } },
   461      { bv: Owz, fn: func(p *hir.Ir) hir.Register { return p.Rz } },
   462      { bv: Opd, fn: func(p *hir.Ir) hir.Register { return p.Pd } },
   463  }
   464  
   465  func (self *CodeGen) rload(v *hir.Ir, r hir.Register) {
   466      if _, ok := self.regs[r]; !ok && !r.Z() {
   467          panic(fmt.Sprintf("pgen: access to unallocated register %s: %s", r.String(), v.Disassemble(nil)))
   468      }
   469  }
   470  
   471  func (self *CodeGen) rstore(v *hir.Ir, r hir.Register) {
   472      if _, ok := self.regs[r]; !ok && !r.Z() {
   473          if self.ctxt.ralloc(r); self.regi < len(allocationOrder) {
   474              self.regi, self.regs[r] = self.regi + 1, allocationOrder[self.regi]
   475          } else {
   476              panic("pgen: program is too complex to translate on x86_64 (requiring too many registers): " + v.Disassemble(nil))
   477          }
   478      }
   479  }
   480  
   481  func (self *CodeGen) ldret(v *hir.Ir) {
   482      for i := 0; i < int(v.Rn); i++ {
   483          if r := v.Rr[i]; r & hir.ArgPointer == 0 {
   484              self.rload(v, hir.GenericRegister(r))
   485          } else {
   486              self.rload(v, hir.PointerRegister(r & hir.ArgMask))
   487          }
   488      }
   489  }
   490  
   491  func (self *CodeGen) ldcall(v *hir.Ir) {
   492      for i := 0; i < int(v.An); i++ {
   493          if r := v.Ar[i]; r & hir.ArgPointer == 0 {
   494              self.rload(v, hir.GenericRegister(r))
   495          } else {
   496              self.rload(v, hir.PointerRegister(r & hir.ArgMask))
   497          }
   498      }
   499  }
   500  
   501  func (self *CodeGen) stcall(v *hir.Ir) {
   502      for i := 0; i < int(v.Rn); i++ {
   503          if r := v.Rr[i]; r & hir.ArgPointer == 0 {
   504              self.rstore(v, hir.GenericRegister(r))
   505          } else {
   506              self.rstore(v, hir.PointerRegister(r & hir.ArgMask))
   507          }
   508      }
   509  }
   510  
   511  func (self *CodeGen) rcheck(v *hir.Ir, p Operands) {
   512      for _, cc := range _readChecks {
   513          if p & Oret  != 0 { self.ldret(v) }
   514          if p & Ocall != 0 { self.ldcall(v) }
   515          if p & cc.bv != 0 { self.rload(v, cc.fn(v)) }
   516      }
   517  }
   518  
   519  func (self *CodeGen) walloc(v *hir.Ir, p Operands) {
   520      for _, cc := range _writeAllocs {
   521          if p & Ocall != 0 { self.stcall(v) }
   522          if p & cc.bv != 0 { self.rstore(v, cc.fn(v)) }
   523      }
   524  }
   525  
   526  func (self *CodeGen) rindex(r x86_64.Register64) hir.Register {
   527      for k, v := range self.regs { if v == r { return k } }
   528      return nil
   529  }
   530  
   531  /** Generator Helpers **/
   532  
   533  func (self *CodeGen) r(reg hir.Register) x86_64.Register64 {
   534      if rr, ok := self.regs[reg]; !ok {
   535          panic("pgen: access to unallocated register: " + reg.String())
   536      } else {
   537          return rr
   538      }
   539  }
   540  
   541  func (self *CodeGen) to(v *hir.Ir) *x86_64.Label {
   542      return self.ref(fmt.Sprintf("_PC_%p", v))
   543  }
   544  
   545  func (self *CodeGen) tab(i int64) *_SwitchTable {
   546      p := len(self.stab)
   547      self.stab = append(self.stab, newSwitchTable(int(i)))
   548      return &self.stab[p]
   549  }
   550  
   551  func (self *CodeGen) ref(s string) *x86_64.Label {
   552      var k bool
   553      var p *x86_64.Label
   554  
   555      /* check for existance */
   556      if p, k = self.jmps[s]; k {
   557          return p
   558      }
   559  
   560      /* create a new label if not */
   561      p = x86_64.CreateLabel(s)
   562      self.jmps[s] = p
   563      return p
   564  }
   565  
   566  func (self *CodeGen) i32(p *x86_64.Program, v *hir.Ir) interface{} {
   567      if isInt32(v.Iv) {
   568          return v.Iv
   569      } else {
   570          p.MOVQ(v.Iv, RAX)
   571          return RAX
   572      }
   573  }
   574  
   575  func (self *CodeGen) ptr(p *x86_64.Program, r hir.PointerRegister, d int64) *x86_64.MemoryOperand {
   576      if isInt32(d) {
   577          return Ptr(self.r(r), int32(d))
   578      } else {
   579          p.MOVQ(d, RAX)
   580          return Sib(self.r(r), RAX, 1, 0)
   581      }
   582  }
   583  
   584  func (self *CodeGen) clr(p *x86_64.Program, r hir.Register) {
   585      rx := self.r(r)
   586      p.XORL(x86_64.Register32(rx), x86_64.Register32(rx))
   587  }
   588  
   589  func (self *CodeGen) set(p *x86_64.Program, r hir.Register, i int64) {
   590      if i == 0 {
   591          self.clr(p, r)
   592      } else {
   593          p.MOVQ(i, self.r(r))
   594      }
   595  }
   596  
   597  func (self *CodeGen) dup(p *x86_64.Program, r hir.Register, d hir.Register) {
   598      if r != d {
   599          p.MOVQ(self.r(r), self.r(d))
   600      }
   601  }
   602  
   603  /** OpCode Generators **/
   604  
   605  var translators = [256]func(*CodeGen, *x86_64.Program, *hir.Ir) {
   606      hir.OP_ip    : (*CodeGen).translate_OP_ip,
   607      hir.OP_lb    : (*CodeGen).translate_OP_lb,
   608      hir.OP_lw    : (*CodeGen).translate_OP_lw,
   609      hir.OP_ll    : (*CodeGen).translate_OP_ll,
   610      hir.OP_lq    : (*CodeGen).translate_OP_lq,
   611      hir.OP_lp    : (*CodeGen).translate_OP_lp,
   612      hir.OP_sb    : (*CodeGen).translate_OP_sb,
   613      hir.OP_sw    : (*CodeGen).translate_OP_sw,
   614      hir.OP_sl    : (*CodeGen).translate_OP_sl,
   615      hir.OP_sq    : (*CodeGen).translate_OP_sq,
   616      hir.OP_sp    : (*CodeGen).translate_OP_sp,
   617      hir.OP_ldaq  : (*CodeGen).translate_OP_ldaq,
   618      hir.OP_ldap  : (*CodeGen).translate_OP_ldap,
   619      hir.OP_addp  : (*CodeGen).translate_OP_addp,
   620      hir.OP_subp  : (*CodeGen).translate_OP_subp,
   621      hir.OP_addpi : (*CodeGen).translate_OP_addpi,
   622      hir.OP_add   : (*CodeGen).translate_OP_add,
   623      hir.OP_sub   : (*CodeGen).translate_OP_sub,
   624      hir.OP_bts   : (*CodeGen).translate_OP_bts,
   625      hir.OP_addi  : (*CodeGen).translate_OP_addi,
   626      hir.OP_muli  : (*CodeGen).translate_OP_muli,
   627      hir.OP_andi  : (*CodeGen).translate_OP_andi,
   628      hir.OP_xori  : (*CodeGen).translate_OP_xori,
   629      hir.OP_shri  : (*CodeGen).translate_OP_shri,
   630      hir.OP_bsi   : (*CodeGen).translate_OP_bsi,
   631      hir.OP_swapw : (*CodeGen).translate_OP_swapw,
   632      hir.OP_swapl : (*CodeGen).translate_OP_swapl,
   633      hir.OP_swapq : (*CodeGen).translate_OP_swapq,
   634      hir.OP_sxlq  : (*CodeGen).translate_OP_sxlq,
   635      hir.OP_beq   : (*CodeGen).translate_OP_beq,
   636      hir.OP_bne   : (*CodeGen).translate_OP_bne,
   637      hir.OP_blt   : (*CodeGen).translate_OP_blt,
   638      hir.OP_bltu  : (*CodeGen).translate_OP_bltu,
   639      hir.OP_bgeu  : (*CodeGen).translate_OP_bgeu,
   640      hir.OP_beqp  : (*CodeGen).translate_OP_beqp,
   641      hir.OP_bnep  : (*CodeGen).translate_OP_bnep,
   642      hir.OP_bsw   : (*CodeGen).translate_OP_bsw,
   643      hir.OP_jmp   : (*CodeGen).translate_OP_jmp,
   644      hir.OP_bzero : (*CodeGen).translate_OP_bzero,
   645      hir.OP_bcopy : (*CodeGen).translate_OP_bcopy,
   646      hir.OP_ccall : (*CodeGen).translate_OP_ccall,
   647      hir.OP_gcall : (*CodeGen).translate_OP_gcall,
   648      hir.OP_icall : (*CodeGen).translate_OP_icall,
   649      hir.OP_ret   : (*CodeGen).translate_OP_ret,
   650      hir.OP_break : (*CodeGen).translate_OP_break,
   651  }
   652  
   653  func (self *CodeGen) translate_OP_ip(p *x86_64.Program, v *hir.Ir) {
   654      if v.Pd != hir.Pn {
   655          if addr := uintptr(v.Pr); addr > math.MaxUint32 {
   656              p.MOVQ(addr, self.r(v.Pd))
   657          } else {
   658              p.MOVL(addr, x86_64.Register32(self.r(v.Pd)))
   659          }
   660      }
   661  }
   662  
   663  func (self *CodeGen) translate_OP_lb(p *x86_64.Program, v *hir.Ir) {
   664      if v.Rx != hir.Rz {
   665          if v.Ps == hir.Pn {
   666              panic("lb: load from nil pointer")
   667          } else {
   668              p.MOVZBQ(self.ptr(p, v.Ps, v.Iv), self.r(v.Rx))
   669          }
   670      }
   671  }
   672  
   673  func (self *CodeGen) translate_OP_lw(p *x86_64.Program, v *hir.Ir) {
   674      if v.Rx != hir.Rz {
   675          if v.Ps == hir.Pn {
   676              panic("lw: load from nil pointer")
   677          } else {
   678              p.MOVZWQ(self.ptr(p, v.Ps, v.Iv), self.r(v.Rx))
   679          }
   680      }
   681  }
   682  
   683  func (self *CodeGen) translate_OP_ll(p *x86_64.Program, v *hir.Ir) {
   684      if v.Rx != hir.Rz {
   685          if v.Ps == hir.Pn {
   686              panic("ll: load from nil pointer")
   687          } else {
   688              p.MOVL(self.ptr(p, v.Ps, v.Iv), x86_64.Register32(self.r(v.Rx)))
   689          }
   690      }
   691  }
   692  
   693  func (self *CodeGen) translate_OP_lq(p *x86_64.Program, v *hir.Ir) {
   694      if v.Rx != hir.Rz {
   695          if v.Ps == hir.Pn {
   696              panic("lq: load from nil pointer")
   697          } else {
   698              p.MOVQ(self.ptr(p, v.Ps, v.Iv), self.r(v.Rx))
   699          }
   700      }
   701  }
   702  
   703  func (self *CodeGen) translate_OP_lp(p *x86_64.Program, v *hir.Ir) {
   704      if v.Pd != hir.Pn {
   705          if v.Ps == hir.Pn {
   706              panic("lp: load from nil pointer")
   707          } else {
   708              p.MOVQ(self.ptr(p, v.Ps, v.Iv), self.r(v.Pd))
   709          }
   710      }
   711  }
   712  
   713  func (self *CodeGen) translate_OP_sb(p *x86_64.Program, v *hir.Ir) {
   714      if v.Pd == hir.Pn {
   715          panic("sb: store to nil pointer")
   716      } else if v.Rx == hir.Rz {
   717          p.MOVB(0, self.ptr(p, v.Pd, v.Iv))
   718      } else {
   719          p.MOVB(x86_64.Register8(self.r(v.Rx)), self.ptr(p, v.Pd, v.Iv))
   720      }
   721  }
   722  
   723  func (self *CodeGen) translate_OP_sw(p *x86_64.Program, v *hir.Ir) {
   724      if v.Pd == hir.Pn {
   725          panic("sw: store to nil pointer")
   726      } else if v.Rx == hir.Rz {
   727          p.MOVW(0, self.ptr(p, v.Pd, v.Iv))
   728      } else {
   729          p.MOVW(x86_64.Register16(self.r(v.Rx)), self.ptr(p, v.Pd, v.Iv))
   730      }
   731  }
   732  
   733  func (self *CodeGen) translate_OP_sl(p *x86_64.Program, v *hir.Ir) {
   734      if v.Pd == hir.Pn {
   735          panic("sl: store to nil pointer")
   736      } else if v.Rx == hir.Rz {
   737          p.MOVL(0, self.ptr(p, v.Pd, v.Iv))
   738      } else {
   739          p.MOVL(x86_64.Register32(self.r(v.Rx)), self.ptr(p, v.Pd, v.Iv))
   740      }
   741  }
   742  
   743  func (self *CodeGen) translate_OP_sq(p *x86_64.Program, v *hir.Ir) {
   744      if v.Pd == hir.Pn {
   745          panic("sq: store to nil pointer")
   746      } else if v.Rx == hir.Rz {
   747          p.MOVQ(0, self.ptr(p, v.Pd, v.Iv))
   748      } else {
   749          p.MOVQ(self.r(v.Rx), self.ptr(p, v.Pd, v.Iv))
   750      }
   751  }
   752  
   753  func (self *CodeGen) translate_OP_sp(p *x86_64.Program, v *hir.Ir) {
   754      if v.Pd == hir.Pn {
   755          panic("sp: store to nil pointer")
   756      } else {
   757          self.wbStorePointer(p, v.Ps, self.ptr(p, v.Pd, v.Iv))
   758      }
   759  }
   760  
   761  func (self *CodeGen) translate_OP_ldaq(p *x86_64.Program, v *hir.Ir) {
   762      if v.Rx != hir.Rz {
   763          if i := int(v.Iv); i < self.ctxt.argc() {
   764              self.abiLoadInt(p, i, v.Rx)
   765          } else {
   766              panic(fmt.Sprintf("ldaq: argument index out of range: %d", i))
   767          }
   768      }
   769  }
   770  
   771  func (self *CodeGen) translate_OP_ldap(p *x86_64.Program, v *hir.Ir) {
   772      if v.Pd != hir.Pn {
   773          if i := int(v.Iv); i < self.ctxt.argc() {
   774              self.abiLoadPtr(p, i, v.Pd)
   775          } else {
   776              panic(fmt.Sprintf("ldap: argument index out of range: %d", v.Iv))
   777          }
   778      }
   779  }
   780  
   781  func (self *CodeGen) translate_OP_addp(p *x86_64.Program, v *hir.Ir) {
   782      if v.Pd != hir.Pn {
   783          if v.Ps == hir.Pn {
   784              if v.Rx != hir.Rz {
   785                  panic("addp: direct conversion of integer to pointer")
   786              } else {
   787                  self.clr(p, v.Pd)
   788              }
   789          } else {
   790              if v.Rx != hir.Rz {
   791                  p.LEAQ(Sib(self.r(v.Ps), self.r(v.Rx), 1, 0), self.r(v.Pd))
   792              } else {
   793                  self.dup(p, v.Ps, v.Pd)
   794              }
   795          }
   796      }
   797  }
   798  
   799  func (self *CodeGen) translate_OP_subp(p *x86_64.Program, v *hir.Ir) {
   800      if v.Pd != hir.Pn {
   801          if v.Ps == hir.Pn {
   802              panic("subp: direct conversion of integer to pointer")
   803          } else if self.dup(p, v.Ps, v.Pd); v.Rx != hir.Rz {
   804              p.SUBQ(self.r(v.Rx), self.r(v.Pd))
   805          }
   806      }
   807  }
   808  
   809  func (self *CodeGen) translate_OP_addpi(p *x86_64.Program, v *hir.Ir) {
   810      if v.Pd != hir.Pn {
   811          if v.Ps == hir.Pn {
   812              if v.Iv != 0 {
   813                  panic("addpi: direct conversion of integer to pointer")
   814              } else {
   815                  self.clr(p, v.Pd)
   816              }
   817          } else {
   818              if !isInt32(v.Iv) {
   819                  panic("addpi: offset too large, may result in an invalid pointer")
   820              } else {
   821                  p.LEAQ(Ptr(self.r(v.Ps), int32(v.Iv)), self.r(v.Pd))
   822              }
   823          }
   824      }
   825  }
   826  
   827  func (self *CodeGen) translate_OP_add(p *x86_64.Program, v *hir.Ir) {
   828      if v.Rz != hir.Rz {
   829          if v.Rx == hir.Rz {
   830              if v.Ry == hir.Rz {
   831                  self.clr(p, v.Rz)
   832              } else {
   833                  self.dup(p, v.Ry, v.Rz)
   834              }
   835          } else {
   836              if v.Ry == hir.Rz {
   837                  self.dup(p, v.Rx, v.Rz)
   838              } else if v.Ry == v.Rz {
   839                  p.ADDQ(self.r(v.Rx), self.r(v.Rz))
   840              } else {
   841                  self.dup(p, v.Rx, v.Rz)
   842                  p.ADDQ(self.r(v.Ry), self.r(v.Rz))
   843              }
   844          }
   845      }
   846  }
   847  
   848  func (self *CodeGen) translate_OP_sub(p *x86_64.Program, v *hir.Ir) {
   849      if v.Rz != hir.Rz {
   850          if v.Rx == hir.Rz {
   851              if v.Ry == hir.Rz {
   852                  self.clr(p, v.Rz)
   853              } else {
   854                  self.dup(p, v.Ry, v.Rz)
   855              }
   856          } else {
   857              if v.Ry == hir.Rz {
   858                  self.dup(p, v.Rx, v.Rz)
   859              } else if v.Ry == v.Rz {
   860                  p.SUBQ(self.r(v.Rx), self.r(v.Rz))
   861                  p.NEGQ(self.r(v.Rz))
   862              } else {
   863                  self.dup(p, v.Rx, v.Rz)
   864                  p.SUBQ(self.r(v.Ry), self.r(v.Rz))
   865              }
   866          }
   867      }
   868  }
   869  
   870  func (self *CodeGen) translate_OP_bts(p *x86_64.Program, v *hir.Ir) {
   871      x := v.Rx
   872      y := v.Ry
   873      z := v.Rz
   874  
   875      /* special case: y is zero */
   876      if y == hir.Rz {
   877          return
   878      }
   879  
   880      /* testing and setting the bits at the same time */
   881      if x == hir.Rz {
   882          p.BTSQ(0, self.r(y))
   883      } else {
   884          p.BTSQ(self.r(x), self.r(y))
   885      }
   886  
   887      /* set the result if expected */
   888      if z != hir.Rz {
   889          p.SETC(x86_64.Register8(self.r(z)))
   890          p.ANDL(1, x86_64.Register32(self.r(z)))
   891      }
   892  }
   893  
   894  func (self *CodeGen) translate_OP_addi(p *x86_64.Program, v *hir.Ir) {
   895      if v.Ry != hir.Rz {
   896          if v.Rx != hir.Rz {
   897              if self.dup(p, v.Rx, v.Ry); v.Iv != 0 {
   898                  p.ADDQ(self.i32(p, v), self.r(v.Ry))
   899              }
   900          } else {
   901              if v.Iv == 0 {
   902                  self.clr(p, v.Ry)
   903              } else if !isInt32(v.Iv) {
   904                  p.MOVQ(v.Iv, self.r(v.Ry))
   905              } else {
   906                  p.MOVL(v.Iv, x86_64.Register32(self.r(v.Ry)))
   907              }
   908          }
   909      }
   910  }
   911  
   912  func (self *CodeGen) translate_OP_muli(p *x86_64.Program, v *hir.Ir) {
   913      var z x86_64.Register
   914      var x x86_64.Register64
   915      var y x86_64.Register64
   916  
   917      /* no need to calculate if the result was to be discarded */
   918      if v.Ry == hir.Rz {
   919          return
   920      }
   921  
   922      /* multiply anything by zero is zero */
   923      if v.Rx == hir.Rz {
   924          self.clr(p, v.Ry)
   925          return
   926      }
   927  
   928      /* get the allocated registers */
   929      x = self.r(v.Rx)
   930      y = self.r(v.Ry)
   931  
   932      /* optimized multiplication */
   933      switch {
   934          case v.Iv == 0: self.clr(p, v.Ry)           // x * 0 == 0
   935          case v.Iv == 1: self.dup(p, v.Rx, v.Ry)     // x * 1 == x
   936  
   937          /* multiply by 2, 4 or 8, choose between ADD / SHL and LEA */
   938          case v.Iv == 2: if x == y { p.ADDQ(x, y) } else { p.LEAQ(Sib(x, x, 1, 0), y) }
   939          case v.Iv == 4: if x == y { p.SHLQ(2, y) } else { p.LEAQ(Sib(z, x, 4, 0), y) }
   940          case v.Iv == 8: if x == y { p.SHLQ(3, y) } else { p.LEAQ(Sib(z, x, 8, 0), y) }
   941  
   942          /* small multipliers, use optimized multiplication algorithm */
   943          case v.Iv == 3  : p.LEAQ(Sib(x, x, 2, 0), y)                                // x * 3  == x + x * 2
   944          case v.Iv == 5  : p.LEAQ(Sib(x, x, 4, 0), y)                                // x * 5  == x + x * 4
   945          case v.Iv == 6  : p.LEAQ(Sib(x, x, 2, 0), y); p.ADDQ(y, y)                  // x * 6  == x * 3 * 2
   946          case v.Iv == 9  : p.LEAQ(Sib(x, x, 8, 0), y)                                // x * 9  == x + x * 8
   947          case v.Iv == 10 : p.LEAQ(Sib(x, x, 4, 0), y); p.ADDQ(y, y)                  // x * 10 == x * 5 * 2
   948          case v.Iv == 12 : p.LEAQ(Sib(x, x, 2, 0), y); p.SHLQ(2, y)                  // x * 12 == x * 3 * 4
   949          case v.Iv == 15 : p.LEAQ(Sib(x, x, 4, 0), y); p.LEAQ(Sib(y, y, 2, 0), y)    // x * 15 == x * 5 * 3
   950          case v.Iv == 18 : p.LEAQ(Sib(x, x, 8, 0), y); p.ADDQ(y, y)                  // x * 18 == x * 9 * 2
   951          case v.Iv == 20 : p.LEAQ(Sib(x, x, 4, 0), y); p.SHLQ(2, y)                  // x * 20 == x * 5 * 4
   952          case v.Iv == 24 : p.LEAQ(Sib(x, x, 2, 0), y); p.SHLQ(3, y)                  // x * 24 == x * 3 * 8
   953          case v.Iv == 25 : p.LEAQ(Sib(x, x, 4, 0), y); p.LEAQ(Sib(y, y, 4, 0), y)    // x * 25 == x * 5 * 5
   954          case v.Iv == 27 : p.LEAQ(Sib(x, x, 8, 0), y); p.LEAQ(Sib(y, y, 2, 0), y)    // x * 27 == x * 9 * 3
   955          case v.Iv == 36 : p.LEAQ(Sib(x, x, 8, 0), y); p.SHLQ(2, y)                  // x * 36 == x * 9 * 4
   956          case v.Iv == 40 : p.LEAQ(Sib(x, x, 4, 0), y); p.SHLQ(3, y)                  // x * 40 == x * 5 * 8
   957          case v.Iv == 45 : p.LEAQ(Sib(x, x, 8, 0), y); p.LEAQ(Sib(y, y, 4, 0), y)    // x * 45 == x * 9 * 5
   958          case v.Iv == 48 : p.LEAQ(Sib(x, x, 2, 0), y); p.SHLQ(4, y)                  // x * 48 == x * 3 * 16
   959          case v.Iv == 72 : p.LEAQ(Sib(x, x, 8, 0), y); p.SHLQ(3, y)                  // x * 72 == x * 9 * 8
   960          case v.Iv == 80 : p.LEAQ(Sib(x, x, 4, 0), y); p.SHLQ(4, y)                  // x * 80 == x * 5 * 16
   961          case v.Iv == 81 : p.LEAQ(Sib(x, x, 8, 0), y); p.LEAQ(Sib(y, y, 8, 0), y)    // x * 81 == x * 9 * 9
   962  
   963          /* multiplier is a power of 2, use shifts */
   964          case isPow2(v.Iv): {
   965              self.dup(p, v.Rx, v.Ry)
   966              p.SHLQ(bits.TrailingZeros64(uint64(v.Iv)), y)
   967          }
   968  
   969          /* multiplier can fit into a 32-bit integer, use 3-operand IMUL instruction */
   970          case isInt32(v.Iv): {
   971              p.IMULQ(v.Iv, x, y)
   972          }
   973  
   974          /* none of above matches, we need an extra temporary register */
   975          default: {
   976              self.dup(p, v.Rx, v.Ry)
   977              p.MOVQ(v.Iv, RAX)
   978              p.IMULQ(RAX, y)
   979          }
   980      }
   981  }
   982  
   983  func (self *CodeGen) translate_OP_andi(p *x86_64.Program, v *hir.Ir) {
   984      if v.Ry != hir.Rz {
   985          if v.Iv == 0 || v.Rx == hir.Rz {
   986              self.clr(p, v.Ry)
   987          } else {
   988              self.dup(p, v.Rx, v.Ry)
   989              p.ANDQ(self.i32(p, v), self.r(v.Ry))
   990          }
   991      }
   992  }
   993  
   994  func (self *CodeGen) translate_OP_xori(p *x86_64.Program, v *hir.Ir) {
   995      if v.Ry != hir.Rz {
   996          if v.Rx != hir.Rz {
   997              if self.dup(p, v.Rx, v.Ry); v.Iv != 0 {
   998                  p.XORQ(self.i32(p, v), self.r(v.Ry))
   999              }
  1000          } else {
  1001              if v.Iv == 0 {
  1002                  self.clr(p, v.Ry)
  1003              } else if !isInt32(v.Iv) {
  1004                  p.MOVQ(v.Iv, self.r(v.Ry))
  1005              } else {
  1006                  p.MOVL(v.Iv, x86_64.Register32(self.r(v.Ry)))
  1007              }
  1008          }
  1009      }
  1010  }
  1011  
  1012  func (self *CodeGen) translate_OP_shri(p *x86_64.Program, v *hir.Ir) {
  1013      if v.Ry != hir.Rz {
  1014          if v.Iv < 0 {
  1015              panic("shri: negative bit count")
  1016          } else if v.Iv >= 64 || v.Rx == hir.Rz {
  1017              p.XORL(self.r(v.Ry), self.r(v.Ry))
  1018          } else if self.dup(p, v.Rx, v.Ry); v.Iv != 0 {
  1019              p.SHRQ(v.Iv, self.r(v.Ry))
  1020          }
  1021      }
  1022  }
  1023  
  1024  func (self *CodeGen) translate_OP_bsi(p *x86_64.Program, v *hir.Ir) {
  1025      if v.Ry != hir.Rz {
  1026          if v.Iv < 0 {
  1027              panic("sbiti: negative bit index")
  1028          } else if v.Rx == hir.Rz {
  1029              self.set(p, v.Ry, 1 << v.Iv)
  1030          } else if self.dup(p, v.Rx, v.Ry); v.Iv < 31 {
  1031              p.ORQ(1 << v.Iv, self.r(v.Ry))
  1032          } else if v.Iv < 64 {
  1033              p.BTSQ(v.Iv, self.r(v.Ry))
  1034          }
  1035      }
  1036  }
  1037  
  1038  func (self *CodeGen) translate_OP_swapw(p *x86_64.Program, v *hir.Ir) {
  1039      if v.Ry != hir.Rz {
  1040          self.dup(p, v.Rx, v.Ry)
  1041          p.ROLW(8, x86_64.Register16(self.r(v.Ry)))
  1042      }
  1043  }
  1044  
  1045  func (self *CodeGen) translate_OP_swapl(p *x86_64.Program, v *hir.Ir) {
  1046      if v.Ry != hir.Rz {
  1047          self.dup(p, v.Rx, v.Ry)
  1048          p.BSWAPL(x86_64.Register32(self.r(v.Ry)))
  1049      }
  1050  }
  1051  
  1052  func (self *CodeGen) translate_OP_swapq(p *x86_64.Program, v *hir.Ir) {
  1053      if v.Ry != hir.Rz {
  1054          self.dup(p, v.Rx, v.Ry)
  1055          p.BSWAPQ(self.r(v.Ry))
  1056      }
  1057  }
  1058  
  1059  func (self *CodeGen) translate_OP_sxlq(p *x86_64.Program, v *hir.Ir) {
  1060      if v.Ry != hir.Rz {
  1061          if v.Rx == hir.Rz {
  1062              self.clr(p, v.Ry)
  1063          } else {
  1064              p.MOVSLQ(x86_64.Register32(self.r(v.Rx)), self.r(v.Ry))
  1065          }
  1066      }
  1067  }
  1068  
  1069  func (self *CodeGen) translate_OP_beq(p *x86_64.Program, v *hir.Ir) {
  1070      if v.Rx == v.Ry {
  1071          p.JMP(self.to(v.Br))
  1072      } else if v.Rx == hir.Rz {
  1073          p.TESTQ(self.r(v.Ry), self.r(v.Ry))
  1074          p.JZ(self.to(v.Br))
  1075      } else if v.Ry == hir.Rz {
  1076          p.TESTQ(self.r(v.Rx), self.r(v.Rx))
  1077          p.JZ(self.to(v.Br))
  1078      } else {
  1079          p.CMPQ(self.r(v.Ry), self.r(v.Rx))
  1080          p.JE(self.to(v.Br))
  1081      }
  1082  }
  1083  
  1084  func (self *CodeGen) translate_OP_bne(p *x86_64.Program, v *hir.Ir) {
  1085      if v.Rx != v.Ry {
  1086          if v.Rx == hir.Rz {
  1087              p.TESTQ(self.r(v.Ry), self.r(v.Ry))
  1088              p.JNZ(self.to(v.Br))
  1089          } else if v.Ry == hir.Rz {
  1090              p.TESTQ(self.r(v.Rx), self.r(v.Rx))
  1091              p.JNZ(self.to(v.Br))
  1092          } else {
  1093              p.CMPQ(self.r(v.Ry), self.r(v.Rx))
  1094              p.JNE(self.to(v.Br))
  1095          }
  1096      }
  1097  }
  1098  
  1099  func (self *CodeGen) translate_OP_blt(p *x86_64.Program, v *hir.Ir) {
  1100      if v.Rx != v.Ry {
  1101          if v.Rx == hir.Rz {
  1102              p.TESTQ(self.r(v.Ry), self.r(v.Ry))
  1103              p.JNS(self.to(v.Br))
  1104          } else if v.Ry == hir.Rz {
  1105              p.TESTQ(self.r(v.Rx), self.r(v.Rx))
  1106              p.JS(self.to(v.Br))
  1107          } else {
  1108              p.CMPQ(self.r(v.Ry), self.r(v.Rx))
  1109              p.JL(self.to(v.Br))
  1110          }
  1111      }
  1112  }
  1113  
  1114  func (self *CodeGen) translate_OP_bltu(p *x86_64.Program, v *hir.Ir) {
  1115      if v.Rx != v.Ry {
  1116          if v.Rx == hir.Rz {
  1117              p.TESTQ(self.r(v.Ry), self.r(v.Ry))
  1118              p.JNZ(self.to(v.Br))
  1119          } else if v.Ry != hir.Rz {
  1120              p.CMPQ(self.r(v.Ry), self.r(v.Rx))
  1121              p.JB(self.to(v.Br))
  1122          }
  1123      }
  1124  }
  1125  
  1126  func (self *CodeGen) translate_OP_bgeu(p *x86_64.Program, v *hir.Ir) {
  1127      if v.Ry == hir.Rz || v.Rx == v.Ry {
  1128          p.JMP(self.to(v.Br))
  1129      } else if v.Rx == hir.Rz {
  1130          p.TESTQ(self.r(v.Ry), self.r(v.Ry))
  1131          p.JZ(self.to(v.Br))
  1132      } else {
  1133          p.CMPQ(self.r(v.Ry), self.r(v.Rx))
  1134          p.JAE(self.to(v.Br))
  1135      }
  1136  }
  1137  
  1138  func (self *CodeGen) translate_OP_beqp(p *x86_64.Program, v *hir.Ir) {
  1139      if v.Ps == v.Pd {
  1140          p.JMP(self.to(v.Br))
  1141      } else if v.Ps == hir.Pn {
  1142          p.TESTQ(self.r(v.Pd), self.r(v.Pd))
  1143          p.JZ(self.to(v.Br))
  1144      } else if v.Pd == hir.Pn {
  1145          p.TESTQ(self.r(v.Ps), self.r(v.Ps))
  1146          p.JZ(self.to(v.Br))
  1147      } else {
  1148          p.CMPQ(self.r(v.Pd), self.r(v.Ps))
  1149          p.JE(self.to(v.Br))
  1150      }
  1151  }
  1152  
  1153  func (self *CodeGen) translate_OP_bnep(p *x86_64.Program, v *hir.Ir) {
  1154      if v.Ps != v.Pd {
  1155          if v.Ps == hir.Pn {
  1156              p.TESTQ(self.r(v.Pd), self.r(v.Pd))
  1157              p.JNZ(self.to(v.Br))
  1158          } else if v.Pd == hir.Pn {
  1159              p.TESTQ(self.r(v.Ps), self.r(v.Ps))
  1160              p.JNZ(self.to(v.Br))
  1161          } else {
  1162              p.CMPQ(self.r(v.Pd), self.r(v.Ps))
  1163              p.JNE(self.to(v.Br))
  1164          }
  1165      }
  1166  }
  1167  
  1168  func (self *CodeGen) translate_OP_bsw(p *x86_64.Program, v *hir.Ir) {
  1169      nsw := v.Iv
  1170      tab := v.Switch()
  1171  
  1172      /* empty switch */
  1173      if nsw == 0 {
  1174          return
  1175      }
  1176  
  1177      /* allocate switch buffer and default switch label */
  1178      buf := self.tab(nsw)
  1179      def := x86_64.CreateLabel("_default")
  1180  
  1181      /* set default switch targets */
  1182      for i := 0; i < int(v.Iv); i++ {
  1183          buf.mark(i, def)
  1184      }
  1185  
  1186      /* assign the specified switch targets */
  1187      for i, ref := range tab {
  1188          if ref != nil {
  1189              buf.mark(i, self.to(ref))
  1190          }
  1191      }
  1192  
  1193      /* switch on v.Rx */
  1194      p.CMPQ   (nsw, self.r(v.Rx))
  1195      p.JAE    (def)
  1196      p.LEAQ   (x86_64.Ref(buf.ref), RAX)
  1197      p.MOVSLQ (Sib(RAX, self.r(v.Rx), 4, 0), RSI)
  1198      p.ADDQ   (RSI, RAX)
  1199      p.JMPQ   (RAX)
  1200      p.Link   (def)
  1201  }
  1202  
  1203  func (self *CodeGen) translate_OP_jmp(p *x86_64.Program, v *hir.Ir) {
  1204      p.JMP(self.to(v.Br))
  1205  }
  1206  
  1207  func (self *CodeGen) translate_OP_bzero(p *x86_64.Program, v *hir.Ir) {
  1208      if v.Pd == hir.Pn {
  1209          panic("bzero: zeroing nil pointer")
  1210      } else if v.Iv != 0 {
  1211          self.abiBlockZero(p, v.Pd, v.Iv)
  1212      }
  1213  }
  1214  
  1215  func (self *CodeGen) translate_OP_bcopy(p *x86_64.Program, v *hir.Ir) {
  1216      if v.Ps == hir.Pn {
  1217          panic("bcopy: copy from nil pointer")
  1218      } else if v.Pd == hir.Pn {
  1219          panic("bcopy: copy into nil pointer")
  1220      } else if v.Rx != hir.Rz && v.Ps != v.Pd {
  1221          self.abiBlockCopy(p, v.Pd, v.Ps, v.Rx)
  1222      }
  1223  }
  1224  
  1225  func (self *CodeGen) translate_OP_ccall(p *x86_64.Program, v *hir.Ir) {
  1226      self.abiCallNative(p, v)
  1227  }
  1228  
  1229  func (self *CodeGen) translate_OP_gcall(p *x86_64.Program, v *hir.Ir) {
  1230      self.abiCallGo(p, v)
  1231  }
  1232  
  1233  func (self *CodeGen) translate_OP_icall(p *x86_64.Program, v *hir.Ir) {
  1234      self.abiCallMethod(p, v)
  1235  }
  1236  
  1237  func (self *CodeGen) translate_OP_ret(p *x86_64.Program, v *hir.Ir) {
  1238      var i uint8
  1239      var r uint8
  1240  
  1241      /* store each return values */
  1242      for i = 0; i < v.Rn; i++ {
  1243          if r = v.Rr[i]; r & hir.ArgPointer == 0 {
  1244              self.abiStoreInt(p, hir.GenericRegister(r & hir.ArgMask), int(i))
  1245          } else {
  1246              self.abiStorePtr(p, hir.PointerRegister(r & hir.ArgMask), int(i))
  1247          }
  1248      }
  1249  
  1250      /* return by jumping to the epilogue */
  1251      p.JMP(self.halt)
  1252  }
  1253  
  1254  func (self *CodeGen) translate_OP_break(p *x86_64.Program, _ *hir.Ir) {
  1255      p.INT(3)
  1256  }