Commit 8c67f210 authored by isharipo's avatar isharipo Committed by Matthew Dempsky

cmd/internal/obj: change Prog.From3 to RestArgs ([]Addr)

This change makes it easier to express instructions
with arbitrary number of operands.

Rationale: previous approach with operand "hiding" does
not scale well, AVX and especially AVX512 have many
instructions with 3+ operands.

x86 asm backend is updated to handle up to 6 explicit operands.
It also fixes issue with 4-th immediate operand type checks.
All `ytab` tables are updated accordingly.

Changes to non-x86 backends only include these patterns:
`p.From3 = X` => `p.SetFrom3(X)`
`p.From3.X = Y` => `p.GetFrom3().X = Y`

Over time, other backends can adapt Prog.RestArgs
and reduce the amount of workarounds.

-- Performance --

x/benchmark/build:

$ benchstat upstream.bench patched.bench
name      old time/op                 new time/op                 delta
Build-48                  21.7s ± 2%                  21.8s ± 2%   ~     (p=0.218 n=10+10)

name      old binary-size             new binary-size             delta
Build-48                  10.3M ± 0%                  10.3M ± 0%   ~     (all equal)

name      old build-time/op           new build-time/op           delta
Build-48                  21.7s ± 2%                  21.8s ± 2%   ~     (p=0.218 n=10+10)

name      old build-peak-RSS-bytes    new build-peak-RSS-bytes    delta
Build-48                  145MB ± 5%                  148MB ± 5%   ~     (p=0.218 n=10+10)

name      old build-user+sys-time/op  new build-user+sys-time/op  delta
Build-48                  21.0s ± 2%                  21.2s ± 2%   ~     (p=0.075 n=10+10)

Microbenchmark shows a slight slowdown.

name        old time/op  new time/op  delta
AMD64asm-4  49.5ms ± 1%  49.9ms ± 1%  +0.67%  (p=0.001 n=23+15)

func BenchmarkAMD64asm(b *testing.B) {
  for i := 0; i < b.N; i++ {
    TestAMD64EndToEnd(nil)
    TestAMD64Encoder(nil)
  }
}

