mirror of
https://github.com/golang/go
synced 2024-11-18 00:14:47 -07:00
cmd/internal/obj: change Prog.From3 to RestArgs ([]Addr)
This change makes it easier to express instructions with arbitrary number of operands. Rationale: previous approach with operand "hiding" does not scale well, AVX and especially AVX512 have many instructions with 3+ operands. x86 asm backend is updated to handle up to 6 explicit operands. It also fixes issue with 4-th immediate operand type checks. All `ytab` tables are updated accordingly. Changes to non-x86 backends only include these patterns: `p.From3 = X` => `p.SetFrom3(X)` `p.From3.X = Y` => `p.GetFrom3().X = Y` Over time, other backends can adapt Prog.RestArgs and reduce the amount of workarounds. -- Performance -- x/benchmark/build: $ benchstat upstream.bench patched.bench name old time/op new time/op delta Build-48 21.7s ± 2% 21.8s ± 2% ~ (p=0.218 n=10+10) name old binary-size new binary-size delta Build-48 10.3M ± 0% 10.3M ± 0% ~ (all equal) name old build-time/op new build-time/op delta Build-48 21.7s ± 2% 21.8s ± 2% ~ (p=0.218 n=10+10) name old build-peak-RSS-bytes new build-peak-RSS-bytes delta Build-48 145MB ± 5% 148MB ± 5% ~ (p=0.218 n=10+10) name old build-user+sys-time/op new build-user+sys-time/op delta Build-48 21.0s ± 2% 21.2s ± 2% ~ (p=0.075 n=10+10) Microbenchmark shows a slight slowdown. name old time/op new time/op delta AMD64asm-4 49.5ms ± 1% 49.9ms ± 1% +0.67% (p=0.001 n=23+15) func BenchmarkAMD64asm(b *testing.B) { for i := 0; i < b.N; i++ { TestAMD64EndToEnd(nil) TestAMD64Encoder(nil) } } Change-Id: I4f1d37b5c2c966da3f2127705ccac9bff0038183 Reviewed-on: https://go-review.googlesource.com/63490 Run-TryBot: Iskander Sharipov <iskander.sharipov@intel.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
e1cf2be7a8
commit
8c67f210a1
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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{}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 {
|
||||
|
40
src/cmd/internal/obj/x86/ytab.go
Normal file
40
src/cmd/internal/obj/x86/ytab.go
Normal file
@ -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
|
||||
}
|
Loading…
Reference in New Issue
Block a user