]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj: change Prog.From3 to RestArgs ([]Addr)
authorisharipo <iskander.sharipov@intel.com>
Wed, 13 Sep 2017 11:32:08 +0000 (14:32 +0300)
committerMatthew Dempsky <mdempsky@google.com>
Fri, 15 Sep 2017 21:05:03 +0000 (21:05 +0000)
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: Matthew Dempsky <mdempsky@google.com>
21 files changed:
src/cmd/asm/internal/arch/amd64.go [deleted file]
src/cmd/asm/internal/asm/asm.go
src/cmd/compile/internal/arm64/ssa.go
src/cmd/compile/internal/ppc64/ssa.go
src/cmd/compile/internal/s390x/ssa.go
src/cmd/internal/obj/arm/asm5.go
src/cmd/internal/obj/arm/obj5.go
src/cmd/internal/obj/arm64/asm7.go
src/cmd/internal/obj/arm64/obj7.go
src/cmd/internal/obj/go.go
src/cmd/internal/obj/link.go
src/cmd/internal/obj/pass.go
src/cmd/internal/obj/ppc64/asm9.go
src/cmd/internal/obj/ppc64/obj9.go
src/cmd/internal/obj/s390x/asmz.go
src/cmd/internal/obj/s390x/objz.go
src/cmd/internal/obj/sizeof_test.go
src/cmd/internal/obj/util.go
src/cmd/internal/obj/x86/asm6.go
src/cmd/internal/obj/x86/obj6.go
src/cmd/internal/obj/x86/ytab.go [new file with mode: 0644]

diff --git a/src/cmd/asm/internal/arch/amd64.go b/src/cmd/asm/internal/arch/amd64.go
deleted file mode 100644 (file)
index ff20d32..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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
-}
index 24aa0537ca61de4137858a350279a64e08d71cd5..b5e4bddb96b18415af43a52d239b77ea0bb73eb6 100644 (file)
@@ -384,7 +384,7 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
                                prog.Reg = p.getRegister(prog, op, &a[1])
                        } else {
                                // Compare register with immediate and jump.
-                               prog.From3 = newAddr(a[1])
+                               prog.SetFrom3(a[1])
                        }
                        break
                }
@@ -567,7 +567,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
                        if arch.IsARMBFX(op) {
                                // a[0] and a[1] must be constants, a[2] must be a register
                                prog.From = a[0]
-                               prog.From3 = newAddr(a[1])
+                               prog.SetFrom3(a[1])
                                prog.To = a[2]
                                break
                        }
@@ -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.To = a[2]
                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.From3 = newAddr(a[1])
+                       prog.SetFrom3(a[1])
                        prog.To = a[2]
                case sys.ARM64:
                        // ARM64 instructions with one input and two outputs.
@@ -601,7 +596,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
                        prog.To = a[2]
                case sys.I386:
                        prog.From = a[0]
-                       prog.From3 = newAddr(a[1])
+                       prog.SetFrom3(a[1])
                        prog.To = a[2]
                case sys.PPC64:
                        if arch.IsPPC64CMP(op) {
@@ -623,7 +618,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
                                prog.To = a[2]
                        case obj.TYPE_CONST:
                                prog.From = a[0]
-                               prog.From3 = newAddr(a[1])
+                               prog.SetFrom3(a[1])
                                prog.To = a[2]
                        default:
                                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) {
                        if a[1].Type == obj.TYPE_REG {
                                prog.Reg = p.getRegister(prog, op, &a[1])
                        } else {
-                               prog.From3 = newAddr(a[1])
+                               prog.SetFrom3(a[1])
                        }
                        prog.To = a[2]
                default:
@@ -646,7 +641,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
                        if arch.IsARMBFX(op) {
                                // a[0] and a[1] must be constants, a[2] and a[3] must be registers
                                prog.From = a[0]
-                               prog.From3 = newAddr(a[1])
+                               prog.SetFrom3(a[1])
                                prog.Reg = p.getRegister(prog, op, &a[2])
                                prog.To = a[3]
                                break
@@ -666,26 +661,15 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
                        }
                }
                if p.arch.Family == sys.AMD64 {
-                       // 4 operand instruction have form ymm1, ymm2, ymm3/m256, imm8
-                       // So From3 is always just a register, so we store imm8 in Offset field,
-                       // 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.From = a[0]
+                       prog.RestArgs = []obj.Addr{a[1], a[2]}
                        prog.To = a[3]
-                       prog.RegTo2 = -1
                        break
                }
                if p.arch.Family == sys.ARM64 {
                        prog.From = a[0]
                        prog.Reg = p.getRegister(prog, op, &a[1])
-                       prog.From3 = newAddr(a[2])
+                       prog.SetFrom3(a[2])
                        prog.To = a[3]
                        break
                }
@@ -693,12 +677,12 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
                        if arch.IsPPC64RLD(op) {
                                prog.From = a[0]
                                prog.Reg = p.getRegister(prog, op, &a[1])
-                               prog.From3 = newAddr(a[2])
+                               prog.SetFrom3(a[2])
                                prog.To = a[3]
                                break
                        } else if arch.IsPPC64ISEL(op) {
                                // 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.Reg = p.getRegister(prog, op, &a[1]) // rb
                                prog.To = a[3]                            // rt
@@ -712,13 +696,13 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
                        if a[1].Type == obj.TYPE_REG {
                                prog.From = a[0]
                                prog.Reg = p.getRegister(prog, op, &a[1])
-                               prog.From3 = newAddr(a[2])
+                               prog.SetFrom3(a[2])
                                prog.To = a[3]
                                break
                        } else if a[1].Type == obj.TYPE_CONST {
                                prog.From = a[0]
                                prog.Reg = p.getRegister(prog, op, &a[2])
-                               prog.From3 = newAddr(a[1])
+                               prog.SetFrom3(a[1])
                                prog.To = a[3]
                                break
                        } else {
@@ -733,7 +717,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
                        }
                        prog.From = a[0]
                        prog.Reg = p.getRegister(prog, op, &a[1])
-                       prog.From3 = newAddr(a[2])
+                       prog.SetFrom3(a[2])
                        prog.To = a[3]
                        break
                }
@@ -752,10 +736,10 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
                        } else {
                                mask = (^uint32(0) >> uint(mask2+1)) & (^uint32(0) << uint(31-(mask1-1)))
                        }
-                       prog.From3 = &obj.Addr{
+                       prog.SetFrom3(obj.Addr{
                                Type:   obj.TYPE_CONST,
                                Offset: int64(mask),
-                       }
+                       })
                        prog.To = a[4]
                        break
                }
index 24a8fb83a4661eb674b257c7baf7b967939ab31d..e74207b8569898e8e357bde01dbbd1d2f93401ed 100644 (file)
@@ -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.Reg = arm64.COND_LO
                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.Reg = v.Reg()
        case ssa.OpARM64DUFFZERO:
index c56f53c2069a951368e3070b63f8979085738a67..330d58becf724b585d6da61e6e4b0bb5db2eb0ae 100644 (file)
@@ -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.Reg = r
        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.Offset = cr
 }
@@ -551,9 +551,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
                p.From.Type = obj.TYPE_REG
                p.From.Reg = r1
                p.Reg = r3
-               p.From3 = new(obj.Addr)
-               p.From3.Type = obj.TYPE_REG
-               p.From3.Reg = r2
+               p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: r2})
                p.To.Type = obj.TYPE_REG
                p.To.Reg = r
 
index 8722345a097066797d7231f7565dbd135926a292..6e637487cd1c1525d0b1c6cad0d8acf0da001fd7 100644 (file)
@@ -534,10 +534,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
                p := s.Prog(s390x.AMVC)
                p.From.Type = obj.TYPE_CONST
                p.From.Offset = vo.Val()
-               p.From3 = new(obj.Addr)
-               p.From3.Type = obj.TYPE_MEM
-               p.From3.Reg = v.Args[1].Reg()
-               p.From3.Offset = vo.Off()
+               p.SetFrom3(obj.Addr{
+                       Type:   obj.TYPE_MEM,
+                       Reg:    v.Args[1].Reg(),
+                       Offset: vo.Off(),
+               })
                p.To.Type = obj.TYPE_MEM
                p.To.Reg = v.Args[0].Reg()
                p.To.Offset = vo.Off()
@@ -570,9 +571,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
                mvc := s.Prog(s390x.AMVC)
                mvc.From.Type = obj.TYPE_CONST
                mvc.From.Offset = 256
-               mvc.From3 = new(obj.Addr)
-               mvc.From3.Type = obj.TYPE_MEM
-               mvc.From3.Reg = v.Args[1].Reg()
+               mvc.SetFrom3(obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[1].Reg()})
                mvc.To.Type = obj.TYPE_MEM
                mvc.To.Reg = v.Args[0].Reg()
 
@@ -599,9 +598,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
                        mvc := s.Prog(s390x.AMVC)
                        mvc.From.Type = obj.TYPE_CONST
                        mvc.From.Offset = v.AuxInt
-                       mvc.From3 = new(obj.Addr)
-                       mvc.From3.Type = obj.TYPE_MEM
-                       mvc.From3.Reg = v.Args[1].Reg()
+                       mvc.SetFrom3(obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[1].Reg()})
                        mvc.To.Type = obj.TYPE_MEM
                        mvc.To.Reg = v.Args[0].Reg()
                }
index 98b45feb603d7d5b56b8df9e4337a0207d1537cd..479005f2941324b9c1d6943c2cb3800dc839a74a 100644 (file)
@@ -2068,11 +2068,11 @@ func (c *ctxt5) asmout(p *obj.Prog, o *Optab, out []uint32) {
                if r == 0 {
                        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)
                        break
                }