Change-Id: I4f1d37b5c2c966da3f2127705ccac9bff0038183
Reviewed-on: https://go-review.googlesource.com/63490
Run-TryBot: Iskander Sharipov <iskander.sharipov@intel.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarMatthew Dempsky <mdempsky@google.com>
parent e1cf2be7
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file encapsulates some of the odd characteristics of the
// AMD64 instruction set, to minimize its interaction
// with the core of the assembler.
package arch
import (
"cmd/internal/obj"
"cmd/internal/obj/x86"
)
// IsAMD4OP reports whether the op (as defined by an amd64.A* constant) is
// a 4-operand instruction.
func IsAMD4OP(op obj.As) bool {
switch op {
case x86.AVPERM2F128,
x86.AVPALIGNR,
x86.AVPERM2I128,
x86.AVINSERTI128,
x86.AVPBLENDD:
return true
}
return false
}
...@@ -384,7 +384,7 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) { ...@@ -384,7 +384,7 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
prog.Reg = p.getRegister(prog, op, &a[1]) prog.Reg = p.getRegister(prog, op, &a[1])
} else { } else {
// Compare register with immediate and jump. // Compare register with immediate and jump.
prog.From3 = newAddr(a[1]) prog.SetFrom3(a[1])
} }
break break
} }
...@@ -567,7 +567,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { ...@@ -567,7 +567,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
if arch.IsARMBFX(op) { if arch.IsARMBFX(op) {
// a[0] and a[1] must be constants, a[2] must be a register // a[0] and a[1] must be constants, a[2] must be a register
prog.From = a[0] prog.From = a[0]
prog.From3 = newAddr(a[1]) prog.SetFrom3(a[1])
prog.To = a[2] prog.To = a[2]
break break
} }
...@@ -576,13 +576,8 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { ...@@ -576,13 +576,8 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.Reg = p.getRegister(prog, op, &a[1]) prog.Reg = p.getRegister(prog, op, &a[1])
prog.To = a[2] prog.To = a[2]
case sys.AMD64: case sys.AMD64:
// Catch missing operand here, because we store immediate as part of From3, and can't distinguish
// missing operand from legal value 0 in obj/x86/asm6.
if arch.IsAMD4OP(op) {
p.errorf("4 operands required, but only 3 are provided for %s instruction", op)
}
prog.From = a[0] prog.From = a[0]
prog.From3 = newAddr(a[1]) prog.SetFrom3(a[1])
prog.To = a[2] prog.To = a[2]
case sys.ARM64: case sys.ARM64:
// ARM64 instructions with one input and two outputs. // ARM64 instructions with one input and two outputs.
...@@ -601,7 +596,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { ...@@ -601,7 +596,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.To = a[2] prog.To = a[2]
case sys.I386: case sys.I386:
prog.From = a[0] prog.From = a[0]
prog.From3 = newAddr(a[1]) prog.SetFrom3(a[1])
prog.To = a[2] prog.To = a[2]
case sys.PPC64: case sys.PPC64:
if arch.IsPPC64CMP(op) { if arch.IsPPC64CMP(op) {
...@@ -623,7 +618,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { ...@@ -623,7 +618,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.To = a[2] prog.To = a[2]
case obj.TYPE_CONST: case obj.TYPE_CONST:
prog.From = a[0] prog.From = a[0]
prog.From3 = newAddr(a[1]) prog.SetFrom3(a[1])
prog.To = a[2] prog.To = a[2]
default: default:
p.errorf("invalid addressing modes for %s instruction", op) p.errorf("invalid addressing modes for %s instruction", op)
...@@ -634,7 +629,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { ...@@ -634,7 +629,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
if a[1].Type == obj.TYPE_REG { if a[1].Type == obj.TYPE_REG {
prog.Reg = p.getRegister(prog, op, &a[1]) prog.Reg = p.getRegister(prog, op, &a[1])
} else { } else {
prog.From3 = newAddr(a[1]) prog.SetFrom3(a[1])
} }
prog.To = a[2] prog.To = a[2]
default: default:
...@@ -646,7 +641,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { ...@@ -646,7 +641,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
if arch.IsARMBFX(op) { if arch.IsARMBFX(op) {
// a[0] and a[1] must be constants, a[2] and a[3] must be registers // a[0] and a[1] must be constants, a[2] and a[3] must be registers
prog.From = a[0] prog.From = a[0]
prog.From3 = newAddr(a[1]) prog.SetFrom3(a[1])
prog.Reg = p.getRegister(prog, op, &a[2]) prog.Reg = p.getRegister(prog, op, &a[2])
prog.To = a[3] prog.To = a[3]
break break
...@@ -666,26 +661,15 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { ...@@ -666,26 +661,15 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
} }
} }
if p.arch.Family == sys.AMD64 { if p.arch.Family == sys.AMD64 {
// 4 operand instruction have form ymm1, ymm2, ymm3/m256, imm8 prog.From = a[0]
// So From3 is always just a register, so we store imm8 in Offset field, prog.RestArgs = []obj.Addr{a[1], a[2]}
// to avoid increasing size of Prog.
prog.From = a[1]
prog.From3 = newAddr(a[2])
if a[0].Type != obj.TYPE_CONST {
p.errorf("first operand must be an immediate in %s instruction", op)
}
if prog.From3.Type != obj.TYPE_REG {
p.errorf("third operand must be a register in %s instruction", op)
}
prog.From3.Offset = int64(p.getImmediate(prog, op, &a[0]))
prog.To = a[3] prog.To = a[3]
prog.RegTo2 = -1
break break
} }
if p.arch.Family == sys.ARM64 { if p.arch.Family == sys.ARM64 {
prog.From = a[0] prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1]) prog.Reg = p.getRegister(prog, op, &a[1])
prog.From3 = newAddr(a[2]) prog.SetFrom3(a[2])
prog.To = a[3] prog.To = a[3]
break break
} }
...@@ -693,12 +677,12 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { ...@@ -693,12 +677,12 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
if arch.IsPPC64RLD(op) { if arch.IsPPC64RLD(op) {
prog.From = a[0] prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1]) prog.Reg = p.getRegister(prog, op, &a[1])
prog.From3 = newAddr(a[2]) prog.SetFrom3(a[2])
prog.To = a[3] prog.To = a[3]
break break
} else if arch.IsPPC64ISEL(op) { } else if arch.IsPPC64ISEL(op) {
// ISEL BC,RB,RA,RT becomes isel rt,ra,rb,bc // ISEL BC,RB,RA,RT becomes isel rt,ra,rb,bc
prog.From3 = newAddr(a[2]) // ra prog.SetFrom3(a[2]) // ra
prog.From = a[0] // bc prog.From = a[0] // bc
prog.Reg = p.getRegister(prog, op, &a[1]) // rb prog.Reg = p.getRegister(prog, op, &a[1]) // rb
prog.To = a[3] // rt prog.To = a[3] // rt
...@@ -712,13 +696,13 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { ...@@ -712,13 +696,13 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
if a[1].Type == obj.TYPE_REG { if a[1].Type == obj.TYPE_REG {
prog.From = a[0] prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1]) prog.Reg = p.getRegister(prog, op, &a[1])
prog.From3 = newAddr(a[2]) prog.SetFrom3(a[2])
prog.To = a[3] prog.To = a[3]
break break
} else if a[1].Type == obj.TYPE_CONST { } else if a[1].Type == obj.TYPE_CONST {
prog.From = a[0] prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[2]) prog.Reg = p.getRegister(prog, op, &a[2])
prog.From3 = newAddr(a[1]) prog.SetFrom3(a[1])
prog.To = a[3] prog.To = a[3]
break break
} else { } else {
...@@ -733,7 +717,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { ...@@ -733,7 +717,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
} }
prog.From = a[0] prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1]) prog.Reg = p.getRegister(prog, op, &a[1])
prog.From3 = newAddr(a[2]) prog.SetFrom3(a[2])
prog.To = a[3] prog.To = a[3]
break break
} }
...@@ -752,10 +736,10 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { ...@@ -752,10 +736,10 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
} else { } else {
mask = (^uint32(0) >> uint(mask2+1)) & (^uint32(0) << uint(31-(mask1-1))) mask = (^uint32(0) >> uint(mask2+1)) & (^uint32(0) << uint(31-(mask1-1)))
} }
prog.From3 = &obj.Addr{ prog.SetFrom3(obj.Addr{
Type: obj.TYPE_CONST, Type: obj.TYPE_CONST,
Offset: int64(mask), Offset: int64(mask),
} })
prog.To = a[4] prog.To = a[4]
break break
} }
......
...@@ -571,7 +571,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -571,7 +571,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
p.From.Reg = arm64.COND_LO p.From.Reg = arm64.COND_LO
p.Reg = v.Args[0].Reg() p.Reg = v.Args[0].Reg()
p.From3 = &obj.Addr{Type: obj.TYPE_REG, Reg: r1} p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: r1})
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg() p.To.Reg = v.Reg()
case ssa.OpARM64DUFFZERO: case ssa.OpARM64DUFFZERO:
......
...@@ -124,7 +124,7 @@ func ssaGenISEL(s *gc.SSAGenState, v *ssa.Value, cr int64, r1, r2 int16) { ...@@ -124,7 +124,7 @@ func ssaGenISEL(s *gc.SSAGenState, v *ssa.Value, cr int64, r1, r2 int16) {
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = r p.To.Reg = r
p.Reg = r1 p.Reg = r1
p.From3 = &obj.Addr{Type: obj.TYPE_REG, Reg: r2} p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: r2})
p.From.Type = obj.TYPE_CONST p.From.Type = obj.TYPE_CONST
p.From.Offset = cr p.From.Offset = cr
} }
...@@ -551,9 +551,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -551,9 +551,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = r1 p.From.Reg = r1
p.Reg = r3 p.Reg = r3
p.From3 = new(obj.Addr) p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: r2})
p.From3.Type = obj.TYPE_REG
p.From3.Reg = r2
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = r p.To.Reg = r
......
...@@ -534,10 +534,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -534,10 +534,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := s.Prog(s390x.AMVC) p := s.Prog(s390x.AMVC)
p.From.Type = obj.TYPE_CONST p.From.Type = obj.TYPE_CONST
p.From.Offset = vo.Val() p.From.Offset = vo.Val()
p.From3 = new(obj.Addr) p.SetFrom3(obj.Addr{
p.From3.Type = obj.TYPE_MEM Type: obj.TYPE_MEM,
p.From3.Reg = v.Args[1].Reg() Reg: v.Args[1].Reg(),
p.From3.Offset = vo.Off() Offset: vo.Off(),
})
p.To.Type = obj.TYPE_MEM p.To.Type = obj.TYPE_MEM
p.To.Reg = v.Args[0].Reg() p.To.Reg = v.Args[0].Reg()
p.To.Offset = vo.Off() p.To.Offset = vo.Off()
...@@ -570,9 +571,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -570,9 +571,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
mvc := s.Prog(s390x.AMVC) mvc := s.Prog(s390x.AMVC)
mvc.From.Type = obj.TYPE_CONST mvc.From.Type = obj.TYPE_CONST
mvc.From.Offset = 256 mvc.From.Offset = 256
mvc.From3 = new(obj.Addr) mvc.SetFrom3(obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[1].Reg()})
mvc.From3.Type = obj.TYPE_MEM
mvc.From3.Reg = v.Args[1].Reg()
mvc.To.Type = obj.TYPE_MEM mvc.To.Type = obj.TYPE_MEM
mvc.To.Reg = v.Args[0].Reg() mvc.To.Reg = v.Args[0].Reg()
...@@ -599,9 +598,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -599,9 +598,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
mvc := s.Prog(s390x.AMVC) mvc := s.Prog(s390x.AMVC)
mvc.From.Type = obj.TYPE_CONST mvc.From.Type = obj.TYPE_CONST
mvc.From.Offset = v.AuxInt mvc.From.Offset = v.AuxInt
mvc.From3 = new(obj.Addr) mvc.SetFrom3(obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[1].Reg()})
mvc.From3.Type = obj.TYPE_MEM
mvc.From3.Reg = v.Args[1].Reg()
mvc.To.Type = obj.TYPE_MEM mvc.To.Type = obj.TYPE_MEM
mvc.To.Reg = v.Args[0].Reg() mvc.To.Reg = v.Args[0].Reg()
} }
......
...@@ -2068,11 +2068,11 @@ func (c *ctxt5) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -2068,11 +2068,11 @@ func (c *ctxt5) asmout(p *obj.Prog, o *Optab, out []uint32) {
if r == 0 { if r == 0 {
r = rt r = rt
} }
if p.From3 == nil || p.From3.Type != obj.TYPE_CONST { if p.GetFrom3() == nil || p.GetFrom3().Type != obj.TYPE_CONST {
c.ctxt.Diag("%v: missing or wrong LSB", p) c.ctxt.Diag("%v: missing or wrong LSB", p)
break break
} }
lsb := p.From3.Offset lsb := p.GetFrom3().Offset
width := p.From.Offset width := p.From.Offset
if lsb < 0 || lsb > 31 || width <= 0 || (lsb+width) > 31 { if lsb < 0 || lsb > 31 || width <= 0 || (lsb+width) > 31 {
c.ctxt.Diag("%v: wrong width or LSB", p) c.ctxt.Diag("%v: wrong width or LSB", p)
...@@ -3310,8 +3310,8 @@ func (c *ctxt5) chipfloat5(e float64) int { ...@@ -3310,8 +3310,8 @@ func (c *ctxt5) chipfloat5(e float64) int {
func nocache(p *obj.Prog) { func nocache(p *obj.Prog) {
p.Optab = 0 p.Optab = 0
p.From.Class = 0 p.From.Class = 0
if p.From3 != nil { if p.GetFrom3() != nil {
p.From3.Class = 0 p.GetFrom3().Class = 0
} }
p.To.Class = 0 p.To.Class = 0
} }
...@@ -186,7 +186,7 @@ func (c *ctxt5) rewriteToUseGot(p *obj.Prog) { ...@@ -186,7 +186,7 @@ func (c *ctxt5) rewriteToUseGot(p *obj.Prog) {
p.From.Offset = 0 p.From.Offset = 0
} }
} }
if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN { if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
c.ctxt.Diag("don't know how to handle %v with -dynlink", p) c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
} }
var source *obj.Addr var source *obj.Addr
......
...@@ -2331,7 +2331,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -2331,7 +2331,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
var r int var r int
var ra int var ra int
if p.From3Type() == obj.TYPE_REG { if p.From3Type() == obj.TYPE_REG {
r = int(p.From3.Reg) r = int(p.GetFrom3().Reg)
ra = int(p.Reg) ra = int(p.Reg)
if ra == 0 { if ra == 0 {
ra = REGZERO ra = REGZERO
...@@ -2393,7 +2393,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -2393,7 +2393,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
cond ^= 1 cond ^= 1
} else { } else {
rf = int(p.From3.Reg) /* CSEL */ rf = int(p.GetFrom3().Reg) /* CSEL */
} }
} else { } else {
/* CSET */ /* CSET */
...@@ -2418,12 +2418,12 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -2418,12 +2418,12 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
cond -= COND_EQ cond -= COND_EQ
} }
var rf int var rf int
if p.From3.Type == obj.TYPE_REG { if p.GetFrom3().Type == obj.TYPE_REG {
o1 = c.oprrr(p, p.As) o1 = c.oprrr(p, p.As)
rf = int(p.From3.Reg) /* Rm */ rf = int(p.GetFrom3().Reg) /* Rm */
} else { } else {
o1 = c.opirr(p, p.As) o1 = c.opirr(p, p.As)
rf = int(p.From3.Offset & 0x1F) rf = int(p.GetFrom3().Offset & 0x1F)
} }
o1 |= (uint32(rf&31) << 16) | (uint32(cond&15) << 12) | (uint32(p.Reg&31) << 5) | uint32(nzcv) o1 |= (uint32(rf&31) << 16) | (uint32(cond&15) << 12) | (uint32(p.Reg&31) << 5) | uint32(nzcv)
...@@ -2767,12 +2767,12 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -2767,12 +2767,12 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
o1 = c.op0(p, p.As) o1 = c.op0(p, p.As)
case 42: /* bfm R,r,s,R */ case 42: /* bfm R,r,s,R */
o1 = c.opbfm(p, p.As, int(p.From.Offset), int(p.From3.Offset), int(p.Reg), int(p.To.Reg)) o1 = c.opbfm(p, p.As, int(p.From.Offset), int(p.GetFrom3().Offset), int(p.Reg), int(p.To.Reg))
case 43: /* bfm aliases */ case 43: /* bfm aliases */
r := int(p.From.Offset) r := int(p.From.Offset)
s := int(p.From3.Offset) s := int(p.GetFrom3().Offset)
rf := int(p.Reg) rf := int(p.Reg)
rt := int(p.To.Reg) rt := int(p.To.Reg)
if rf == 0 { if rf == 0 {
...@@ -2821,7 +2821,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -2821,7 +2821,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
} }
case 44: /* extr $b, Rn, Rm, Rd */ case 44: /* extr $b, Rn, Rm, Rd */
o1 = c.opextr(p, p.As, int32(p.From.Offset), int(p.From3.Reg), int(p.Reg), int(p.To.Reg)) o1 = c.opextr(p, p.As, int32(p.From.Offset), int(p.GetFrom3().Reg), int(p.Reg), int(p.To.Reg))
case 45: /* sxt/uxt[bhw] R,R; movT R,R -> sxtT R,R */ case 45: /* sxt/uxt[bhw] R,R; movT R,R -> sxtT R,R */
rf := int(p.From.Reg) rf := int(p.From.Reg)
...@@ -2977,11 +2977,11 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -2977,11 +2977,11 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
c.ctxt.Diag("implausible condition\n%v", p) c.ctxt.Diag("implausible condition\n%v", p)
} }
rf := int(p.Reg) rf := int(p.Reg)
if p.From3 == nil || p.From3.Reg < REG_F0 || p.From3.Reg > REG_F31 { if p.GetFrom3() == nil || p.GetFrom3().Reg < REG_F0 || p.GetFrom3().Reg > REG_F31 {
c.ctxt.Diag("illegal FCCMP\n%v", p) c.ctxt.Diag("illegal FCCMP\n%v", p)
break break
} }
rt := int(p.From3.Reg) rt := int(p.GetFrom3().Reg)
o1 |= uint32(rf&31)<<16 | uint32(cond&15)<<12 | uint32(rt&31)<<5 | uint32(nzcv) o1 |= uint32(rf&31)<<16 | uint32(cond&15)<<12 | uint32(rt&31)<<5 | uint32(nzcv)
case 58: /* ldar/ldxr/ldaxr */ case 58: /* ldar/ldxr/ldaxr */
......
...@@ -382,7 +382,7 @@ func (c *ctxt7) rewriteToUseGot(p *obj.Prog) { ...@@ -382,7 +382,7 @@ func (c *ctxt7) rewriteToUseGot(p *obj.Prog) {
p.From.Offset = 0 p.From.Offset = 0
} }
} }
if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN { if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
c.ctxt.Diag("don't know how to handle %v with -dynlink", p) c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
} }
var source *obj.Addr var source *obj.Addr
......
...@@ -10,7 +10,7 @@ func Nopout(p *Prog) { ...@@ -10,7 +10,7 @@ func Nopout(p *Prog) {
p.As = ANOP p.As = ANOP
p.Scond = 0 p.Scond = 0
p.From = Addr{} p.From = Addr{}
p.From3 = nil p.RestArgs = nil
p.Reg = 0 p.Reg = 0
p.To = Addr{} p.To = Addr{}
} }
...@@ -209,14 +209,19 @@ const ( ...@@ -209,14 +209,19 @@ const (
// //
// The general instruction form is: // The general instruction form is:
// //
// As.Scond From, Reg, From3, To, RegTo2 // (1) As.Scond From [, ...RestArgs], To
// (2) As.Scond From, Reg [, ...RestArgs], To, RegTo2
// //
// where As is an opcode and the others are arguments: // where As is an opcode and the others are arguments:
// From, Reg, From3 are sources, and To, RegTo2 are destinations. // From, Reg are sources, and To, RegTo2 are destinations.
// RestArgs can hold additional sources and destinations.
// Usually, not all arguments are present. // Usually, not all arguments are present.
// For example, MOVL R1, R2 encodes using only As=MOVL, From=R1, To=R2. // For example, MOVL R1, R2 encodes using only As=MOVL, From=R1, To=R2.
// The Scond field holds additional condition bits for systems (like arm) // The Scond field holds additional condition bits for systems (like arm)
// that have generalized conditional execution. // that have generalized conditional execution.
// (2) form is present for compatibility with older code,
// to avoid too much changes in a single swing.
// (1) scheme is enough to express any kind of operand combination.
// //
// Jump instructions use the Pcond field to point to the target instruction, // Jump instructions use the Pcond field to point to the target instruction,
// which must be in the same linked list as the jump instruction. // which must be in the same linked list as the jump instruction.
...@@ -235,7 +240,7 @@ type Prog struct { ...@@ -235,7 +240,7 @@ type Prog struct {
Ctxt *Link // linker context Ctxt *Link // linker context
Link *Prog // next Prog in linked list Link *Prog // next Prog in linked list
From Addr // first source operand From Addr // first source operand
From3 *Addr // third source operand (second is Reg below) RestArgs []Addr // can pack any operands that not fit into {Prog.From, Prog.To}
To Addr // destination operand (second is RegTo2 below) To Addr // destination operand (second is RegTo2 below)
Pcond *Prog // target of conditional jump Pcond *Prog // target of conditional jump
Forwd *Prog // for x86 back end Forwd *Prog // for x86 back end
...@@ -255,12 +260,39 @@ type Prog struct { ...@@ -255,12 +260,39 @@ type Prog struct {
Isize uint8 // for x86 back end: size of the instruction in bytes Isize uint8 // for x86 back end: size of the instruction in bytes
} }
// From3Type returns From3.Type, or TYPE_NONE when From3 is nil. // From3Type returns p.GetFrom3().Type, or TYPE_NONE when
// p.GetFrom3() returns nil.
//
// Deprecated: for the same reasons as Prog.GetFrom3.
func (p *Prog) From3Type() AddrType { func (p *Prog) From3Type() AddrType {
if p.From3 == nil { if p.RestArgs == nil {
return TYPE_NONE return TYPE_NONE
} }
return p.From3.Type return p.RestArgs[0].Type
}
// GetFrom3 returns second source operand (the first is Prog.From).
// In combination with Prog.From and Prog.To it makes common 3 operand
// case easier to use.
//
// Should be used only when RestArgs is set with SetFrom3.
//
// Deprecated: better use RestArgs directly or define backend-specific getters.
// Introduced to simplify transition to []Addr.
// Usage of this is discouraged due to fragility and lack of guarantees.
func (p *Prog) GetFrom3() *Addr {
if p.RestArgs == nil {
return nil
}
return &p.RestArgs[0]
}
// SetFrom3 assigns []Addr{a} to p.RestArgs.
// In pair with Prog.GetFrom3 it can help in emulation of Prog.From3.
//
// Deprecated: for the same reasons as Prog.GetFrom3.
func (p *Prog) SetFrom3(a Addr) {
p.RestArgs = []Addr{a}
} }
// An As denotes an assembler opcode. // An As denotes an assembler opcode.
......
...@@ -124,8 +124,8 @@ func linkpatch(ctxt *Link, sym *LSym, newprog ProgAlloc) { ...@@ -124,8 +124,8 @@ func linkpatch(ctxt *Link, sym *LSym, newprog ProgAlloc) {
for p := sym.Func.Text; p != nil; p = p.Link { for p := sym.Func.Text; p != nil; p = p.Link {
checkaddr(ctxt, p, &p.From) checkaddr(ctxt, p, &p.From)
if p.From3 != nil { if p.GetFrom3() != nil {
checkaddr(ctxt, p, p.From3) checkaddr(ctxt, p, p.GetFrom3())
} }
checkaddr(ctxt, p, &p.To) checkaddr(ctxt, p, &p.To)
......
...@@ -900,11 +900,11 @@ func (c *ctxt9) oplook(p *obj.Prog) *Optab { ...@@ -900,11 +900,11 @@ func (c *ctxt9) oplook(p *obj.Prog) *Optab {
a1-- a1--
a3 := C_NONE + 1 a3 := C_NONE + 1
if p.From3 != nil { if p.GetFrom3() != nil {
a3 = int(p.From3.Class) a3 = int(p.GetFrom3().Class)
if a3 == 0 { if a3 == 0 {
a3 = c.aclass(p.From3) + 1 a3 = c.aclass(p.GetFrom3()) + 1
p.From3.Class = int8(a3) p.GetFrom3().Class = int8(a3)
} }
} }
...@@ -2461,7 +2461,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -2461,7 +2461,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
if r == 0 { if r == 0 {
r = int(p.To.Reg) r = int(p.To.Reg)
} }
d := c.vregoff(p.From3) d := c.vregoff(p.GetFrom3())
var a int var a int
switch p.As { switch p.As {
...@@ -2714,7 +2714,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -2714,7 +2714,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), REGTMP, uint32(v)) o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), REGTMP, uint32(v))
case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */ case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */
v := c.regoff(p.From3) v := c.regoff(p.GetFrom3())
r := int(p.From.Reg) r := int(p.From.Reg)
o1 = AOP_IRR(c.opirr(p.As), uint32(p.To.Reg), uint32(r), uint32(v)) o1 = AOP_IRR(c.opirr(p.As), uint32(p.To.Reg), uint32(r), uint32(v))
...@@ -2723,7 +2723,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -2723,7 +2723,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
if p.To.Reg == REGTMP || p.From.Reg == REGTMP { if p.To.Reg == REGTMP || p.From.Reg == REGTMP {
c.ctxt.Diag("can't synthesize large constant\n%v", p) c.ctxt.Diag("can't synthesize large constant\n%v", p)
} }
v := c.regoff(p.From3) v := c.regoff(p.GetFrom3())
o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, uint32(v)>>16) o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, uint32(v)>>16)
o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(v)) o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(v))
o3 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), REGTMP) o3 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), REGTMP)
...@@ -2736,7 +2736,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -2736,7 +2736,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
case 29: /* rldic[lr]? $sh,s,$mask,a -- left, right, plain give different masks */ case 29: /* rldic[lr]? $sh,s,$mask,a -- left, right, plain give different masks */
v := c.regoff(&p.From) v := c.regoff(&p.From)
d := c.vregoff(p.From3) d := c.vregoff(p.GetFrom3())
var mask [2]uint8 var mask [2]uint8
c.maskgen64(p, mask[:], uint64(d)) c.maskgen64(p, mask[:], uint64(d))
var a int var a int
...@@ -2776,7 +2776,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -2776,7 +2776,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
case 30: /* rldimi $sh,s,$mask,a */ case 30: /* rldimi $sh,s,$mask,a */
v := c.regoff(&p.From) v := c.regoff(&p.From)
d := c.vregoff(p.From3) d := c.vregoff(p.GetFrom3())
// Original opcodes had mask operands which had to be converted to a shift count as expected by // Original opcodes had mask operands which had to be converted to a shift count as expected by
// the ppc64 asm. // the ppc64 asm.
...@@ -2847,7 +2847,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -2847,7 +2847,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), 0, uint32(r)) o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), 0, uint32(r))
case 34: /* FMADDx fra,frb,frc,frt (t=a*c±b) */ case 34: /* FMADDx fra,frb,frc,frt (t=a*c±b) */
o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg)) | (uint32(p.From3.Reg)&31)<<6 o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg)) | (uint32(p.GetFrom3().Reg)&31)<<6
case 35: /* mov r,lext/lauto/loreg ==> cau $(v>>16),sb,r'; store o(r') */ case 35: /* mov r,lext/lauto/loreg ==> cau $(v>>16),sb,r'; store o(r') */
v := c.regoff(&p.To) v := c.regoff(&p.To)
...@@ -2889,10 +2889,10 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -2889,10 +2889,10 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
o1 = uint32(c.regoff(&p.From)) o1 = uint32(c.regoff(&p.From))
case 41: /* stswi */ case 41: /* stswi */
o1 = AOP_RRR(c.opirr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), 0) | (uint32(c.regoff(p.From3))&0x7F)<<11 o1 = AOP_RRR(c.opirr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), 0) | (uint32(c.regoff(p.GetFrom3()))&0x7F)<<11
case 42: /* lswi */ case 42: /* lswi */
o1 = AOP_RRR(c.opirr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), 0) | (uint32(c.regoff(p.From3))&0x7F)<<11 o1 = AOP_RRR(c.opirr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), 0) | (uint32(c.regoff(p.GetFrom3()))&0x7F)<<11
case 43: /* unary indexed source: dcbf (b); dcbf (a+b) */ case 43: /* unary indexed source: dcbf (b); dcbf (a+b) */
o1 = AOP_RRR(c.oprrr(p.As), 0, uint32(p.From.Index), uint32(p.From.Reg)) o1 = AOP_RRR(c.oprrr(p.As), 0, uint32(p.From.Index), uint32(p.From.Reg))
...@@ -3062,13 +3062,13 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -3062,13 +3062,13 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
v := c.regoff(&p.From) v := c.regoff(&p.From)
var mask [2]uint8 var mask [2]uint8
c.maskgen(p, mask[:], uint32(c.regoff(p.From3))) c.maskgen(p, mask[:], uint32(c.regoff(p.GetFrom3())))
o1 = AOP_RRR(c.opirr(p.As), uint32(p.Reg), uint32(p.To.Reg), uint32(v)) o1 = AOP_RRR(c.opirr(p.As), uint32(p.Reg), uint32(p.To.Reg), uint32(v))
o1 |= (uint32(mask[0])&31)<<6 | (uint32(mask[1])&31)<<1 o1 |= (uint32(mask[0])&31)<<6 | (uint32(mask[1])&31)<<1
case 63: /* rlwmi b,s,$mask,a */ case 63: /* rlwmi b,s,$mask,a */
var mask [2]uint8 var mask [2]uint8
c.maskgen(p, mask[:], uint32(c.regoff(p.From3))) c.maskgen(p, mask[:], uint32(c.regoff(p.GetFrom3())))
o1 = AOP_RRR(c.opirr(p.As), uint32(p.Reg), uint32(p.To.Reg), uint32(p.From.Reg)) o1 = AOP_RRR(c.opirr(p.As), uint32(p.Reg), uint32(p.To.Reg), uint32(p.From.Reg))
o1 |= (uint32(mask[0])&31)<<6 | (uint32(mask[1])&31)<<1 o1 |= (uint32(mask[0])&31)<<6 | (uint32(mask[1])&31)<<1
...@@ -3076,7 +3076,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -3076,7 +3076,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
case 64: /* mtfsf fr[, $m] {,fpcsr} */ case 64: /* mtfsf fr[, $m] {,fpcsr} */
var v int32 var v int32
if p.From3Type() != obj.TYPE_NONE { if p.From3Type() != obj.TYPE_NONE {
v = c.regoff(p.From3) & 255 v = c.regoff(p.GetFrom3()) & 255
} else { } else {
v = 255 v = 255
} }
...@@ -3131,7 +3131,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -3131,7 +3131,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
if p.To.Reg != 0 { if p.To.Reg != 0 {
c.ctxt.Diag("can't use both mask and CR(n)\n%v", p) c.ctxt.Diag("can't use both mask and CR(n)\n%v", p)
} }
v = c.regoff(p.From3) & 0xff v = c.regoff(p.GetFrom3()) & 0xff
} else { } else {
if p.To.Reg == 0 { if p.To.Reg == 0 {
v = 0xff /* CR */ v = 0xff /* CR */
...@@ -3270,7 +3270,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -3270,7 +3270,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
/* imm imm reg reg */ /* imm imm reg reg */
/* operand order: SIX, VRA, ST, VRT */ /* operand order: SIX, VRA, ST, VRT */
six := int(c.regoff(&p.From)) six := int(c.regoff(&p.From))
st := int(c.regoff(p.From3)) st := int(c.regoff(p.GetFrom3()))
o1 = AOP_IIRR(c.opiirr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(st), uint32(six)) o1 = AOP_IIRR(c.opiirr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(st), uint32(six))
} else if p.From3Type() == obj.TYPE_NONE && p.Reg != 0 { } else if p.From3Type() == obj.TYPE_NONE && p.Reg != 0 {
/* imm reg reg */ /* imm reg reg */
...@@ -3288,19 +3288,19 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -3288,19 +3288,19 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
if p.From.Type == obj.TYPE_REG { if p.From.Type == obj.TYPE_REG {
/* reg reg reg reg */ /* reg reg reg reg */
/* 4-register operand order: VRA, VRB, VRC, VRT */ /* 4-register operand order: VRA, VRB, VRC, VRT */
o1 = AOP_RRRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(p.From3.Reg)) o1 = AOP_RRRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(p.GetFrom3().Reg))
} else if p.From.Type == obj.TYPE_CONST { } else if p.From.Type == obj.TYPE_CONST {
/* imm reg reg reg */ /* imm reg reg reg */
/* operand order: SHB, VRA, VRB, VRT */ /* operand order: SHB, VRA, VRB, VRT */
shb := int(c.regoff(&p.From)) shb := int(c.regoff(&p.From))
o1 = AOP_IRRR(c.opirrr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(p.From3.Reg), uint32(shb)) o1 = AOP_IRRR(c.opirrr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(p.GetFrom3().Reg), uint32(shb))
} }
case 84: // ISEL BC,RA,RB,RT -> isel rt,ra,rb,bc case 84: // ISEL BC,RA,RB,RT -> isel rt,ra,rb,bc
bc := c.vregoff(&p.From) bc := c.vregoff(&p.From)
// rt = To.Reg, ra = p.Reg, rb = p.From3.Reg // rt = To.Reg, ra = p.Reg, rb = p.From3.Reg
o1 = AOP_ISEL(OP_ISEL, uint32(p.To.Reg), uint32(p.Reg), uint32(p.From3.Reg), uint32(bc)) o1 = AOP_ISEL(OP_ISEL, uint32(p.To.Reg), uint32(p.Reg), uint32(p.GetFrom3().Reg), uint32(bc))
case 85: /* vector instructions, VX-form */ case 85: /* vector instructions, VX-form */
/* reg none reg */ /* reg none reg */
...@@ -3348,7 +3348,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -3348,7 +3348,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
case 89: /* VSX instructions, XX2-form */ case 89: /* VSX instructions, XX2-form */
/* reg none reg OR reg imm reg */ /* reg none reg OR reg imm reg */
/* 2-register operand order: XB, XT or XB, UIM, XT*/ /* 2-register operand order: XB, XT or XB, UIM, XT*/
uim := int(c.regoff(p.From3)) uim := int(c.regoff(p.GetFrom3()))
o1 = AOP_XX2(c.oprrr(p.As), uint32(p.To.Reg), uint32(uim), uint32(p.From.Reg)) o1 = AOP_XX2(c.oprrr(p.As), uint32(p.To.Reg), uint32(uim), uint32(p.From.Reg))
case 90: /* VSX instructions, XX3-form */ case 90: /* VSX instructions, XX3-form */
...@@ -3359,14 +3359,14 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -3359,14 +3359,14 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
} else if p.From3Type() == obj.TYPE_CONST { } else if p.From3Type() == obj.TYPE_CONST {
/* reg reg reg imm */ /* reg reg reg imm */
/* operand order: XA, XB, DM, XT */ /* operand order: XA, XB, DM, XT */
dm := int(c.regoff(p.From3)) dm := int(c.regoff(p.GetFrom3()))
o1 = AOP_XX3I(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(dm)) o1 = AOP_XX3I(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(dm))
} }
case 91: /* VSX instructions, XX4-form */ case 91: /* VSX instructions, XX4-form */
/* reg reg reg reg */ /* reg reg reg reg */
/* 3-register operand order: XA, XB, XC, XT */ /* 3-register operand order: XA, XB, XC, XT */
o1 = AOP_XX4(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(p.From3.Reg)) o1 = AOP_XX4(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(p.GetFrom3().Reg))
case 92: /* X-form instructions, 3-operands */ case 92: /* X-form instructions, 3-operands */
if p.To.Type == obj.TYPE_CONST { if p.To.Type == obj.TYPE_CONST {
...@@ -3384,7 +3384,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -3384,7 +3384,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
} else if p.From3Type() == obj.TYPE_CONST { } else if p.From3Type() == obj.TYPE_CONST {
/* reg reg imm */ /* reg reg imm */
/* operand order: RB, L, RA */ /* operand order: RB, L, RA */
l := int(c.regoff(p.From3)) l := int(c.regoff(p.GetFrom3()))
o1 = AOP_RRR(c.opirr(p.As), uint32(l), uint32(p.To.Reg), uint32(p.From.Reg)) o1 = AOP_RRR(c.opirr(p.As), uint32(l), uint32(p.To.Reg), uint32(p.From.Reg))
} else if p.To.Type == obj.TYPE_REG { } else if p.To.Type == obj.TYPE_REG {
cr := int32(p.To.Reg) cr := int32(p.To.Reg)
...@@ -3425,7 +3425,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -3425,7 +3425,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
case 94: /* Z23-form instructions, 4-operands */ case 94: /* Z23-form instructions, 4-operands */
/* reg reg reg imm */ /* reg reg reg imm */
/* operand order: RA, RB, CY, RT */ /* operand order: RA, RB, CY, RT */
cy := int(c.regoff(p.From3)) cy := int(c.regoff(p.GetFrom3()))
o1 = AOP_Z23I(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(cy)) o1 = AOP_Z23I(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(cy))
} }
......
...@@ -176,7 +176,7 @@ func (c *ctxt9) rewriteToUseGot(p *obj.Prog) { ...@@ -176,7 +176,7 @@ func (c *ctxt9) rewriteToUseGot(p *obj.Prog) {
p.From.Offset = 0 p.From.Offset = 0
} }
} }
if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN { if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
c.ctxt.Diag("don't know how to handle %v with -dynlink", p) c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
} }
var source *obj.Addr var source *obj.Addr
......
...@@ -654,11 +654,11 @@ func (c *ctxtz) oplook(p *obj.Prog) *Optab { ...@@ -654,11 +654,11 @@ func (c *ctxtz) oplook(p *obj.Prog) *Optab {
a1-- a1--
a3 := C_NONE + 1 a3 := C_NONE + 1
if p.From3 != nil { if p.GetFrom3() != nil {
a3 = int(p.From3.Class) a3 = int(p.GetFrom3().Class)
if a3 == 0 { if a3 == 0 {
a3 = c.aclass(p.From3) + 1 a3 = c.aclass(p.GetFrom3()) + 1
p.From3.Class = int8(a3) p.GetFrom3().Class = int8(a3)
} }
} }
...@@ -3534,11 +3534,11 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3534,11 +3534,11 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
if l < 1 || l > 256 { if l < 1 || l > 256 {
c.ctxt.Diag("number of bytes (%v) not in range [1,256]", l) c.ctxt.Diag("number of bytes (%v) not in range [1,256]", l)
} }
if p.From3.Index != 0 || p.To.Index != 0 { if p.GetFrom3().Index != 0 || p.To.Index != 0 {
c.ctxt.Diag("cannot use index reg") c.ctxt.Diag("cannot use index reg")
} }
b1 := p.To.Reg b1 := p.To.Reg
b2 := p.From3.Reg b2 := p.GetFrom3().Reg
if b1 == 0 { if b1 == 0 {
b1 = o.param b1 = o.param
} }
...@@ -3546,7 +3546,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3546,7 +3546,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
b2 = o.param b2 = o.param
} }
d1 := c.regoff(&p.To) d1 := c.regoff(&p.To)
d2 := c.regoff(p.From3) d2 := c.regoff(p.GetFrom3())
if d1 < 0 || d1 >= DISP12 { if d1 < 0 || d1 >= DISP12 {
if b2 == REGTMP { if b2 == REGTMP {
c.ctxt.Diag("REGTMP conflict") c.ctxt.Diag("REGTMP conflict")
...@@ -3688,10 +3688,10 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3688,10 +3688,10 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
} }
mask := c.branchMask(p) mask := c.branchMask(p)
if int32(int16(v)) != v { if int32(int16(v)) != v {
zRIL(_a, opcode2, uint32(p.From.Reg), uint32(c.regoff(p.From3)), asm) zRIL(_a, opcode2, uint32(p.From.Reg), uint32(c.regoff(p.GetFrom3())), asm)
zRIL(_c, op_BRCL, mask, uint32(v-sizeRIL/2), asm) zRIL(_c, op_BRCL, mask, uint32(v-sizeRIL/2), asm)
} else { } else {
zRIE(_c, opcode, uint32(p.From.Reg), mask, uint32(v), 0, 0, 0, uint32(c.regoff(p.From3)), asm) zRIE(_c, opcode, uint32(p.From.Reg), mask, uint32(v), 0, 0, 0, uint32(c.regoff(p.GetFrom3())), asm)
} }
case 93: // GOT lookup case 93: // GOT lookup
...@@ -3893,9 +3893,9 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3893,9 +3893,9 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
case 101: // VRX LOAD case 101: // VRX LOAD
op, m3, _ := vop(p.As) op, m3, _ := vop(p.As)
src := &p.From src := &p.From
if p.From3 != nil { if p.GetFrom3() != nil {
m3 = uint32(c.vregoff(&p.From)) m3 = uint32(c.vregoff(&p.From))
src = p.From3 src = p.GetFrom3()
} }
b2 := src.Reg b2 := src.Reg
if b2 == 0 { if b2 == 0 {
...@@ -3917,12 +3917,12 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3917,12 +3917,12 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
case 103: // VRV GATHER case 103: // VRV GATHER
op, _, _ := vop(p.As) op, _, _ := vop(p.As)
m3 := uint32(c.vregoff(&p.From)) m3 := uint32(c.vregoff(&p.From))
b2 := p.From3.Reg b2 := p.GetFrom3().Reg
if b2 == 0 { if b2 == 0 {
b2 = o.param b2 = o.param
} }
d2 := uint32(c.vregoff(p.From3)) d2 := uint32(c.vregoff(p.GetFrom3()))
zVRV(op, uint32(p.To.Reg), uint32(p.From3.Index), uint32(b2), d2, m3, asm) zVRV(op, uint32(p.To.Reg), uint32(p.GetFrom3().Index), uint32(b2), d2, m3, asm)
case 104: // VRS SHIFT/ROTATE and LOAD GR FROM VR ELEMENT case 104: // VRS SHIFT/ROTATE and LOAD GR FROM VR ELEMENT
op, m4, _ := vop(p.As) op, m4, _ := vop(p.As)
...@@ -3962,8 +3962,8 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3962,8 +3962,8 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
case 108: // VRS LOAD WITH LENGTH case 108: // VRS LOAD WITH LENGTH
op, _, _ := vop(p.As) op, _, _ := vop(p.As)
offset := uint32(c.vregoff(p.From3)) offset := uint32(c.vregoff(p.GetFrom3()))
reg := p.From3.Reg reg := p.GetFrom3().Reg
if reg == 0 { if reg == 0 {
reg = o.param reg = o.param
} }
...@@ -3972,9 +3972,9 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3972,9 +3972,9 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
case 109: // VRI-a case 109: // VRI-a
op, m3, _ := vop(p.As) op, m3, _ := vop(p.As)
i2 := uint32(c.vregoff(&p.From)) i2 := uint32(c.vregoff(&p.From))
if p.From3 != nil { if p.GetFrom3() != nil {
m3 = uint32(c.vregoff(&p.From)) m3 = uint32(c.vregoff(&p.From))
i2 = uint32(c.vregoff(p.From3)) i2 = uint32(c.vregoff(p.GetFrom3()))
} }
switch p.As { switch p.As {
case AVZERO: case AVZERO:
...@@ -3987,7 +3987,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3987,7 +3987,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
case 110: case 110:
op, m4, _ := vop(p.As) op, m4, _ := vop(p.As)
i2 := uint32(c.vregoff(&p.From)) i2 := uint32(c.vregoff(&p.From))
i3 := uint32(c.vregoff(p.From3)) i3 := uint32(c.vregoff(p.GetFrom3()))
zVRIb(op, uint32(p.To.Reg), i2, i3, m4, asm) zVRIb(op, uint32(p.To.Reg), i2, i3, m4, asm)
case 111: case 111:
...@@ -3998,7 +3998,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -3998,7 +3998,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
case 112: case 112:
op, m5, _ := vop(p.As) op, m5, _ := vop(p.As)
i4 := uint32(c.vregoff(&p.From)) i4 := uint32(c.vregoff(&p.From))
zVRId(op, uint32(p.To.Reg), uint32(p.Reg), uint32(p.From3.Reg), i4, m5, asm) zVRId(op, uint32(p.To.Reg), uint32(p.Reg), uint32(p.GetFrom3().Reg), i4, m5, asm)
case 113: case 113:
op, m4, _ := vop(p.As) op, m4, _ := vop(p.As)
...@@ -4044,7 +4044,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -4044,7 +4044,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
v1 := uint32(p.To.Reg) v1 := uint32(p.To.Reg)
v2 := uint32(p.From.Reg) v2 := uint32(p.From.Reg)
v3 := uint32(p.Reg) v3 := uint32(p.Reg)
v4 := uint32(p.From3.Reg) v4 := uint32(p.GetFrom3().Reg)
zVRRd(op, v1, v2, v3, m6, m5, v4, asm) zVRRd(op, v1, v2, v3, m6, m5, v4, asm)
case 121: // VRR-e case 121: // VRR-e
...@@ -4053,7 +4053,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -4053,7 +4053,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
v1 := uint32(p.To.Reg) v1 := uint32(p.To.Reg)
v2 := uint32(p.From.Reg) v2 := uint32(p.From.Reg)
v3 := uint32(p.Reg) v3 := uint32(p.Reg)
v4 := uint32(p.From3.Reg) v4 := uint32(p.GetFrom3().Reg)
zVRRe(op, v1, v2, v3, m6, m5, v4, asm) zVRRe(op, v1, v2, v3, m6, m5, v4, asm)
case 122: // VRR-f LOAD VRS FROM GRS DISJOINT case 122: // VRR-f LOAD VRS FROM GRS DISJOINT
...@@ -4063,7 +4063,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { ...@@ -4063,7 +4063,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
case 123: // VPDI $m4, V2, V3, V1 case 123: // VPDI $m4, V2, V3, V1
op, _, _ := vop(p.As) op, _, _ := vop(p.As)
m4 := c.regoff(&p.From) m4 := c.regoff(&p.From)
zVRRc(op, uint32(p.To.Reg), uint32(p.Reg), uint32(p.From3.Reg), 0, 0, uint32(m4), asm) zVRRc(op, uint32(p.To.Reg), uint32(p.Reg), uint32(p.GetFrom3().Reg), 0, 0, uint32(m4), asm)
} }
} }
......
...@@ -140,7 +140,7 @@ func (c *ctxtz) rewriteToUseGot(p *obj.Prog) { ...@@ -140,7 +140,7 @@ func (c *ctxtz) rewriteToUseGot(p *obj.Prog) {
p.From.Offset = 0 p.From.Offset = 0
} }
} }
if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN { if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
c.ctxt.Diag("don't know how to handle %v with -dynlink", p) c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
} }
var source *obj.Addr var source *obj.Addr
......
...@@ -24,7 +24,7 @@ func TestSizeof(t *testing.T) { ...@@ -24,7 +24,7 @@ func TestSizeof(t *testing.T) {
}{ }{
{Addr{}, 32, 48}, {Addr{}, 32, 48},
{LSym{}, 56, 104}, {LSym{}, 56, 104},
{Prog{}, 124, 184}, {Prog{}, 132, 200},
} }
for _, tt := range tests { for _, tt := range tests {
......
...@@ -83,11 +83,7 @@ func (p *Prog) String() string { ...@@ -83,11 +83,7 @@ func (p *Prog) String() string {
fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), p.As, sc) fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), p.As, sc)
sep := "\t" sep := "\t"
quadOpAmd64 := p.RegTo2 == -1
if quadOpAmd64 {
fmt.Fprintf(&buf, "%s$%d", sep, p.From3.Offset)
sep = ", "
}
if p.From.Type != TYPE_NONE { if p.From.Type != TYPE_NONE {
fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From)) fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From))
sep = ", " sep = ", "
...@@ -97,14 +93,11 @@ func (p *Prog) String() string { ...@@ -97,14 +93,11 @@ func (p *Prog) String() string {
fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg))) fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg)))
sep = ", " sep = ", "
} }
if p.From3Type() != TYPE_NONE { for i := range p.RestArgs {
if quadOpAmd64 { fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.RestArgs[i]))
fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.From3.Reg)))
} else {
fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3))
}
sep = ", " sep = ", "
} }
if p.As == ATEXT { if p.As == ATEXT {
// If there are attributes, print them. Otherwise, skip the comma. // If there are attributes, print them. Otherwise, skip the comma.
// In short, print one of these two: // In short, print one of these two:
...@@ -119,7 +112,7 @@ func (p *Prog) String() string { ...@@ -119,7 +112,7 @@ func (p *Prog) String() string {
if p.To.Type != TYPE_NONE { if p.To.Type != TYPE_NONE {
fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To)) fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To))
} }
if p.RegTo2 != REG_NONE && !quadOpAmd64 { if p.RegTo2 != REG_NONE {
fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2))) fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2)))
} }
return buf.String() return buf.String()
......
...@@ -72,14 +72,6 @@ type Optab struct { ...@@ -72,14 +72,6 @@ type Optab struct {
op [23]uint8 op [23]uint8
} }
type ytab struct {
from uint8
from3 uint8
to uint8
zcase uint8
zoffset uint8
}
type Movtab struct { type Movtab struct {
as obj.As as obj.As
ft uint8 ft uint8
...@@ -323,414 +315,418 @@ var reg [MAXREG]int ...@@ -323,414 +315,418 @@ var reg [MAXREG]int
var regrex [MAXREG + 1]int var regrex [MAXREG + 1]int
var ynone = []ytab{ var ynone = []ytab{
{Ynone, Ynone, Ynone, Zlit, 1}, {Zlit, 1, argList{}},
} }
var ytext = []ytab{ var ytext = []ytab{
{Ymb, Ynone, Ytextsize, Zpseudo, 0}, {Zpseudo, 0, argList{Ymb, Ytextsize}},
{Ymb, Yi32, Ytextsize, Zpseudo, 1}, {Zpseudo, 1, argList{Ymb, Yi32, Ytextsize}},
} }
var ynop = []ytab{ var ynop = []ytab{
{Ynone, Ynone, Ynone, Zpseudo, 0}, {Zpseudo, 0, argList{}},
{Ynone, Ynone, Yiauto, Zpseudo, 0}, {Zpseudo, 0, argList{Yiauto}},
{Ynone, Ynone, Yml, Zpseudo, 0}, {Zpseudo, 0, argList{Yml}},
{Ynone, Ynone, Yrf, Zpseudo, 0}, {Zpseudo, 0, argList{Yrf}},
{Ynone, Ynone, Yxr, Zpseudo, 0}, {Zpseudo, 0, argList{Yxr}},
{Yiauto, Ynone, Ynone, Zpseudo, 0}, {Zpseudo, 0, argList{Yiauto}},
{Yml, Ynone, Ynone, Zpseudo, 0}, {Zpseudo, 0, argList{Yml}},
{Yrf, Ynone, Ynone, Zpseudo, 0}, {Zpseudo, 0, argList{Yrf}},
{Yxr, Ynone, Ynone, Zpseudo, 1}, {Zpseudo, 1, argList{Yxr}},
} }
var yfuncdata = []ytab{ var yfuncdata = []ytab{
{Yi32, Ynone, Ym, Zpseudo, 0}, {Zpseudo, 0, argList{Yi32, Ym}},
} }
var ypcdata = []ytab{ var ypcdata = []ytab{
{Yi32, Ynone, Yi32, Zpseudo, 0}, {Zpseudo, 0, argList{Yi32, Yi32}},
} }
var yxorb = []ytab{ var yxorb = []ytab{
{Yi32, Ynone, Yal, Zib_, 1}, {Zib_, 1, argList{Yi32, Yal}},
{Yi32, Ynone, Ymb, Zibo_m, 2}, {Zibo_m, 2, argList{Yi32, Ymb}},
{Yrb, Ynone, Ymb, Zr_m, 1}, {Zr_m, 1, argList{Yrb, Ymb}},
{Ymb, Ynone, Yrb, Zm_r, 1}, {Zm_r, 1, argList{Ymb, Yrb}},
} }
var yaddl = []ytab{ var yaddl = []ytab{
{Yi8, Ynone, Yml, Zibo_m, 2}, {Zibo_m, 2, argList{Yi8, Yml}},
{Yi32, Ynone, Yax, Zil_, 1}, {Zil_, 1, argList{Yi32, Yax}},
{Yi32, Ynone, Yml, Zilo_m, 2}, {Zilo_m, 2, argList{Yi32, Yml}},
{Yrl, Ynone, Yml, Zr_m, 1}, {Zr_m, 1, argList{Yrl, Yml}},
{Yml, Ynone, Yrl, Zm_r, 1}, {Zm_r, 1, argList{Yml, Yrl}},
} }
var yincl = []ytab{ var yincl = []ytab{
{Ynone, Ynone, Yrl, Z_rp, 1}, {Z_rp, 1, argList{Yrl}},
{Ynone, Ynone, Yml, Zo_m, 2}, {Zo_m, 2, argList{Yml}},
} }
var yincq = []ytab{ var yincq = []ytab{
{Ynone, Ynone, Yml, Zo_m, 2}, {Zo_m, 2, argList{Yml}},
} }
var ycmpb = []ytab{ var ycmpb = []ytab{
{Yal, Ynone, Yi32, Z_ib, 1}, {Z_ib, 1, argList{Yal, Yi32}},
{Ymb, Ynone, Yi32, Zm_ibo, 2}, {Zm_ibo, 2, argList{Ymb, Yi32}},
{Ymb, Ynone, Yrb, Zm_r, 1}, {Zm_r, 1, argList{Ymb, Yrb}},
{Yrb, Ynone, Ymb, Zr_m, 1}, {Zr_m, 1, argList{Yrb, Ymb}},
} }
var ycmpl = []ytab{ var ycmpl = []ytab{
{Yml, Ynone, Yi8, Zm_ibo, 2}, {Zm_ibo, 2, argList{Yml, Yi8}},
{Yax, Ynone, Yi32, Z_il, 1}, {Z_il, 1, argList{Yax, Yi32}},
{Yml, Ynone, Yi32, Zm_ilo, 2}, {Zm_ilo, 2, argList{Yml, Yi32}},
{Yml, Ynone, Yrl, Zm_r, 1}, {Zm_r, 1, argList{Yml, Yrl}},
{Yrl, Ynone, Yml, Zr_m, 1}, {Zr_m, 1, argList{Yrl, Yml}},
} }
var yshb = []ytab{ var yshb = []ytab{
{Yi1, Ynone, Ymb, Zo_m, 2}, {Zo_m, 2, argList{Yi1, Ymb}},
{Yu8, Ynone, Ymb, Zibo_m, 2}, {Zibo_m, 2, argList{Yu8, Ymb}},
{Ycx, Ynone, Ymb, Zo_m, 2}, {Zo_m, 2, argList{Ycx, Ymb}},
} }
var yshl = []ytab{ var yshl = []ytab{
{Yi1, Ynone, Yml, Zo_m, 2}, {Zo_m, 2, argList{Yi1, Yml}},
{Yu8, Ynone, Yml, Zibo_m, 2}, {Zibo_m, 2, argList{Yu8, Yml}},
{Ycl, Ynone, Yml, Zo_m, 2}, {Zo_m, 2, argList{Ycl, Yml}},
{Ycx, Ynone, Yml, Zo_m, 2}, {Zo_m, 2, argList{Ycx, Yml}},
} }
var ytestl = []ytab{ var ytestl = []ytab{
{Yi32, Ynone, Yax, Zil_, 1}, {Zil_, 1, argList{Yi32, Yax}},
{Yi32, Ynone, Yml, Zilo_m, 2}, {Zilo_m, 2, argList{Yi32, Yml}},
{Yrl, Ynone, Yml, Zr_m, 1}, {Zr_m, 1, argList{Yrl, Yml}},
{Yml, Ynone, Yrl, Zm_r, 1}, {Zm_r, 1, argList{Yml, Yrl}},
} }
var ymovb = []ytab{ var ymovb = []ytab{
{Yrb, Ynone, Ymb, Zr_m, 1}, {Zr_m, 1, argList{Yrb, Ymb}},
{Ymb, Ynone, Yrb, Zm_r, 1}, {Zm_r, 1, argList{Ymb, Yrb}},
{Yi32, Ynone, Yrb, Zib_rp, 1}, {Zib_rp, 1, argList{Yi32, Yrb}},
{Yi32, Ynone, Ymb, Zibo_m, 2}, {Zibo_m, 2, argList{Yi32, Ymb}},
} }
var ybtl = []ytab{ var ybtl = []ytab{
{Yi8, Ynone, Yml, Zibo_m, 2}, {Zibo_m, 2, argList{Yi8, Yml}},
{Yrl, Ynone, Yml, Zr_m, 1}, {Zr_m, 1, argList{Yrl, Yml}},
} }
var ymovw = []ytab{ var ymovw = []ytab{
{Yrl, Ynone, Yml, Zr_m, 1}, {Zr_m, 1, argList{Yrl, Yml}},
{Yml, Ynone, Yrl, Zm_r, 1}, {Zm_r, 1, argList{Yml, Yrl}},
{Yi0, Ynone, Yrl, Zclr, 1}, {Zclr, 1, argList{Yi0, Yrl}},
{Yi32, Ynone, Yrl, Zil_rp, 1}, {Zil_rp, 1, argList{Yi32, Yrl}},
{Yi32, Ynone, Yml, Zilo_m, 2}, {Zilo_m, 2, argList{Yi32, Yml}},
{Yiauto, Ynone, Yrl, Zaut_r, 2}, {Zaut_r, 2, argList{Yiauto, Yrl}},
} }
var ymovl = []ytab{ var ymovl = []ytab{
{Yrl, Ynone, Yml, Zr_m, 1}, {Zr_m, 1, argList{Yrl, Yml}},
{Yml, Ynone, Yrl, Zm_r, 1}, {Zm_r, 1, argList{Yml, Yrl}},
{Yi0, Ynone, Yrl, Zclr, 1}, {Zclr, 1, argList{Yi0, Yrl}},
{Yi32, Ynone, Yrl, Zil_rp, 1}, {Zil_rp, 1, argList{Yi32, Yrl}},
{Yi32, Ynone, Yml, Zilo_m, 2}, {Zilo_m, 2, argList{Yi32, Yml}},
{Yml, Ynone, Ymr, Zm_r_xm, 1}, // MMX MOVD {Zm_r_xm, 1, argList{Yml, Ymr}}, // MMX MOVD
{Ymr, Ynone, Yml, Zr_m_xm, 1}, // MMX MOVD {Zr_m_xm, 1, argList{Ymr, Yml}}, // MMX MOVD
{Yml, Ynone, Yxr, Zm_r_xm, 2}, // XMM MOVD (32 bit) {Zm_r_xm, 2, argList{Yml, Yxr}}, // XMM MOVD (32 bit)
{Yxr, Ynone, Yml, Zr_m_xm, 2}, // XMM MOVD (32 bit) {Zr_m_xm, 2, argList{Yxr, Yml}}, // XMM MOVD (32 bit)
{Yiauto, Ynone, Yrl, Zaut_r, 2}, {Zaut_r, 2, argList{Yiauto, Yrl}},
} }
var yret = []ytab{ var yret = []ytab{
{Ynone, Ynone, Ynone, Zo_iw, 1}, {Zo_iw, 1, argList{}},
{Yi32, Ynone, Ynone, Zo_iw, 1}, {Zo_iw, 1, argList{Yi32}},
} }
var ymovq = []ytab{ var ymovq = []ytab{
// valid in 32-bit mode // valid in 32-bit mode
{Ym, Ynone, Ymr, Zm_r_xm_nr, 1}, // 0x6f MMX MOVQ (shorter encoding) {Zm_r_xm_nr, 1, argList{Ym, Ymr}}, // 0x6f MMX MOVQ (shorter encoding)
{Ymr, Ynone, Ym, Zr_m_xm_nr, 1}, // 0x7f MMX MOVQ {Zr_m_xm_nr, 1, argList{Ymr, Ym}}, // 0x7f MMX MOVQ
{Yxr, Ynone, Ymr, Zm_r_xm_nr, 2}, // Pf2, 0xd6 MOVDQ2Q {Zm_r_xm_nr, 2, argList{Yxr, Ymr}}, // Pf2, 0xd6 MOVDQ2Q
{Yxm, Ynone, Yxr, Zm_r_xm_nr, 2}, // Pf3, 0x7e MOVQ xmm1/m64 -> xmm2 {Zm_r_xm_nr, 2, argList{Yxm, Yxr}}, // Pf3, 0x7e MOVQ xmm1/m64 -> xmm2
{Yxr, Ynone, Yxm, Zr_m_xm_nr, 2}, // Pe, 0xd6 MOVQ xmm1 -> xmm2/m64 {Zr_m_xm_nr, 2, argList{Yxr, Yxm}}, // Pe, 0xd6 MOVQ xmm1 -> xmm2/m64
// valid only in 64-bit mode, usually with 64-bit prefix // valid only in 64-bit mode, usually with 64-bit prefix
{Yrl, Ynone, Yml, Zr_m, 1}, // 0x89 {Zr_m, 1, argList{Yrl, Yml}}, // 0x89
{Yml, Ynone, Yrl, Zm_r, 1}, // 0x8b {Zm_r, 1, argList{Yml, Yrl}}, // 0x8b
{Yi0, Ynone, Yrl, Zclr, 1}, // 0x31 {Zclr, 1, argList{Yi0, Yrl}}, // 0x31
{Ys32, Ynone, Yrl, Zilo_m, 2}, // 32 bit signed 0xc7,(0) {Zilo_m, 2, argList{Ys32, Yrl}}, // 32 bit signed 0xc7,(0)
{Yi64, Ynone, Yrl, Ziq_rp, 1}, // 0xb8 -- 32/64 bit immediate {Ziq_rp, 1, argList{Yi64, Yrl}}, // 0xb8 -- 32/64 bit immediate
{Yi32, Ynone, Yml, Zilo_m, 2}, // 0xc7,(0) {Zilo_m, 2, argList{Yi32, Yml}}, // 0xc7,(0)
{Ymm, Ynone, Ymr, Zm_r_xm, 1}, // 0x6e MMX MOVD {Zm_r_xm, 1, argList{Ymm, Ymr}}, // 0x6e MMX MOVD
{Ymr, Ynone, Ymm, Zr_m_xm, 1}, // 0x7e MMX MOVD {Zr_m_xm, 1, argList{Ymr, Ymm}}, // 0x7e MMX MOVD
{Yml, Ynone, Yxr, Zm_r_xm, 2}, // Pe, 0x6e MOVD xmm load {Zm_r_xm, 2, argList{Yml, Yxr}}, // Pe, 0x6e MOVD xmm load
{Yxr, Ynone, Yml, Zr_m_xm, 2}, // Pe, 0x7e MOVD xmm store {Zr_m_xm, 2, argList{Yxr, Yml}}, // Pe, 0x7e MOVD xmm store
{Yiauto, Ynone, Yrl, Zaut_r, 1}, // 0 built-in LEAQ {Zaut_r, 1, argList{Yiauto, Yrl}}, // 0 built-in LEAQ
} }
var ym_rl = []ytab{ var ym_rl = []ytab{
{Ym, Ynone, Yrl, Zm_r, 1}, {Zm_r, 1, argList{Ym, Yrl}},
} }
var yrl_m = []ytab{ var yrl_m = []ytab{
{Yrl, Ynone, Ym, Zr_m, 1}, {Zr_m, 1, argList{Yrl, Ym}},
} }
var ymb_rl = []ytab{ var ymb_rl = []ytab{
{Ymb, Ynone, Yrl, Zmb_r, 1}, {Zmb_r, 1, argList{Ymb, Yrl}},
} }
var yml_rl = []ytab{ var yml_rl = []ytab{
{Yml, Ynone, Yrl, Zm_r, 1}, {Zm_r, 1, argList{Yml, Yrl}},
} }
var yrl_ml = []ytab{ var yrl_ml = []ytab{
{Yrl, Ynone, Yml, Zr_m, 1}, {Zr_m, 1, argList{Yrl, Yml}},
} }
var yml_mb = []ytab{ var yml_mb = []ytab{
{Yrb, Ynone, Ymb, Zr_m, 1}, {Zr_m, 1, argList{Yrb, Ymb}},
{Ymb, Ynone, Yrb, Zm_r, 1}, {Zm_r, 1, argList{Ymb, Yrb}},
} }
var yrb_mb = []ytab{ var yrb_mb = []ytab{
{Yrb, Ynone, Ymb, Zr_m, 1}, {Zr_m, 1, argList{Yrb, Ymb}},
} }
var yxchg = []ytab{ var yxchg = []ytab{
{Yax, Ynone, Yrl, Z_rp, 1}, {Z_rp, 1, argList{Yax, Yrl}},
{Yrl, Ynone, Yax, Zrp_, 1}, {Zrp_, 1, argList{Yrl, Yax}},
{Yrl, Ynone, Yml, Zr_m, 1}, {Zr_m, 1, argList{Yrl, Yml}},
{Yml, Ynone, Yrl, Zm_r, 1}, {Zm_r, 1, argList{Yml, Yrl}},
} }
var ydivl = []ytab{ var ydivl = []ytab{
{Yml, Ynone, Ynone, Zm_o, 2}, {Zm_o, 2, argList{Yml}},
} }
var ydivb = []ytab{ var ydivb = []ytab{
{Ymb, Ynone, Ynone, Zm_o, 2}, {Zm_o, 2, argList{Ymb}},
} }
var yimul = []ytab{ var yimul = []ytab{
{Yml, Ynone, Ynone, Zm_o, 2}, {Zm_o, 2, argList{Yml}},
{Yi8, Ynone, Yrl, Zib_rr, 1}, {Zib_rr, 1, argList{Yi8, Yrl}},
{Yi32, Ynone, Yrl, Zil_rr, 1}, {Zil_rr, 1, argList{Yi32, Yrl}},
{Yml, Ynone, Yrl, Zm_r, 2}, {Zm_r, 2, argList{Yml, Yrl}},
} }
var yimul3 = []ytab{ var yimul3 = []ytab{
{Yi8, Yml, Yrl, Zibm_r, 2}, {Zibm_r, 2, argList{Yi8, Yml, Yrl}},
} }
var ybyte = []ytab{ var ybyte = []ytab{
{Yi64, Ynone, Ynone, Zbyte, 1}, {Zbyte, 1, argList{Yi64}},
} }
var yin = []ytab{ var yin = []ytab{
{Yi32, Ynone, Ynone, Zib_, 1}, {Zib_, 1, argList{Yi32}},
{Ynone, Ynone, Ynone, Zlit, 1}, {Zlit, 1, argList{}},
} }
var yint = []ytab{ var yint = []ytab{
{Yi32, Ynone, Ynone, Zib_, 1}, {Zib_, 1, argList{Yi32}},
} }
var ypushl = []ytab{ var ypushl = []ytab{
{Yrl, Ynone, Ynone, Zrp_, 1}, {Zrp_, 1, argList{Yrl}},
{Ym, Ynone, Ynone, Zm_o, 2}, {Zm_o, 2, argList{Ym}},
{Yi8, Ynone, Ynone, Zib_, 1}, {Zib_, 1, argList{Yi8}},
{Yi32, Ynone, Ynone, Zil_, 1}, {Zil_, 1, argList{Yi32}},
} }
var ypopl = []ytab{ var ypopl = []ytab{
{Ynone, Ynone, Yrl, Z_rp, 1}, {Z_rp, 1, argList{Yrl}},
{Ynone, Ynone, Ym, Zo_m, 2}, {Zo_m, 2, argList{Ym}},
} }
var yclflush = []ytab{ var yclflush = []ytab{
{Ynone, Ynone, Ym, Zo_m, 2}, {Zo_m, 2, argList{Ym}},
} }
var ybswap = []ytab{ var ybswap = []ytab{
{Ynone, Ynone, Yrl, Z_rp, 2}, {Z_rp, 2, argList{Yrl}},
} }
var yscond = []ytab{ var yscond = []ytab{
{Ynone, Ynone, Ymb, Zo_m, 2}, {Zo_m, 2, argList{Ymb}},
} }
var yjcond = []ytab{ var yjcond = []ytab{
{Ynone, Ynone, Ybr, Zbr, 0}, {Zbr, 0, argList{Ybr}},
{Yi0, Ynone, Ybr, Zbr, 0}, {Zbr, 0, argList{Yi0, Ybr}},
{Yi1, Ynone, Ybr, Zbr, 1}, {Zbr, 1, argList{Yi1, Ybr}},
} }
var yloop = []ytab{ var yloop = []ytab{
{Ynone, Ynone, Ybr, Zloop, 1}, {Zloop, 1, argList{Ybr}},
} }
var ycall = []ytab{ var ycall = []ytab{
{Ynone, Ynone, Yml, Zcallindreg, 0}, {Zcallindreg, 0, argList{Yml}},
{Yrx, Ynone, Yrx, Zcallindreg, 2}, {Zcallindreg, 2, argList{Yrx, Yrx}},
{Ynone, Ynone, Yindir, Zcallind, 2}, {Zcallind, 2, argList{Yindir}},
{Ynone, Ynone, Ybr, Zcall, 0}, {Zcall, 0, argList{Ybr}},
{Ynone, Ynone, Yi32, Zcallcon, 1}, {Zcallcon, 1, argList{Yi32}},
} }
var yduff = []ytab{ var yduff = []ytab{
{Ynone, Ynone, Yi32, Zcallduff, 1}, {Zcallduff, 1, argList{Yi32}},
} }
var yjmp = []ytab{ var yjmp = []ytab{
{Ynone, Ynone, Yml, Zo_m64, 2}, {Zo_m64, 2, argList{Yml}},
{Ynone, Ynone, Ybr, Zjmp, 0}, {Zjmp, 0, argList{Ybr}},
{Ynone, Ynone, Yi32, Zjmpcon, 1}, {Zjmpcon, 1, argList{Yi32}},
} }
var yfmvd = []ytab{ var yfmvd = []ytab{
{Ym, Ynone, Yf0, Zm_o, 2}, {Zm_o, 2, argList{Ym, Yf0}},
{Yf0, Ynone, Ym, Zo_m, 2}, {Zo_m, 2, argList{Yf0, Ym}},
{Yrf, Ynone, Yf0, Zm_o, 2}, {Zm_o, 2, argList{Yrf, Yf0}},
{Yf0, Ynone, Yrf, Zo_m, 2}, {Zo_m, 2, argList{Yf0, Yrf}},
} }
var yfmvdp = []ytab{ var yfmvdp = []ytab{
{Yf0, Ynone, Ym, Zo_m, 2}, {Zo_m, 2, argList{Yf0, Ym}},
{Yf0, Ynone, Yrf, Zo_m, 2}, {Zo_m, 2, argList{Yf0, Yrf}},
} }
var yfmvf = []ytab{ var yfmvf = []ytab{
{Ym, Ynone, Yf0, Zm_o, 2}, {Zm_o, 2, argList{Ym, Yf0}},
{Yf0, Ynone, Ym, Zo_m, 2}, {Zo_m, 2, argList{Yf0, Ym}},
} }
var yfmvx = []ytab{ var yfmvx = []ytab{
{Ym, Ynone, Yf0, Zm_o, 2}, {Zm_o, 2, argList{Ym, Yf0}},
} }
var yfmvp = []ytab{ var yfmvp = []ytab{
{Yf0, Ynone, Ym, Zo_m, 2}, {Zo_m, 2, argList{Yf0, Ym}},
} }
var yfcmv = []ytab{ var yfcmv = []ytab{
{Yrf, Ynone, Yf0, Zm_o, 2}, {Zm_o, 2, argList{Yrf, Yf0}},
} }
var yfadd = []ytab{ var yfadd = []ytab{
{Ym, Ynone, Yf0, Zm_o, 2}, {Zm_o, 2, argList{Ym, Yf0}},
{Yrf, Ynone, Yf0, Zm_o, 2}, {Zm_o, 2, argList{Yrf, Yf0}},
{Yf0, Ynone, Yrf, Zo_m, 2}, {Zo_m, 2, argList{Yf0, Yrf}},
} }
var yfxch = []ytab{ var yfxch = []ytab{
{Yf0, Ynone, Yrf, Zo_m, 2}, {Zo_m, 2, argList{Yf0, Yrf}},
{Yrf, Ynone, Yf0, Zm_o, 2}, {Zm_o, 2, argList{Yrf, Yf0}},
} }
var ycompp = []ytab{ var ycompp = []ytab{
{Yf0, Ynone, Yrf, Zo_m, 2}, /* botch is really f0,f1 */ {Zo_m, 2, argList{Yf0, Yrf}}, /* botch is really f0,f1 */
} }
var ystsw = []ytab{ var ystsw = []ytab{
{Ynone, Ynone, Ym, Zo_m, 2}, {Zo_m, 2, argList{Ym}},
{Ynone, Ynone, Yax, Zlit, 1}, {Zlit, 1, argList{Yax}},
} }
var ysvrs = []ytab{ var ysvrs_mo = []ytab{
{Ynone, Ynone, Ym, Zo_m, 2}, {Zm_o, 2, argList{Ym}},
{Ym, Ynone, Ynone, Zm_o, 2}, }
// unaryDst version of "ysvrs_mo".
var ysvrs_om = []ytab{
{Zo_m, 2, argList{Ym}},
} }
var ymm = []ytab{ var ymm = []ytab{
{Ymm, Ynone, Ymr, Zm_r_xm, 1}, {Zm_r_xm, 1, argList{Ymm, Ymr}},
{Yxm, Ynone, Yxr, Zm_r_xm, 2}, {Zm_r_xm, 2, argList{Yxm, Yxr}},
} }
var yxm = []ytab{ var yxm = []ytab{
{Yxm, Ynone, Yxr, Zm_r_xm, 1}, {Zm_r_xm, 1, argList{Yxm, Yxr}},
} }
var yxm_q4 = []ytab{ var yxm_q4 = []ytab{
{Yxm, Ynone, Yxr, Zm_r, 1}, {Zm_r, 1, argList{Yxm, Yxr}},
} }
var yxcvm1 = []ytab{ var yxcvm1 = []ytab{
{Yxm, Ynone, Yxr, Zm_r_xm, 2}, {Zm_r_xm, 2, argList{Yxm, Yxr}},
{Yxm, Ynone, Ymr, Zm_r_xm, 2}, {Zm_r_xm, 2, argList{Yxm, Ymr}},
} }
var yxcvm2 = []ytab{ var yxcvm2 = []ytab{
{Yxm, Ynone, Yxr, Zm_r_xm, 2}, {Zm_r_xm, 2, argList{Yxm, Yxr}},
{Ymm, Ynone, Yxr, Zm_r_xm, 2}, {Zm_r_xm, 2, argList{Ymm, Yxr}},
} }
var yxr = []ytab{ var yxr = []ytab{
{Yxr, Ynone, Yxr, Zm_r_xm, 1}, {Zm_r_xm, 1, argList{Yxr, Yxr}},
} }
var yxr_ml = []ytab{ var yxr_ml = []ytab{
{Yxr, Ynone, Yml, Zr_m_xm, 1}, {Zr_m_xm, 1, argList{Yxr, Yml}},
} }
var ymr = []ytab{ var ymr = []ytab{
{Ymr, Ynone, Ymr, Zm_r, 1}, {Zm_r, 1, argList{Ymr, Ymr}},
} }
var ymr_ml = []ytab{ var ymr_ml = []ytab{
{Ymr, Ynone, Yml, Zr_m_xm, 1}, {Zr_m_xm, 1, argList{Ymr, Yml}},
} }
var yxcmpi = []ytab{ var yxcmpi = []ytab{
{Yxm, Yxr, Yi8, Zm_r_i_xm, 2}, {Zm_r_i_xm, 2, argList{Yxm, Yxr, Yi8}},
} }
var yxmov = []ytab{ var yxmov = []ytab{
{Yxm, Ynone, Yxr, Zm_r_xm, 1}, {Zm_r_xm, 1, argList{Yxm, Yxr}},
{Yxr, Ynone, Yxm, Zr_m_xm, 1}, {Zr_m_xm, 1, argList{Yxr, Yxm}},
} }
var yxcvfl = []ytab{ var yxcvfl = []ytab{
{Yxm, Ynone, Yrl, Zm_r_xm, 1}, {Zm_r_xm, 1, argList{Yxm, Yrl}},
} }
var yxcvlf = []ytab{ var yxcvlf = []ytab{
{Yml, Ynone, Yxr, Zm_r_xm, 1}, {Zm_r_xm, 1, argList{Yml, Yxr}},
} }
var yxcvfq = []ytab{ var yxcvfq = []ytab{
{Yxm, Ynone, Yrl, Zm_r_xm, 2}, {Zm_r_xm, 2, argList{Yxm, Yrl}},
} }
var yxcvqf = []ytab{ var yxcvqf = []ytab{
{Yml, Ynone, Yxr, Zm_r_xm, 2}, {Zm_r_xm, 2, argList{Yml, Yxr}},
} }
var yps = []ytab{ var yps = []ytab{
{Ymm, Ynone, Ymr, Zm_r_xm, 1}, {Zm_r_xm, 1, argList{Ymm, Ymr}},
{Yi8, Ynone, Ymr, Zibo_m_xm, 2}, {Zibo_m_xm, 2, argList{Yi8, Ymr}},
{Yxm, Ynone, Yxr, Zm_r_xm, 2}, {Zm_r_xm, 2, argList{Yxm, Yxr}},
{Yi8, Ynone, Yxr, Zibo_m_xm, 3}, {Zibo_m_xm, 3, argList{Yi8, Yxr}},
} }
var yxrrl = []ytab{ var yxrrl = []ytab{
{Yxr, Ynone, Yrl, Zm_r, 1}, {Zm_r, 1, argList{Yxr, Yrl}},
} }
var ymrxr = []ytab{ var ymrxr = []ytab{
{Ymr, Ynone, Yxr, Zm_r, 1}, {Zm_r, 1, argList{Ymr, Yxr}},
{Yxm, Ynone, Yxr, Zm_r_xm, 1}, {Zm_r_xm, 1, argList{Yxm, Yxr}},
} }
var ymshuf = []ytab{ var ymshuf = []ytab{
{Yi8, Ymm, Ymr, Zibm_r, 2}, {Zibm_r, 2, argList{Yi8, Ymm, Ymr}},
} }
var ymshufb = []ytab{ var ymshufb = []ytab{
{Yxm, Ynone, Yxr, Zm2_r, 2}, {Zm2_r, 2, argList{Yxm, Yxr}},
} }
// It should never have more than 1 entry, // It should never have more than 1 entry,
...@@ -739,60 +735,60 @@ var ymshufb = []ytab{ ...@@ -739,60 +735,60 @@ var ymshufb = []ytab{
// ROUNDPD and ROUNDPS and recently added BLENDPD, // ROUNDPD and ROUNDPS and recently added BLENDPD,
// to name a few. // to name a few.
var yxshuf = []ytab{ var yxshuf = []ytab{
{Yu8, Yxm, Yxr, Zibm_r, 2}, {Zibm_r, 2, argList{Yu8, Yxm, Yxr}},
} }
var yextrw = []ytab{ var yextrw = []ytab{
{Yu8, Yxr, Yrl, Zibm_r, 2}, {Zibm_r, 2, argList{Yu8, Yxr, Yrl}},
} }
var yextr = []ytab{ var yextr = []ytab{
{Yu8, Yxr, Ymm, Zibr_m, 3}, {Zibr_m, 3, argList{Yu8, Yxr, Ymm}},
} }
var yinsrw = []ytab{ var yinsrw = []ytab{
{Yu8, Yml, Yxr, Zibm_r, 2}, {Zibm_r, 2, argList{Yu8, Yml, Yxr}},
} }
var yinsr = []ytab{ var yinsr = []ytab{
{Yu8, Ymm, Yxr, Zibm_r, 3}, {Zibm_r, 3, argList{Yu8, Ymm, Yxr}},
} }
var ypsdq = []ytab{ var ypsdq = []ytab{
{Yi8, Ynone, Yxr, Zibo_m, 2}, {Zibo_m, 2, argList{Yi8, Yxr}},
} }
var ymskb = []ytab{ var ymskb = []ytab{
{Yxr, Ynone, Yrl, Zm_r_xm, 2}, {Zm_r_xm, 2, argList{Yxr, Yrl}},
{Ymr, Ynone, Yrl, Zm_r_xm, 1}, {Zm_r_xm, 1, argList{Ymr, Yrl}},
} }
var ycrc32l = []ytab{ var ycrc32l = []ytab{
{Yml, Ynone, Yrl, Zlitm_r, 0}, {Zlitm_r, 0, argList{Yml, Yrl}},
} }
var yprefetch = []ytab{ var yprefetch = []ytab{
{Ym, Ynone, Ynone, Zm_o, 2}, {Zm_o, 2, argList{Ym}},
} }
var yaes = []ytab{ var yaes = []ytab{
{Yxm, Ynone, Yxr, Zlitm_r, 2}, {Zlitm_r, 2, argList{Yxm, Yxr}},
} }
var yxbegin = []ytab{ var yxbegin = []ytab{
{Ynone, Ynone, Ybr, Zjmp, 1}, {Zjmp, 1, argList{Ybr}},
} }
var yxabort = []ytab{ var yxabort = []ytab{
{Yu8, Ynone, Ynone, Zib_, 1}, {Zib_, 1, argList{Yu8}},
} }
var ylddqu = []ytab{ var ylddqu = []ytab{
{Ym, Ynone, Yxr, Zm_r, 1}, {Zm_r, 1, argList{Ym, Yxr}},
} }
var ypalignr = []ytab{ var ypalignr = []ytab{
{Yu8, Yxm, Yxr, Zibm_r, 2}, {Zibm_r, 2, argList{Yu8, Yxm, Yxr}},
} }
// VEX instructions that come in two forms: // VEX instructions that come in two forms:
...@@ -815,87 +811,87 @@ var ypalignr = []ytab{ ...@@ -815,87 +811,87 @@ var ypalignr = []ytab{
// {AVPXOR, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xEF, VEX_256_66_0F_WIG, 0xEF}} // {AVPXOR, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xEF, VEX_256_66_0F_WIG, 0xEF}}
// //
var yvex_xy3 = []ytab{ var yvex_xy3 = []ytab{
{Yxm, Yxr, Yxr, Zvex_rm_v_r, 2}, {Zvex_rm_v_r, 2, argList{Yxm, Yxr, Yxr}},
{Yym, Yyr, Yyr, Zvex_rm_v_r, 2}, {Zvex_rm_v_r, 2, argList{Yym, Yyr, Yyr}},
} }
var yvex_x3 = []ytab{ var yvex_x3 = []ytab{
{Yxm, Yxr, Yxr, Zvex_rm_v_r, 2}, {Zvex_rm_v_r, 2, argList{Yxm, Yxr, Yxr}},
} }
var yvex_ri3 = []ytab{ var yvex_ri3 = []ytab{
{Yi8, Ymb, Yrl, Zvex_i_rm_r, 2}, {Zvex_i_rm_r, 2, argList{Yi8, Ymb, Yrl}},
} }
var yvex_xyi3 = []ytab{ var yvex_xyi3 = []ytab{
{Yu8, Yxm, Yxr, Zvex_i_rm_r, 2}, {Zvex_i_rm_r, 2, argList{Yu8, Yxm, Yxr}},
{Yu8, Yym, Yyr, Zvex_i_rm_r, 2}, {Zvex_i_rm_r, 2, argList{Yu8, Yym, Yyr}},
{Yi8, Yxm, Yxr, Zvex_i_rm_r, 2}, {Zvex_i_rm_r, 2, argList{Yi8, Yxm, Yxr}},
{Yi8, Yym, Yyr, Zvex_i_rm_r, 2}, {Zvex_i_rm_r, 2, argList{Yi8, Yym, Yyr}},
} }
var yvex_yyi4 = []ytab{ //TODO don't hide 4 op, some version have xmm version var yvex_yyi4 = []ytab{
{Yym, Yyr, Yyr, Zvex_i_rm_v_r, 2}, {Zvex_i_rm_v_r, 2, argList{Yu8, Yym, Yyr, Yyr}},
} }
var yvex_xyi4 = []ytab{ var yvex_xyi4 = []ytab{
{Yxm, Yyr, Yyr, Zvex_i_rm_v_r, 2}, {Zvex_i_rm_v_r, 2, argList{Yu8, Yxm, Yyr, Yyr}},
} }
var yvex_shift = []ytab{ var yvex_shift = []ytab{
{Yi8, Yxr, Yxr, Zvex_i_r_v, 3}, {Zvex_i_r_v, 3, argList{Yi8, Yxr, Yxr}},
{Yi8, Yyr, Yyr, Zvex_i_r_v, 3}, {Zvex_i_r_v, 3, argList{Yi8, Yyr, Yyr}},
{Yxm, Yxr, Yxr, Zvex_rm_v_r, 2}, {Zvex_rm_v_r, 2, argList{Yxm, Yxr, Yxr}},
{Yxm, Yyr, Yyr, Zvex_rm_v_r, 2}, {Zvex_rm_v_r, 2, argList{Yxm, Yyr, Yyr}},
} }
var yvex_shift_dq = []ytab{ var yvex_shift_dq = []ytab{
{Yi8, Yxr, Yxr, Zvex_i_r_v, 3}, {Zvex_i_r_v, 3, argList{Yi8, Yxr, Yxr}},
{Yi8, Yyr, Yyr, Zvex_i_r_v, 3}, {Zvex_i_r_v, 3, argList{Yi8, Yyr, Yyr}},
} }
var yvex_r3 = []ytab{ var yvex_r3 = []ytab{
{Yml, Yrl, Yrl, Zvex_rm_v_r, 2}, {Zvex_rm_v_r, 2, argList{Yml, Yrl, Yrl}},
} }
var yvex_vmr3 = []ytab{ var yvex_vmr3 = []ytab{
{Yrl, Yml, Yrl, Zvex_v_rm_r, 2}, {Zvex_v_rm_r, 2, argList{Yrl, Yml, Yrl}},
} }
var yvex_xy2 = []ytab{ var yvex_xy2 = []ytab{
{Yxm, Ynone, Yxr, Zvex_rm_v_r, 2}, {Zvex_rm_v_r, 2, argList{Yxm, Yxr}},
{Yym, Ynone, Yyr, Zvex_rm_v_r, 2}, {Zvex_rm_v_r, 2, argList{Yym, Yyr}},
} }
var yvex_xyr2 = []ytab{ var yvex_xyr2 = []ytab{
{Yxr, Ynone, Yrl, Zvex_rm_v_r, 2}, {Zvex_rm_v_r, 2, argList{Yxr, Yrl}},
{Yyr, Ynone, Yrl, Zvex_rm_v_r, 2}, {Zvex_rm_v_r, 2, argList{Yyr, Yrl}},
} }
var yvex_vmovdqa = []ytab{ var yvex_vmovdqa = []ytab{
{Yxm, Ynone, Yxr, Zvex_rm_v_r, 2}, {Zvex_rm_v_r, 2, argList{Yxm, Yxr}},
{Yxr, Ynone, Yxm, Zvex_r_v_rm, 2}, {Zvex_r_v_rm, 2, argList{Yxr, Yxm}},
{Yym, Ynone, Yyr, Zvex_rm_v_r, 2}, {Zvex_rm_v_r, 2, argList{Yym, Yyr}},
{Yyr, Ynone, Yym, Zvex_r_v_rm, 2}, {Zvex_r_v_rm, 2, argList{Yyr, Yym}},
} }
var yvex_vmovntdq = []ytab{ var yvex_vmovntdq = []ytab{
{Yxr, Ynone, Ym, Zvex_r_v_rm, 2}, {Zvex_r_v_rm, 2, argList{Yxr, Ym}},
{Yyr, Ynone, Ym, Zvex_r_v_rm, 2}, {Zvex_r_v_rm, 2, argList{Yyr, Ym}},
} }
var yvex_vpbroadcast = []ytab{ var yvex_vpbroadcast = []ytab{
{Yxm, Ynone, Yxr, Zvex_rm_v_r, 2}, {Zvex_rm_v_r, 2, argList{Yxm, Yxr}},
{Yxm, Ynone, Yyr, Zvex_rm_v_r, 2}, {Zvex_rm_v_r, 2, argList{Yxm, Yyr}},
} }
var yvex_vpbroadcast_sd = []ytab{ var yvex_vpbroadcast_sd = []ytab{
{Yxm, Ynone, Yyr, Zvex_rm_v_r, 2}, {Zvex_rm_v_r, 2, argList{Yxm, Yyr}},
} }
var ymmxmm0f38 = []ytab{ var ymmxmm0f38 = []ytab{
{Ymm, Ynone, Ymr, Zlitm_r, 3}, {Zlitm_r, 3, argList{Ymm, Ymr}},
{Yxm, Ynone, Yxr, Zlitm_r, 5}, {Zlitm_r, 5, argList{Yxm, Yxr}},
} }
/* /*
...@@ -1120,10 +1116,10 @@ var optab = ...@@ -1120,10 +1116,10 @@ var optab =
{ADPPS, yxshuf, Pq, [23]uint8{0x3a, 0x40, 0}}, {ADPPS, yxshuf, Pq, [23]uint8{0x3a, 0x40, 0}},
{AEMMS, ynone, Pm, [23]uint8{0x77}}, {AEMMS, ynone, Pm, [23]uint8{0x77}},
{AENTER, nil, 0, [23]uint8{}}, /* botch */ {AENTER, nil, 0, [23]uint8{}}, /* botch */
{AFXRSTOR, ysvrs, Pm, [23]uint8{0xae, 01, 0xae, 01}}, {AFXRSTOR, ysvrs_mo, Pm, [23]uint8{0xae, 01, 0xae, 01}},
{AFXSAVE, ysvrs, Pm, [23]uint8{0xae, 00, 0xae, 00}}, {AFXSAVE, ysvrs_om, Pm, [23]uint8{0xae, 00, 0xae, 00}},
{AFXRSTOR64, ysvrs, Pw, [23]uint8{0x0f, 0xae, 01, 0x0f, 0xae, 01}}, {AFXRSTOR64, ysvrs_mo, Pw, [23]uint8{0x0f, 0xae, 01, 0x0f, 0xae, 01}},
{AFXSAVE64, ysvrs, Pw, [23]uint8{0x0f, 0xae, 00, 0x0f, 0xae, 00}}, {AFXSAVE64, ysvrs_om, Pw, [23]uint8{0x0f, 0xae, 00, 0x0f, 0xae, 00}},
{AHLT, ynone, Px, [23]uint8{0xf4}}, {AHLT, ynone, Px, [23]uint8{0xf4}},
{AIDIVB, ydivb, Pb, [23]uint8{0xf6, 07}}, {AIDIVB, ydivb, Pb, [23]uint8{0xf6, 07}},
{AIDIVL, ydivl, Px, [23]uint8{0xf7, 07}}, {AIDIVL, ydivl, Px, [23]uint8{0xf7, 07}},
...@@ -1178,7 +1174,7 @@ var optab = ...@@ -1178,7 +1174,7 @@ var optab =
{ALARL, yml_rl, Pm, [23]uint8{0x02}}, {ALARL, yml_rl, Pm, [23]uint8{0x02}},
{ALARW, yml_rl, Pq, [23]uint8{0x02}}, {ALARW, yml_rl, Pq, [23]uint8{0x02}},
{ALDDQU, ylddqu, Pf2, [23]uint8{0xf0}}, {ALDDQU, ylddqu, Pf2, [23]uint8{0xf0}},
{ALDMXCSR, ysvrs, Pm, [23]uint8{0xae, 02, 0xae, 02}}, {ALDMXCSR, ysvrs_mo, Pm, [23]uint8{0xae, 02, 0xae, 02}},
{ALEAL, ym_rl, Px, [23]uint8{0x8d}}, {ALEAL, ym_rl, Px, [23]uint8{0x8d}},
{ALEAQ, ym_rl, Pw, [23]uint8{0x8d}}, {ALEAQ, ym_rl, Pw, [23]uint8{0x8d}},
{ALEAVEL, ynone, P32, [23]uint8{0xc9}}, {ALEAVEL, ynone, P32, [23]uint8{0xc9}},
...@@ -1493,7 +1489,7 @@ var optab = ...@@ -1493,7 +1489,7 @@ var optab =
{ASTC, ynone, Px, [23]uint8{0xf9}}, {ASTC, ynone, Px, [23]uint8{0xf9}},
{ASTD, ynone, Px, [23]uint8{0xfd}}, {ASTD, ynone, Px, [23]uint8{0xfd}},
{ASTI, ynone, Px, [23]uint8{0xfb}}, {ASTI, ynone, Px, [23]uint8{0xfb}},
{ASTMXCSR, ysvrs, Pm, [23]uint8{0xae, 03, 0xae, 03}}, {ASTMXCSR, ysvrs_om, Pm, [23]uint8{0xae, 03, 0xae, 03}},
{ASTOSB, ynone, Pb, [23]uint8{0xaa}}, {ASTOSB, ynone, Pb, [23]uint8{0xaa}},
{ASTOSL, ynone, Px, [23]uint8{0xab}}, {ASTOSL, ynone, Px, [23]uint8{0xab}},
{ASTOSQ, ynone, Pw, [23]uint8{0xab}}, {ASTOSQ, ynone, Pw, [23]uint8{0xab}},
...@@ -1604,12 +1600,12 @@ var optab = ...@@ -1604,12 +1600,12 @@ var optab =
{AFDIVRD, yfadd, Px, [23]uint8{0xdc, 07, 0xd8, 07, 0xdc, 06}}, {AFDIVRD, yfadd, Px, [23]uint8{0xdc, 07, 0xd8, 07, 0xdc, 06}},
{AFXCHD, yfxch, Px, [23]uint8{0xd9, 01, 0xd9, 01}}, {AFXCHD, yfxch, Px, [23]uint8{0xd9, 01, 0xd9, 01}},
{AFFREE, nil, 0, [23]uint8{}}, {AFFREE, nil, 0, [23]uint8{}},
{AFLDCW, ysvrs, Px, [23]uint8{0xd9, 05, 0xd9, 05}}, {AFLDCW, ysvrs_mo, Px, [23]uint8{0xd9, 05, 0xd9, 05}},
{AFLDENV, ysvrs, Px, [23]uint8{0xd9, 04, 0xd9, 04}}, {AFLDENV, ysvrs_mo, Px, [23]uint8{0xd9, 04, 0xd9, 04}},
{AFRSTOR, ysvrs, Px, [23]uint8{0xdd, 04, 0xdd, 04}}, {AFRSTOR, ysvrs_mo, Px, [23]uint8{0xdd, 04, 0xdd, 04}},
{AFSAVE, ysvrs, Px, [23]uint8{0xdd, 06, 0xdd, 06}}, {AFSAVE, ysvrs_om, Px, [23]uint8{0xdd, 06, 0xdd, 06}},
{AFSTCW, ysvrs, Px, [23]uint8{0xd9, 07, 0xd9, 07}}, {AFSTCW, ysvrs_om, Px, [23]uint8{0xd9, 07, 0xd9, 07}},
{AFSTENV, ysvrs, Px, [23]uint8{0xd9, 06, 0xd9, 06}}, {AFSTENV, ysvrs_om, Px, [23]uint8{0xd9, 06, 0xd9, 06}},
{AFSTSW, ystsw, Px, [23]uint8{0xdd, 07, 0xdf, 0xe0}}, {AFSTSW, ystsw, Px, [23]uint8{0xdd, 07, 0xdf, 0xe0}},
{AF2XM1, ynone, Px, [23]uint8{0xd9, 0xf0}}, {AF2XM1, ynone, Px, [23]uint8{0xd9, 0xf0}},
{AFABS, ynone, Px, [23]uint8{0xd9, 0xe1}}, {AFABS, ynone, Px, [23]uint8{0xd9, 0xe1}},
...@@ -3403,9 +3399,10 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) { ...@@ -3403,9 +3399,10 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
// Similarly SHRQ CX, AX:DX is really SHRQ CX(DX*0), AX. // Similarly SHRQ CX, AX:DX is really SHRQ CX(DX*0), AX.
// Change encoding generated by assemblers and compilers and remove. // Change encoding generated by assemblers and compilers and remove.
if (p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_REG) && p.From.Index != REG_NONE && p.From.Scale == 0 { if (p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_REG) && p.From.Index != REG_NONE && p.From.Scale == 0 {
p.From3 = new(obj.Addr) p.SetFrom3(obj.Addr{
p.From3.Type = obj.TYPE_REG Type: obj.TYPE_REG,
p.From3.Reg = p.From.Index Reg: p.From.Index,
})
p.From.Index = 0 p.From.Index = 0
} }
...@@ -3414,8 +3411,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) { ...@@ -3414,8 +3411,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
switch p.As { switch p.As {
case AIMUL3Q, APEXTRW, APINSRW, APINSRD, APINSRQ, APSHUFHW, APSHUFL, APSHUFW, ASHUFPD, ASHUFPS, AAESKEYGENASSIST, APSHUFD, APCLMULQDQ: case AIMUL3Q, APEXTRW, APINSRW, APINSRD, APINSRQ, APSHUFHW, APSHUFL, APSHUFW, ASHUFPD, ASHUFPS, AAESKEYGENASSIST, APSHUFD, APCLMULQDQ:
if p.From3Type() == obj.TYPE_NONE { if p.From3Type() == obj.TYPE_NONE {
p.From3 = new(obj.Addr) p.SetFrom3(p.From)
*p.From3 = p.From
p.From = obj.Addr{} p.From = obj.Addr{}
p.From.Type = obj.TYPE_CONST p.From.Type = obj.TYPE_CONST
p.From.Offset = p.To.Offset p.From.Offset = p.To.Offset
...@@ -3423,12 +3419,11 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) { ...@@ -3423,12 +3419,11 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
} }
case ACMPSD, ACMPSS, ACMPPS, ACMPPD: case ACMPSD, ACMPSS, ACMPPS, ACMPPD:
if p.From3Type() == obj.TYPE_NONE { if p.From3Type() == obj.TYPE_NONE {
p.From3 = new(obj.Addr) p.SetFrom3(p.To)
*p.From3 = p.To
p.To = obj.Addr{} p.To = obj.Addr{}
p.To.Type = obj.TYPE_CONST p.To.Type = obj.TYPE_CONST
p.To.Offset = p.From3.Offset p.To.Offset = p.GetFrom3().Offset
p.From3.Offset = 0 p.GetFrom3().Offset = 0
} }
} }
...@@ -3440,10 +3435,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) { ...@@ -3440,10 +3435,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
} }
ft := int(p.Ft) * Ymax ft := int(p.Ft) * Ymax
f3t := Ynone * Ymax var f3t int
if p.From3 != nil {
f3t = oclass(ctxt, p, p.From3) * Ymax
}
tt := int(p.Tt) * Ymax tt := int(p.Tt) * Ymax
xo := obj.Bool2int(o.op[0] == 0x0f) xo := obj.Bool2int(o.op[0] == 0x0f)
...@@ -3455,9 +3447,22 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) { ...@@ -3455,9 +3447,22 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
var r *obj.Reloc var r *obj.Reloc
var rel obj.Reloc var rel obj.Reloc
var v int64 var v int64
for i := range o.ytab {
yt := &o.ytab[i] args := make([]int, 0, 6)
if ycover[ft+int(yt.from)] != 0 && ycover[f3t+int(yt.from3)] != 0 && ycover[tt+int(yt.to)] != 0 { if ft != Ynone*Ymax {
args = append(args, ft)
}
for i := range p.RestArgs {
args = append(args, oclass(ctxt, p, &p.RestArgs[i])*Ymax)
}
if tt != Ynone*Ymax {
args = append(args, tt)
}
for _, yt := range o.ytab {
if !yt.match(args) {
z += int(yt.zoffset) + xo
} else {
switch o.prefix { switch o.prefix {
case Px1: /* first option valid only in 32-bit mode */ case Px1: /* first option valid only in 32-bit mode */
if ctxt.Arch.Family == sys.AMD64 && z == 0 { if ctxt.Arch.Family == sys.AMD64 && z == 0 {
...@@ -3604,7 +3609,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) { ...@@ -3604,7 +3609,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
case Zm_r_i_xm: case Zm_r_i_xm:
asmbuf.mediaop(ctxt, o, op, int(yt.zoffset), z) asmbuf.mediaop(ctxt, o, op, int(yt.zoffset), z)
asmbuf.asmand(ctxt, cursym, p, &p.From, p.From3) asmbuf.asmand(ctxt, cursym, p, &p.From, p.GetFrom3())
asmbuf.Put1(byte(p.To.Offset)) asmbuf.Put1(byte(p.To.Offset))
case Zibm_r, Zibr_m: case Zibm_r, Zibr_m:
...@@ -3618,9 +3623,9 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) { ...@@ -3618,9 +3623,9 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
asmbuf.Put1(byte(op)) asmbuf.Put1(byte(op))
} }
if yt.zcase == Zibr_m { if yt.zcase == Zibr_m {
asmbuf.asmand(ctxt, cursym, p, &p.To, p.From3) asmbuf.asmand(ctxt, cursym, p, &p.To, p.GetFrom3())
} else { } else {
asmbuf.asmand(ctxt, cursym, p, p.From3, &p.To) asmbuf.asmand(ctxt, cursym, p, p.GetFrom3(), &p.To)
} }
asmbuf.Put1(byte(p.From.Offset)) asmbuf.Put1(byte(p.From.Offset))
...@@ -3642,36 +3647,37 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) { ...@@ -3642,36 +3647,37 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
asmbuf.asmand(ctxt, cursym, p, &p.To, &p.From) asmbuf.asmand(ctxt, cursym, p, &p.To, &p.From)
case Zvex_rm_v_r: case Zvex_rm_v_r:
asmbuf.asmvex(ctxt, &p.From, p.From3, &p.To, o.op[z], o.op[z+1]) asmbuf.asmvex(ctxt, &p.From, p.GetFrom3(), &p.To, o.op[z], o.op[z+1])
asmbuf.asmand(ctxt, cursym, p, &p.From, &p.To) asmbuf.asmand(ctxt, cursym, p, &p.From, &p.To)
case Zvex_i_r_v: case Zvex_i_r_v:
asmbuf.asmvex(ctxt, p.From3, &p.To, nil, o.op[z], o.op[z+1]) asmbuf.asmvex(ctxt, p.GetFrom3(), &p.To, nil, o.op[z], o.op[z+1])
regnum := byte(0x7) regnum := byte(0x7)
if p.From3.Reg >= REG_X0 && p.From3.Reg <= REG_X15 { if p.GetFrom3().Reg >= REG_X0 && p.GetFrom3().Reg <= REG_X15 {
regnum &= byte(p.From3.Reg - REG_X0) regnum &= byte(p.GetFrom3().Reg - REG_X0)
} else { } else {
regnum &= byte(p.From3.Reg - REG_Y0) regnum &= byte(p.GetFrom3().Reg - REG_Y0)
} }
asmbuf.Put1(byte(o.op[z+2]) | regnum) asmbuf.Put1(byte(o.op[z+2]) | regnum)
asmbuf.Put1(byte(p.From.Offset)) asmbuf.Put1(byte(p.From.Offset))
case Zvex_i_rm_v_r: case Zvex_i_rm_v_r:
asmbuf.asmvex(ctxt, &p.From, p.From3, &p.To, o.op[z], o.op[z+1]) imm, from, from3, to := unpackOps4(p)
asmbuf.asmand(ctxt, cursym, p, &p.From, &p.To) asmbuf.asmvex(ctxt, from, from3, to, o.op[z], o.op[z+1])
asmbuf.Put1(byte(p.From3.Offset)) asmbuf.asmand(ctxt, cursym, p, from, to)
asmbuf.Put1(byte(imm.Offset))
case Zvex_i_rm_r: case Zvex_i_rm_r:
asmbuf.asmvex(ctxt, p.From3, nil, &p.To, o.op[z], o.op[z+1]) asmbuf.asmvex(ctxt, p.GetFrom3(), nil, &p.To, o.op[z], o.op[z+1])
asmbuf.asmand(ctxt, cursym, p, p.From3, &p.To) asmbuf.asmand(ctxt, cursym, p, p.GetFrom3(), &p.To)
asmbuf.Put1(byte(p.From.Offset)) asmbuf.Put1(byte(p.From.Offset))
case Zvex_v_rm_r: case Zvex_v_rm_r:
asmbuf.asmvex(ctxt, p.From3, &p.From, &p.To, o.op[z], o.op[z+1]) asmbuf.asmvex(ctxt, p.GetFrom3(), &p.From, &p.To, o.op[z], o.op[z+1])
asmbuf.asmand(ctxt, cursym, p, p.From3, &p.To) asmbuf.asmand(ctxt, cursym, p, p.GetFrom3(), &p.To)
case Zvex_r_v_rm: case Zvex_r_v_rm:
asmbuf.asmvex(ctxt, &p.To, p.From3, &p.From, o.op[z], o.op[z+1]) asmbuf.asmvex(ctxt, &p.To, p.GetFrom3(), &p.From, o.op[z], o.op[z+1])
asmbuf.asmand(ctxt, cursym, p, &p.To, &p.From) asmbuf.asmand(ctxt, cursym, p, &p.To, &p.From)
case Zr_m_xm: case Zr_m_xm:
...@@ -4026,7 +4032,10 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) { ...@@ -4026,7 +4032,10 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
return return
} }
z += int(yt.zoffset) + xo }
f3t = Ynone * Ymax
if p.GetFrom3() != nil {
f3t = oclass(ctxt, p, p.GetFrom3()) * Ymax
} }
for mo := ymovtab; mo[0].as != 0; mo = mo[1:] { for mo := ymovtab; mo[0].as != 0; mo = mo[1:] {
var pp obj.Prog var pp obj.Prog
...@@ -4105,7 +4114,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) { ...@@ -4105,7 +4114,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
case obj.TYPE_CONST: case obj.TYPE_CONST:
asmbuf.Put2(0x0f, t[0]) asmbuf.Put2(0x0f, t[0])
asmbuf.asmandsz(ctxt, cursym, p, &p.To, reg[p.From3.Reg], regrex[p.From3.Reg], 0) asmbuf.asmandsz(ctxt, cursym, p, &p.To, reg[p.GetFrom3().Reg], regrex[p.GetFrom3().Reg], 0)
asmbuf.Put1(byte(p.From.Offset)) asmbuf.Put1(byte(p.From.Offset))
case obj.TYPE_REG: case obj.TYPE_REG:
...@@ -4115,7 +4124,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) { ...@@ -4115,7 +4124,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
case REG_CL, REG_CX: case REG_CL, REG_CX:
asmbuf.Put2(0x0f, t[1]) asmbuf.Put2(0x0f, t[1])
asmbuf.asmandsz(ctxt, cursym, p, &p.To, reg[p.From3.Reg], regrex[p.From3.Reg], 0) asmbuf.asmandsz(ctxt, cursym, p, &p.To, reg[p.GetFrom3().Reg], regrex[p.GetFrom3().Reg], 0)
} }
} }
...@@ -4666,3 +4675,8 @@ func (asmbuf *AsmBuf) asmins(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) { ...@@ -4666,3 +4675,8 @@ func (asmbuf *AsmBuf) asmins(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
} }
} }
} }
// Extract 4 operands from p.
func unpackOps4(p *obj.Prog) (*obj.Addr, *obj.Addr, *obj.Addr, *obj.Addr) {
return &p.From, &p.RestArgs[0], &p.RestArgs[1], &p.To
}
...@@ -201,8 +201,8 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { ...@@ -201,8 +201,8 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
} }
if ctxt.Headtype == objabi.Hnacl && ctxt.Arch.Family == sys.AMD64 { if ctxt.Headtype == objabi.Hnacl && ctxt.Arch.Family == sys.AMD64 {
if p.From3 != nil { if p.GetFrom3() != nil {
nacladdr(ctxt, p, p.From3) nacladdr(ctxt, p, p.GetFrom3())
} }
nacladdr(ctxt, p, &p.From) nacladdr(ctxt, p, &p.From)
nacladdr(ctxt, p, &p.To) nacladdr(ctxt, p, &p.To)
...@@ -398,7 +398,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { ...@@ -398,7 +398,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
q.From.Reg = reg q.From.Reg = reg
} }
} }
if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN { if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
ctxt.Diag("don't know how to handle %v with -dynlink", p) ctxt.Diag("don't know how to handle %v with -dynlink", p)
} }
var source *obj.Addr var source *obj.Addr
...@@ -436,7 +436,9 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { ...@@ -436,7 +436,9 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
p2.As = p.As p2.As = p.As
p2.Scond = p.Scond p2.Scond = p.Scond
p2.From = p.From p2.From = p.From
p2.From3 = p.From3 if p.RestArgs != nil {
p2.RestArgs = append(p2.RestArgs, p.RestArgs...)
}
p2.Reg = p.Reg p2.Reg = p.Reg
p2.To = p.To p2.To = p.To
// p.To.Type was set to TYPE_BRANCH above, but that makes checkaddr // p.To.Type was set to TYPE_BRANCH above, but that makes checkaddr
...@@ -522,7 +524,7 @@ func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { ...@@ -522,7 +524,7 @@ func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
} }
} }
if !isName(&p.From) && !isName(&p.To) && (p.From3 == nil || !isName(p.From3)) { if !isName(&p.From) && !isName(&p.To) && (p.GetFrom3() == nil || !isName(p.GetFrom3())) {
return return
} }
var dst int16 = REG_CX var dst int16 = REG_CX
...@@ -543,7 +545,7 @@ func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { ...@@ -543,7 +545,7 @@ func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
r.As = p.As r.As = p.As
r.Scond = p.Scond r.Scond = p.Scond
r.From = p.From r.From = p.From
r.From3 = p.From3 r.RestArgs = p.RestArgs
r.Reg = p.Reg r.Reg = p.Reg
r.To = p.To r.To = p.To
if isName(&p.From) { if isName(&p.From) {
...@@ -552,8 +554,8 @@ func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { ...@@ -552,8 +554,8 @@ func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
if isName(&p.To) { if isName(&p.To) {
r.To.Reg = dst r.To.Reg = dst
} }
if p.From3 != nil && isName(p.From3) { if p.GetFrom3() != nil && isName(p.GetFrom3()) {
r.From3.Reg = dst r.GetFrom3().Reg = dst
} }
obj.Nopout(p) obj.Nopout(p)
} }
...@@ -857,12 +859,12 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { ...@@ -857,12 +859,12 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
case obj.NAME_PARAM: case obj.NAME_PARAM:
p.From.Offset += int64(deltasp) + int64(pcsize) p.From.Offset += int64(deltasp) + int64(pcsize)
} }
if p.From3 != nil { if p.GetFrom3() != nil {
switch p.From3.Name { switch p.GetFrom3().Name {
case obj.NAME_AUTO: case obj.NAME_AUTO:
p.From3.Offset += int64(deltasp) - int64(bpsize) p.GetFrom3().Offset += int64(deltasp) - int64(bpsize)
case obj.NAME_PARAM: case obj.NAME_PARAM:
p.From3.Offset += int64(deltasp) + int64(pcsize) p.GetFrom3().Offset += int64(deltasp) + int64(pcsize)
} }
} }
switch p.To.Name { switch p.To.Name {
......
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package x86
type argList [6]uint8
type ytab struct {
zcase uint8
zoffset uint8
// Last arg is usually destination.
// For unary instructions unaryDst is used to determine
// if single argument is a source or destination.
args argList
}
// Returns true if yt is compatible with args.
//
// Elements from args and yt.args are used to
// to index ycover table like `ycover[args[i]+yt.args[i]]`.
// This means that args should contain values that already
// multiplied by Ymax.
func (yt *ytab) match(args []int) bool {
// Trailing Yxxx check is required to avoid a case
// where shorter arg list is matched.
// If we had exact yt.args length, it could be `yt.argc != len(args)`.
if len(args) < len(yt.args) && yt.args[len(args)] != Yxxx {
return false
}
for i := range args {
if ycover[args[i]+int(yt.args[i])] == 0 {
return false
}
}
return true
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment