From 8c67f210a181f4d3e003e46e544ae03ce231ca42 Mon Sep 17 00:00:00 2001 From: isharipo Date: Wed, 13 Sep 2017 14:32:08 +0300 Subject: [PATCH] cmd/internal/obj: change Prog.From3 to RestArgs ([]Addr) MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 TryBot-Result: Gobot Gobot Reviewed-by: Matthew Dempsky --- src/cmd/asm/internal/arch/amd64.go | 28 -- src/cmd/asm/internal/asm/asm.go | 50 +-- src/cmd/compile/internal/arm64/ssa.go | 2 +- src/cmd/compile/internal/ppc64/ssa.go | 6 +- src/cmd/compile/internal/s390x/ssa.go | 17 +- src/cmd/internal/obj/arm/asm5.go | 8 +- src/cmd/internal/obj/arm/obj5.go | 2 +- src/cmd/internal/obj/arm64/asm7.go | 20 +- src/cmd/internal/obj/arm64/obj7.go | 2 +- src/cmd/internal/obj/go.go | 2 +- src/cmd/internal/obj/link.go | 84 ++-- src/cmd/internal/obj/pass.go | 4 +- src/cmd/internal/obj/ppc64/asm9.go | 50 +-- src/cmd/internal/obj/ppc64/obj9.go | 2 +- src/cmd/internal/obj/s390x/asmz.go | 46 +- src/cmd/internal/obj/s390x/objz.go | 2 +- src/cmd/internal/obj/sizeof_test.go | 2 +- src/cmd/internal/obj/util.go | 17 +- src/cmd/internal/obj/x86/asm6.go | 584 +++++++++++++------------- src/cmd/internal/obj/x86/obj6.go | 26 +- src/cmd/internal/obj/x86/ytab.go | 40 ++ 21 files changed, 513 insertions(+), 481 deletions(-) delete mode 100644 src/cmd/asm/internal/arch/amd64.go create mode 100644 src/cmd/internal/obj/x86/ytab.go diff --git a/src/cmd/asm/internal/arch/amd64.go b/src/cmd/asm/internal/arch/amd64.go deleted file mode 100644 index ff20d32daa..0000000000 --- a/src/cmd/asm/internal/arch/amd64.go +++ /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 -} diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go index 24aa0537ca..b5e4bddb96 100644 --- a/src/cmd/asm/internal/asm/asm.go +++ b/src/cmd/asm/internal/asm/asm.go @@ -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 } diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index 24a8fb83a4..e74207b856 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -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: diff --git a/src/cmd/compile/internal/ppc64/ssa.go b/src/cmd/compile/internal/ppc64/ssa.go index c56f53c206..330d58becf 100644 --- a/src/cmd/compile/internal/ppc64/ssa.go +++ b/src/cmd/compile/internal/ppc64/ssa.go @@ -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 diff --git a/src/cmd/compile/internal/s390x/ssa.go b/src/cmd/compile/internal/s390x/ssa.go index 8722345a09..6e637487cd 100644 --- a/src/cmd/compile/internal/s390x/ssa.go +++ b/src/cmd/compile/internal/s390x/ssa.go @@ -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() } diff --git a/src/cmd/internal/obj/arm/asm5.go b/src/cmd/internal/obj/arm/asm5.go index 98b45feb60..479005f294 100644 --- a/src/cmd/internal/obj/arm/asm5.go +++ b/src/cmd/internal/obj/arm/asm5.go @@ -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 } diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go index 32c4643166..59f044ec9d 100644 --- a/src/cmd/internal/obj/arm/obj5.go +++ b/src/cmd/internal/obj/arm/obj5.go @@ -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 diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index ddd43485f7..10f0303785 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -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 */ diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go index b1cf7cdd9f..7f22aa88bb 100644 --- a/src/cmd/internal/obj/arm64/obj7.go +++ b/src/cmd/internal/obj/arm64/obj7.go @@ -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 diff --git a/src/cmd/internal/obj/go.go b/src/cmd/internal/obj/go.go index f0b2c46e4f..dbe9b406dd 100644 --- a/src/cmd/internal/obj/go.go +++ b/src/cmd/internal/obj/go.go @@ -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{} } diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index 68e1b70ac0..abd90e34d2 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -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. diff --git a/src/cmd/internal/obj/pass.go b/src/cmd/internal/obj/pass.go index 7cc187d01f..edfc3acf79 100644 --- a/src/cmd/internal/obj/pass.go +++ b/src/cmd/internal/obj/pass.go @@ -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) diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go index dd6429fd0b..2f7e3237b4 100644 --- a/src/cmd/internal/obj/ppc64/asm9.go +++ b/src/cmd/internal/obj/ppc64/asm9.go @@ -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)) } diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go index b1509e3813..c50cd3b06c 100644 --- a/src/cmd/internal/obj/ppc64/obj9.go +++ b/src/cmd/internal/obj/ppc64/obj9.go @@ -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 diff --git a/src/cmd/internal/obj/s390x/asmz.go b/src/cmd/internal/obj/s390x/asmz.go index 6d2b870f0a..e108032c5c 100644 --- a/src/cmd/internal/obj/s390x/asmz.go +++ b/src/cmd/internal/obj/s390x/asmz.go @@ -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) } } diff --git a/src/cmd/internal/obj/s390x/objz.go b/src/cmd/internal/obj/s390x/objz.go index 3d3571a461..bf4dfd49d5 100644 --- a/src/cmd/internal/obj/s390x/objz.go +++ b/src/cmd/internal/obj/s390x/objz.go @@ -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 diff --git a/src/cmd/internal/obj/sizeof_test.go b/src/cmd/internal/obj/sizeof_test.go index 601e9e2ea6..e70d174637 100644 --- a/src/cmd/internal/obj/sizeof_test.go +++ b/src/cmd/internal/obj/sizeof_test.go @@ -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 { diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go index 9bcdbbd127..bf2d209d7f 100644 --- a/src/cmd/internal/obj/util.go +++ b/src/cmd/internal/obj/util.go @@ -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() diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index f636d312d4..86c85c1a6f 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -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 +} diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go index 38aeb4a59d..0e6deafc91 100644 --- a/src/cmd/internal/obj/x86/obj6.go +++ b/src/cmd/internal/obj/x86/obj6.go @@ -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 index 0000000000..dbbef4730e --- /dev/null +++ b/src/cmd/internal/obj/x86/ytab.go @@ -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 +} -- 2.48.1