-               lsb := p.From3.Offset
+               lsb := p.GetFrom3().Offset
                width := p.From.Offset
                if lsb < 0 || lsb > 31 || width <= 0 || (lsb+width) > 31 {
                        c.ctxt.Diag("%v: wrong width or LSB", p)
@@ -3310,8 +3310,8 @@ func (c *ctxt5) chipfloat5(e float64) int {
 func nocache(p *obj.Prog) {
        p.Optab = 0
        p.From.Class = 0
-       if p.From3 != nil {
-               p.From3.Class = 0
+       if p.GetFrom3() != nil {
+               p.GetFrom3().Class = 0
        }
        p.To.Class = 0
 }
index 32c4643166508dddeffb0ff7f0b375f78e93d599..59f044ec9ddb2a8546db8f22b48c3e9e224364ad 100644 (file)
@@ -186,7 +186,7 @@ func (c *ctxt5) rewriteToUseGot(p *obj.Prog) {
                        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)
        }
        var source *obj.Addr
index ddd43485f7276d7d22ae5b94385cedeb79c70025..10f0303785c261119b6c50f5665b9737ffcfaac5 100644 (file)
@@ -2331,7 +2331,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                var r int
                var ra int
                if p.From3Type() == obj.TYPE_REG {
-                       r = int(p.From3.Reg)
+                       r = int(p.GetFrom3().Reg)
                        ra = int(p.Reg)
                        if ra == 0 {
                                ra = REGZERO
@@ -2393,7 +2393,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
 
                                cond ^= 1
                        } else {
-                               rf = int(p.From3.Reg) /* CSEL */
+                               rf = int(p.GetFrom3().Reg) /* CSEL */
                        }
                } else {
                        /* CSET */
@@ -2418,12 +2418,12 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                        cond -= COND_EQ
                }
                var rf int
-               if p.From3.Type == obj.TYPE_REG {
+               if p.GetFrom3().Type == obj.TYPE_REG {
                        o1 = c.oprrr(p, p.As)
-                       rf = int(p.From3.Reg) /* Rm */
+                       rf = int(p.GetFrom3().Reg) /* Rm */
                } else {
                        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)
@@ -2767,12 +2767,12 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                o1 = c.op0(p, p.As)
 
        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 */
                r := int(p.From.Offset)
 
-               s := int(p.From3.Offset)
+               s := int(p.GetFrom3().Offset)
                rf := int(p.Reg)
                rt := int(p.To.Reg)
                if rf == 0 {
@@ -2821,7 +2821,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                }
 
        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 */
                rf := int(p.From.Reg)
@@ -2977,11 +2977,11 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                        c.ctxt.Diag("implausible condition\n%v", p)
                }
                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)
                        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)
 
        case 58: /* ldar/ldxr/ldaxr */
index b1cf7cdd9fa917a86948581ff18b33b67dafdde2..7f22aa88bb8ff13825f82562de43fa2ce9175c21 100644 (file)
@@ -382,7 +382,7 @@ func (c *ctxt7) rewriteToUseGot(p *obj.Prog) {
                        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)
        }
        var source *obj.Addr
index f0b2c46e4f1896a035882bbce08f1fe090760ab0..dbe9b406ddaa15e6919c36c56966a20f30dc4d0f 100644 (file)
@@ -10,7 +10,7 @@ func Nopout(p *Prog) {
        p.As = ANOP
        p.Scond = 0
        p.From = Addr{}
-       p.From3 = nil
+       p.RestArgs = nil
        p.Reg = 0
        p.To = Addr{}
 }
