mirror of
https://github.com/golang/go
synced 2024-09-25 09:20:18 -06:00
cmd/compile/internal/mips64: copy cmd/compile/internal/ppc64
Just a mechanical copy, no code changes. This is to reduce code difference when adding the mips64 port. Change-Id: Id06e975f414a7b09f4827167b30813b228a3bfaf Reviewed-on: https://go-review.googlesource.com/14324 Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
5cc86c6f55
commit
14f919578d
149
src/cmd/compile/internal/mips64/cgen.go
Normal file
149
src/cmd/compile/internal/mips64/cgen.go
Normal file
@ -0,0 +1,149 @@
|
||||
// Copyright 2009 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 ppc64
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/ppc64"
|
||||
)
|
||||
|
||||
func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
|
||||
// determine alignment.
|
||||
// want to avoid unaligned access, so have to use
|
||||
// smaller operations for less aligned types.
|
||||
// for example moving [4]byte must use 4 MOVB not 1 MOVW.
|
||||
align := int(n.Type.Align)
|
||||
|
||||
var op int
|
||||
switch align {
|
||||
default:
|
||||
gc.Fatalf("sgen: invalid alignment %d for %v", align, n.Type)
|
||||
|
||||
case 1:
|
||||
op = ppc64.AMOVBU
|
||||
|
||||
case 2:
|
||||
op = ppc64.AMOVHU
|
||||
|
||||
case 4:
|
||||
op = ppc64.AMOVWZU // there is no lwau, only lwaux
|
||||
|
||||
case 8:
|
||||
op = ppc64.AMOVDU
|
||||
}
|
||||
|
||||
if w%int64(align) != 0 {
|
||||
gc.Fatalf("sgen: unaligned size %d (align=%d) for %v", w, align, n.Type)
|
||||
}
|
||||
c := int32(w / int64(align))
|
||||
|
||||
// if we are copying forward on the stack and
|
||||
// the src and dst overlap, then reverse direction
|
||||
dir := align
|
||||
|
||||
if osrc < odst && int64(odst) < int64(osrc)+w {
|
||||
dir = -dir
|
||||
}
|
||||
|
||||
var dst gc.Node
|
||||
var src gc.Node
|
||||
if n.Ullman >= res.Ullman {
|
||||
gc.Agenr(n, &dst, res) // temporarily use dst
|
||||
gc.Regalloc(&src, gc.Types[gc.Tptr], nil)
|
||||
gins(ppc64.AMOVD, &dst, &src)
|
||||
if res.Op == gc.ONAME {
|
||||
gc.Gvardef(res)
|
||||
}
|
||||
gc.Agen(res, &dst)
|
||||
} else {
|
||||
if res.Op == gc.ONAME {
|
||||
gc.Gvardef(res)
|
||||
}
|
||||
gc.Agenr(res, &dst, res)
|
||||
gc.Agenr(n, &src, nil)
|
||||
}
|
||||
|
||||
var tmp gc.Node
|
||||
gc.Regalloc(&tmp, gc.Types[gc.Tptr], nil)
|
||||
|
||||
// set up end marker
|
||||
var nend gc.Node
|
||||
|
||||
// move src and dest to the end of block if necessary
|
||||
if dir < 0 {
|
||||
if c >= 4 {
|
||||
gc.Regalloc(&nend, gc.Types[gc.Tptr], nil)
|
||||
gins(ppc64.AMOVD, &src, &nend)
|
||||
}
|
||||
|
||||
p := gins(ppc64.AADD, nil, &src)
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = w
|
||||
|
||||
p = gins(ppc64.AADD, nil, &dst)
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = w
|
||||
} else {
|
||||
p := gins(ppc64.AADD, nil, &src)
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = int64(-dir)
|
||||
|
||||
p = gins(ppc64.AADD, nil, &dst)
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = int64(-dir)
|
||||
|
||||
if c >= 4 {
|
||||
gc.Regalloc(&nend, gc.Types[gc.Tptr], nil)
|
||||
p := gins(ppc64.AMOVD, &src, &nend)
|
||||
p.From.Type = obj.TYPE_ADDR
|
||||
p.From.Offset = w
|
||||
}
|
||||
}
|
||||
|
||||
// move
|
||||
// TODO: enable duffcopy for larger copies.
|
||||
if c >= 4 {
|
||||
p := gins(op, &src, &tmp)
|
||||
p.From.Type = obj.TYPE_MEM
|
||||
p.From.Offset = int64(dir)
|
||||
ploop := p
|
||||
|
||||
p = gins(op, &tmp, &dst)
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Offset = int64(dir)
|
||||
|
||||
p = gins(ppc64.ACMP, &src, &nend)
|
||||
|
||||
gc.Patch(gc.Gbranch(ppc64.ABNE, nil, 0), ploop)
|
||||
gc.Regfree(&nend)
|
||||
} else {
|
||||
// TODO(austin): Instead of generating ADD $-8,R8; ADD
|
||||
// $-8,R7; n*(MOVDU 8(R8),R9; MOVDU R9,8(R7);) just
|
||||
// generate the offsets directly and eliminate the
|
||||
// ADDs. That will produce shorter, more
|
||||
// pipeline-able code.
|
||||
var p *obj.Prog
|
||||
for {
|
||||
tmp14 := c
|
||||
c--
|
||||
if tmp14 <= 0 {
|
||||
break
|
||||
}
|
||||
|
||||
p = gins(op, &src, &tmp)
|
||||
p.From.Type = obj.TYPE_MEM
|
||||
p.From.Offset = int64(dir)
|
||||
|
||||
p = gins(op, &tmp, &dst)
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Offset = int64(dir)
|
||||
}
|
||||
}
|
||||
|
||||
gc.Regfree(&dst)
|
||||
gc.Regfree(&src)
|
||||
gc.Regfree(&tmp)
|
||||
}
|
100
src/cmd/compile/internal/mips64/galign.go
Normal file
100
src/cmd/compile/internal/mips64/galign.go
Normal file
@ -0,0 +1,100 @@
|
||||
// Copyright 2009 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 ppc64
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/ppc64"
|
||||
)
|
||||
|
||||
var thechar int = '9'
|
||||
|
||||
var thestring string = "ppc64"
|
||||
|
||||
var thelinkarch *obj.LinkArch
|
||||
|
||||
func linkarchinit() {
|
||||
thestring = obj.Getgoarch()
|
||||
gc.Thearch.Thestring = thestring
|
||||
if thestring == "ppc64le" {
|
||||
thelinkarch = &ppc64.Linkppc64le
|
||||
} else {
|
||||
thelinkarch = &ppc64.Linkppc64
|
||||
}
|
||||
gc.Thearch.Thelinkarch = thelinkarch
|
||||
}
|
||||
|
||||
var MAXWIDTH int64 = 1 << 50
|
||||
|
||||
/*
|
||||
* go declares several platform-specific type aliases:
|
||||
* int, uint, and uintptr
|
||||
*/
|
||||
var typedefs = []gc.Typedef{
|
||||
{"int", gc.TINT, gc.TINT64},
|
||||
{"uint", gc.TUINT, gc.TUINT64},
|
||||
{"uintptr", gc.TUINTPTR, gc.TUINT64},
|
||||
}
|
||||
|
||||
func betypeinit() {
|
||||
gc.Widthptr = 8
|
||||
gc.Widthint = 8
|
||||
gc.Widthreg = 8
|
||||
}
|
||||
|
||||
func Main() {
|
||||
gc.Thearch.Thechar = thechar
|
||||
gc.Thearch.Thestring = thestring
|
||||
gc.Thearch.Thelinkarch = thelinkarch
|
||||
gc.Thearch.Typedefs = typedefs
|
||||
gc.Thearch.REGSP = ppc64.REGSP
|
||||
gc.Thearch.REGCTXT = ppc64.REGCTXT
|
||||
gc.Thearch.REGCALLX = ppc64.REG_R3
|
||||
gc.Thearch.REGCALLX2 = ppc64.REG_R4
|
||||
gc.Thearch.REGRETURN = ppc64.REG_R3
|
||||
gc.Thearch.REGMIN = ppc64.REG_R0
|
||||
gc.Thearch.REGMAX = ppc64.REG_R31
|
||||
gc.Thearch.FREGMIN = ppc64.REG_F0
|
||||
gc.Thearch.FREGMAX = ppc64.REG_F31
|
||||
gc.Thearch.MAXWIDTH = MAXWIDTH
|
||||
gc.Thearch.ReservedRegs = resvd
|
||||
|
||||
gc.Thearch.Betypeinit = betypeinit
|
||||
gc.Thearch.Cgen_hmul = cgen_hmul
|
||||
gc.Thearch.Cgen_shift = cgen_shift
|
||||
gc.Thearch.Clearfat = clearfat
|
||||
gc.Thearch.Defframe = defframe
|
||||
gc.Thearch.Dodiv = dodiv
|
||||
gc.Thearch.Excise = excise
|
||||
gc.Thearch.Expandchecks = expandchecks
|
||||
gc.Thearch.Getg = getg
|
||||
gc.Thearch.Gins = gins
|
||||
gc.Thearch.Ginscmp = ginscmp
|
||||
gc.Thearch.Ginscon = ginscon
|
||||
gc.Thearch.Ginsnop = ginsnop
|
||||
gc.Thearch.Gmove = gmove
|
||||
gc.Thearch.Linkarchinit = linkarchinit
|
||||
gc.Thearch.Peep = peep
|
||||
gc.Thearch.Proginfo = proginfo
|
||||
gc.Thearch.Regtyp = regtyp
|
||||
gc.Thearch.Sameaddr = sameaddr
|
||||
gc.Thearch.Smallindir = smallindir
|
||||
gc.Thearch.Stackaddr = stackaddr
|
||||
gc.Thearch.Blockcopy = blockcopy
|
||||
gc.Thearch.Sudoaddable = sudoaddable
|
||||
gc.Thearch.Sudoclean = sudoclean
|
||||
gc.Thearch.Excludedregs = excludedregs
|
||||
gc.Thearch.RtoB = RtoB
|
||||
gc.Thearch.FtoB = RtoB
|
||||
gc.Thearch.BtoR = BtoR
|
||||
gc.Thearch.BtoF = BtoF
|
||||
gc.Thearch.Optoas = optoas
|
||||
gc.Thearch.Doregbits = doregbits
|
||||
gc.Thearch.Regnames = regnames
|
||||
|
||||
gc.Main()
|
||||
gc.Exit(0)
|
||||
}
|
564
src/cmd/compile/internal/mips64/ggen.go
Normal file
564
src/cmd/compile/internal/mips64/ggen.go
Normal file
@ -0,0 +1,564 @@
|
||||
// Copyright 2009 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 ppc64
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/ppc64"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func defframe(ptxt *obj.Prog) {
|
||||
var n *gc.Node
|
||||
|
||||
// fill in argument size, stack size
|
||||
ptxt.To.Type = obj.TYPE_TEXTSIZE
|
||||
|
||||
ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr)))
|
||||
frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
|
||||
ptxt.To.Offset = int64(frame)
|
||||
|
||||
// insert code to zero ambiguously live variables
|
||||
// so that the garbage collector only sees initialized values
|
||||
// when it looks for pointers.
|
||||
p := ptxt
|
||||
|
||||
hi := int64(0)
|
||||
lo := hi
|
||||
|
||||
// iterate through declarations - they are sorted in decreasing xoffset order.
|
||||
for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
|
||||
n = l.N
|
||||
if !n.Name.Needzero {
|
||||
continue
|
||||
}
|
||||
if n.Class != gc.PAUTO {
|
||||
gc.Fatalf("needzero class %d", n.Class)
|
||||
}
|
||||
if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
|
||||
gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset))
|
||||
}
|
||||
|
||||
if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) {
|
||||
// merge with range we already have
|
||||
lo = n.Xoffset
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// zero old range
|
||||
p = zerorange(p, int64(frame), lo, hi)
|
||||
|
||||
// set new range
|
||||
hi = n.Xoffset + n.Type.Width
|
||||
|
||||
lo = n.Xoffset
|
||||
}
|
||||
|
||||
// zero final range
|
||||
zerorange(p, int64(frame), lo, hi)
|
||||
}
|
||||
|
||||
func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
|
||||
cnt := hi - lo
|
||||
if cnt == 0 {
|
||||
return p
|
||||
}
|
||||
if cnt < int64(4*gc.Widthptr) {
|
||||
for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
|
||||
p = appendpp(p, ppc64.AMOVD, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGSP, 8+frame+lo+i)
|
||||
}
|
||||
// TODO(dfc): https://golang.org/issue/12108
|
||||
// If DUFFZERO is used inside a tail call (see genwrapper) it will
|
||||
// overwrite the link register.
|
||||
} else if false && cnt <= int64(128*gc.Widthptr) {
|
||||
p = appendpp(p, ppc64.AADD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, ppc64.REGRT1, 0)
|
||||
p.Reg = ppc64.REGSP
|
||||
p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
|
||||
f := gc.Sysfunc("duffzero")
|
||||
gc.Naddr(&p.To, f)
|
||||
gc.Afunclit(&p.To, f)
|
||||
p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
|
||||
} else {
|
||||
p = appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, ppc64.REGTMP, 0)
|
||||
p = appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT1, 0)
|
||||
p.Reg = ppc64.REGSP
|
||||
p = appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, ppc64.REGTMP, 0)
|
||||
p = appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT2, 0)
|
||||
p.Reg = ppc64.REGRT1
|
||||
p = appendpp(p, ppc64.AMOVDU, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGRT1, int64(gc.Widthptr))
|
||||
p1 := p
|
||||
p = appendpp(p, ppc64.ACMP, obj.TYPE_REG, ppc64.REGRT1, 0, obj.TYPE_REG, ppc64.REGRT2, 0)
|
||||
p = appendpp(p, ppc64.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
|
||||
gc.Patch(p, p1)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int64, ttype int, treg int, toffset int64) *obj.Prog {
|
||||
q := gc.Ctxt.NewProg()
|
||||
gc.Clearp(q)
|
||||
q.As = int16(as)
|
||||
q.Lineno = p.Lineno
|
||||
q.From.Type = int16(ftype)
|
||||
q.From.Reg = int16(freg)
|
||||
q.From.Offset = foffset
|
||||
q.To.Type = int16(ttype)
|
||||
q.To.Reg = int16(treg)
|
||||
q.To.Offset = toffset
|
||||
q.Link = p.Link
|
||||
p.Link = q
|
||||
return q
|
||||
}
|
||||
|
||||
func ginsnop() {
|
||||
var reg gc.Node
|
||||
gc.Nodreg(®, gc.Types[gc.TINT], ppc64.REG_R0)
|
||||
gins(ppc64.AOR, ®, ®)
|
||||
}
|
||||
|
||||
var panicdiv *gc.Node
|
||||
|
||||
/*
|
||||
* generate division.
|
||||
* generates one of:
|
||||
* res = nl / nr
|
||||
* res = nl % nr
|
||||
* according to op.
|
||||
*/
|
||||
func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
|
||||
// Have to be careful about handling
|
||||
// most negative int divided by -1 correctly.
|
||||
// The hardware will generate undefined result.
|
||||
// Also need to explicitly trap on division on zero,
|
||||
// the hardware will silently generate undefined result.
|
||||
// DIVW will leave unpredicable result in higher 32-bit,
|
||||
// so always use DIVD/DIVDU.
|
||||
t := nl.Type
|
||||
|
||||
t0 := t
|
||||
check := 0
|
||||
if gc.Issigned[t.Etype] {
|
||||
check = 1
|
||||
if gc.Isconst(nl, gc.CTINT) && nl.Int() != -(1<<uint64(t.Width*8-1)) {
|
||||
check = 0
|
||||
} else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 {
|
||||
check = 0
|
||||
}
|
||||
}
|
||||
|
||||
if t.Width < 8 {
|
||||
if gc.Issigned[t.Etype] {
|
||||
t = gc.Types[gc.TINT64]
|
||||
} else {
|
||||
t = gc.Types[gc.TUINT64]
|
||||
}
|
||||
check = 0
|
||||
}
|
||||
|
||||
a := optoas(gc.ODIV, t)
|
||||
|
||||
var tl gc.Node
|
||||
gc.Regalloc(&tl, t0, nil)
|
||||
var tr gc.Node
|
||||
gc.Regalloc(&tr, t0, nil)
|
||||
if nl.Ullman >= nr.Ullman {
|
||||
gc.Cgen(nl, &tl)
|
||||
gc.Cgen(nr, &tr)
|
||||
} else {
|
||||
gc.Cgen(nr, &tr)
|
||||
gc.Cgen(nl, &tl)
|
||||
}
|
||||
|
||||
if t != t0 {
|
||||
// Convert
|
||||
tl2 := tl
|
||||
|
||||
tr2 := tr
|
||||
tl.Type = t
|
||||
tr.Type = t
|
||||
gmove(&tl2, &tl)
|
||||
gmove(&tr2, &tr)
|
||||
}
|
||||
|
||||
// Handle divide-by-zero panic.
|
||||
p1 := gins(optoas(gc.OCMP, t), &tr, nil)
|
||||
|
||||
p1.To.Type = obj.TYPE_REG
|
||||
p1.To.Reg = ppc64.REGZERO
|
||||
p1 = gc.Gbranch(optoas(gc.ONE, t), nil, +1)
|
||||
if panicdiv == nil {
|
||||
panicdiv = gc.Sysfunc("panicdivide")
|
||||
}
|
||||
gc.Ginscall(panicdiv, -1)
|
||||
gc.Patch(p1, gc.Pc)
|
||||
|
||||
var p2 *obj.Prog
|
||||
if check != 0 {
|
||||
var nm1 gc.Node
|
||||
gc.Nodconst(&nm1, t, -1)
|
||||
gins(optoas(gc.OCMP, t), &tr, &nm1)
|
||||
p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
|
||||
if op == gc.ODIV {
|
||||
// a / (-1) is -a.
|
||||
gins(optoas(gc.OMINUS, t), nil, &tl)
|
||||
|
||||
gmove(&tl, res)
|
||||
} else {
|
||||
// a % (-1) is 0.
|
||||
var nz gc.Node
|
||||
gc.Nodconst(&nz, t, 0)
|
||||
|
||||
gmove(&nz, res)
|
||||
}
|
||||
|
||||
p2 = gc.Gbranch(obj.AJMP, nil, 0)
|
||||
gc.Patch(p1, gc.Pc)
|
||||
}
|
||||
|
||||
p1 = gins(a, &tr, &tl)
|
||||
if op == gc.ODIV {
|
||||
gc.Regfree(&tr)
|
||||
gmove(&tl, res)
|
||||
} else {
|
||||
// A%B = A-(A/B*B)
|
||||
var tm gc.Node
|
||||
gc.Regalloc(&tm, t, nil)
|
||||
|
||||
// patch div to use the 3 register form
|
||||
// TODO(minux): add gins3?
|
||||
p1.Reg = p1.To.Reg
|
||||
|
||||
p1.To.Reg = tm.Reg
|
||||
gins(optoas(gc.OMUL, t), &tr, &tm)
|
||||
gc.Regfree(&tr)
|
||||
gins(optoas(gc.OSUB, t), &tm, &tl)
|
||||
gc.Regfree(&tm)
|
||||
gmove(&tl, res)
|
||||
}
|
||||
|
||||
gc.Regfree(&tl)
|
||||
if check != 0 {
|
||||
gc.Patch(p2, gc.Pc)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* generate high multiply:
|
||||
* res = (nl*nr) >> width
|
||||
*/
|
||||
func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
|
||||
// largest ullman on left.
|
||||
if nl.Ullman < nr.Ullman {
|
||||
tmp := (*gc.Node)(nl)
|
||||
nl = nr
|
||||
nr = tmp
|
||||
}
|
||||
|
||||
t := (*gc.Type)(nl.Type)
|
||||
w := int(int(t.Width * 8))
|
||||
var n1 gc.Node
|
||||
gc.Cgenr(nl, &n1, res)
|
||||
var n2 gc.Node
|
||||
gc.Cgenr(nr, &n2, nil)
|
||||
switch gc.Simtype[t.Etype] {
|
||||
case gc.TINT8,
|
||||
gc.TINT16,
|
||||
gc.TINT32:
|
||||
gins(optoas(gc.OMUL, t), &n2, &n1)
|
||||
p := (*obj.Prog)(gins(ppc64.ASRAD, nil, &n1))
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = int64(w)
|
||||
|
||||
case gc.TUINT8,
|
||||
gc.TUINT16,
|
||||
gc.TUINT32:
|
||||
gins(optoas(gc.OMUL, t), &n2, &n1)
|
||||
p := (*obj.Prog)(gins(ppc64.ASRD, nil, &n1))
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = int64(w)
|
||||
|
||||
case gc.TINT64,
|
||||
gc.TUINT64:
|
||||
if gc.Issigned[t.Etype] {
|
||||
gins(ppc64.AMULHD, &n2, &n1)
|
||||
} else {
|
||||
gins(ppc64.AMULHDU, &n2, &n1)
|
||||
}
|
||||
|
||||
default:
|
||||
gc.Fatalf("cgen_hmul %v", t)
|
||||
}
|
||||
|
||||
gc.Cgen(&n1, res)
|
||||
gc.Regfree(&n1)
|
||||
gc.Regfree(&n2)
|
||||
}
|
||||
|
||||
/*
|
||||
* generate shift according to op, one of:
|
||||
* res = nl << nr
|
||||
* res = nl >> nr
|
||||
*/
|
||||
func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
|
||||
a := int(optoas(op, nl.Type))
|
||||
|
||||
if nr.Op == gc.OLITERAL {
|
||||
var n1 gc.Node
|
||||
gc.Regalloc(&n1, nl.Type, res)
|
||||
gc.Cgen(nl, &n1)
|
||||
sc := uint64(nr.Int())
|
||||
if sc >= uint64(nl.Type.Width*8) {
|
||||
// large shift gets 2 shifts by width-1
|
||||
var n3 gc.Node
|
||||
gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
|
||||
|
||||
gins(a, &n3, &n1)
|
||||
gins(a, &n3, &n1)
|
||||
} else {
|
||||
gins(a, nr, &n1)
|
||||
}
|
||||
gmove(&n1, res)
|
||||
gc.Regfree(&n1)
|
||||
return
|
||||
}
|
||||
|
||||
if nl.Ullman >= gc.UINF {
|
||||
var n4 gc.Node
|
||||
gc.Tempname(&n4, nl.Type)
|
||||
gc.Cgen(nl, &n4)
|
||||
nl = &n4
|
||||
}
|
||||
|
||||
if nr.Ullman >= gc.UINF {
|
||||
var n5 gc.Node
|
||||
gc.Tempname(&n5, nr.Type)
|
||||
gc.Cgen(nr, &n5)
|
||||
nr = &n5
|
||||
}
|
||||
|
||||
// Allow either uint32 or uint64 as shift type,
|
||||
// to avoid unnecessary conversion from uint32 to uint64
|
||||
// just to do the comparison.
|
||||
tcount := gc.Types[gc.Simtype[nr.Type.Etype]]
|
||||
|
||||
if tcount.Etype < gc.TUINT32 {
|
||||
tcount = gc.Types[gc.TUINT32]
|
||||
}
|
||||
|
||||
var n1 gc.Node
|
||||
gc.Regalloc(&n1, nr.Type, nil) // to hold the shift type in CX
|
||||
var n3 gc.Node
|
||||
gc.Regalloc(&n3, tcount, &n1) // to clear high bits of CX
|
||||
|
||||
var n2 gc.Node
|
||||
gc.Regalloc(&n2, nl.Type, res)
|
||||
|
||||
if nl.Ullman >= nr.Ullman {
|
||||
gc.Cgen(nl, &n2)
|
||||
gc.Cgen(nr, &n1)
|
||||
gmove(&n1, &n3)
|
||||
} else {
|
||||
gc.Cgen(nr, &n1)
|
||||
gmove(&n1, &n3)
|
||||
gc.Cgen(nl, &n2)
|
||||
}
|
||||
|
||||
gc.Regfree(&n3)
|
||||
|
||||
// test and fix up large shifts
|
||||
if !bounded {
|
||||
gc.Nodconst(&n3, tcount, nl.Type.Width*8)
|
||||
gins(optoas(gc.OCMP, tcount), &n1, &n3)
|
||||
p1 := (*obj.Prog)(gc.Gbranch(optoas(gc.OLT, tcount), nil, +1))
|
||||
if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
|
||||
gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
|
||||
gins(a, &n3, &n2)
|
||||
} else {
|
||||
gc.Nodconst(&n3, nl.Type, 0)
|
||||
gmove(&n3, &n2)
|
||||
}
|
||||
|
||||
gc.Patch(p1, gc.Pc)
|
||||
}
|
||||
|
||||
gins(a, &n1, &n2)
|
||||
|
||||
gmove(&n2, res)
|
||||
|
||||
gc.Regfree(&n1)
|
||||
gc.Regfree(&n2)
|
||||
}
|
||||
|
||||
func clearfat(nl *gc.Node) {
|
||||
/* clear a fat object */
|
||||
if gc.Debug['g'] != 0 {
|
||||
fmt.Printf("clearfat %v (%v, size: %d)\n", nl, nl.Type, nl.Type.Width)
|
||||
}
|
||||
|
||||
w := uint64(uint64(nl.Type.Width))
|
||||
|
||||
// Avoid taking the address for simple enough types.
|
||||
if gc.Componentgen(nil, nl) {
|
||||
return
|
||||
}
|
||||
|
||||
c := uint64(w % 8) // bytes
|
||||
q := uint64(w / 8) // dwords
|
||||
|
||||
if gc.Reginuse(ppc64.REGRT1) {
|
||||
gc.Fatalf("%v in use during clearfat", obj.Rconv(ppc64.REGRT1))
|
||||
}
|
||||
|
||||
var r0 gc.Node
|
||||
gc.Nodreg(&r0, gc.Types[gc.TUINT64], ppc64.REGZERO)
|
||||
var dst gc.Node
|
||||
gc.Nodreg(&dst, gc.Types[gc.Tptr], ppc64.REGRT1)
|
||||
gc.Regrealloc(&dst)
|
||||
gc.Agen(nl, &dst)
|
||||
|
||||
var boff uint64
|
||||
if q > 128 {
|
||||
p := gins(ppc64.ASUB, nil, &dst)
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = 8
|
||||
|
||||
var end gc.Node
|
||||
gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
|
||||
p = gins(ppc64.AMOVD, &dst, &end)
|
||||
p.From.Type = obj.TYPE_ADDR
|
||||
p.From.Offset = int64(q * 8)
|
||||
|
||||
p = gins(ppc64.AMOVDU, &r0, &dst)
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Offset = 8
|
||||
pl := (*obj.Prog)(p)
|
||||
|
||||
p = gins(ppc64.ACMP, &dst, &end)
|
||||
gc.Patch(gc.Gbranch(ppc64.ABNE, nil, 0), pl)
|
||||
|
||||
gc.Regfree(&end)
|
||||
|
||||
// The loop leaves R3 on the last zeroed dword
|
||||
boff = 8
|
||||
// TODO(dfc): https://golang.org/issue/12108
|
||||
// If DUFFZERO is used inside a tail call (see genwrapper) it will
|
||||
// overwrite the link register.
|
||||
} else if false && q >= 4 {
|
||||
p := gins(ppc64.ASUB, nil, &dst)
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = 8
|
||||
f := (*gc.Node)(gc.Sysfunc("duffzero"))
|
||||
p = gins(obj.ADUFFZERO, nil, f)
|
||||
gc.Afunclit(&p.To, f)
|
||||
|
||||
// 4 and 128 = magic constants: see ../../runtime/asm_ppc64x.s
|
||||
p.To.Offset = int64(4 * (128 - q))
|
||||
|
||||
// duffzero leaves R3 on the last zeroed dword
|
||||
boff = 8
|
||||
} else {
|
||||
var p *obj.Prog
|
||||
for t := uint64(0); t < q; t++ {
|
||||
p = gins(ppc64.AMOVD, &r0, &dst)
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Offset = int64(8 * t)
|
||||
}
|
||||
|
||||
boff = 8 * q
|
||||
}
|
||||
|
||||
var p *obj.Prog
|
||||
for t := uint64(0); t < c; t++ {
|
||||
p = gins(ppc64.AMOVB, &r0, &dst)
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Offset = int64(t + boff)
|
||||
}
|
||||
|
||||
gc.Regfree(&dst)
|
||||
}
|
||||
|
||||
// Called after regopt and peep have run.
|
||||
// Expand CHECKNIL pseudo-op into actual nil pointer check.
|
||||
func expandchecks(firstp *obj.Prog) {
|
||||
var p1 *obj.Prog
|
||||
var p2 *obj.Prog
|
||||
|
||||
for p := (*obj.Prog)(firstp); p != nil; p = p.Link {
|
||||
if gc.Debug_checknil != 0 && gc.Ctxt.Debugvlog != 0 {
|
||||
fmt.Printf("expandchecks: %v\n", p)
|
||||
}
|
||||
if p.As != obj.ACHECKNIL {
|
||||
continue
|
||||
}
|
||||
if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
|
||||
gc.Warnl(int(p.Lineno), "generated nil check")
|
||||
}
|
||||
if p.From.Type != obj.TYPE_REG {
|
||||
gc.Fatalf("invalid nil check %v\n", p)
|
||||
}
|
||||
|
||||
/*
|
||||
// check is
|
||||
// TD $4, R0, arg (R0 is always zero)
|
||||
// eqv. to:
|
||||
// tdeq r0, arg
|
||||
// NOTE: this needs special runtime support to make SIGTRAP recoverable.
|
||||
reg = p->from.reg;
|
||||
p->as = ATD;
|
||||
p->from = p->to = p->from3 = zprog.from;
|
||||
p->from.type = TYPE_CONST;
|
||||
p->from.offset = 4;
|
||||
p->from.reg = 0;
|
||||
p->reg = REGZERO;
|
||||
p->to.type = TYPE_REG;
|
||||
p->to.reg = reg;
|
||||
*/
|
||||
// check is
|
||||
// CMP arg, R0
|
||||
// BNE 2(PC) [likely]
|
||||
// MOVD R0, 0(R0)
|
||||
p1 = gc.Ctxt.NewProg()
|
||||
|
||||
p2 = gc.Ctxt.NewProg()
|
||||
gc.Clearp(p1)
|
||||
gc.Clearp(p2)
|
||||
p1.Link = p2
|
||||
p2.Link = p.Link
|
||||
p.Link = p1
|
||||
p1.Lineno = p.Lineno
|
||||
p2.Lineno = p.Lineno
|
||||
p1.Pc = 9999
|
||||
p2.Pc = 9999
|
||||
p.As = ppc64.ACMP
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = ppc64.REGZERO
|
||||
p1.As = ppc64.ABNE
|
||||
|
||||
//p1->from.type = TYPE_CONST;
|
||||
//p1->from.offset = 1; // likely
|
||||
p1.To.Type = obj.TYPE_BRANCH
|
||||
|
||||
p1.To.Val = p2.Link
|
||||
|
||||
// crash by write to memory address 0.
|
||||
p2.As = ppc64.AMOVD
|
||||
|
||||
p2.From.Type = obj.TYPE_REG
|
||||
p2.From.Reg = ppc64.REGZERO
|
||||
p2.To.Type = obj.TYPE_MEM
|
||||
p2.To.Reg = ppc64.REGZERO
|
||||
p2.To.Offset = 0
|
||||
}
|
||||
}
|
||||
|
||||
// res = runtime.getg()
|
||||
func getg(res *gc.Node) {
|
||||
var n1 gc.Node
|
||||
gc.Nodreg(&n1, res.Type, ppc64.REGG)
|
||||
gmove(&n1, res)
|
||||
}
|
1031
src/cmd/compile/internal/mips64/gsubr.go
Normal file
1031
src/cmd/compile/internal/mips64/gsubr.go
Normal file
File diff suppressed because it is too large
Load Diff
12
src/cmd/compile/internal/mips64/opt.go
Normal file
12
src/cmd/compile/internal/mips64/opt.go
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright 2014 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 ppc64
|
||||
|
||||
// Many Power ISA arithmetic and logical instructions come in four
|
||||
// standard variants. These bits let us map between variants.
|
||||
const (
|
||||
V_CC = 1 << 0 // xCC (affect CR field 0 flags)
|
||||
V_V = 1 << 1 // xV (affect SO and OV flags)
|
||||
)
|
1051
src/cmd/compile/internal/mips64/peep.go
Normal file
1051
src/cmd/compile/internal/mips64/peep.go
Normal file
File diff suppressed because it is too large
Load Diff
314
src/cmd/compile/internal/mips64/prog.go
Normal file
314
src/cmd/compile/internal/mips64/prog.go
Normal file
@ -0,0 +1,314 @@
|
||||
// Copyright 2014 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 ppc64
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/ppc64"
|
||||
)
|
||||
|
||||
const (
|
||||
LeftRdwr uint32 = gc.LeftRead | gc.LeftWrite
|
||||
RightRdwr uint32 = gc.RightRead | gc.RightWrite
|
||||
)
|
||||
|
||||
// This table gives the basic information about instruction
|
||||
// generated by the compiler and processed in the optimizer.
|
||||
// See opt.h for bit definitions.
|
||||
//
|
||||
// Instructions not generated need not be listed.
|
||||
// As an exception to that rule, we typically write down all the
|
||||
// size variants of an operation even if we just use a subset.
|
||||
//
|
||||
// The table is formatted for 8-space tabs.
|
||||
var progtable = [ppc64.ALAST]obj.ProgInfo{
|
||||
obj.ATYPE: {Flags: gc.Pseudo | gc.Skip},
|
||||
obj.ATEXT: {Flags: gc.Pseudo},
|
||||
obj.AFUNCDATA: {Flags: gc.Pseudo},
|
||||
obj.APCDATA: {Flags: gc.Pseudo},
|
||||
obj.AUNDEF: {Flags: gc.Break},
|
||||
obj.AUSEFIELD: {Flags: gc.OK},
|
||||
obj.ACHECKNIL: {Flags: gc.LeftRead},
|
||||
obj.AVARDEF: {Flags: gc.Pseudo | gc.RightWrite},
|
||||
obj.AVARKILL: {Flags: gc.Pseudo | gc.RightWrite},
|
||||
|
||||
// NOP is an internal no-op that also stands
|
||||
// for USED and SET annotations, not the Power opcode.
|
||||
obj.ANOP: {Flags: gc.LeftRead | gc.RightWrite},
|
||||
|
||||
// Integer
|
||||
ppc64.AADD: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.ASUB: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.ANEG: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AAND: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AOR: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AXOR: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AMULLD: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AMULLW: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AMULHD: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AMULHDU: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.ADIVD: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.ADIVDU: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.ASLD: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.ASRD: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.ASRAD: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.ACMP: {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead},
|
||||
ppc64.ACMPU: {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead},
|
||||
ppc64.ATD: {Flags: gc.SizeQ | gc.RightRead},
|
||||
|
||||
// Floating point.
|
||||
ppc64.AFADD: {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AFADDS: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AFSUB: {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AFSUBS: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AFMUL: {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AFMULS: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AFDIV: {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AFDIVS: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AFCTIDZ: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AFCFID: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
|
||||
ppc64.AFCMPU: {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
|
||||
ppc64.AFRSP: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
|
||||
|
||||
// Moves
|
||||
ppc64.AMOVB: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
|
||||
ppc64.AMOVBU: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc},
|
||||
ppc64.AMOVBZ: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
|
||||
ppc64.AMOVH: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
|
||||
ppc64.AMOVHU: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc},
|
||||
ppc64.AMOVHZ: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
|
||||
ppc64.AMOVW: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
|
||||
|
||||
// there is no AMOVWU.
|
||||
ppc64.AMOVWZU: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc},
|
||||
ppc64.AMOVWZ: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
|
||||
ppc64.AMOVD: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
|
||||
ppc64.AMOVDU: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move | gc.PostInc},
|
||||
ppc64.AFMOVS: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
|
||||
ppc64.AFMOVD: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
|
||||
|
||||
// Jumps
|
||||
ppc64.ABR: {Flags: gc.Jump | gc.Break},
|
||||
ppc64.ABL: {Flags: gc.Call},
|
||||
ppc64.ABEQ: {Flags: gc.Cjmp},
|
||||
ppc64.ABNE: {Flags: gc.Cjmp},
|
||||
ppc64.ABGE: {Flags: gc.Cjmp},
|
||||
ppc64.ABLT: {Flags: gc.Cjmp},
|
||||
ppc64.ABGT: {Flags: gc.Cjmp},
|
||||
ppc64.ABLE: {Flags: gc.Cjmp},
|
||||
obj.ARET: {Flags: gc.Break},
|
||||
obj.ADUFFZERO: {Flags: gc.Call},
|
||||
obj.ADUFFCOPY: {Flags: gc.Call},
|
||||
}
|
||||
|
||||
var initproginfo_initialized int
|
||||
|
||||
func initproginfo() {
|
||||
var addvariant = []int{V_CC, V_V, V_CC | V_V}
|
||||
|
||||
if initproginfo_initialized != 0 {
|
||||
return
|
||||
}
|
||||
initproginfo_initialized = 1
|
||||
|
||||
// Perform one-time expansion of instructions in progtable to
|
||||
// their CC, V, and VCC variants
|
||||
var as2 int
|
||||
var i int
|
||||
var variant int
|
||||
for as := int(0); as < len(progtable); as++ {
|
||||
if progtable[as].Flags == 0 {
|
||||
continue
|
||||
}
|
||||
variant = as2variant(as)
|
||||
for i = 0; i < len(addvariant); i++ {
|
||||
as2 = variant2as(as, variant|addvariant[i])
|
||||
if as2 != 0 && progtable[as2].Flags == 0 {
|
||||
progtable[as2] = progtable[as]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func proginfo(p *obj.Prog) {
|
||||
initproginfo()
|
||||
|
||||
info := &p.Info
|
||||
*info = progtable[p.As]
|
||||
if info.Flags == 0 {
|
||||
gc.Fatalf("proginfo: unknown instruction %v", p)
|
||||
}
|
||||
|
||||
if (info.Flags&gc.RegRead != 0) && p.Reg == 0 {
|
||||
info.Flags &^= gc.RegRead
|
||||
info.Flags |= gc.RightRead /*CanRegRead |*/
|
||||
}
|
||||
|
||||
if (p.From.Type == obj.TYPE_MEM || p.From.Type == obj.TYPE_ADDR) && p.From.Reg != 0 {
|
||||
info.Regindex |= RtoB(int(p.From.Reg))
|
||||
if info.Flags&gc.PostInc != 0 {
|
||||
info.Regset |= RtoB(int(p.From.Reg))
|
||||
}
|
||||
}
|
||||
|
||||
if (p.To.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_ADDR) && p.To.Reg != 0 {
|
||||
info.Regindex |= RtoB(int(p.To.Reg))
|
||||
if info.Flags&gc.PostInc != 0 {
|
||||
info.Regset |= RtoB(int(p.To.Reg))
|
||||
}
|
||||
}
|
||||
|
||||
if p.From.Type == obj.TYPE_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) {
|
||||
info.Flags &^= gc.LeftRead
|
||||
info.Flags |= gc.LeftAddr
|
||||
}
|
||||
|
||||
if p.As == obj.ADUFFZERO {
|
||||
info.Reguse |= 1<<0 | RtoB(ppc64.REG_R3)
|
||||
info.Regset |= RtoB(ppc64.REG_R3)
|
||||
}
|
||||
|
||||
if p.As == obj.ADUFFCOPY {
|
||||
// TODO(austin) Revisit when duffcopy is implemented
|
||||
info.Reguse |= RtoB(ppc64.REG_R3) | RtoB(ppc64.REG_R4) | RtoB(ppc64.REG_R5)
|
||||
|
||||
info.Regset |= RtoB(ppc64.REG_R3) | RtoB(ppc64.REG_R4)
|
||||
}
|
||||
}
|
||||
|
||||
// Instruction variants table. Initially this contains entries only
|
||||
// for the "base" form of each instruction. On the first call to
|
||||
// as2variant or variant2as, we'll add the variants to the table.
|
||||
var varianttable = [ppc64.ALAST][4]int{
|
||||
ppc64.AADD: [4]int{ppc64.AADD, ppc64.AADDCC, ppc64.AADDV, ppc64.AADDVCC},
|
||||
ppc64.AADDC: [4]int{ppc64.AADDC, ppc64.AADDCCC, ppc64.AADDCV, ppc64.AADDCVCC},
|
||||
ppc64.AADDE: [4]int{ppc64.AADDE, ppc64.AADDECC, ppc64.AADDEV, ppc64.AADDEVCC},
|
||||
ppc64.AADDME: [4]int{ppc64.AADDME, ppc64.AADDMECC, ppc64.AADDMEV, ppc64.AADDMEVCC},
|
||||
ppc64.AADDZE: [4]int{ppc64.AADDZE, ppc64.AADDZECC, ppc64.AADDZEV, ppc64.AADDZEVCC},
|
||||
ppc64.AAND: [4]int{ppc64.AAND, ppc64.AANDCC, 0, 0},
|
||||
ppc64.AANDN: [4]int{ppc64.AANDN, ppc64.AANDNCC, 0, 0},
|
||||
ppc64.ACNTLZD: [4]int{ppc64.ACNTLZD, ppc64.ACNTLZDCC, 0, 0},
|
||||
ppc64.ACNTLZW: [4]int{ppc64.ACNTLZW, ppc64.ACNTLZWCC, 0, 0},
|
||||
ppc64.ADIVD: [4]int{ppc64.ADIVD, ppc64.ADIVDCC, ppc64.ADIVDV, ppc64.ADIVDVCC},
|
||||
ppc64.ADIVDU: [4]int{ppc64.ADIVDU, ppc64.ADIVDUCC, ppc64.ADIVDUV, ppc64.ADIVDUVCC},
|
||||
ppc64.ADIVW: [4]int{ppc64.ADIVW, ppc64.ADIVWCC, ppc64.ADIVWV, ppc64.ADIVWVCC},
|
||||
ppc64.ADIVWU: [4]int{ppc64.ADIVWU, ppc64.ADIVWUCC, ppc64.ADIVWUV, ppc64.ADIVWUVCC},
|
||||
ppc64.AEQV: [4]int{ppc64.AEQV, ppc64.AEQVCC, 0, 0},
|
||||
ppc64.AEXTSB: [4]int{ppc64.AEXTSB, ppc64.AEXTSBCC, 0, 0},
|
||||
ppc64.AEXTSH: [4]int{ppc64.AEXTSH, ppc64.AEXTSHCC, 0, 0},
|
||||
ppc64.AEXTSW: [4]int{ppc64.AEXTSW, ppc64.AEXTSWCC, 0, 0},
|
||||
ppc64.AFABS: [4]int{ppc64.AFABS, ppc64.AFABSCC, 0, 0},
|
||||
ppc64.AFADD: [4]int{ppc64.AFADD, ppc64.AFADDCC, 0, 0},
|
||||
ppc64.AFADDS: [4]int{ppc64.AFADDS, ppc64.AFADDSCC, 0, 0},
|
||||
ppc64.AFCFID: [4]int{ppc64.AFCFID, ppc64.AFCFIDCC, 0, 0},
|
||||
ppc64.AFCTID: [4]int{ppc64.AFCTID, ppc64.AFCTIDCC, 0, 0},
|
||||
ppc64.AFCTIDZ: [4]int{ppc64.AFCTIDZ, ppc64.AFCTIDZCC, 0, 0},
|
||||
ppc64.AFCTIW: [4]int{ppc64.AFCTIW, ppc64.AFCTIWCC, 0, 0},
|
||||
ppc64.AFCTIWZ: [4]int{ppc64.AFCTIWZ, ppc64.AFCTIWZCC, 0, 0},
|
||||
ppc64.AFDIV: [4]int{ppc64.AFDIV, ppc64.AFDIVCC, 0, 0},
|
||||
ppc64.AFDIVS: [4]int{ppc64.AFDIVS, ppc64.AFDIVSCC, 0, 0},
|
||||
ppc64.AFMADD: [4]int{ppc64.AFMADD, ppc64.AFMADDCC, 0, 0},
|
||||
ppc64.AFMADDS: [4]int{ppc64.AFMADDS, ppc64.AFMADDSCC, 0, 0},
|
||||
ppc64.AFMOVD: [4]int{ppc64.AFMOVD, ppc64.AFMOVDCC, 0, 0},
|
||||
ppc64.AFMSUB: [4]int{ppc64.AFMSUB, ppc64.AFMSUBCC, 0, 0},
|
||||
ppc64.AFMSUBS: [4]int{ppc64.AFMSUBS, ppc64.AFMSUBSCC, 0, 0},
|
||||
ppc64.AFMUL: [4]int{ppc64.AFMUL, ppc64.AFMULCC, 0, 0},
|
||||
ppc64.AFMULS: [4]int{ppc64.AFMULS, ppc64.AFMULSCC, 0, 0},
|
||||
ppc64.AFNABS: [4]int{ppc64.AFNABS, ppc64.AFNABSCC, 0, 0},
|
||||
ppc64.AFNEG: [4]int{ppc64.AFNEG, ppc64.AFNEGCC, 0, 0},
|
||||
ppc64.AFNMADD: [4]int{ppc64.AFNMADD, ppc64.AFNMADDCC, 0, 0},
|
||||
ppc64.AFNMADDS: [4]int{ppc64.AFNMADDS, ppc64.AFNMADDSCC, 0, 0},
|
||||
ppc64.AFNMSUB: [4]int{ppc64.AFNMSUB, ppc64.AFNMSUBCC, 0, 0},
|
||||
ppc64.AFNMSUBS: [4]int{ppc64.AFNMSUBS, ppc64.AFNMSUBSCC, 0, 0},
|
||||
ppc64.AFRES: [4]int{ppc64.AFRES, ppc64.AFRESCC, 0, 0},
|
||||
ppc64.AFRSP: [4]int{ppc64.AFRSP, ppc64.AFRSPCC, 0, 0},
|
||||
ppc64.AFRSQRTE: [4]int{ppc64.AFRSQRTE, ppc64.AFRSQRTECC, 0, 0},
|
||||
ppc64.AFSEL: [4]int{ppc64.AFSEL, ppc64.AFSELCC, 0, 0},
|
||||
ppc64.AFSQRT: [4]int{ppc64.AFSQRT, ppc64.AFSQRTCC, 0, 0},
|
||||
ppc64.AFSQRTS: [4]int{ppc64.AFSQRTS, ppc64.AFSQRTSCC, 0, 0},
|
||||
ppc64.AFSUB: [4]int{ppc64.AFSUB, ppc64.AFSUBCC, 0, 0},
|
||||
ppc64.AFSUBS: [4]int{ppc64.AFSUBS, ppc64.AFSUBSCC, 0, 0},
|
||||
ppc64.AMTFSB0: [4]int{ppc64.AMTFSB0, ppc64.AMTFSB0CC, 0, 0},
|
||||
ppc64.AMTFSB1: [4]int{ppc64.AMTFSB1, ppc64.AMTFSB1CC, 0, 0},
|
||||
ppc64.AMULHD: [4]int{ppc64.AMULHD, ppc64.AMULHDCC, 0, 0},
|
||||
ppc64.AMULHDU: [4]int{ppc64.AMULHDU, ppc64.AMULHDUCC, 0, 0},
|
||||
ppc64.AMULHW: [4]int{ppc64.AMULHW, ppc64.AMULHWCC, 0, 0},
|
||||
ppc64.AMULHWU: [4]int{ppc64.AMULHWU, ppc64.AMULHWUCC, 0, 0},
|
||||
ppc64.AMULLD: [4]int{ppc64.AMULLD, ppc64.AMULLDCC, ppc64.AMULLDV, ppc64.AMULLDVCC},
|
||||
ppc64.AMULLW: [4]int{ppc64.AMULLW, ppc64.AMULLWCC, ppc64.AMULLWV, ppc64.AMULLWVCC},
|
||||
ppc64.ANAND: [4]int{ppc64.ANAND, ppc64.ANANDCC, 0, 0},
|
||||
ppc64.ANEG: [4]int{ppc64.ANEG, ppc64.ANEGCC, ppc64.ANEGV, ppc64.ANEGVCC},
|
||||
ppc64.ANOR: [4]int{ppc64.ANOR, ppc64.ANORCC, 0, 0},
|
||||
ppc64.AOR: [4]int{ppc64.AOR, ppc64.AORCC, 0, 0},
|
||||
ppc64.AORN: [4]int{ppc64.AORN, ppc64.AORNCC, 0, 0},
|
||||
ppc64.AREM: [4]int{ppc64.AREM, ppc64.AREMCC, ppc64.AREMV, ppc64.AREMVCC},
|
||||
ppc64.AREMD: [4]int{ppc64.AREMD, ppc64.AREMDCC, ppc64.AREMDV, ppc64.AREMDVCC},
|
||||
ppc64.AREMDU: [4]int{ppc64.AREMDU, ppc64.AREMDUCC, ppc64.AREMDUV, ppc64.AREMDUVCC},
|
||||
ppc64.AREMU: [4]int{ppc64.AREMU, ppc64.AREMUCC, ppc64.AREMUV, ppc64.AREMUVCC},
|
||||
ppc64.ARLDC: [4]int{ppc64.ARLDC, ppc64.ARLDCCC, 0, 0},
|
||||
ppc64.ARLDCL: [4]int{ppc64.ARLDCL, ppc64.ARLDCLCC, 0, 0},
|
||||
ppc64.ARLDCR: [4]int{ppc64.ARLDCR, ppc64.ARLDCRCC, 0, 0},
|
||||
ppc64.ARLDMI: [4]int{ppc64.ARLDMI, ppc64.ARLDMICC, 0, 0},
|
||||
ppc64.ARLWMI: [4]int{ppc64.ARLWMI, ppc64.ARLWMICC, 0, 0},
|
||||
ppc64.ARLWNM: [4]int{ppc64.ARLWNM, ppc64.ARLWNMCC, 0, 0},
|
||||
ppc64.ASLD: [4]int{ppc64.ASLD, ppc64.ASLDCC, 0, 0},
|
||||
ppc64.ASLW: [4]int{ppc64.ASLW, ppc64.ASLWCC, 0, 0},
|
||||
ppc64.ASRAD: [4]int{ppc64.ASRAD, ppc64.ASRADCC, 0, 0},
|
||||
ppc64.ASRAW: [4]int{ppc64.ASRAW, ppc64.ASRAWCC, 0, 0},
|
||||
ppc64.ASRD: [4]int{ppc64.ASRD, ppc64.ASRDCC, 0, 0},
|
||||
ppc64.ASRW: [4]int{ppc64.ASRW, ppc64.ASRWCC, 0, 0},
|
||||
ppc64.ASUB: [4]int{ppc64.ASUB, ppc64.ASUBCC, ppc64.ASUBV, ppc64.ASUBVCC},
|
||||
ppc64.ASUBC: [4]int{ppc64.ASUBC, ppc64.ASUBCCC, ppc64.ASUBCV, ppc64.ASUBCVCC},
|
||||
ppc64.ASUBE: [4]int{ppc64.ASUBE, ppc64.ASUBECC, ppc64.ASUBEV, ppc64.ASUBEVCC},
|
||||
ppc64.ASUBME: [4]int{ppc64.ASUBME, ppc64.ASUBMECC, ppc64.ASUBMEV, ppc64.ASUBMEVCC},
|
||||
ppc64.ASUBZE: [4]int{ppc64.ASUBZE, ppc64.ASUBZECC, ppc64.ASUBZEV, ppc64.ASUBZEVCC},
|
||||
ppc64.AXOR: [4]int{ppc64.AXOR, ppc64.AXORCC, 0, 0},
|
||||
}
|
||||
|
||||
var initvariants_initialized int
|
||||
|
||||
func initvariants() {
|
||||
if initvariants_initialized != 0 {
|
||||
return
|
||||
}
|
||||
initvariants_initialized = 1
|
||||
|
||||
var j int
|
||||
for i := int(0); i < len(varianttable); i++ {
|
||||
if varianttable[i][0] == 0 {
|
||||
// Instruction has no variants
|
||||
varianttable[i][0] = i
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Copy base form to other variants
|
||||
if varianttable[i][0] == i {
|
||||
for j = 0; j < len(varianttable[i]); j++ {
|
||||
varianttable[varianttable[i][j]] = varianttable[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// as2variant returns the variant (V_*) flags of instruction as.
|
||||
func as2variant(as int) int {
|
||||
initvariants()
|
||||
for i := int(0); i < len(varianttable[as]); i++ {
|
||||
if varianttable[as][i] == as {
|
||||
return i
|
||||
}
|
||||
}
|
||||
gc.Fatalf("as2variant: instruction %v is not a variant of itself", obj.Aconv(as))
|
||||
return 0
|
||||
}
|
||||
|
||||
// variant2as returns the instruction as with the given variant (V_*) flags.
|
||||
// If no such variant exists, this returns 0.
|
||||
func variant2as(as int, flags int) int {
|
||||
initvariants()
|
||||
return varianttable[as][flags]
|
||||
}
|
162
src/cmd/compile/internal/mips64/reg.go
Normal file
162
src/cmd/compile/internal/mips64/reg.go
Normal file
@ -0,0 +1,162 @@
|
||||
// Derived from Inferno utils/6c/reg.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.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 ppc64
|
||||
|
||||
import "cmd/internal/obj/ppc64"
|
||||
import "cmd/compile/internal/gc"
|
||||
|
||||
const (
|
||||
NREGVAR = 64 /* 32 general + 32 floating */
|
||||
)
|
||||
|
||||
var regname = []string{
|
||||
".R0",
|
||||
".R1",
|
||||
".R2",
|
||||
".R3",
|
||||
".R4",
|
||||
".R5",
|
||||
".R6",
|
||||
".R7",
|
||||
".R8",
|
||||
".R9",
|
||||
".R10",
|
||||
".R11",
|
||||
".R12",
|
||||
".R13",
|
||||
".R14",
|
||||
".R15",
|
||||
".R16",
|
||||
".R17",
|
||||
".R18",
|
||||
".R19",
|
||||
".R20",
|
||||
".R21",
|
||||
".R22",
|
||||
".R23",
|
||||
".R24",
|
||||
".R25",
|
||||
".R26",
|
||||
".R27",
|
||||
".R28",
|
||||
".R29",
|
||||
".R30",
|
||||
".R31",
|
||||
".F0",
|
||||
".F1",
|
||||
".F2",
|
||||
".F3",
|
||||
".F4",
|
||||
".F5",
|
||||
".F6",
|
||||
".F7",
|
||||
".F8",
|
||||
".F9",
|
||||
".F10",
|
||||
".F11",
|
||||
".F12",
|
||||
".F13",
|
||||
".F14",
|
||||
".F15",
|
||||
".F16",
|
||||
".F17",
|
||||
".F18",
|
||||
".F19",
|
||||
".F20",
|
||||
".F21",
|
||||
".F22",
|
||||
".F23",
|
||||
".F24",
|
||||
".F25",
|
||||
".F26",
|
||||
".F27",
|
||||
".F28",
|
||||
".F29",
|
||||
".F30",
|
||||
".F31",
|
||||
}
|
||||
|
||||
func regnames(n *int) []string {
|
||||
*n = NREGVAR
|
||||
return regname
|
||||
}
|
||||
|
||||
func excludedregs() uint64 {
|
||||
// Exclude registers with fixed functions
|
||||
regbits := uint64(1<<0 | RtoB(ppc64.REGSP) | RtoB(ppc64.REGG) | RtoB(ppc64.REGTLS))
|
||||
|
||||
// Also exclude floating point registers with fixed constants
|
||||
regbits |= RtoB(ppc64.REG_F27) | RtoB(ppc64.REG_F28) | RtoB(ppc64.REG_F29) | RtoB(ppc64.REG_F30) | RtoB(ppc64.REG_F31)
|
||||
|
||||
return regbits
|
||||
}
|
||||
|
||||
func doregbits(r int) uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
/*
|
||||
* track register variables including external registers:
|
||||
* bit reg
|
||||
* 0 R0
|
||||
* 1 R1
|
||||
* ... ...
|
||||
* 31 R31
|
||||
* 32+0 F0
|
||||
* 32+1 F1
|
||||
* ... ...
|
||||
* 32+31 F31
|
||||
*/
|
||||
func RtoB(r int) uint64 {
|
||||
if r > ppc64.REG_R0 && r <= ppc64.REG_R31 {
|
||||
return 1 << uint(r-ppc64.REG_R0)
|
||||
}
|
||||
if r >= ppc64.REG_F0 && r <= ppc64.REG_F31 {
|
||||
return 1 << uint(32+r-ppc64.REG_F0)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func BtoR(b uint64) int {
|
||||
b &= 0xffffffff
|
||||
if b == 0 {
|
||||
return 0
|
||||
}
|
||||
return gc.Bitno(b) + ppc64.REG_R0
|
||||
}
|
||||
|
||||
func BtoF(b uint64) int {
|
||||
b >>= 32
|
||||
if b == 0 {
|
||||
return 0
|
||||
}
|
||||
return gc.Bitno(b) + ppc64.REG_F0
|
||||
}
|
Loading…
Reference in New Issue
Block a user