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 }