index 68e1b70ac0dee9fd064cb1ad3dd6d003e3de16dd..abd90e34d27c59f52c5860fb6db767a81ef8816c 100644 (file)
@@ -209,14 +209,19 @@ const (
 //
 // 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:
-// 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.
 // 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)
 // 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,
 // which must be in the same linked list as the jump instruction.
@@ -232,35 +237,62 @@ const (
 // The other fields not yet mentioned are for use by the back ends and should
 // be left zeroed by creators of Prog lists.
 type Prog struct {
-       Ctxt   *Link    // linker context
-       Link   *Prog    // next Prog in linked list
-       From   Addr     // first source operand
-       From3  *Addr    // third source operand (second is Reg below)
-       To     Addr     // destination operand (second is RegTo2 below)
-       Pcond  *Prog    // target of conditional jump
-       Forwd  *Prog    // for x86 back end
-       Rel    *Prog    // for x86, arm back ends
-       Pc     int64    // for back ends or assembler: virtual or actual program counter, depending on phase
-       Pos    src.XPos // source position of this instruction
-       Spadj  int32    // effect of instruction on stack pointer (increment or decrement amount)
-       As     As       // assembler opcode
-       Reg    int16    // 2nd source operand
-       RegTo2 int16    // 2nd destination operand
-       Mark   uint16   // bitmask of arch-specific items
-       Optab  uint16   // arch-specific opcode index
-       Scond  uint8    // condition bits for conditional instruction (e.g., on ARM)
-       Back   uint8    // for x86 back end: backwards branch state
-       Ft     uint8    // for x86 back end: type index of Prog.From
-       Tt     uint8    // for x86 back end: type index of Prog.To
-       Isize  uint8    // for x86 back end: size of the instruction in bytes
+       Ctxt     *Link    // linker context
+       Link     *Prog    // next Prog in linked list
+       From     Addr     // first source operand
+       RestArgs []Addr   // can pack any operands that not fit into {Prog.From, Prog.To}
+       To       Addr     // destination operand (second is RegTo2 below)
+       Pcond    *Prog    // target of conditional jump
+       Forwd    *Prog    // for x86 back end
+       Rel      *Prog    // for x86, arm back ends
+       Pc       int64    // for back ends or assembler: virtual or actual program counter, depending on phase
+       Pos      src.XPos // source position of this instruction
+       Spadj    int32    // effect of instruction on stack pointer (increment or decrement amount)
+       As       As       // assembler opcode
+       Reg      int16    // 2nd source operand
+       RegTo2   int16    // 2nd destination operand
+       Mark     uint16   // bitmask of arch-specific items
+       Optab    uint16   // arch-specific opcode index
+       Scond    uint8    // condition bits for conditional instruction (e.g., on ARM)
+       Back     uint8    // for x86 back end: backwards branch state
+       Ft       uint8    // for x86 back end: type index of Prog.From
+       Tt       uint8    // for x86 back end: type index of Prog.To
+       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 {
-       if p.From3 == nil {
+       if p.RestArgs == nil {
                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.
index 7cc187d01f89daa2f8358c852ac05e2e0d944c5b..edfc3acf79496cae35c7b09238e370c18632d271 100644 (file)
@@ -124,8 +124,8 @@ func linkpatch(ctxt *Link, sym *LSym, newprog ProgAlloc) {
 
        for p := sym.Func.Text; p != nil; p = p.Link {
                checkaddr(ctxt, p, &p.From)
-               if p.From3 != nil {
-                       checkaddr(ctxt, p, p.From3)
+               if p.GetFrom3() != nil {
+                       checkaddr(ctxt, p, p.GetFrom3())
                }
                checkaddr(ctxt, p, &p.To)
 
index dd6429fd0bcd4403f4e0da6f9ff092de1ebf15a3..2f7e3237b475b21aab1ade4a180288d0ec2de3ae 100644 (file)
@@ -900,11 +900,11 @@ func (c *ctxt9) oplook(p *obj.Prog) *Optab {
 
        a1--
        a3 := C_NONE + 1
-       if p.From3 != nil {
-               a3 = int(p.From3.Class)
+       if p.GetFrom3() != nil {
+               a3 = int(p.GetFrom3().Class)
                if a3 == 0 {
-                       a3 = c.aclass(p.From3) + 1
-                       p.From3.Class = int8(a3)
+                       a3 = c.aclass(p.GetFrom3()) + 1
+                       p.GetFrom3().Class = int8(a3)
                }
        }
 
@@ -2461,7 +2461,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                if r == 0 {
                        r = int(p.To.Reg)
                }
-               d := c.vregoff(p.From3)
+               d := c.vregoff(p.GetFrom3())
                var a int
                switch p.As {
 
@@ -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))
 
        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)
                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) {
                if p.To.Reg == REGTMP || p.From.Reg == REGTMP {
                        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)
                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)
@@ -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 */
                v := c.regoff(&p.From)
 
-               d := c.vregoff(p.From3)
+               d := c.vregoff(p.GetFrom3())
                var mask [2]uint8
                c.maskgen64(p, mask[:], uint64(d))
                var a int
@@ -2776,7 +2776,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
        case 30: /* rldimi $sh,s,$mask,a */
                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
                // the ppc64 asm.
@@ -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))
 
        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') */
                v := c.regoff(&p.To)
@@ -2889,10 +2889,10 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                o1 = uint32(c.regoff(&p.From))
 
        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 */
-               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) */
                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) {
                v := c.regoff(&p.From)
 
                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 |= (uint32(mask[0])&31)<<6 | (uint32(mask[1])&31)<<1
 
        case 63: /* rlwmi b,s,$mask,a */
                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 |= (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) {
        case 64: /* mtfsf fr[, $m] {,fpcsr} */
                var v int32
                if p.From3Type() != obj.TYPE_NONE {
-                       v = c.regoff(p.From3) & 255
+                       v = c.regoff(p.GetFrom3()) & 255
                } else {
                        v = 255
                }
@@ -3131,7 +3131,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                        if p.To.Reg != 0 {
                                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 {
                        if p.To.Reg == 0 {
                                v = 0xff /* CR */
@@ -3270,7 +3270,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                        /* imm imm reg reg */
                        /* operand order: SIX, VRA, ST, VRT */
                        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))
                } else if p.From3Type() == obj.TYPE_NONE && p.Reg != 0 {
                        /* imm reg reg */
@@ -3288,19 +3288,19 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                if p.From.Type == obj.TYPE_REG {
                        /* reg reg reg reg */
                        /* 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 {
                        /* imm reg reg reg */
                        /* operand order: SHB, VRA, VRB, VRT */
                        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
                bc := c.vregoff(&p.From)
 
                // 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 */
                /* reg none reg */
@@ -3348,7 +3348,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
        case 89: /* VSX instructions, XX2-form */
                /* reg none reg OR reg imm reg */
                /* 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))
 
        case 90: /* VSX instructions, XX3-form */
@@ -3359,14 +3359,14 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                } else if p.From3Type() == obj.TYPE_CONST {
                        /* reg reg reg imm */
                        /* 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))
                }
 
        case 91: /* VSX instructions, XX4-form */
                /* reg reg reg reg */
                /* 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 */
                if p.To.Type == obj.TYPE_CONST {
@@ -3384,7 +3384,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                } else if p.From3Type() == obj.TYPE_CONST {
                        /* reg reg imm */
                        /* 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))
                } else if p.To.Type == obj.TYPE_REG {
                        cr := int32(p.To.Reg)
@@ -3425,7 +3425,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
        case 94: /* Z23-form instructions, 4-operands */
                /* reg reg reg imm */
                /* 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))
        }
 
index b1509e3813b0414fe3fa8feba0166975b9144670..c50cd3b06c8b0b25ec7dd6df40f45ba3bd53ebbd 100644 (file)
@@ -176,7 +176,7 @@ func (c *ctxt9) rewriteToUseGot(p *obj.Prog) {
                        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)
        }
        var source *obj.Addr
index 6d2b870f0aca95a5cf8e4714a787bb752edd3036..e108032c5c7d63ec9ab48d75d751113b08d3e8ca 100644 (file)
@@ -654,11 +654,11 @@ func (c *ctxtz) oplook(p *obj.Prog) *Optab {
 
        a1--
        a3 := C_NONE + 1
-       if p.From3 != nil {
-               a3 = int(p.From3.Class)
+       if p.GetFrom3() != nil {
+               a3 = int(p.GetFrom3().Class)
                if a3 == 0 {
-                       a3 = c.aclass(p.From3) + 1
-                       p.From3.Class = int8(a3)
+                       a3 = c.aclass(p.GetFrom3()) + 1
+                       p.GetFrom3().Class = int8(a3)
                }
        }
 
@@ -3534,11 +3534,11 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
                if l < 1 || l > 256 {
                        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")
                }
                b1 := p.To.Reg
-               b2 := p.From3.Reg
+               b2 := p.GetFrom3().Reg
                if b1 == 0 {
                        b1 = o.param
                }
@@ -3546,7 +3546,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
                        b2 = o.param
                }
                d1 := c.regoff(&p.To)
-               d2 := c.regoff(p.From3)
+               d2 := c.regoff(p.GetFrom3())
                if d1 < 0 || d1 >= DISP12 {
                        if b2 == REGTMP {
                                c.ctxt.Diag("REGTMP conflict")
@@ -3688,10 +3688,10 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
                }
                mask := c.branchMask(p)
                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)
                } 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
@@ -3893,9 +3893,9 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
        case 101: // VRX LOAD
                op, m3, _ := vop(p.As)
                src := &p.From
-               if p.From3 != nil {
+               if p.GetFrom3() != nil {
                        m3 = uint32(c.vregoff(&p.From))
-                       src = p.From3
+                       src = p.GetFrom3()
                }
                b2 := src.Reg
                if b2 == 0 {
@@ -3917,12 +3917,12 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
        case 103: // VRV GATHER
                op, _, _ := vop(p.As)
                m3 := uint32(c.vregoff(&p.From))
-               b2 := p.From3.Reg
+               b2 := p.GetFrom3().Reg
                if b2 == 0 {
                        b2 = o.param
                }
-               d2 := uint32(c.vregoff(p.From3))
-               zVRV(op, uint32(p.To.Reg), uint32(p.From3.Index), uint32(b2), d2, m3, asm)
+               d2 := uint32(c.vregoff(p.GetFrom3()))
+               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
                op, m4, _ := vop(p.As)
@@ -3962,8 +3962,8 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
 
        case 108: // VRS LOAD WITH LENGTH
                op, _, _ := vop(p.As)
-               offset := uint32(c.vregoff(p.From3))
-               reg := p.From3.Reg
+               offset := uint32(c.vregoff(p.GetFrom3()))
+               reg := p.GetFrom3().Reg
                if reg == 0 {
                        reg = o.param
                }
@@ -3972,9 +3972,9 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
        case 109: // VRI-a
                op, m3, _ := vop(p.As)
                i2 := uint32(c.vregoff(&p.From))
-               if p.From3 != nil {
+               if p.GetFrom3() != nil {
                        m3 = uint32(c.vregoff(&p.From))
-                       i2 = uint32(c.vregoff(p.From3))
+                       i2 = uint32(c.vregoff(p.GetFrom3()))
                }
                switch p.As {
                case AVZERO:
@@ -3987,7 +3987,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
        case 110:
                op, m4, _ := vop(p.As)
                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)
 
        case 111:
@@ -3998,7 +3998,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
        case 112:
                op, m5, _ := vop(p.As)
                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:
                op, m4, _ := vop(p.As)
@@ -4044,7 +4044,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
                v1 := uint32(p.To.Reg)
                v2 := uint32(p.From.Reg)
                v3 := uint32(p.Reg)
-               v4 := uint32(p.From3.Reg)
+               v4 := uint32(p.GetFrom3().Reg)
                zVRRd(op, v1, v2, v3, m6, m5, v4, asm)
 
        case 121: // VRR-e
@@ -4053,7 +4053,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
                v1 := uint32(p.To.Reg)
                v2 := uint32(p.From.Reg)
                v3 := uint32(p.Reg)
-               v4 := uint32(p.From3.Reg)
+               v4 := uint32(p.GetFrom3().Reg)
                zVRRe(op, v1, v2, v3, m6, m5, v4, asm)
 
        case 122: // VRR-f LOAD VRS FROM GRS DISJOINT
@@ -4063,7 +4063,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) {
        case 123: // VPDI $m4, V2, V3, V1
                op, _, _ := vop(p.As)
                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)
        }
 }
 
index 3d3571a4611df4c0a2eb152ac22af54cd7160ae6..bf4dfd49d55341ea27f5442116e2e4a7e5eef44a 100644 (file)
@@ -140,7 +140,7 @@ func (c *ctxtz) rewriteToUseGot(p *obj.Prog) {
                        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)
        }
        var source *obj.Addr
index 601e9e2ea64dacef09276e059a360293f9976892..e70d174637ddae5f453772441643b46378401eb5 100644 (file)
@@ -24,7 +24,7 @@ func TestSizeof(t *testing.T) {
        }{
                {Addr{}, 32, 48},
                {LSym{}, 56, 104},
-               {Prog{}, 124, 184},
+               {Prog{}, 132, 200},
        }
 
        for _, tt := range tests {
index 9bcdbbd127e5d0c7cafa71aa1cf5c259dba3d92c..bf2d209d7f10d0dbeec9bdd3802a1cd0c71a014a 100644 (file)
@@ -83,11 +83,7 @@ func (p *Prog) String() string {
 
        fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), p.As, sc)
        sep := "\t"
-       quadOpAmd64 := p.RegTo2 == -1
-       if quadOpAmd64 {
-               fmt.Fprintf(&buf, "%s$%d", sep, p.From3.Offset)
-               sep = ", "
-       }
+
        if p.From.Type != TYPE_NONE {
                fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From))
                sep = ", "
@@ -97,14 +93,11 @@ func (p *Prog) String() string {
                fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg)))
                sep = ", "
        }
-       if p.From3Type() != TYPE_NONE {
-               if quadOpAmd64 {
-                       fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.From3.Reg)))
-               } else {
-                       fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3))
-               }
+       for i := range p.RestArgs {
+               fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.RestArgs[i]))
                sep = ", "
        }
+
        if p.As == ATEXT {
                // If there are attributes, print them. Otherwise, skip the comma.
                // In short, print one of these two:
@@ -119,7 +112,7 @@ func (p *Prog) String() string {
        if p.To.Type != TYPE_NONE {
                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)))
        }
        return buf.String()
index f636d312d40d5e8009ed98d54fe6593200d1e97d..86c85c1a6fee757fd2ee2d65b6756294ab82f14a 100644 (file)
@@ -72,14 +72,6 @@ type Optab struct {
        op     [23]uint8
 }
 
-type ytab struct {
-       from    uint8
-       from3   uint8
-       to      uint8
-       zcase   uint8
-       zoffset uint8
-}
-
 type Movtab struct {
        as   obj.As
        ft   uint8
@@ -323,414 +315,418 @@ var reg [MAXREG]int
 var regrex [MAXREG + 1]int
 
 var ynone = []ytab{
-       {Ynone, Ynone, Ynone, Zlit, 1},
+       {Zlit, 1, argList{}},
 }
 
 var ytext = []ytab{
-       {Ymb, Ynone, Ytextsize, Zpseudo, 0},
-       {Ymb, Yi32, Ytextsize, Zpseudo, 1},
+       {Zpseudo, 0, argList{Ymb, Ytextsize}},
+       {Zpseudo, 1, argList{Ymb, Yi32, Ytextsize}},
 }
 
 var ynop = []ytab{
-       {Ynone, Ynone, Ynone, Zpseudo, 0},
-       {Ynone, Ynone, Yiauto, Zpseudo, 0},
-       {Ynone, Ynone, Yml, Zpseudo, 0},
-       {Ynone, Ynone, Yrf, Zpseudo, 0},
-       {Ynone, Ynone, Yxr, Zpseudo, 0},
-       {Yiauto, Ynone, Ynone, Zpseudo, 0},
-       {Yml, Ynone, Ynone, Zpseudo, 0},
-       {Yrf, Ynone, Ynone, Zpseudo, 0},
-       {Yxr, Ynone, Ynone, Zpseudo, 1},
+       {Zpseudo, 0, argList{}},
+       {Zpseudo, 0, argList{Yiauto}},
+       {Zpseudo, 0, argList{Yml}},
+       {Zpseudo, 0, argList{Yrf}},
+       {Zpseudo, 0, argList{Yxr}},
+       {Zpseudo, 0, argList{Yiauto}},
+       {Zpseudo, 0, argList{Yml}},
+       {Zpseudo, 0, argList{Yrf}},
+       {Zpseudo, 1, argList{Yxr}},
 }
 
 var yfuncdata = []ytab{
-       {Yi32, Ynone, Ym, Zpseudo, 0},
+       {Zpseudo, 0, argList{Yi32, Ym}},
 }
 
 var ypcdata = []ytab{
-       {Yi32, Ynone, Yi32, Zpseudo, 0},
+       {Zpseudo, 0, argList{Yi32, Yi32}},
 }
 
 var yxorb = []ytab{
-       {Yi32, Ynone, Yal, Zib_, 1},
-       {Yi32, Ynone, Ymb, Zibo_m, 2},
-       {Yrb, Ynone, Ymb, Zr_m, 1},
-       {Ymb, Ynone, Yrb, Zm_r, 1},
+       {Zib_, 1, argList{Yi32, Yal}},
+       {Zibo_m, 2, argList{Yi32, Ymb}},
+       {Zr_m, 1, argList{Yrb, Ymb}},
+       {Zm_r, 1, argList{Ymb, Yrb}},
 }
 
 var yaddl = []ytab{
-       {Yi8, Ynone, Yml, Zibo_m, 2},
-       {Yi32, Ynone, Yax, Zil_, 1},
-       {Yi32, Ynone, Yml, Zilo_m, 2},
-       {Yrl, Ynone, Yml, Zr_m, 1},
-       {Yml, Ynone, Yrl, Zm_r, 1},
+       {Zibo_m, 2, argList{Yi8, Yml}},
+       {Zil_, 1, argList{Yi32, Yax}},
+       {Zilo_m, 2, argList{Yi32, Yml}},
+       {Zr_m, 1, argList{Yrl, Yml}},
+       {Zm_r, 1, argList{Yml, Yrl}},
 }
 
 var yincl = []ytab{
-       {Ynone, Ynone, Yrl, Z_rp, 1},
-       {Ynone, Ynone, Yml, Zo_m, 2},
+       {Z_rp, 1, argList{Yrl}},
+       {Zo_m, 2, argList{Yml}},
 }
 
 var yincq = []ytab{
-       {Ynone, Ynone, Yml, Zo_m, 2},
+       {Zo_m, 2, argList{Yml}},
 }
 
 var ycmpb = []ytab{
-       {Yal, Ynone, Yi32, Z_ib, 1},
-       {Ymb, Ynone, Yi32, Zm_ibo, 2},
-       {Ymb, Ynone, Yrb, Zm_r, 1},
-       {Yrb, Ynone, Ymb, Zr_m, 1},
+       {Z_ib, 1, argList{Yal, Yi32}},
+       {Zm_ibo, 2, argList{Ymb, Yi32}},
+       {Zm_r, 1, argList{Ymb, Yrb}},
+       {Zr_m, 1, argList{Yrb, Ymb}},
 }
 
 var ycmpl = []ytab{
-       {Yml, Ynone, Yi8, Zm_ibo, 2},
-       {Yax, Ynone, Yi32, Z_il, 1},
-       {Yml, Ynone, Yi32, Zm_ilo, 2},
-       {Yml, Ynone, Yrl, Zm_r, 1},
-       {Yrl, Ynone, Yml, Zr_m, 1},
+       {Zm_ibo, 2, argList{Yml, Yi8}},
+       {Z_il, 1, argList{Yax, Yi32}},
+       {Zm_ilo, 2, argList{Yml, Yi32}},
+       {Zm_r, 1, argList{Yml, Yrl}},
+       {Zr_m, 1, argList{Yrl, Yml}},
 }
 
 var yshb = []ytab{
-       {Yi1, Ynone, Ymb, Zo_m, 2},
-       {Yu8, Ynone, Ymb, Zibo_m, 2},
-       {Ycx, Ynone, Ymb, Zo_m, 2},
+       {Zo_m, 2, argList{Yi1, Ymb}},
+       {Zibo_m, 2, argList{Yu8, Ymb}},
+       {Zo_m, 2, argList{Ycx, Ymb}},
 }
 
 var yshl = []ytab{
-       {Yi1, Ynone, Yml, Zo_m, 2},
-       {Yu8, Ynone, Yml, Zibo_m, 2},
-       {Ycl, Ynone, Yml, Zo_m, 2},
-       {Ycx, Ynone, Yml, Zo_m, 2},
+       {Zo_m, 2, argList{Yi1, Yml}},
+       {Zibo_m, 2, argList{Yu8, Yml}},
+       {Zo_m, 2, argList{Ycl, Yml}},
+       {Zo_m, 2, argList{Ycx, Yml}},
 }
 
 var ytestl = []ytab{
-       {Yi32, Ynone, Yax, Zil_, 1},
-       {Yi32, Ynone, Yml, Zilo_m, 2},
-       {Yrl, Ynone, Yml, Zr_m, 1},
-       {Yml, Ynone, Yrl, Zm_r, 1},
+       {Zil_, 1, argList{Yi32, Yax}},
+       {Zilo_m, 2, argList{Yi32, Yml}},
+       {Zr_m, 1, argList{Yrl, Yml}},
+       {Zm_r, 1, argList{Yml, Yrl}},
 }
 
 var ymovb = []ytab{
-       {Yrb, Ynone, Ymb, Zr_m, 1},
-       {Ymb, Ynone, Yrb, Zm_r, 1},
-       {Yi32, Ynone, Yrb, Zib_rp, 1},
-       {Yi32, Ynone, Ymb, Zibo_m, 2},
+       {Zr_m, 1, argList{Yrb, Ymb}},
+       {Zm_r, 1, argList{Ymb, Yrb}},
+       {Zib_rp, 1, argList{Yi32, Yrb}},
+       {Zibo_m, 2, argList{Yi32, Ymb}},
 }
 
 var ybtl = []ytab{
-       {Yi8, Ynone, Yml, Zibo_m, 2},
-       {Yrl, Ynone, Yml, Zr_m, 1},
+       {Zibo_m, 2, argList{Yi8, Yml}},
+       {Zr_m, 1, argList{Yrl, Yml}},
 }
 
 var ymovw = []ytab{
-       {Yrl, Ynone, Yml, Zr_m, 1},
-       {Yml, Ynone, Yrl, Zm_r, 1},
-       {Yi0, Ynone, Yrl, Zclr, 1},
-       {Yi32, Ynone, Yrl, Zil_rp, 1},
-       {Yi32, Ynone, Yml, Zilo_m, 2},
-       {Yiauto, Ynone, Yrl, Zaut_r, 2},
+       {Zr_m, 1, argList{Yrl, Yml}},
+       {Zm_r, 1, argList{Yml, Yrl}},
+       {Zclr, 1, argList{Yi0, Yrl}},
+       {Zil_rp, 1, argList{Yi32, Yrl}},
+       {Zilo_m, 2, argList{Yi32, Yml}},
+       {Zaut_r, 2, argList{Yiauto, Yrl}},
 }
 
 var ymovl = []ytab{
-       {Yrl, Ynone, Yml, Zr_m, 1},
-       {Yml, Ynone, Yrl, Zm_r, 1},
-       {Yi0, Ynone, Yrl, Zclr, 1},
-       {Yi32, Ynone, Yrl, Zil_rp, 1},
-       {Yi32, Ynone, Yml, Zilo_m, 2},
-       {Yml, Ynone, Ymr, Zm_r_xm, 1}, // MMX MOVD
-       {Ymr, Ynone, Yml, Zr_m_xm, 1}, // MMX MOVD
-       {Yml, Ynone, Yxr, Zm_r_xm, 2}, // XMM MOVD (32 bit)
-       {Yxr, Ynone, Yml, Zr_m_xm, 2}, // XMM MOVD (32 bit)
-       {Yiauto, Ynone, Yrl, Zaut_r, 2},
+       {Zr_m, 1, argList{Yrl, Yml}},
+       {Zm_r, 1, argList{Yml, Yrl}},
+       {Zclr, 1, argList{Yi0, Yrl}},
+       {Zil_rp, 1, argList{Yi32, Yrl}},
+       {Zilo_m, 2, argList{Yi32, Yml}},
+       {Zm_r_xm, 1, argList{Yml, Ymr}}, // MMX MOVD
+       {Zr_m_xm, 1, argList{Ymr, Yml}}, // MMX MOVD
+       {Zm_r_xm, 2, argList{Yml, Yxr}}, // XMM MOVD (32 bit)
+       {Zr_m_xm, 2, argList{Yxr, Yml}}, // XMM MOVD (32 bit)
+       {Zaut_r, 2, argList{Yiauto, Yrl}},
 }
 
 var yret = []ytab{
-       {Ynone, Ynone, Ynone, Zo_iw, 1},
-       {Yi32, Ynone, Ynone, Zo_iw, 1},
+       {Zo_iw, 1, argList{}},
+       {Zo_iw, 1, argList{Yi32}},
 }
 
 var ymovq = []ytab{
        // valid in 32-bit mode
-       {Ym, Ynone, Ymr, Zm_r_xm_nr, 1},  // 0x6f MMX MOVQ (shorter encoding)
-       {Ymr, Ynone, Ym, Zr_m_xm_nr, 1},  // 0x7f MMX MOVQ
-       {Yxr, Ynone, Ymr, Zm_r_xm_nr, 2}, // Pf2, 0xd6 MOVDQ2Q
-       {Yxm, Ynone, Yxr, Zm_r_xm_nr, 2}, // Pf3, 0x7e MOVQ xmm1/m64 -> xmm2
-       {Yxr, Ynone, Yxm, Zr_m_xm_nr, 2}, // Pe, 0xd6 MOVQ xmm1 -> xmm2/m64
+       {Zm_r_xm_nr, 1, argList{Ym, Ymr}},  // 0x6f MMX MOVQ (shorter encoding)
+       {Zr_m_xm_nr, 1, argList{Ymr, Ym}},  // 0x7f MMX MOVQ
+       {Zm_r_xm_nr, 2, argList{Yxr, Ymr}}, // Pf2, 0xd6 MOVDQ2Q
+       {Zm_r_xm_nr, 2, argList{Yxm, Yxr}}, // Pf3, 0x7e MOVQ xmm1/m64 -> xmm2
+       {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
-       {Yrl, Ynone, Yml, Zr_m, 1},      // 0x89
-       {Yml, Ynone, Yrl, Zm_r, 1},      // 0x8b
-       {Yi0, Ynone, Yrl, Zclr, 1},      // 0x31
-       {Ys32, Ynone, Yrl, Zilo_m, 2},   // 32 bit signed 0xc7,(0)
-       {Yi64, Ynone, Yrl, Ziq_rp, 1},   // 0xb8 -- 32/64 bit immediate
-       {Yi32, Ynone, Yml, Zilo_m, 2},   // 0xc7,(0)
-       {Ymm, Ynone, Ymr, Zm_r_xm, 1},   // 0x6e MMX MOVD
-       {Ymr, Ynone, Ymm, Zr_m_xm, 1},   // 0x7e MMX MOVD
-       {Yml, Ynone, Yxr, Zm_r_xm, 2},   // Pe, 0x6e MOVD xmm load
-       {Yxr, Ynone, Yml, Zr_m_xm, 2},   // Pe, 0x7e MOVD xmm store
-       {Yiauto, Ynone, Yrl, Zaut_r, 1}, // 0 built-in LEAQ
+       {Zr_m, 1, argList{Yrl, Yml}},      // 0x89
+       {Zm_r, 1, argList{Yml, Yrl}},      // 0x8b
+       {Zclr, 1, argList{Yi0, Yrl}},      // 0x31
+       {Zilo_m, 2, argList{Ys32, Yrl}},   // 32 bit signed 0xc7,(0)
+       {Ziq_rp, 1, argList{Yi64, Yrl}},   // 0xb8 -- 32/64 bit immediate
+       {Zilo_m, 2, argList{Yi32, Yml}},   // 0xc7,(0)
+       {Zm_r_xm, 1, argList{Ymm, Ymr}},   // 0x6e MMX MOVD
+       {Zr_m_xm, 1, argList{Ymr, Ymm}},   // 0x7e MMX MOVD
+       {Zm_r_xm, 2, argList{Yml, Yxr}},   // Pe, 0x6e MOVD xmm load
+       {Zr_m_xm, 2, argList{Yxr, Yml}},   // Pe, 0x7e MOVD xmm store
+       {Zaut_r, 1, argList{Yiauto, Yrl}}, // 0 built-in LEAQ
 }
 
 var ym_rl = []ytab{
-       {Ym, Ynone, Yrl, Zm_r, 1},
+       {Zm_r, 1, argList{Ym, Yrl}},
 }
 
 var yrl_m = []ytab{
-       {Yrl, Ynone, Ym, Zr_m, 1},
+       {Zr_m, 1, argList{Yrl, Ym}},
 }
 
 var ymb_rl = []ytab{
-       {Ymb, Ynone, Yrl, Zmb_r, 1},
+       {Zmb_r, 1, argList{Ymb, Yrl}},
 }
 
 var yml_rl = []ytab{
-       {Yml, Ynone, Yrl, Zm_r, 1},
+       {Zm_r, 1, argList{Yml, Yrl}},
 }
 
 var yrl_ml = []ytab{
-       {Yrl, Ynone, Yml, Zr_m, 1},
+       {Zr_m, 1, argList{Yrl, Yml}},
 }
 
 var yml_mb = []ytab{
-       {Yrb, Ynone, Ymb, Zr_m, 1},
-       {Ymb, Ynone, Yrb, Zm_r, 1},
+       {Zr_m, 1, argList{Yrb, Ymb}},
+       {Zm_r, 1, argList{Ymb, Yrb}},
 }
 
 var yrb_mb = []ytab{
-       {Yrb, Ynone, Ymb, Zr_m, 1},
+       {Zr_m, 1, argList{Yrb, Ymb}},
 }
 
 var yxchg = []ytab{
-       {Yax, Ynone, Yrl, Z_rp, 1},
-       {Yrl, Ynone, Yax, Zrp_, 1},
-       {Yrl, Ynone, Yml, Zr_m, 1},
-       {Yml, Ynone, Yrl, Zm_r, 1},
+       {Z_rp, 1, argList{Yax, Yrl}},
+       {Zrp_, 1, argList{Yrl, Yax}},
+       {Zr_m, 1, argList{Yrl, Yml}},
+       {Zm_r, 1, argList{Yml, Yrl}},
 }
 
 var ydivl = []ytab{
-       {Yml, Ynone, Ynone, Zm_o, 2},
+       {Zm_o, 2, argList{Yml}},
 }
 
 var ydivb = []ytab{
-       {Ymb, Ynone, Ynone, Zm_o, 2},
+       {Zm_o, 2, argList{Ymb}},
 }
 
 var yimul = []ytab{
-       {Yml, Ynone, Ynone, Zm_o, 2},
-       {Yi8, Ynone, Yrl, Zib_rr, 1},
-       {Yi32, Ynone, Yrl, Zil_rr, 1},
-       {Yml, Ynone, Yrl, Zm_r, 2},
+       {Zm_o, 2, argList{Yml}},
+       {Zib_rr, 1, argList{Yi8, Yrl}},
+       {Zil_rr, 1, argList{Yi32, Yrl}},
+       {Zm_r, 2, argList{Yml, Yrl}},
 }
 
 var yimul3 = []ytab{
-       {Yi8, Yml, Yrl, Zibm_r, 2},
+       {Zibm_r, 2, argList{Yi8, Yml, Yrl}},
 }
 
 var ybyte = []ytab{
-       {Yi64, Ynone, Ynone, Zbyte, 1},
+       {Zbyte, 1, argList{Yi64}},
 }
 
 var yin = []ytab{
-       {Yi32, Ynone, Ynone, Zib_, 1},
-       {Ynone, Ynone, Ynone, Zlit, 1},
+       {Zib_, 1, argList{Yi32}},
+       {Zlit, 1, argList{}},
 }
 
 var yint = []ytab{
-       {Yi32, Ynone, Ynone, Zib_, 1},
+       {Zib_, 1, argList{Yi32}},
 }
 
 var ypushl = []ytab{
-       {Yrl, Ynone, Ynone, Zrp_, 1},
-       {Ym, Ynone, Ynone, Zm_o, 2},
-       {Yi8, Ynone, Ynone, Zib_, 1},
-       {Yi32, Ynone, Ynone, Zil_, 1},
+       {Zrp_, 1, argList{Yrl}},
+       {Zm_o, 2, argList{Ym}},
+       {Zib_, 1, argList{Yi8}},
+       {Zil_, 1, argList{Yi32}},
 }
 
 var ypopl = []ytab{
-       {Ynone, Ynone, Yrl, Z_rp, 1},
-       {Ynone, Ynone, Ym, Zo_m, 2},
+       {Z_rp, 1, argList{Yrl}},
+       {Zo_m, 2, argList{Ym}},
 }
 
 var yclflush = []ytab{
-       {Ynone, Ynone, Ym, Zo_m, 2},
+       {Zo_m, 2, argList{Ym}},
 }
 
 var ybswap = []ytab{
-       {Ynone, Ynone, Yrl, Z_rp, 2},
+       {Z_rp, 2, argList{Yrl}},
 }
 
 var yscond = []ytab{
-       {Ynone, Ynone, Ymb, Zo_m, 2},
+       {Zo_m, 2, argList{Ymb}},
 }
 
 var yjcond = []ytab{
-       {Ynone, Ynone, Ybr, Zbr, 0},
-       {Yi0, Ynone, Ybr, Zbr, 0},
-       {Yi1, Ynone, Ybr, Zbr, 1},
+       {Zbr, 0, argList{Ybr}},
+       {Zbr, 0, argList{Yi0, Ybr}},
+       {Zbr, 1, argList{Yi1, Ybr}},
 }
 
 var yloop = []ytab{
-       {Ynone, Ynone, Ybr, Zloop, 1},
+       {Zloop, 1, argList{Ybr}},
 }
 
 var ycall = []ytab{
-       {Ynone, Ynone, Yml, Zcallindreg, 0},
-       {Yrx, Ynone, Yrx, Zcallindreg, 2},
-       {Ynone, Ynone, Yindir, Zcallind, 2},
-       {Ynone, Ynone, Ybr, Zcall, 0},
-       {Ynone, Ynone, Yi32, Zcallcon, 1},
+       {Zcallindreg, 0, argList{Yml}},
+       {Zcallindreg, 2, argList{Yrx, Yrx}},
+       {Zcallind, 2, argList{Yindir}},
+       {Zcall, 0, argList{Ybr}},
+       {Zcallcon, 1, argList{Yi32}},
 }
 
 var yduff = []ytab{
-       {Ynone, Ynone, Yi32, Zcallduff, 1},
+       {Zcallduff, 1, argList{Yi32}},
 }
 
 var yjmp = []ytab{
-       {Ynone, Ynone, Yml, Zo_m64, 2},
-       {Ynone, Ynone, Ybr, Zjmp, 0},
-       {Ynone, Ynone, Yi32, Zjmpcon, 1},
+       {Zo_m64, 2, argList{Yml}},
+       {Zjmp, 0, argList{Ybr}},
+       {Zjmpcon, 1, argList{Yi32}},
 }
 
 var yfmvd = []ytab{
-       {Ym, Ynone, Yf0, Zm_o, 2},
-       {Yf0, Ynone, Ym, Zo_m, 2},
-       {Yrf, Ynone, Yf0, Zm_o, 2},
-       {Yf0, Ynone, Yrf, Zo_m, 2},
+       {Zm_o, 2, argList{Ym, Yf0}},
+       {Zo_m, 2, argList{Yf0, Ym}},
+       {Zm_o, 2, argList{Yrf, Yf0}},
+       {Zo_m, 2, argList{Yf0, Yrf}},
 }
 
 var yfmvdp = []ytab{
-       {Yf0, Ynone, Ym, Zo_m, 2},
-       {Yf0, Ynone, Yrf, Zo_m, 2},
+       {Zo_m, 2, argList{Yf0, Ym}},
+       {Zo_m, 2, argList{Yf0, Yrf}},
 }
 
 var yfmvf = []ytab{
-       {Ym, Ynone, Yf0, Zm_o, 2},
-       {Yf0, Ynone, Ym, Zo_m, 2},
+       {Zm_o, 2, argList{Ym, Yf0}},
+       {Zo_m, 2, argList{Yf0, Ym}},
 }
 
 var yfmvx = []ytab{
-       {Ym, Ynone, Yf0, Zm_o, 2},
+       {Zm_o, 2, argList{Ym, Yf0}},
 }
 
 var yfmvp = []ytab{
-       {Yf0, Ynone, Ym, Zo_m, 2},
+       {Zo_m, 2, argList{Yf0, Ym}},
 }
 
 var yfcmv = []ytab{
-       {Yrf, Ynone, Yf0, Zm_o, 2},
+       {Zm_o, 2, argList{Yrf, Yf0}},
 }
 
 var yfadd = []ytab{
-       {Ym, Ynone, Yf0, Zm_o, 2},
-       {Yrf, Ynone, Yf0, Zm_o, 2},
-       {Yf0, Ynone, Yrf, Zo_m, 2},
+       {Zm_o, 2, argList{Ym, Yf0}},
+       {Zm_o, 2, argList{Yrf, Yf0}},
+       {Zo_m, 2, argList{Yf0, Yrf}},
 }
 
 var yfxch = []ytab{
-       {Yf0, Ynone, Yrf, Zo_m, 2},
-       {Yrf, Ynone, Yf0, Zm_o, 2},
+       {Zo_m, 2, argList{Yf0, Yrf}},
+       {Zm_o, 2, argList{Yrf, Yf0}},
 }
 
 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{
-       {Ynone, Ynone, Ym, Zo_m, 2},
-       {Ynone, Ynone, Yax, Zlit, 1},
+       {Zo_m, 2, argList{Ym}},
+       {Zlit, 1, argList{Yax}},
+}
+
+var ysvrs_mo = []ytab{
+       {Zm_o, 2, argList{Ym}},
 }
 
-var ysvrs = []ytab{
-       {Ynone, Ynone, Ym, Zo_m, 2},
-       {Ym, Ynone, Ynone, Zm_o, 2},
+// unaryDst version of "ysvrs_mo".
+var ysvrs_om = []ytab{
+       {Zo_m, 2, argList{Ym}},
 }
 
 var ymm = []ytab{
-       {Ymm, Ynone, Ymr, Zm_r_xm, 1},
-       {Yxm, Ynone, Yxr, Zm_r_xm, 2},
+       {Zm_r_xm, 1, argList{Ymm, Ymr}},
+       {Zm_r_xm, 2, argList{Yxm, Yxr}},
 }
 
 var yxm = []ytab{
-       {Yxm, Ynone, Yxr, Zm_r_xm, 1},
+       {Zm_r_xm, 1, argList{Yxm, Yxr}},
 }
 
 var yxm_q4 = []ytab{
-       {Yxm, Ynone, Yxr, Zm_r, 1},
+       {Zm_r, 1, argList{Yxm, Yxr}},
 }
 
 var yxcvm1 = []ytab{
-       {Yxm, Ynone, Yxr, Zm_r_xm, 2},
-       {Yxm, Ynone, Ymr, Zm_r_xm, 2},
+       {Zm_r_xm, 2, argList{Yxm, Yxr}},
+       {Zm_r_xm, 2, argList{Yxm, Ymr}},
 }
 
 var yxcvm2 = []ytab{
-       {Yxm, Ynone, Yxr, Zm_r_xm, 2},
-       {Ymm, Ynone, Yxr, Zm_r_xm, 2},
+       {Zm_r_xm, 2, argList{Yxm, Yxr}},
+       {Zm_r_xm, 2, argList{Ymm, Yxr}},
 }
 
 var yxr = []ytab{
-       {Yxr, Ynone, Yxr, Zm_r_xm, 1},
+       {Zm_r_xm, 1, argList{Yxr, Yxr}},
 }
 
 var yxr_ml = []ytab{
-       {Yxr, Ynone, Yml, Zr_m_xm, 1},
+       {Zr_m_xm, 1, argList{Yxr, Yml}},
 }
 
 var ymr = []ytab{
-       {Ymr, Ynone, Ymr, Zm_r, 1},
+       {Zm_r, 1, argList{Ymr, Ymr}},
 }
 
 var ymr_ml = []ytab{
-       {Ymr, Ynone, Yml, Zr_m_xm, 1},
+       {Zr_m_xm, 1, argList{Ymr, Yml}},
 }
 
 var yxcmpi = []ytab{
-       {Yxm, Yxr, Yi8, Zm_r_i_xm, 2},
+       {Zm_r_i_xm, 2, argList{Yxm, Yxr, Yi8}},
 }
 
 var yxmov = []ytab{
-       {Yxm, Ynone, Yxr, Zm_r_xm, 1},
-       {Yxr, Ynone, Yxm, Zr_m_xm, 1},
+       {Zm_r_xm, 1, argList{Yxm, Yxr}},
+       {Zr_m_xm, 1, argList{Yxr, Yxm}},
 }
 
 var yxcvfl = []ytab{
-       {Yxm, Ynone, Yrl, Zm_r_xm, 1},
+       {Zm_r_xm, 1, argList{Yxm, Yrl}},
 }
 
 var yxcvlf = []ytab{
-       {Yml, Ynone, Yxr, Zm_r_xm, 1},
+       {Zm_r_xm, 1, argList{Yml, Yxr}},
 }
 
 var yxcvfq = []ytab{
-       {Yxm, Ynone, Yrl, Zm_r_xm, 2},
+       {Zm_r_xm, 2, argList{Yxm, Yrl}},
 }
 
 var yxcvqf = []ytab{
-       {Yml, Ynone, Yxr, Zm_r_xm, 2},
+       {Zm_r_xm, 2, argList{Yml, Yxr}},
 }
 
 var yps = []ytab{
-       {Ymm, Ynone, Ymr, Zm_r_xm, 1},
-       {Yi8, Ynone, Ymr, Zibo_m_xm, 2},
-       {Yxm, Ynone, Yxr, Zm_r_xm, 2},
-       {Yi8, Ynone, Yxr, Zibo_m_xm, 3},
+       {Zm_r_xm, 1, argList{Ymm, Ymr}},
+       {Zibo_m_xm, 2, argList{Yi8, Ymr}},
+       {Zm_r_xm, 2, argList{Yxm, Yxr}},
+       {Zibo_m_xm, 3, argList{Yi8, Yxr}},
 }
 
 var yxrrl = []ytab{
-       {Yxr, Ynone, Yrl, Zm_r, 1},
+       {Zm_r, 1, argList{Yxr, Yrl}},
 }
 
 var ymrxr = []ytab{
-       {Ymr, Ynone, Yxr, Zm_r, 1},
-       {Yxm, Ynone, Yxr, Zm_r_xm, 1},
+       {Zm_r, 1, argList{Ymr, Yxr}},
+       {Zm_r_xm, 1, argList{Yxm, Yxr}},
 }
 
 var ymshuf = []ytab{
-       {Yi8, Ymm, Ymr, Zibm_r, 2},
+       {Zibm_r, 2, argList{Yi8, Ymm, Ymr}},
 }
 
 var ymshufb = []ytab{
-       {Yxm, Ynone, Yxr, Zm2_r, 2},
+       {Zm2_r, 2, argList{Yxm, Yxr}},
 }
 
 // It should never have more than 1 entry,
@@ -739,60 +735,60 @@ var ymshufb = []ytab{
 // ROUNDPD and ROUNDPS and recently added BLENDPD,
 // to name a few.
 var yxshuf = []ytab{
-       {Yu8, Yxm, Yxr, Zibm_r, 2},
+       {Zibm_r, 2, argList{Yu8, Yxm, Yxr}},
 }
 
 var yextrw = []ytab{
-       {Yu8, Yxr, Yrl, Zibm_r, 2},
+       {Zibm_r, 2, argList{Yu8, Yxr, Yrl}},
 }
 
 var yextr = []ytab{
-       {Yu8, Yxr, Ymm, Zibr_m, 3},
+       {Zibr_m, 3, argList{Yu8, Yxr, Ymm}},
 }
 
 var yinsrw = []ytab{
-       {Yu8, Yml, Yxr, Zibm_r, 2},
+       {Zibm_r, 2, argList{Yu8, Yml, Yxr}},
 }
 
 var yinsr = []ytab{
-       {Yu8, Ymm, Yxr, Zibm_r, 3},
+       {Zibm_r, 3, argList{Yu8, Ymm, Yxr}},
 }
 
 var ypsdq = []ytab{
-       {Yi8, Ynone, Yxr, Zibo_m, 2},
+       {Zibo_m, 2, argList{Yi8, Yxr}},
 }
 
 var ymskb = []ytab{
-       {Yxr, Ynone, Yrl, Zm_r_xm, 2},
-       {Ymr, Ynone, Yrl, Zm_r_xm, 1},
+       {Zm_r_xm, 2, argList{Yxr, Yrl}},
+       {Zm_r_xm, 1, argList{Ymr, Yrl}},
 }
 
 var ycrc32l = []ytab{
-       {Yml, Ynone, Yrl, Zlitm_r, 0},
+       {Zlitm_r, 0, argList{Yml, Yrl}},
 }
 
 var yprefetch = []ytab{
-       {Ym, Ynone, Ynone, Zm_o, 2},
+       {Zm_o, 2, argList{Ym}},
 }
 
 var yaes = []ytab{
-       {Yxm, Ynone, Yxr, Zlitm_r, 2},
+       {Zlitm_r, 2, argList{Yxm, Yxr}},
 }
 
 var yxbegin = []ytab{
-       {Ynone, Ynone, Ybr, Zjmp, 1},
+       {Zjmp, 1, argList{Ybr}},
 }
 
 var yxabort = []ytab{
-       {Yu8, Ynone, Ynone, Zib_, 1},
+       {Zib_, 1, argList{Yu8}},
 }
 
 var ylddqu = []ytab{
-       {Ym, Ynone, Yxr, Zm_r, 1},
+       {Zm_r, 1, argList{Ym, Yxr}},
 }
 
 var ypalignr = []ytab{
-       {Yu8, Yxm, Yxr, Zibm_r, 2},
+       {Zibm_r, 2, argList{Yu8, Yxm, Yxr}},
 }
 
 // VEX instructions that come in two forms:
@@ -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}}
 //
 var yvex_xy3 = []ytab{
-       {Yxm, Yxr, Yxr, Zvex_rm_v_r, 2},
-       {Yym, Yyr, Yyr, Zvex_rm_v_r, 2},
+       {Zvex_rm_v_r, 2, argList{Yxm, Yxr, Yxr}},
+       {Zvex_rm_v_r, 2, argList{Yym, Yyr, Yyr}},
 }
 
 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{
-       {Yi8, Ymb, Yrl, Zvex_i_rm_r, 2},
+       {Zvex_i_rm_r, 2, argList{Yi8, Ymb, Yrl}},
 }
 
 var yvex_xyi3 = []ytab{
-       {Yu8, Yxm, Yxr, Zvex_i_rm_r, 2},
-       {Yu8, Yym, Yyr, Zvex_i_rm_r, 2},
-       {Yi8, Yxm, Yxr, Zvex_i_rm_r, 2},
-       {Yi8, Yym, Yyr, Zvex_i_rm_r, 2},
+       {Zvex_i_rm_r, 2, argList{Yu8, Yxm, Yxr}},
+       {Zvex_i_rm_r, 2, argList{Yu8, Yym, Yyr}},
+       {Zvex_i_rm_r, 2, argList{Yi8, Yxm, Yxr}},
+       {Zvex_i_rm_r, 2, argList{Yi8, Yym, Yyr}},
 }
 
-var yvex_yyi4 = []ytab{ //TODO don't hide 4 op, some version have xmm version
-       {Yym, Yyr, Yyr, Zvex_i_rm_v_r, 2},
+var yvex_yyi4 = []ytab{
+       {Zvex_i_rm_v_r, 2, argList{Yu8, Yym, Yyr, Yyr}},
 }
 
 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{
-       {Yi8, Yxr, Yxr, Zvex_i_r_v, 3},
-       {Yi8, Yyr, Yyr, Zvex_i_r_v, 3},
-       {Yxm, Yxr, Yxr, Zvex_rm_v_r, 2},
-       {Yxm, Yyr, Yyr, Zvex_rm_v_r, 2},
+       {Zvex_i_r_v, 3, argList{Yi8, Yxr, Yxr}},
+       {Zvex_i_r_v, 3, argList{Yi8, Yyr, Yyr}},
+       {Zvex_rm_v_r, 2, argList{Yxm, Yxr, Yxr}},
+       {Zvex_rm_v_r, 2, argList{Yxm, Yyr, Yyr}},
 }
 
 var yvex_shift_dq = []ytab{
-       {Yi8, Yxr, Yxr, Zvex_i_r_v, 3},
-       {Yi8, Yyr, Yyr, Zvex_i_r_v, 3},
+       {Zvex_i_r_v, 3, argList{Yi8, Yxr, Yxr}},
+       {Zvex_i_r_v, 3, argList{Yi8, Yyr, Yyr}},
 }
 
 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{
-       {Yrl, Yml, Yrl, Zvex_v_rm_r, 2},
+       {Zvex_v_rm_r, 2, argList{Yrl, Yml, Yrl}},
 }
 
 var yvex_xy2 = []ytab{
-       {Yxm, Ynone, Yxr, Zvex_rm_v_r, 2},
-       {Yym, Ynone, Yyr, Zvex_rm_v_r, 2},
+       {Zvex_rm_v_r, 2, argList{Yxm, Yxr}},
+       {Zvex_rm_v_r, 2, argList{Yym, Yyr}},
 }
 
 var yvex_xyr2 = []ytab{
-       {Yxr, Ynone, Yrl, Zvex_rm_v_r, 2},
-       {Yyr, Ynone, Yrl, Zvex_rm_v_r, 2},
+       {Zvex_rm_v_r, 2, argList{Yxr, Yrl}},
+       {Zvex_rm_v_r, 2, argList{Yyr, Yrl}},
 }
 
 var yvex_vmovdqa = []ytab{
-       {Yxm, Ynone, Yxr, Zvex_rm_v_r, 2},
-       {Yxr, Ynone, Yxm, Zvex_r_v_rm, 2},
-       {Yym, Ynone, Yyr, Zvex_rm_v_r, 2},
-       {Yyr, Ynone, Yym, Zvex_r_v_rm, 2},
+       {Zvex_rm_v_r, 2, argList{Yxm, Yxr}},
+       {Zvex_r_v_rm, 2, argList{Yxr, Yxm}},
+       {Zvex_rm_v_r, 2, argList{Yym, Yyr}},
+       {Zvex_r_v_rm, 2, argList{Yyr, Yym}},
 }
 
 var yvex_vmovntdq = []ytab{
-       {Yxr, Ynone, Ym, Zvex_r_v_rm, 2},
-       {Yyr, Ynone, Ym, Zvex_r_v_rm, 2},
+       {Zvex_r_v_rm, 2, argList{Yxr, Ym}},
+       {Zvex_r_v_rm, 2, argList{Yyr, Ym}},
 }
 
 var yvex_vpbroadcast = []ytab{
-       {Yxm, Ynone, Yxr, Zvex_rm_v_r, 2},
-       {Yxm, Ynone, Yyr, Zvex_rm_v_r, 2},
+       {Zvex_rm_v_r, 2, argList{Yxm, Yxr}},
+       {Zvex_rm_v_r, 2, argList{Yxm, Yyr}},
 }
 
 var yvex_vpbroadcast_sd = []ytab{
-       {Yxm, Ynone, Yyr, Zvex_rm_v_r, 2},
+       {Zvex_rm_v_r, 2, argList{Yxm, Yyr}},
 }
 
 var ymmxmm0f38 = []ytab{
-       {Ymm, Ynone, Ymr, Zlitm_r, 3},
-       {Yxm, Ynone, Yxr, Zlitm_r, 5},
+       {Zlitm_r, 3, argList{Ymm, Ymr}},
+       {Zlitm_r, 5, argList{Yxm, Yxr}},
 }
 
 /*
@@ -1120,10 +1116,10 @@ var optab =
        {ADPPS, yxshuf, Pq, [23]uint8{0x3a, 0x40, 0}},
        {AEMMS, ynone, Pm, [23]uint8{0x77}},
        {AENTER, nil, 0, [23]uint8{}}, /* botch */
-       {AFXRSTOR, ysvrs, Pm, [23]uint8{0xae, 01, 0xae, 01}},
-       {AFXSAVE, ysvrs, Pm, [23]uint8{0xae, 00, 0xae, 00}},
-       {AFXRSTOR64, ysvrs, Pw, [23]uint8{0x0f, 0xae, 01, 0x0f, 0xae, 01}},
-       {AFXSAVE64, ysvrs, Pw, [23]uint8{0x0f, 0xae, 00, 0x0f, 0xae, 00}},
+       {AFXRSTOR, ysvrs_mo, Pm, [23]uint8{0xae, 01, 0xae, 01}},
+       {AFXSAVE, ysvrs_om, Pm, [23]uint8{0xae, 00, 0xae, 00}},
+       {AFXRSTOR64, ysvrs_mo, Pw, [23]uint8{0x0f, 0xae, 01, 0x0f, 0xae, 01}},
+       {AFXSAVE64, ysvrs_om, Pw, [23]uint8{0x0f, 0xae, 00, 0x0f, 0xae, 00}},
        {AHLT, ynone, Px, [23]uint8{0xf4}},
        {AIDIVB, ydivb, Pb, [23]uint8{0xf6, 07}},
        {AIDIVL, ydivl, Px, [23]uint8{0xf7, 07}},
@@ -1178,7 +1174,7 @@ var optab =
        {ALARL, yml_rl, Pm, [23]uint8{0x02}},
        {ALARW, yml_rl, Pq, [23]uint8{0x02}},
        {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}},
        {ALEAQ, ym_rl, Pw, [23]uint8{0x8d}},
        {ALEAVEL, ynone, P32, [23]uint8{0xc9}},
@@ -1493,7 +1489,7 @@ var optab =
        {ASTC, ynone, Px, [23]uint8{0xf9}},
        {ASTD, ynone, Px, [23]uint8{0xfd}},
        {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}},
        {ASTOSL, ynone, Px, [23]uint8{0xab}},
        {ASTOSQ, ynone, Pw, [23]uint8{0xab}},
@@ -1604,12 +1600,12 @@ var optab =
        {AFDIVRD, yfadd, Px, [23]uint8{0xdc, 07, 0xd8, 07, 0xdc, 06}},
        {AFXCHD, yfxch, Px, [23]uint8{0xd9, 01, 0xd9, 01}},
        {AFFREE, nil, 0, [23]uint8{}},
-       {AFLDCW, ysvrs, Px, [23]uint8{0xd9, 05, 0xd9, 05}},
-       {AFLDENV, ysvrs, Px, [23]uint8{0xd9, 04, 0xd9, 04}},
-       {AFRSTOR, ysvrs, Px, [23]uint8{0xdd, 04, 0xdd, 04}},
-       {AFSAVE, ysvrs, Px, [23]uint8{0xdd, 06, 0xdd, 06}},
-       {AFSTCW, ysvrs, Px, [23]uint8{0xd9, 07, 0xd9, 07}},
-       {AFSTENV, ysvrs, Px, [23]uint8{0xd9, 06, 0xd9, 06}},
+       {AFLDCW, ysvrs_mo, Px, [23]uint8{0xd9, 05, 0xd9, 05}},
+       {AFLDENV, ysvrs_mo, Px, [23]uint8{0xd9, 04, 0xd9, 04}},
+       {AFRSTOR, ysvrs_mo, Px, [23]uint8{0xdd, 04, 0xdd, 04}},
+       {AFSAVE, ysvrs_om, Px, [23]uint8{0xdd, 06, 0xdd, 06}},
+       {AFSTCW, ysvrs_om, Px, [23]uint8{0xd9, 07, 0xd9, 07}},
+       {AFSTENV, ysvrs_om, Px, [23]uint8{0xd9, 06, 0xd9, 06}},
        {AFSTSW, ystsw, Px, [23]uint8{0xdd, 07, 0xdf, 0xe0}},
        {AF2XM1, ynone, Px, [23]uint8{0xd9, 0xf0}},
        {AFABS, ynone, Px, [23]uint8{0xd9, 0xe1}},
@@ -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.
        // 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 {
-               p.From3 = new(obj.Addr)
-               p.From3.Type = obj.TYPE_REG
-               p.From3.Reg = p.From.Index
+               p.SetFrom3(obj.Addr{
+                       Type: obj.TYPE_REG,
+                       Reg:  p.From.Index,
+               })
                p.From.Index = 0
        }
 
@@ -3414,8 +3411,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
        switch p.As {
        case AIMUL3Q, APEXTRW, APINSRW, APINSRD, APINSRQ, APSHUFHW, APSHUFL, APSHUFW, ASHUFPD, ASHUFPS, AAESKEYGENASSIST, APSHUFD, APCLMULQDQ:
                if p.From3Type() == obj.TYPE_NONE {
-                       p.From3 = new(obj.Addr)
-                       *p.From3 = p.From
+                       p.SetFrom3(p.From)
                        p.From = obj.Addr{}
                        p.From.Type = obj.TYPE_CONST
                        p.From.Offset = p.To.Offset
@@ -3423,12 +3419,11 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
                }
        case ACMPSD, ACMPSS, ACMPPS, ACMPPD:
                if p.From3Type() == obj.TYPE_NONE {
-                       p.From3 = new(obj.Addr)
-                       *p.From3 = p.To
+                       p.SetFrom3(p.To)
                        p.To = obj.Addr{}
                        p.To.Type = obj.TYPE_CONST
-                       p.To.Offset = p.From3.Offset
-                       p.From3.Offset = 0
+                       p.To.Offset = p.GetFrom3().Offset
+                       p.GetFrom3().Offset = 0
                }
        }
 
@@ -3440,10 +3435,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
        }
 
        ft := int(p.Ft) * Ymax
-       f3t := Ynone * Ymax
-       if p.From3 != nil {
-               f3t = oclass(ctxt, p, p.From3) * Ymax
-       }
+       var f3t int
        tt := int(p.Tt) * Ymax
 
        xo := obj.Bool2int(o.op[0] == 0x0f)
@@ -3455,9 +3447,22 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
        var r *obj.Reloc
        var rel obj.Reloc
        var v int64
-       for i := range o.ytab {
-               yt := &o.ytab[i]
-               if ycover[ft+int(yt.from)] != 0 && ycover[f3t+int(yt.from3)] != 0 && ycover[tt+int(yt.to)] != 0 {
+
+       args := make([]int, 0, 6)
+       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 {
                        case Px1: /* first option valid only in 32-bit mode */
                                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) {
 
                        case Zm_r_i_xm:
                                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))
 
                        case Zibm_r, Zibr_m:
@@ -3618,9 +3623,9 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
                                        asmbuf.Put1(byte(op))
                                }
                                if yt.zcase == Zibr_m {
-                                       asmbuf.asmand(ctxt, cursym, p, &p.To, p.From3)
+                                       asmbuf.asmand(ctxt, cursym, p, &p.To, p.GetFrom3())
                                } 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))
 
@@ -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)
 
                        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)
 
                        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)
