mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
The Node type ODOT and its variants all represent a selector, with a simple name to the right of the dot. Before this change this was represented by using an ONAME Node in the Right field. This ONAME node served no useful purpose. This CL changes these Node types to store the symbol in the Sym field instead, thus not requiring allocating a Node for each selector. When compiling x/tools/go/types this CL eliminates nearly 5000 calls to newname and reduces the total number of Nodes allocated by about 6.6%. It seems to cut compilation time by 1 to 2 percent. Getting this right was somewhat subtle, and I added two dubious changes to produce the exact same output as before. One is to ishairy in inl.go: the ONAME node increased the cost of ODOT and friends by 1, and I retained that, although really ODOT is not more expensive than any other node. The other is to varexpr in walk.go: because the ONAME in the Right field of an ODOT has no class, varexpr would always return false for an ODOT, although in fact for some ODOT's it seemingly ought to return true; I added an && false for now. I will send separate CLs, that will break toolstash -cmp, to clean these up. This CL passes toolstash -cmp. Change-Id: I4af8a10cc59078c436130ce472f25abc3a9b2f80 Reviewed-on: https://go-review.googlesource.com/20890 TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
1421 lines
28 KiB
Go
1421 lines
28 KiB
Go
// Derived from Inferno utils/6c/txt.c
|
|
// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
|
|
//
|
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
|
|
package amd64
|
|
|
|
import (
|
|
"cmd/compile/internal/big"
|
|
"cmd/compile/internal/gc"
|
|
"cmd/internal/obj"
|
|
"cmd/internal/obj/x86"
|
|
"fmt"
|
|
)
|
|
|
|
var resvd = []int{
|
|
x86.REG_DI, // for movstring
|
|
x86.REG_SI, // for movstring
|
|
|
|
x86.REG_AX, // for divide
|
|
x86.REG_CX, // for shift
|
|
x86.REG_DX, // for divide
|
|
x86.REG_SP, // for stack
|
|
}
|
|
|
|
/*
|
|
* generate
|
|
* as $c, reg
|
|
*/
|
|
func gconreg(as obj.As, c int64, reg int) {
|
|
var nr gc.Node
|
|
|
|
switch as {
|
|
case x86.AADDL,
|
|
x86.AMOVL,
|
|
x86.ALEAL:
|
|
gc.Nodreg(&nr, gc.Types[gc.TINT32], reg)
|
|
|
|
default:
|
|
gc.Nodreg(&nr, gc.Types[gc.TINT64], reg)
|
|
}
|
|
|
|
ginscon(as, c, &nr)
|
|
}
|
|
|
|
/*
|
|
* generate
|
|
* as $c, n
|
|
*/
|
|
func ginscon(as obj.As, c int64, n2 *gc.Node) {
|
|
var n1 gc.Node
|
|
|
|
switch as {
|
|
case x86.AADDL,
|
|
x86.AMOVL,
|
|
x86.ALEAL:
|
|
gc.Nodconst(&n1, gc.Types[gc.TINT32], c)
|
|
|
|
default:
|
|
gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
|
|
}
|
|
|
|
if as != x86.AMOVQ && (c < -(1<<31) || c >= 1<<31) {
|
|
// cannot have 64-bit immediate in ADD, etc.
|
|
// instead, MOV into register first.
|
|
var ntmp gc.Node
|
|
gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
|
|
|
|
gins(x86.AMOVQ, &n1, &ntmp)
|
|
gins(as, &ntmp, n2)
|
|
gc.Regfree(&ntmp)
|
|
return
|
|
}
|
|
|
|
gins(as, &n1, n2)
|
|
}
|
|
|
|
func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
|
|
if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && gc.Smallintconst(n1) && n2.Op != gc.OLITERAL {
|
|
// Reverse comparison to place constant last.
|
|
op = gc.Brrev(op)
|
|
n1, n2 = n2, n1
|
|
}
|
|
// General case.
|
|
var r1, r2, g1, g2 gc.Node
|
|
|
|
// A special case to make write barriers more efficient.
|
|
// Comparing the first field of a named struct can be done directly.
|
|
base := n1
|
|
if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Field(0).Sym == n1.Sym {
|
|
base = n1.Left
|
|
}
|
|
|
|
if base.Op == gc.ONAME && base.Class&gc.PHEAP == 0 || n1.Op == gc.OINDREG {
|
|
r1 = *n1
|
|
} else {
|
|
gc.Regalloc(&r1, t, n1)
|
|
gc.Regalloc(&g1, n1.Type, &r1)
|
|
gc.Cgen(n1, &g1)
|
|
gmove(&g1, &r1)
|
|
}
|
|
if n2.Op == gc.OLITERAL && gc.Isint[t.Etype] && gc.Smallintconst(n2) {
|
|
r2 = *n2
|
|
} else {
|
|
gc.Regalloc(&r2, t, n2)
|
|
gc.Regalloc(&g2, n1.Type, &r2)
|
|
gc.Cgen(n2, &g2)
|
|
gmove(&g2, &r2)
|
|
}
|
|
gins(optoas(gc.OCMP, t), &r1, &r2)
|
|
if r1.Op == gc.OREGISTER {
|
|
gc.Regfree(&g1)
|
|
gc.Regfree(&r1)
|
|
}
|
|
if r2.Op == gc.OREGISTER {
|
|
gc.Regfree(&g2)
|
|
gc.Regfree(&r2)
|
|
}
|
|
return gc.Gbranch(optoas(op, t), nil, likely)
|
|
}
|
|
|
|
func ginsboolval(a obj.As, n *gc.Node) {
|
|
gins(jmptoset(a), nil, n)
|
|
}
|
|
|
|
// set up nodes representing 2^63
|
|
var (
|
|
bigi gc.Node
|
|
bigf gc.Node
|
|
bignodes_did bool
|
|
)
|
|
|
|
func bignodes() {
|
|
if bignodes_did {
|
|
return
|
|
}
|
|
bignodes_did = true
|
|
|
|
var i big.Int
|
|
i.SetInt64(1)
|
|
i.Lsh(&i, 63)
|
|
|
|
gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
|
|
bigi.SetBigInt(&i)
|
|
|
|
bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64])
|
|
}
|
|
|
|
/*
|
|
* generate move:
|
|
* t = f
|
|
* hard part is conversions.
|
|
*/
|
|
func gmove(f *gc.Node, t *gc.Node) {
|
|
if gc.Debug['M'] != 0 {
|
|
fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong))
|
|
}
|
|
|
|
ft := gc.Simsimtype(f.Type)
|
|
tt := gc.Simsimtype(t.Type)
|
|
cvt := t.Type
|
|
|
|
if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
|
|
gc.Complexmove(f, t)
|
|
return
|
|
}
|
|
|
|
// cannot have two memory operands
|
|
var a obj.As
|
|
if gc.Ismem(f) && gc.Ismem(t) {
|
|
goto hard
|
|
}
|
|
|
|
// convert constant to desired type
|
|
if f.Op == gc.OLITERAL {
|
|
var con gc.Node
|
|
f.Convconst(&con, t.Type)
|
|
f = &con
|
|
ft = tt // so big switch will choose a simple mov
|
|
|
|
// some constants can't move directly to memory.
|
|
if gc.Ismem(t) {
|
|
// float constants come from memory.
|
|
if gc.Isfloat[tt] {
|
|
goto hard
|
|
}
|
|
|
|
// 64-bit immediates are really 32-bit sign-extended
|
|
// unless moving into a register.
|
|
if gc.Isint[tt] {
|
|
if i := con.Int(); int64(int32(i)) != i {
|
|
goto hard
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// value -> value copy, only one memory operand.
|
|
// figure out the instruction to use.
|
|
// break out of switch for one-instruction gins.
|
|
// goto rdst for "destination must be register".
|
|
// goto hard for "convert to cvt type first".
|
|
// otherwise handle and return.
|
|
|
|
switch uint32(ft)<<16 | uint32(tt) {
|
|
default:
|
|
gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong))
|
|
|
|
/*
|
|
* integer copy and truncate
|
|
*/
|
|
case gc.TINT8<<16 | gc.TINT8, // same size
|
|
gc.TINT8<<16 | gc.TUINT8,
|
|
gc.TUINT8<<16 | gc.TINT8,
|
|
gc.TUINT8<<16 | gc.TUINT8,
|
|
gc.TINT16<<16 | gc.TINT8,
|
|
// truncate
|
|
gc.TUINT16<<16 | gc.TINT8,
|
|
gc.TINT32<<16 | gc.TINT8,
|
|
gc.TUINT32<<16 | gc.TINT8,
|
|
gc.TINT64<<16 | gc.TINT8,
|
|
gc.TUINT64<<16 | gc.TINT8,
|
|
gc.TINT16<<16 | gc.TUINT8,
|
|
gc.TUINT16<<16 | gc.TUINT8,
|
|
gc.TINT32<<16 | gc.TUINT8,
|
|
gc.TUINT32<<16 | gc.TUINT8,
|
|
gc.TINT64<<16 | gc.TUINT8,
|
|
gc.TUINT64<<16 | gc.TUINT8:
|
|
a = x86.AMOVB
|
|
|
|
case gc.TINT16<<16 | gc.TINT16, // same size
|
|
gc.TINT16<<16 | gc.TUINT16,
|
|
gc.TUINT16<<16 | gc.TINT16,
|
|
gc.TUINT16<<16 | gc.TUINT16,
|
|
gc.TINT32<<16 | gc.TINT16,
|
|
// truncate
|
|
gc.TUINT32<<16 | gc.TINT16,
|
|
gc.TINT64<<16 | gc.TINT16,
|
|
gc.TUINT64<<16 | gc.TINT16,
|
|
gc.TINT32<<16 | gc.TUINT16,
|
|
gc.TUINT32<<16 | gc.TUINT16,
|
|
gc.TINT64<<16 | gc.TUINT16,
|
|
gc.TUINT64<<16 | gc.TUINT16:
|
|
a = x86.AMOVW
|
|
|
|
case gc.TINT32<<16 | gc.TINT32, // same size
|
|
gc.TINT32<<16 | gc.TUINT32,
|
|
gc.TUINT32<<16 | gc.TINT32,
|
|
gc.TUINT32<<16 | gc.TUINT32:
|
|
a = x86.AMOVL
|
|
|
|
case gc.TINT64<<16 | gc.TINT32, // truncate
|
|
gc.TUINT64<<16 | gc.TINT32,
|
|
gc.TINT64<<16 | gc.TUINT32,
|
|
gc.TUINT64<<16 | gc.TUINT32:
|
|
a = x86.AMOVQL
|
|
|
|
case gc.TINT64<<16 | gc.TINT64, // same size
|
|
gc.TINT64<<16 | gc.TUINT64,
|
|
gc.TUINT64<<16 | gc.TINT64,
|
|
gc.TUINT64<<16 | gc.TUINT64:
|
|
a = x86.AMOVQ
|
|
|
|
/*
|
|
* integer up-conversions
|
|
*/
|
|
case gc.TINT8<<16 | gc.TINT16, // sign extend int8
|
|
gc.TINT8<<16 | gc.TUINT16:
|
|
a = x86.AMOVBWSX
|
|
|
|
goto rdst
|
|
|
|
case gc.TINT8<<16 | gc.TINT32,
|
|
gc.TINT8<<16 | gc.TUINT32:
|
|
a = x86.AMOVBLSX
|
|
goto rdst
|
|
|
|
case gc.TINT8<<16 | gc.TINT64,
|
|
gc.TINT8<<16 | gc.TUINT64:
|
|
a = x86.AMOVBQSX
|
|
goto rdst
|
|
|
|
case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8
|
|
gc.TUINT8<<16 | gc.TUINT16:
|
|
a = x86.AMOVBWZX
|
|
|
|
goto rdst
|
|
|
|
case gc.TUINT8<<16 | gc.TINT32,
|
|
gc.TUINT8<<16 | gc.TUINT32:
|
|
a = x86.AMOVBLZX
|
|
goto rdst
|
|
|
|
case gc.TUINT8<<16 | gc.TINT64,
|
|
gc.TUINT8<<16 | gc.TUINT64:
|
|
a = x86.AMOVBQZX
|
|
goto rdst
|
|
|
|
case gc.TINT16<<16 | gc.TINT32, // sign extend int16
|
|
gc.TINT16<<16 | gc.TUINT32:
|
|
a = x86.AMOVWLSX
|
|
|
|
goto rdst
|
|
|
|
case gc.TINT16<<16 | gc.TINT64,
|
|
gc.TINT16<<16 | gc.TUINT64:
|
|
a = x86.AMOVWQSX
|
|
goto rdst
|
|
|
|
case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16
|
|
gc.TUINT16<<16 | gc.TUINT32:
|
|
a = x86.AMOVWLZX
|
|
|
|
goto rdst
|
|
|
|
case gc.TUINT16<<16 | gc.TINT64,
|
|
gc.TUINT16<<16 | gc.TUINT64:
|
|
a = x86.AMOVWQZX
|
|
goto rdst
|
|
|
|
case gc.TINT32<<16 | gc.TINT64, // sign extend int32
|
|
gc.TINT32<<16 | gc.TUINT64:
|
|
a = x86.AMOVLQSX
|
|
|
|
goto rdst
|
|
|
|
// AMOVL into a register zeros the top of the register,
|
|
// so this is not always necessary, but if we rely on AMOVL
|
|
// the optimizer is almost certain to screw with us.
|
|
case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32
|
|
gc.TUINT32<<16 | gc.TUINT64:
|
|
a = x86.AMOVLQZX
|
|
|
|
goto rdst
|
|
|
|
/*
|
|
* float to integer
|
|
*/
|
|
case gc.TFLOAT32<<16 | gc.TINT32:
|
|
a = x86.ACVTTSS2SL
|
|
|
|
goto rdst
|
|
|
|
case gc.TFLOAT64<<16 | gc.TINT32:
|
|
a = x86.ACVTTSD2SL
|
|
goto rdst
|
|
|
|
case gc.TFLOAT32<<16 | gc.TINT64:
|
|
a = x86.ACVTTSS2SQ
|
|
goto rdst
|
|
|
|
case gc.TFLOAT64<<16 | gc.TINT64:
|
|
a = x86.ACVTTSD2SQ
|
|
goto rdst
|
|
|
|
// convert via int32.
|
|
case gc.TFLOAT32<<16 | gc.TINT16,
|
|
gc.TFLOAT32<<16 | gc.TINT8,
|
|
gc.TFLOAT32<<16 | gc.TUINT16,
|
|
gc.TFLOAT32<<16 | gc.TUINT8,
|
|
gc.TFLOAT64<<16 | gc.TINT16,
|
|
gc.TFLOAT64<<16 | gc.TINT8,
|
|
gc.TFLOAT64<<16 | gc.TUINT16,
|
|
gc.TFLOAT64<<16 | gc.TUINT8:
|
|
cvt = gc.Types[gc.TINT32]
|
|
|
|
goto hard
|
|
|
|
// convert via int64.
|
|
case gc.TFLOAT32<<16 | gc.TUINT32,
|
|
gc.TFLOAT64<<16 | gc.TUINT32:
|
|
cvt = gc.Types[gc.TINT64]
|
|
|
|
goto hard
|
|
|
|
// algorithm is:
|
|
// if small enough, use native float64 -> int64 conversion.
|
|
// otherwise, subtract 2^63, convert, and add it back.
|
|
case gc.TFLOAT32<<16 | gc.TUINT64,
|
|
gc.TFLOAT64<<16 | gc.TUINT64:
|
|
a := x86.ACVTTSS2SQ
|
|
|
|
if ft == gc.TFLOAT64 {
|
|
a = x86.ACVTTSD2SQ
|
|
}
|
|
bignodes()
|
|
var r1 gc.Node
|
|
gc.Regalloc(&r1, gc.Types[ft], nil)
|
|
var r2 gc.Node
|
|
gc.Regalloc(&r2, gc.Types[tt], t)
|
|
var r3 gc.Node
|
|
gc.Regalloc(&r3, gc.Types[ft], nil)
|
|
var r4 gc.Node
|
|
gc.Regalloc(&r4, gc.Types[tt], nil)
|
|
gins(optoas(gc.OAS, f.Type), f, &r1)
|
|
gins(optoas(gc.OCMP, f.Type), &bigf, &r1)
|
|
p1 := gc.Gbranch(optoas(gc.OLE, f.Type), nil, +1)
|
|
gins(a, &r1, &r2)
|
|
p2 := gc.Gbranch(obj.AJMP, nil, 0)
|
|
gc.Patch(p1, gc.Pc)
|
|
gins(optoas(gc.OAS, f.Type), &bigf, &r3)
|
|
gins(optoas(gc.OSUB, f.Type), &r3, &r1)
|
|
gins(a, &r1, &r2)
|
|
gins(x86.AMOVQ, &bigi, &r4)
|
|
gins(x86.AXORQ, &r4, &r2)
|
|
gc.Patch(p2, gc.Pc)
|
|
gmove(&r2, t)
|
|
gc.Regfree(&r4)
|
|
gc.Regfree(&r3)
|
|
gc.Regfree(&r2)
|
|
gc.Regfree(&r1)
|
|
return
|
|
|
|
/*
|
|
* integer to float
|
|
*/
|
|
case gc.TINT32<<16 | gc.TFLOAT32:
|
|
a = x86.ACVTSL2SS
|
|
|
|
goto rdst
|
|
|
|
case gc.TINT32<<16 | gc.TFLOAT64:
|
|
a = x86.ACVTSL2SD
|
|
goto rdst
|
|
|
|
case gc.TINT64<<16 | gc.TFLOAT32:
|
|
a = x86.ACVTSQ2SS
|
|
goto rdst
|
|
|
|
case gc.TINT64<<16 | gc.TFLOAT64:
|
|
a = x86.ACVTSQ2SD
|
|
goto rdst
|
|
|
|
// convert via int32
|
|
case gc.TINT16<<16 | gc.TFLOAT32,
|
|
gc.TINT16<<16 | gc.TFLOAT64,
|
|
gc.TINT8<<16 | gc.TFLOAT32,
|
|
gc.TINT8<<16 | gc.TFLOAT64,
|
|
gc.TUINT16<<16 | gc.TFLOAT32,
|
|
gc.TUINT16<<16 | gc.TFLOAT64,
|
|
gc.TUINT8<<16 | gc.TFLOAT32,
|
|
gc.TUINT8<<16 | gc.TFLOAT64:
|
|
cvt = gc.Types[gc.TINT32]
|
|
|
|
goto hard
|
|
|
|
// convert via int64.
|
|
case gc.TUINT32<<16 | gc.TFLOAT32,
|
|
gc.TUINT32<<16 | gc.TFLOAT64:
|
|
cvt = gc.Types[gc.TINT64]
|
|
|
|
goto hard
|
|
|
|
// algorithm is:
|
|
// if small enough, use native int64 -> uint64 conversion.
|
|
// otherwise, halve (rounding to odd?), convert, and double.
|
|
case gc.TUINT64<<16 | gc.TFLOAT32,
|
|
gc.TUINT64<<16 | gc.TFLOAT64:
|
|
a := x86.ACVTSQ2SS
|
|
|
|
if tt == gc.TFLOAT64 {
|
|
a = x86.ACVTSQ2SD
|
|
}
|
|
var zero gc.Node
|
|
gc.Nodconst(&zero, gc.Types[gc.TUINT64], 0)
|
|
var one gc.Node
|
|
gc.Nodconst(&one, gc.Types[gc.TUINT64], 1)
|
|
var r1 gc.Node
|
|
gc.Regalloc(&r1, f.Type, f)
|
|
var r2 gc.Node
|
|
gc.Regalloc(&r2, t.Type, t)
|
|
var r3 gc.Node
|
|
gc.Regalloc(&r3, f.Type, nil)
|
|
var r4 gc.Node
|
|
gc.Regalloc(&r4, f.Type, nil)
|
|
gmove(f, &r1)
|
|
gins(x86.ACMPQ, &r1, &zero)
|
|
p1 := gc.Gbranch(x86.AJLT, nil, +1)
|
|
gins(a, &r1, &r2)
|
|
p2 := gc.Gbranch(obj.AJMP, nil, 0)
|
|
gc.Patch(p1, gc.Pc)
|
|
gmove(&r1, &r3)
|
|
gins(x86.ASHRQ, &one, &r3)
|
|
gmove(&r1, &r4)
|
|
gins(x86.AANDL, &one, &r4)
|
|
gins(x86.AORQ, &r4, &r3)
|
|
gins(a, &r3, &r2)
|
|
gins(optoas(gc.OADD, t.Type), &r2, &r2)
|
|
gc.Patch(p2, gc.Pc)
|
|
gmove(&r2, t)
|
|
gc.Regfree(&r4)
|
|
gc.Regfree(&r3)
|
|
gc.Regfree(&r2)
|
|
gc.Regfree(&r1)
|
|
return
|
|
|
|
/*
|
|
* float to float
|
|
*/
|
|
case gc.TFLOAT32<<16 | gc.TFLOAT32:
|
|
a = x86.AMOVSS
|
|
|
|
case gc.TFLOAT64<<16 | gc.TFLOAT64:
|
|
a = x86.AMOVSD
|
|
|
|
case gc.TFLOAT32<<16 | gc.TFLOAT64:
|
|
a = x86.ACVTSS2SD
|
|
goto rdst
|
|
|
|
case gc.TFLOAT64<<16 | gc.TFLOAT32:
|
|
a = x86.ACVTSD2SS
|
|
goto rdst
|
|
}
|
|
|
|
gins(a, f, t)
|
|
return
|
|
|
|
// requires register destination
|
|
rdst:
|
|
{
|
|
var r1 gc.Node
|
|
gc.Regalloc(&r1, t.Type, t)
|
|
|
|
gins(a, f, &r1)
|
|
gmove(&r1, t)
|
|
gc.Regfree(&r1)
|
|
return
|
|
}
|
|
|
|
// requires register intermediate
|
|
hard:
|
|
var r1 gc.Node
|
|
gc.Regalloc(&r1, cvt, t)
|
|
|
|
gmove(f, &r1)
|
|
gmove(&r1, t)
|
|
gc.Regfree(&r1)
|
|
return
|
|
}
|
|
|
|
func samaddr(f *gc.Node, t *gc.Node) bool {
|
|
if f.Op != t.Op {
|
|
return false
|
|
}
|
|
|
|
switch f.Op {
|
|
case gc.OREGISTER:
|
|
if f.Reg != t.Reg {
|
|
break
|
|
}
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
/*
|
|
* generate one instruction:
|
|
* as f, t
|
|
*/
|
|
func gins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
|
|
// Node nod;
|
|
|
|
// if(f != N && f->op == OINDEX) {
|
|
// gc.Regalloc(&nod, ®node, Z);
|
|
// v = constnode.vconst;
|
|
// gc.Cgen(f->right, &nod);
|
|
// constnode.vconst = v;
|
|
// idx.reg = nod.reg;
|
|
// gc.Regfree(&nod);
|
|
// }
|
|
// if(t != N && t->op == OINDEX) {
|
|
// gc.Regalloc(&nod, ®node, Z);
|
|
// v = constnode.vconst;
|
|
// gc.Cgen(t->right, &nod);
|
|
// constnode.vconst = v;
|
|
// idx.reg = nod.reg;
|
|
// gc.Regfree(&nod);
|
|
// }
|
|
|
|
if f != nil && f.Op == gc.OADDR && (as == x86.AMOVL || as == x86.AMOVQ) {
|
|
// Turn MOVL $xxx into LEAL xxx.
|
|
// These should be equivalent but most of the backend
|
|
// only expects to see LEAL, because that's what we had
|
|
// historically generated. Various hidden assumptions are baked in by now.
|
|
if as == x86.AMOVL {
|
|
as = x86.ALEAL
|
|
} else {
|
|
as = x86.ALEAQ
|
|
}
|
|
f = f.Left
|
|
}
|
|
|
|
switch as {
|
|
case x86.AMOVB,
|
|
x86.AMOVW,
|
|
x86.AMOVL,
|
|
x86.AMOVQ,
|
|
x86.AMOVSS,
|
|
x86.AMOVSD:
|
|
if f != nil && t != nil && samaddr(f, t) {
|
|
return nil
|
|
}
|
|
|
|
case x86.ALEAQ:
|
|
if f != nil && gc.Isconst(f, gc.CTNIL) {
|
|
gc.Fatalf("gins LEAQ nil %v", f.Type)
|
|
}
|
|
}
|
|
|
|
p := gc.Prog(as)
|
|
gc.Naddr(&p.From, f)
|
|
gc.Naddr(&p.To, t)
|
|
|
|
if gc.Debug['g'] != 0 {
|
|
fmt.Printf("%v\n", p)
|
|
}
|
|
|
|
w := int32(0)
|
|
switch as {
|
|
case x86.AMOVB:
|
|
w = 1
|
|
|
|
case x86.AMOVW:
|
|
w = 2
|
|
|
|
case x86.AMOVL:
|
|
w = 4
|
|
|
|
case x86.AMOVQ:
|
|
w = 8
|
|
}
|
|
|
|
if w != 0 && ((f != nil && p.From.Width < int64(w)) || (t != nil && p.To.Width > int64(w))) {
|
|
gc.Dump("f", f)
|
|
gc.Dump("t", t)
|
|
gc.Fatalf("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width)
|
|
}
|
|
|
|
if p.To.Type == obj.TYPE_ADDR && w > 0 {
|
|
gc.Fatalf("bad use of addr: %v", p)
|
|
}
|
|
|
|
return p
|
|
}
|
|
|
|
func ginsnop() {
|
|
// This is actually not the x86 NOP anymore,
|
|
// but at the point where it gets used, AX is dead
|
|
// so it's okay if we lose the high bits.
|
|
var reg gc.Node
|
|
gc.Nodreg(®, gc.Types[gc.TINT], x86.REG_AX)
|
|
gins(x86.AXCHGL, ®, ®)
|
|
}
|
|
|
|
/*
|
|
* return Axxx for Oxxx on type t.
|
|
*/
|
|
func optoas(op gc.Op, t *gc.Type) obj.As {
|
|
if t == nil {
|
|
gc.Fatalf("optoas: t is nil")
|
|
}
|
|
|
|
// avoid constant conversions in switches below
|
|
const (
|
|
OMINUS_ = uint32(gc.OMINUS) << 16
|
|
OLSH_ = uint32(gc.OLSH) << 16
|
|
ORSH_ = uint32(gc.ORSH) << 16
|
|
OADD_ = uint32(gc.OADD) << 16
|
|
OSUB_ = uint32(gc.OSUB) << 16
|
|
OMUL_ = uint32(gc.OMUL) << 16
|
|
ODIV_ = uint32(gc.ODIV) << 16
|
|
OMOD_ = uint32(gc.OMOD) << 16
|
|
OOR_ = uint32(gc.OOR) << 16
|
|
OAND_ = uint32(gc.OAND) << 16
|
|
OXOR_ = uint32(gc.OXOR) << 16
|
|
OEQ_ = uint32(gc.OEQ) << 16
|
|
ONE_ = uint32(gc.ONE) << 16
|
|
OLT_ = uint32(gc.OLT) << 16
|
|
OLE_ = uint32(gc.OLE) << 16
|
|
OGE_ = uint32(gc.OGE) << 16
|
|
OGT_ = uint32(gc.OGT) << 16
|
|
OCMP_ = uint32(gc.OCMP) << 16
|
|
OPS_ = uint32(gc.OPS) << 16
|
|
OPC_ = uint32(gc.OPC) << 16
|
|
OAS_ = uint32(gc.OAS) << 16
|
|
OHMUL_ = uint32(gc.OHMUL) << 16
|
|
OSQRT_ = uint32(gc.OSQRT) << 16
|
|
OADDR_ = uint32(gc.OADDR) << 16
|
|
OINC_ = uint32(gc.OINC) << 16
|
|
ODEC_ = uint32(gc.ODEC) << 16
|
|
OLROT_ = uint32(gc.OLROT) << 16
|
|
ORROTC_ = uint32(gc.ORROTC) << 16
|
|
OEXTEND_ = uint32(gc.OEXTEND) << 16
|
|
)
|
|
|
|
a := obj.AXXX
|
|
switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
|
|
default:
|
|
gc.Fatalf("optoas: no entry %v-%v", gc.Oconv(op, 0), t)
|
|
|
|
case OADDR_ | gc.TPTR32:
|
|
a = x86.ALEAL
|
|
|
|
case OADDR_ | gc.TPTR64:
|
|
a = x86.ALEAQ
|
|
|
|
case OEQ_ | gc.TBOOL,
|
|
OEQ_ | gc.TINT8,
|
|
OEQ_ | gc.TUINT8,
|
|
OEQ_ | gc.TINT16,
|
|
OEQ_ | gc.TUINT16,
|
|
OEQ_ | gc.TINT32,
|
|
OEQ_ | gc.TUINT32,
|
|
OEQ_ | gc.TINT64,
|
|
OEQ_ | gc.TUINT64,
|
|
OEQ_ | gc.TPTR32,
|
|
OEQ_ | gc.TPTR64,
|
|
OEQ_ | gc.TFLOAT32,
|
|
OEQ_ | gc.TFLOAT64:
|
|
a = x86.AJEQ
|
|
|
|
case ONE_ | gc.TBOOL,
|
|
ONE_ | gc.TINT8,
|
|
ONE_ | gc.TUINT8,
|
|
ONE_ | gc.TINT16,
|
|
ONE_ | gc.TUINT16,
|
|
ONE_ | gc.TINT32,
|
|
ONE_ | gc.TUINT32,
|
|
ONE_ | gc.TINT64,
|
|
ONE_ | gc.TUINT64,
|
|
ONE_ | gc.TPTR32,
|
|
ONE_ | gc.TPTR64,
|
|
ONE_ | gc.TFLOAT32,
|
|
ONE_ | gc.TFLOAT64:
|
|
a = x86.AJNE
|
|
|
|
case OPS_ | gc.TBOOL,
|
|
OPS_ | gc.TINT8,
|
|
OPS_ | gc.TUINT8,
|
|
OPS_ | gc.TINT16,
|
|
OPS_ | gc.TUINT16,
|
|
OPS_ | gc.TINT32,
|
|
OPS_ | gc.TUINT32,
|
|
OPS_ | gc.TINT64,
|
|
OPS_ | gc.TUINT64,
|
|
OPS_ | gc.TPTR32,
|
|
OPS_ | gc.TPTR64,
|
|
OPS_ | gc.TFLOAT32,
|
|
OPS_ | gc.TFLOAT64:
|
|
a = x86.AJPS
|
|
|
|
case OPC_ | gc.TBOOL,
|
|
OPC_ | gc.TINT8,
|
|
OPC_ | gc.TUINT8,
|
|
OPC_ | gc.TINT16,
|
|
OPC_ | gc.TUINT16,
|
|
OPC_ | gc.TINT32,
|
|
OPC_ | gc.TUINT32,
|
|
OPC_ | gc.TINT64,
|
|
OPC_ | gc.TUINT64,
|
|
OPC_ | gc.TPTR32,
|
|
OPC_ | gc.TPTR64,
|
|
OPC_ | gc.TFLOAT32,
|
|
OPC_ | gc.TFLOAT64:
|
|
a = x86.AJPC
|
|
|
|
case OLT_ | gc.TINT8,
|
|
OLT_ | gc.TINT16,
|
|
OLT_ | gc.TINT32,
|
|
OLT_ | gc.TINT64:
|
|
a = x86.AJLT
|
|
|
|
case OLT_ | gc.TUINT8,
|
|
OLT_ | gc.TUINT16,
|
|
OLT_ | gc.TUINT32,
|
|
OLT_ | gc.TUINT64:
|
|
a = x86.AJCS
|
|
|
|
case OLE_ | gc.TINT8,
|
|
OLE_ | gc.TINT16,
|
|
OLE_ | gc.TINT32,
|
|
OLE_ | gc.TINT64:
|
|
a = x86.AJLE
|
|
|
|
case OLE_ | gc.TUINT8,
|
|
OLE_ | gc.TUINT16,
|
|
OLE_ | gc.TUINT32,
|
|
OLE_ | gc.TUINT64:
|
|
a = x86.AJLS
|
|
|
|
case OGT_ | gc.TINT8,
|
|
OGT_ | gc.TINT16,
|
|
OGT_ | gc.TINT32,
|
|
OGT_ | gc.TINT64:
|
|
a = x86.AJGT
|
|
|
|
case OGT_ | gc.TUINT8,
|
|
OGT_ | gc.TUINT16,
|
|
OGT_ | gc.TUINT32,
|
|
OGT_ | gc.TUINT64,
|
|
OLT_ | gc.TFLOAT32,
|
|
OLT_ | gc.TFLOAT64:
|
|
a = x86.AJHI
|
|
|
|
case OGE_ | gc.TINT8,
|
|
OGE_ | gc.TINT16,
|
|
OGE_ | gc.TINT32,
|
|
OGE_ | gc.TINT64:
|
|
a = x86.AJGE
|
|
|
|
case OGE_ | gc.TUINT8,
|
|
OGE_ | gc.TUINT16,
|
|
OGE_ | gc.TUINT32,
|
|
OGE_ | gc.TUINT64,
|
|
OLE_ | gc.TFLOAT32,
|
|
OLE_ | gc.TFLOAT64:
|
|
a = x86.AJCC
|
|
|
|
case OCMP_ | gc.TBOOL,
|
|
OCMP_ | gc.TINT8,
|
|
OCMP_ | gc.TUINT8:
|
|
a = x86.ACMPB
|
|
|
|
case OCMP_ | gc.TINT16,
|
|
OCMP_ | gc.TUINT16:
|
|
a = x86.ACMPW
|
|
|
|
case OCMP_ | gc.TINT32,
|
|
OCMP_ | gc.TUINT32,
|
|
OCMP_ | gc.TPTR32:
|
|
a = x86.ACMPL
|
|
|
|
case OCMP_ | gc.TINT64,
|
|
OCMP_ | gc.TUINT64,
|
|
OCMP_ | gc.TPTR64:
|
|
a = x86.ACMPQ
|
|
|
|
case OCMP_ | gc.TFLOAT32:
|
|
a = x86.AUCOMISS
|
|
|
|
case OCMP_ | gc.TFLOAT64:
|
|
a = x86.AUCOMISD
|
|
|
|
case OAS_ | gc.TBOOL,
|
|
OAS_ | gc.TINT8,
|
|
OAS_ | gc.TUINT8:
|
|
a = x86.AMOVB
|
|
|
|
case OAS_ | gc.TINT16,
|
|
OAS_ | gc.TUINT16:
|
|
a = x86.AMOVW
|
|
|
|
case OAS_ | gc.TINT32,
|
|
OAS_ | gc.TUINT32,
|
|
OAS_ | gc.TPTR32:
|
|
a = x86.AMOVL
|
|
|
|
case OAS_ | gc.TINT64,
|
|
OAS_ | gc.TUINT64,
|
|
OAS_ | gc.TPTR64:
|
|
a = x86.AMOVQ
|
|
|
|
case OAS_ | gc.TFLOAT32:
|
|
a = x86.AMOVSS
|
|
|
|
case OAS_ | gc.TFLOAT64:
|
|
a = x86.AMOVSD
|
|
|
|
case OADD_ | gc.TINT8,
|
|
OADD_ | gc.TUINT8:
|
|
a = x86.AADDB
|
|
|
|
case OADD_ | gc.TINT16,
|
|
OADD_ | gc.TUINT16:
|
|
a = x86.AADDW
|
|
|
|
case OADD_ | gc.TINT32,
|
|
OADD_ | gc.TUINT32,
|
|
OADD_ | gc.TPTR32:
|
|
a = x86.AADDL
|
|
|
|
case OADD_ | gc.TINT64,
|
|
OADD_ | gc.TUINT64,
|
|
OADD_ | gc.TPTR64:
|
|
a = x86.AADDQ
|
|
|
|
case OADD_ | gc.TFLOAT32:
|
|
a = x86.AADDSS
|
|
|
|
case OADD_ | gc.TFLOAT64:
|
|
a = x86.AADDSD
|
|
|
|
case OSUB_ | gc.TINT8,
|
|
OSUB_ | gc.TUINT8:
|
|
a = x86.ASUBB
|
|
|
|
case OSUB_ | gc.TINT16,
|
|
OSUB_ | gc.TUINT16:
|
|
a = x86.ASUBW
|
|
|
|
case OSUB_ | gc.TINT32,
|
|
OSUB_ | gc.TUINT32,
|
|
OSUB_ | gc.TPTR32:
|
|
a = x86.ASUBL
|
|
|
|
case OSUB_ | gc.TINT64,
|
|
OSUB_ | gc.TUINT64,
|
|
OSUB_ | gc.TPTR64:
|
|
a = x86.ASUBQ
|
|
|
|
case OSUB_ | gc.TFLOAT32:
|
|
a = x86.ASUBSS
|
|
|
|
case OSUB_ | gc.TFLOAT64:
|
|
a = x86.ASUBSD
|
|
|
|
case OINC_ | gc.TINT8,
|
|
OINC_ | gc.TUINT8:
|
|
a = x86.AINCB
|
|
|
|
case OINC_ | gc.TINT16,
|
|
OINC_ | gc.TUINT16:
|
|
a = x86.AINCW
|
|
|
|
case OINC_ | gc.TINT32,
|
|
OINC_ | gc.TUINT32,
|
|
OINC_ | gc.TPTR32:
|
|
a = x86.AINCL
|
|
|
|
case OINC_ | gc.TINT64,
|
|
OINC_ | gc.TUINT64,
|
|
OINC_ | gc.TPTR64:
|
|
a = x86.AINCQ
|
|
|
|
case ODEC_ | gc.TINT8,
|
|
ODEC_ | gc.TUINT8:
|
|
a = x86.ADECB
|
|
|
|
case ODEC_ | gc.TINT16,
|
|
ODEC_ | gc.TUINT16:
|
|
a = x86.ADECW
|
|
|
|
case ODEC_ | gc.TINT32,
|
|
ODEC_ | gc.TUINT32,
|
|
ODEC_ | gc.TPTR32:
|
|
a = x86.ADECL
|
|
|
|
case ODEC_ | gc.TINT64,
|
|
ODEC_ | gc.TUINT64,
|
|
ODEC_ | gc.TPTR64:
|
|
a = x86.ADECQ
|
|
|
|
case OMINUS_ | gc.TINT8,
|
|
OMINUS_ | gc.TUINT8:
|
|
a = x86.ANEGB
|
|
|
|
case OMINUS_ | gc.TINT16,
|
|
OMINUS_ | gc.TUINT16:
|
|
a = x86.ANEGW
|
|
|
|
case OMINUS_ | gc.TINT32,
|
|
OMINUS_ | gc.TUINT32,
|
|
OMINUS_ | gc.TPTR32:
|
|
a = x86.ANEGL
|
|
|
|
case OMINUS_ | gc.TINT64,
|
|
OMINUS_ | gc.TUINT64,
|
|
OMINUS_ | gc.TPTR64:
|
|
a = x86.ANEGQ
|
|
|
|
case OAND_ | gc.TBOOL,
|
|
OAND_ | gc.TINT8,
|
|
OAND_ | gc.TUINT8:
|
|
a = x86.AANDB
|
|
|
|
case OAND_ | gc.TINT16,
|
|
OAND_ | gc.TUINT16:
|
|
a = x86.AANDW
|
|
|
|
case OAND_ | gc.TINT32,
|
|
OAND_ | gc.TUINT32,
|
|
OAND_ | gc.TPTR32:
|
|
a = x86.AANDL
|
|
|
|
case OAND_ | gc.TINT64,
|
|
OAND_ | gc.TUINT64,
|
|
OAND_ | gc.TPTR64:
|
|
a = x86.AANDQ
|
|
|
|
case OOR_ | gc.TBOOL,
|
|
OOR_ | gc.TINT8,
|
|
OOR_ | gc.TUINT8:
|
|
a = x86.AORB
|
|
|
|
case OOR_ | gc.TINT16,
|
|
OOR_ | gc.TUINT16:
|
|
a = x86.AORW
|
|
|
|
case OOR_ | gc.TINT32,
|
|
OOR_ | gc.TUINT32,
|
|
OOR_ | gc.TPTR32:
|
|
a = x86.AORL
|
|
|
|
case OOR_ | gc.TINT64,
|
|
OOR_ | gc.TUINT64,
|
|
OOR_ | gc.TPTR64:
|
|
a = x86.AORQ
|
|
|
|
case OXOR_ | gc.TINT8,
|
|
OXOR_ | gc.TUINT8:
|
|
a = x86.AXORB
|
|
|
|
case OXOR_ | gc.TINT16,
|
|
OXOR_ | gc.TUINT16:
|
|
a = x86.AXORW
|
|
|
|
case OXOR_ | gc.TINT32,
|
|
OXOR_ | gc.TUINT32,
|
|
OXOR_ | gc.TPTR32:
|
|
a = x86.AXORL
|
|
|
|
case OXOR_ | gc.TINT64,
|
|
OXOR_ | gc.TUINT64,
|
|
OXOR_ | gc.TPTR64:
|
|
a = x86.AXORQ
|
|
|
|
case OLROT_ | gc.TINT8,
|
|
OLROT_ | gc.TUINT8:
|
|
a = x86.AROLB
|
|
|
|
case OLROT_ | gc.TINT16,
|
|
OLROT_ | gc.TUINT16:
|
|
a = x86.AROLW
|
|
|
|
case OLROT_ | gc.TINT32,
|
|
OLROT_ | gc.TUINT32,
|
|
OLROT_ | gc.TPTR32:
|
|
a = x86.AROLL
|
|
|
|
case OLROT_ | gc.TINT64,
|
|
OLROT_ | gc.TUINT64,
|
|
OLROT_ | gc.TPTR64:
|
|
a = x86.AROLQ
|
|
|
|
case OLSH_ | gc.TINT8,
|
|
OLSH_ | gc.TUINT8:
|
|
a = x86.ASHLB
|
|
|
|
case OLSH_ | gc.TINT16,
|
|
OLSH_ | gc.TUINT16:
|
|
a = x86.ASHLW
|
|
|
|
case OLSH_ | gc.TINT32,
|
|
OLSH_ | gc.TUINT32,
|
|
OLSH_ | gc.TPTR32:
|
|
a = x86.ASHLL
|
|
|
|
case OLSH_ | gc.TINT64,
|
|
OLSH_ | gc.TUINT64,
|
|
OLSH_ | gc.TPTR64:
|
|
a = x86.ASHLQ
|
|
|
|
case ORSH_ | gc.TUINT8:
|
|
a = x86.ASHRB
|
|
|
|
case ORSH_ | gc.TUINT16:
|
|
a = x86.ASHRW
|
|
|
|
case ORSH_ | gc.TUINT32,
|
|
ORSH_ | gc.TPTR32:
|
|
a = x86.ASHRL
|
|
|
|
case ORSH_ | gc.TUINT64,
|
|
ORSH_ | gc.TPTR64:
|
|
a = x86.ASHRQ
|
|
|
|
case ORSH_ | gc.TINT8:
|
|
a = x86.ASARB
|
|
|
|
case ORSH_ | gc.TINT16:
|
|
a = x86.ASARW
|
|
|
|
case ORSH_ | gc.TINT32:
|
|
a = x86.ASARL
|
|
|
|
case ORSH_ | gc.TINT64:
|
|
a = x86.ASARQ
|
|
|
|
case ORROTC_ | gc.TINT8,
|
|
ORROTC_ | gc.TUINT8:
|
|
a = x86.ARCRB
|
|
|
|
case ORROTC_ | gc.TINT16,
|
|
ORROTC_ | gc.TUINT16:
|
|
a = x86.ARCRW
|
|
|
|
case ORROTC_ | gc.TINT32,
|
|
ORROTC_ | gc.TUINT32:
|
|
a = x86.ARCRL
|
|
|
|
case ORROTC_ | gc.TINT64,
|
|
ORROTC_ | gc.TUINT64:
|
|
a = x86.ARCRQ
|
|
|
|
case OHMUL_ | gc.TINT8,
|
|
OMUL_ | gc.TINT8,
|
|
OMUL_ | gc.TUINT8:
|
|
a = x86.AIMULB
|
|
|
|
case OHMUL_ | gc.TINT16,
|
|
OMUL_ | gc.TINT16,
|
|
OMUL_ | gc.TUINT16:
|
|
a = x86.AIMULW
|
|
|
|
case OHMUL_ | gc.TINT32,
|
|
OMUL_ | gc.TINT32,
|
|
OMUL_ | gc.TUINT32,
|
|
OMUL_ | gc.TPTR32:
|
|
a = x86.AIMULL
|
|
|
|
case OHMUL_ | gc.TINT64,
|
|
OMUL_ | gc.TINT64,
|
|
OMUL_ | gc.TUINT64,
|
|
OMUL_ | gc.TPTR64:
|
|
a = x86.AIMULQ
|
|
|
|
case OHMUL_ | gc.TUINT8:
|
|
a = x86.AMULB
|
|
|
|
case OHMUL_ | gc.TUINT16:
|
|
a = x86.AMULW
|
|
|
|
case OHMUL_ | gc.TUINT32,
|
|
OHMUL_ | gc.TPTR32:
|
|
a = x86.AMULL
|
|
|
|
case OHMUL_ | gc.TUINT64,
|
|
OHMUL_ | gc.TPTR64:
|
|
a = x86.AMULQ
|
|
|
|
case OMUL_ | gc.TFLOAT32:
|
|
a = x86.AMULSS
|
|
|
|
case OMUL_ | gc.TFLOAT64:
|
|
a = x86.AMULSD
|
|
|
|
case ODIV_ | gc.TINT8,
|
|
OMOD_ | gc.TINT8:
|
|
a = x86.AIDIVB
|
|
|
|
case ODIV_ | gc.TUINT8,
|
|
OMOD_ | gc.TUINT8:
|
|
a = x86.ADIVB
|
|
|
|
case ODIV_ | gc.TINT16,
|
|
OMOD_ | gc.TINT16:
|
|
a = x86.AIDIVW
|
|
|
|
case ODIV_ | gc.TUINT16,
|
|
OMOD_ | gc.TUINT16:
|
|
a = x86.ADIVW
|
|
|
|
case ODIV_ | gc.TINT32,
|
|
OMOD_ | gc.TINT32:
|
|
a = x86.AIDIVL
|
|
|
|
case ODIV_ | gc.TUINT32,
|
|
ODIV_ | gc.TPTR32,
|
|
OMOD_ | gc.TUINT32,
|
|
OMOD_ | gc.TPTR32:
|
|
a = x86.ADIVL
|
|
|
|
case ODIV_ | gc.TINT64,
|
|
OMOD_ | gc.TINT64:
|
|
a = x86.AIDIVQ
|
|
|
|
case ODIV_ | gc.TUINT64,
|
|
ODIV_ | gc.TPTR64,
|
|
OMOD_ | gc.TUINT64,
|
|
OMOD_ | gc.TPTR64:
|
|
a = x86.ADIVQ
|
|
|
|
case OEXTEND_ | gc.TINT16:
|
|
a = x86.ACWD
|
|
|
|
case OEXTEND_ | gc.TINT32:
|
|
a = x86.ACDQ
|
|
|
|
case OEXTEND_ | gc.TINT64:
|
|
a = x86.ACQO
|
|
|
|
case ODIV_ | gc.TFLOAT32:
|
|
a = x86.ADIVSS
|
|
|
|
case ODIV_ | gc.TFLOAT64:
|
|
a = x86.ADIVSD
|
|
|
|
case OSQRT_ | gc.TFLOAT64:
|
|
a = x86.ASQRTSD
|
|
}
|
|
|
|
return a
|
|
}
|
|
|
|
// jmptoset returns ASETxx for AJxx.
|
|
func jmptoset(jmp obj.As) obj.As {
|
|
switch jmp {
|
|
case x86.AJEQ:
|
|
return x86.ASETEQ
|
|
case x86.AJNE:
|
|
return x86.ASETNE
|
|
case x86.AJLT:
|
|
return x86.ASETLT
|
|
case x86.AJCS:
|
|
return x86.ASETCS
|
|
case x86.AJLE:
|
|
return x86.ASETLE
|
|
case x86.AJLS:
|
|
return x86.ASETLS
|
|
case x86.AJGT:
|
|
return x86.ASETGT
|
|
case x86.AJHI:
|
|
return x86.ASETHI
|
|
case x86.AJGE:
|
|
return x86.ASETGE
|
|
case x86.AJCC:
|
|
return x86.ASETCC
|
|
case x86.AJMI:
|
|
return x86.ASETMI
|
|
case x86.AJOC:
|
|
return x86.ASETOC
|
|
case x86.AJOS:
|
|
return x86.ASETOS
|
|
case x86.AJPC:
|
|
return x86.ASETPC
|
|
case x86.AJPL:
|
|
return x86.ASETPL
|
|
case x86.AJPS:
|
|
return x86.ASETPS
|
|
}
|
|
gc.Fatalf("jmptoset: no entry for %v", jmp)
|
|
panic("unreachable")
|
|
}
|
|
|
|
const (
|
|
ODynam = 1 << 0
|
|
OAddable = 1 << 1
|
|
)
|
|
|
|
var clean [20]gc.Node
|
|
|
|
var cleani int = 0
|
|
|
|
func sudoclean() {
|
|
if clean[cleani-1].Op != gc.OEMPTY {
|
|
gc.Regfree(&clean[cleani-1])
|
|
}
|
|
if clean[cleani-2].Op != gc.OEMPTY {
|
|
gc.Regfree(&clean[cleani-2])
|
|
}
|
|
cleani -= 2
|
|
}
|
|
|
|
/*
|
|
* generate code to compute address of n,
|
|
* a reference to a (perhaps nested) field inside
|
|
* an array or struct.
|
|
* return 0 on failure, 1 on success.
|
|
* on success, leaves usable address in a.
|
|
*
|
|
* caller is responsible for calling sudoclean
|
|
* after successful sudoaddable,
|
|
* to release the register used for a.
|
|
*/
|
|
func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool {
|
|
if n.Type == nil {
|
|
return false
|
|
}
|
|
|
|
*a = obj.Addr{}
|
|
|
|
switch n.Op {
|
|
case gc.OLITERAL:
|
|
if !gc.Isconst(n, gc.CTINT) {
|
|
break
|
|
}
|
|
v := n.Int()
|
|
if v >= 32000 || v <= -32000 {
|
|
break
|
|
}
|
|
switch as {
|
|
default:
|
|
return false
|
|
|
|
case x86.AADDB,
|
|
x86.AADDW,
|
|
x86.AADDL,
|
|
x86.AADDQ,
|
|
x86.ASUBB,
|
|
x86.ASUBW,
|
|
x86.ASUBL,
|
|
x86.ASUBQ,
|
|
x86.AANDB,
|
|
x86.AANDW,
|
|
x86.AANDL,
|
|
x86.AANDQ,
|
|
x86.AORB,
|
|
x86.AORW,
|
|
x86.AORL,
|
|
x86.AORQ,
|
|
x86.AXORB,
|
|
x86.AXORW,
|
|
x86.AXORL,
|
|
x86.AXORQ,
|
|
x86.AINCB,
|
|
x86.AINCW,
|
|
x86.AINCL,
|
|
x86.AINCQ,
|
|
x86.ADECB,
|
|
x86.ADECW,
|
|
x86.ADECL,
|
|
x86.ADECQ,
|
|
x86.AMOVB,
|
|
x86.AMOVW,
|
|
x86.AMOVL,
|
|
x86.AMOVQ:
|
|
break
|
|
}
|
|
|
|
cleani += 2
|
|
reg := &clean[cleani-1]
|
|
reg1 := &clean[cleani-2]
|
|
reg.Op = gc.OEMPTY
|
|
reg1.Op = gc.OEMPTY
|
|
gc.Naddr(a, n)
|
|
return true
|
|
|
|
case gc.ODOT,
|
|
gc.ODOTPTR:
|
|
cleani += 2
|
|
reg := &clean[cleani-1]
|
|
reg1 := &clean[cleani-2]
|
|
reg.Op = gc.OEMPTY
|
|
reg1.Op = gc.OEMPTY
|
|
var nn *gc.Node
|
|
var oary [10]int64
|
|
o := gc.Dotoffset(n, oary[:], &nn)
|
|
if nn == nil {
|
|
sudoclean()
|
|
return false
|
|
}
|
|
|
|
if nn.Addable && o == 1 && oary[0] >= 0 {
|
|
// directly addressable set of DOTs
|
|
n1 := *nn
|
|
|
|
n1.Type = n.Type
|
|
n1.Xoffset += oary[0]
|
|
gc.Naddr(a, &n1)
|
|
return true
|
|
}
|
|
|
|
gc.Regalloc(reg, gc.Types[gc.Tptr], nil)
|
|
n1 := *reg
|
|
n1.Op = gc.OINDREG
|
|
if oary[0] >= 0 {
|
|
gc.Agen(nn, reg)
|
|
n1.Xoffset = oary[0]
|
|
} else {
|
|
gc.Cgen(nn, reg)
|
|
gc.Cgen_checknil(reg)
|
|
n1.Xoffset = -(oary[0] + 1)
|
|
}
|
|
|
|
for i := 1; i < o; i++ {
|
|
if oary[i] >= 0 {
|
|
gc.Fatalf("can't happen")
|
|
}
|
|
gins(movptr, &n1, reg)
|
|
gc.Cgen_checknil(reg)
|
|
n1.Xoffset = -(oary[i] + 1)
|
|
}
|
|
|
|
a.Type = obj.TYPE_NONE
|
|
a.Index = x86.REG_NONE
|
|
gc.Fixlargeoffset(&n1)
|
|
gc.Naddr(a, &n1)
|
|
return true
|
|
|
|
case gc.OINDEX:
|
|
return false
|
|
}
|
|
|
|
return false
|
|
}
|