-                               if p.From3.Reg >= REG_X0 && p.From3.Reg <= REG_X15 {
-                                       regnum &= byte(p.From3.Reg - REG_X0)
+                               if p.GetFrom3().Reg >= REG_X0 && p.GetFrom3().Reg <= REG_X15 {
+                                       regnum &= byte(p.GetFrom3().Reg - REG_X0)
                                } 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(p.From.Offset))
 
                        case Zvex_i_rm_v_r:
-                               asmbuf.asmvex(ctxt, &p.From, p.From3, &p.To, o.op[z], o.op[z+1])
-                               asmbuf.asmand(ctxt, cursym, p, &p.From, &p.To)
-                               asmbuf.Put1(byte(p.From3.Offset))
+                               imm, from, from3, to := unpackOps4(p)
+                               asmbuf.asmvex(ctxt, from, from3, to, o.op[z], o.op[z+1])
+                               asmbuf.asmand(ctxt, cursym, p, from, to)
+                               asmbuf.Put1(byte(imm.Offset))
 
                        case Zvex_i_rm_r:
-                               asmbuf.asmvex(ctxt, p.From3, nil, &p.To, o.op[z], o.op[z+1])
-                               asmbuf.asmand(ctxt, cursym, p, p.From3, &p.To)
+                               asmbuf.asmvex(ctxt, p.GetFrom3(), nil, &p.To, o.op[z], o.op[z+1])
+                               asmbuf.asmand(ctxt, cursym, p, p.GetFrom3(), &p.To)
                                asmbuf.Put1(byte(p.From.Offset))
 
                        case Zvex_v_rm_r:
-                               asmbuf.asmvex(ctxt, p.From3, &p.From, &p.To, o.op[z], o.op[z+1])
-                               asmbuf.asmand(ctxt, cursym, p, p.From3, &p.To)
+                               asmbuf.asmvex(ctxt, p.GetFrom3(), &p.From, &p.To, o.op[z], o.op[z+1])
+                               asmbuf.asmand(ctxt, cursym, p, p.GetFrom3(), &p.To)
 
                        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)
 
                        case Zr_m_xm:
@@ -4026,7 +4032,10 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
 
                        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:] {
                var pp obj.Prog
@@ -4105,7 +4114,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
 
                                        case obj.TYPE_CONST:
                                                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))
 
                                        case obj.TYPE_REG:
@@ -4115,7 +4124,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
 
                                                case REG_CL, REG_CX:
                                                        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) {
                }
        }
 }
+
+// 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
+}
index 38aeb4a59d6442fcc3eaf4db074563eb99870e31..0e6deafc9188b309121380fbbf0e2d99b809fb71 100644 (file)
@@ -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 p.From3 != nil {
-                       nacladdr(ctxt, p, p.From3)
+               if p.GetFrom3() != nil {
+                       nacladdr(ctxt, p, p.GetFrom3())
                }
                nacladdr(ctxt, p, &p.From)
                nacladdr(ctxt, p, &p.To)
@@ -398,7 +398,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
                        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)
        }
        var source *obj.Addr
@@ -436,7 +436,9 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
                p2.As = p.As
                p2.Scond = p.Scond
                p2.From = p.From
-               p2.From3 = p.From3
+               if p.RestArgs != nil {
+                       p2.RestArgs = append(p2.RestArgs, p.RestArgs...)
+               }
                p2.Reg = p.Reg
                p2.To = p.To
                // 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) {
                }
        }
 
-       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
        }
        var dst int16 = REG_CX
@@ -543,7 +545,7 @@ func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
        r.As = p.As
        r.Scond = p.Scond
        r.From = p.From
-       r.From3 = p.From3
+       r.RestArgs = p.RestArgs
        r.Reg = p.Reg
        r.To = p.To
        if isName(&p.From) {
@@ -552,8 +554,8 @@ func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
        if isName(&p.To) {
                r.To.Reg = dst
        }
-       if p.From3 != nil && isName(p.From3) {
-               r.From3.Reg = dst
+       if p.GetFrom3() != nil && isName(p.GetFrom3()) {
+               r.GetFrom3().Reg = dst
        }
        obj.Nopout(p)
 }
@@ -857,12 +859,12 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
                case obj.NAME_PARAM:
                        p.From.Offset += int64(deltasp) + int64(pcsize)
                }
-               if p.From3 != nil {
-                       switch p.From3.Name {
+               if p.GetFrom3() != nil {
+                       switch p.GetFrom3().Name {
                        case obj.NAME_AUTO:
-                               p.From3.Offset += int64(deltasp) - int64(bpsize)
+                               p.GetFrom3().Offset += int64(deltasp) - int64(bpsize)
                        case obj.NAME_PARAM:
-                               p.From3.Offset += int64(deltasp) + int64(pcsize)
+                               p.GetFrom3().Offset += int64(deltasp) + int64(pcsize)
                        }
                }
                switch p.To.Name {
diff --git a/src/cmd/internal/obj/x86/ytab.go b/src/cmd/internal/obj/x86/ytab.go
new file mode 100644 (file)
index 0000000..dbbef47
--- /dev/null
@@ -0,0 +1,40 @@
+// 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
+}