2015-02-13 14:40:36 -05:00
|
|
|
// 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.
|
|
|
|
|
|
2015-05-21 13:28:10 -04:00
|
|
|
package arm
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
import (
|
2015-05-21 13:28:10 -04:00
|
|
|
"cmd/compile/internal/gc"
|
2015-02-13 14:40:36 -05:00
|
|
|
"cmd/internal/obj"
|
|
|
|
|
"cmd/internal/obj/arm"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func defframe(ptxt *obj.Prog) {
|
|
|
|
|
// fill in argument size, stack size
|
|
|
|
|
ptxt.To.Type = obj.TYPE_TEXTSIZE
|
|
|
|
|
|
2015-03-16 15:54:44 -04:00
|
|
|
ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr)))
|
2015-02-23 16:07:24 -05:00
|
|
|
frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
|
2015-02-13 14:40:36 -05:00
|
|
|
ptxt.To.Offset = int64(frame)
|
|
|
|
|
|
|
|
|
|
// insert code to contain ambiguously live variables
|
|
|
|
|
// so that garbage collector only sees initialized values
|
|
|
|
|
// when it looks for pointers.
|
2015-02-23 16:07:24 -05:00
|
|
|
p := ptxt
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
hi := int64(0)
|
|
|
|
|
lo := hi
|
|
|
|
|
r0 := uint32(0)
|
2016-02-25 10:35:19 -08:00
|
|
|
for _, n := range gc.Curfn.Func.Dcl {
|
2015-05-15 10:02:19 -07:00
|
|
|
if !n.Name.Needzero {
|
2015-02-13 14:40:36 -05:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if n.Class != gc.PAUTO {
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("needzero class %d", n.Class)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthptr) {
|
|
|
|
|
// merge with range we already have
|
|
|
|
|
lo = gc.Rnd(n.Xoffset, int64(gc.Widthptr))
|
|
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// zero old range
|
|
|
|
|
p = zerorange(p, int64(frame), lo, hi, &r0)
|
|
|
|
|
|
|
|
|
|
// set new range
|
|
|
|
|
hi = n.Xoffset + n.Type.Width
|
|
|
|
|
|
|
|
|
|
lo = n.Xoffset
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// zero final range
|
|
|
|
|
zerorange(p, int64(frame), lo, hi, &r0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, r0 *uint32) *obj.Prog {
|
2015-02-23 16:07:24 -05:00
|
|
|
cnt := hi - lo
|
2015-02-13 14:40:36 -05:00
|
|
|
if cnt == 0 {
|
|
|
|
|
return p
|
|
|
|
|
}
|
|
|
|
|
if *r0 == 0 {
|
|
|
|
|
p = appendpp(p, arm.AMOVW, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, arm.REG_R0, 0)
|
|
|
|
|
*r0 = 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cnt < int64(4*gc.Widthptr) {
|
2015-02-23 16:07:24 -05:00
|
|
|
for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
|
2015-02-13 14:40:36 -05:00
|
|
|
p = appendpp(p, arm.AMOVW, obj.TYPE_REG, arm.REG_R0, 0, obj.TYPE_MEM, arm.REGSP, int32(4+frame+lo+i))
|
|
|
|
|
}
|
|
|
|
|
} else if !gc.Nacl && (cnt <= int64(128*gc.Widthptr)) {
|
|
|
|
|
p = appendpp(p, arm.AADD, obj.TYPE_CONST, 0, int32(4+frame+lo), obj.TYPE_REG, arm.REG_R1, 0)
|
|
|
|
|
p.Reg = arm.REGSP
|
|
|
|
|
p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
|
2015-02-23 16:07:24 -05:00
|
|
|
f := gc.Sysfunc("duffzero")
|
2015-03-16 15:27:19 -04:00
|
|
|
gc.Naddr(&p.To, f)
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Afunclit(&p.To, f)
|
|
|
|
|
p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
|
|
|
|
|
} else {
|
|
|
|
|
p = appendpp(p, arm.AADD, obj.TYPE_CONST, 0, int32(4+frame+lo), obj.TYPE_REG, arm.REG_R1, 0)
|
|
|
|
|
p.Reg = arm.REGSP
|
|
|
|
|
p = appendpp(p, arm.AADD, obj.TYPE_CONST, 0, int32(cnt), obj.TYPE_REG, arm.REG_R2, 0)
|
|
|
|
|
p.Reg = arm.REG_R1
|
|
|
|
|
p = appendpp(p, arm.AMOVW, obj.TYPE_REG, arm.REG_R0, 0, obj.TYPE_MEM, arm.REG_R1, 4)
|
2015-02-23 16:07:24 -05:00
|
|
|
p1 := p
|
2015-02-13 14:40:36 -05:00
|
|
|
p.Scond |= arm.C_PBIT
|
|
|
|
|
p = appendpp(p, arm.ACMP, obj.TYPE_REG, arm.REG_R1, 0, obj.TYPE_NONE, 0, 0)
|
|
|
|
|
p.Reg = arm.REG_R2
|
|
|
|
|
p = appendpp(p, arm.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
|
|
|
|
|
gc.Patch(p, p1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return p
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-14 20:11:28 -07:00
|
|
|
func appendpp(p *obj.Prog, as int, ftype obj.AddrType, freg int, foffset int32, ttype obj.AddrType, treg int, toffset int32) *obj.Prog {
|
2015-02-23 16:07:24 -05:00
|
|
|
q := gc.Ctxt.NewProg()
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Clearp(q)
|
|
|
|
|
q.As = int16(as)
|
|
|
|
|
q.Lineno = p.Lineno
|
2015-05-14 20:11:28 -07:00
|
|
|
q.From.Type = ftype
|
2015-02-13 14:40:36 -05:00
|
|
|
q.From.Reg = int16(freg)
|
|
|
|
|
q.From.Offset = int64(foffset)
|
2015-05-14 20:11:28 -07:00
|
|
|
q.To.Type = ttype
|
2015-02-13 14:40:36 -05:00
|
|
|
q.To.Reg = int16(treg)
|
|
|
|
|
q.To.Offset = int64(toffset)
|
|
|
|
|
q.Link = p.Link
|
|
|
|
|
p.Link = q
|
|
|
|
|
return q
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* generate high multiply
|
|
|
|
|
* res = (nl * nr) >> wordsize
|
|
|
|
|
*/
|
|
|
|
|
func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
|
|
|
|
|
if nl.Ullman < nr.Ullman {
|
2015-09-06 16:59:57 +02:00
|
|
|
nl, nr = nr, nl
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
t := nl.Type
|
2016-03-04 13:15:40 +11:00
|
|
|
w := t.Width * 8
|
2015-02-23 16:07:24 -05:00
|
|
|
var n1 gc.Node
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&n1, t, res)
|
|
|
|
|
gc.Cgen(nl, &n1)
|
2015-02-23 16:07:24 -05:00
|
|
|
var n2 gc.Node
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&n2, t, nil)
|
|
|
|
|
gc.Cgen(nr, &n2)
|
2015-02-13 14:40:36 -05:00
|
|
|
switch gc.Simtype[t.Etype] {
|
|
|
|
|
case gc.TINT8,
|
|
|
|
|
gc.TINT16:
|
|
|
|
|
gins(optoas(gc.OMUL, t), &n2, &n1)
|
|
|
|
|
gshift(arm.AMOVW, &n1, arm.SHIFT_AR, int32(w), &n1)
|
|
|
|
|
|
|
|
|
|
case gc.TUINT8,
|
|
|
|
|
gc.TUINT16:
|
|
|
|
|
gins(optoas(gc.OMUL, t), &n2, &n1)
|
|
|
|
|
gshift(arm.AMOVW, &n1, arm.SHIFT_LR, int32(w), &n1)
|
|
|
|
|
|
|
|
|
|
// perform a long multiplication.
|
|
|
|
|
case gc.TINT32,
|
|
|
|
|
gc.TUINT32:
|
2015-02-23 16:07:24 -05:00
|
|
|
var p *obj.Prog
|
2015-03-01 07:54:01 +00:00
|
|
|
if gc.Issigned[t.Etype] {
|
2015-02-13 14:40:36 -05:00
|
|
|
p = gins(arm.AMULL, &n2, nil)
|
|
|
|
|
} else {
|
|
|
|
|
p = gins(arm.AMULLU, &n2, nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// n2 * n1 -> (n1 n2)
|
2015-04-13 10:28:57 -07:00
|
|
|
p.Reg = n1.Reg
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
p.To.Type = obj.TYPE_REGREG
|
2015-04-13 10:28:57 -07:00
|
|
|
p.To.Reg = n1.Reg
|
|
|
|
|
p.To.Offset = int64(n2.Reg)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
default:
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("cgen_hmul %v", t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Cgen(&n1, res)
|
|
|
|
|
gc.Regfree(&n1)
|
|
|
|
|
gc.Regfree(&n2)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* generate shift according to op, one of:
|
|
|
|
|
* res = nl << nr
|
|
|
|
|
* res = nl >> nr
|
|
|
|
|
*/
|
2015-09-24 23:21:18 +02:00
|
|
|
func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if nl.Type.Width > 4 {
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("cgen_shift %v", nl.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
w := int(nl.Type.Width * 8)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
if op == gc.OLROT {
|
2015-04-22 20:08:03 -07:00
|
|
|
v := nr.Int()
|
2015-02-23 16:07:24 -05:00
|
|
|
var n1 gc.Node
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&n1, nl.Type, res)
|
2015-02-13 14:40:36 -05:00
|
|
|
if w == 32 {
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Cgen(nl, &n1)
|
2015-02-13 14:40:36 -05:00
|
|
|
gshift(arm.AMOVW, &n1, arm.SHIFT_RR, int32(w)-int32(v), &n1)
|
|
|
|
|
} else {
|
2015-02-23 16:07:24 -05:00
|
|
|
var n2 gc.Node
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&n2, nl.Type, nil)
|
|
|
|
|
gc.Cgen(nl, &n2)
|
2015-02-13 14:40:36 -05:00
|
|
|
gshift(arm.AMOVW, &n2, arm.SHIFT_LL, int32(v), &n1)
|
|
|
|
|
gshift(arm.AORR, &n2, arm.SHIFT_LR, int32(w)-int32(v), &n1)
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regfree(&n2)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// Ensure sign/zero-extended result.
|
|
|
|
|
gins(optoas(gc.OAS, nl.Type), &n1, &n1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gmove(&n1, res)
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regfree(&n1)
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if nr.Op == gc.OLITERAL {
|
2015-02-23 16:07:24 -05:00
|
|
|
var n1 gc.Node
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&n1, nl.Type, res)
|
|
|
|
|
gc.Cgen(nl, &n1)
|
2015-04-22 20:08:03 -07:00
|
|
|
sc := uint64(nr.Int())
|
2015-02-13 14:40:36 -05:00
|
|
|
if sc == 0 {
|
|
|
|
|
} else // nothing to do
|
|
|
|
|
if sc >= uint64(nl.Type.Width*8) {
|
2015-03-01 07:54:01 +00:00
|
|
|
if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
|
2015-02-13 14:40:36 -05:00
|
|
|
gshift(arm.AMOVW, &n1, arm.SHIFT_AR, int32(w), &n1)
|
|
|
|
|
} else {
|
|
|
|
|
gins(arm.AEOR, &n1, &n1)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2015-03-01 07:54:01 +00:00
|
|
|
if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
|
2015-02-13 14:40:36 -05:00
|
|
|
gshift(arm.AMOVW, &n1, arm.SHIFT_AR, int32(sc), &n1)
|
|
|
|
|
} else if op == gc.ORSH {
|
|
|
|
|
gshift(arm.AMOVW, &n1, arm.SHIFT_LR, int32(sc), &n1) // OLSH
|
|
|
|
|
} else {
|
|
|
|
|
gshift(arm.AMOVW, &n1, arm.SHIFT_LL, int32(sc), &n1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if w < 32 && op == gc.OLSH {
|
|
|
|
|
gins(optoas(gc.OAS, nl.Type), &n1, &n1)
|
|
|
|
|
}
|
|
|
|
|
gmove(&n1, res)
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regfree(&n1)
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
tr := nr.Type
|
|
|
|
|
var t gc.Node
|
|
|
|
|
var n1 gc.Node
|
|
|
|
|
var n2 gc.Node
|
|
|
|
|
var n3 gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
if tr.Width > 4 {
|
2015-02-23 16:07:24 -05:00
|
|
|
var nt gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Tempname(&nt, nr.Type)
|
|
|
|
|
if nl.Ullman >= nr.Ullman {
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&n2, nl.Type, res)
|
|
|
|
|
gc.Cgen(nl, &n2)
|
|
|
|
|
gc.Cgen(nr, &nt)
|
2015-02-13 14:40:36 -05:00
|
|
|
n1 = nt
|
|
|
|
|
} else {
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Cgen(nr, &nt)
|
|
|
|
|
gc.Regalloc(&n2, nl.Type, res)
|
|
|
|
|
gc.Cgen(nl, &n2)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var hi gc.Node
|
|
|
|
|
var lo gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
split64(&nt, &lo, &hi)
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&n1, gc.Types[gc.TUINT32], nil)
|
|
|
|
|
gc.Regalloc(&n3, gc.Types[gc.TUINT32], nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
gmove(&lo, &n1)
|
|
|
|
|
gmove(&hi, &n3)
|
|
|
|
|
splitclean()
|
|
|
|
|
gins(arm.ATST, &n3, nil)
|
|
|
|
|
gc.Nodconst(&t, gc.Types[gc.TUINT32], int64(w))
|
2015-02-23 16:07:24 -05:00
|
|
|
p1 := gins(arm.AMOVW, &t, &n1)
|
2015-02-13 14:40:36 -05:00
|
|
|
p1.Scond = arm.C_SCOND_NE
|
|
|
|
|
tr = gc.Types[gc.TUINT32]
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regfree(&n3)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
|
|
|
|
if nl.Ullman >= nr.Ullman {
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&n2, nl.Type, res)
|
|
|
|
|
gc.Cgen(nl, &n2)
|
|
|
|
|
gc.Regalloc(&n1, nr.Type, nil)
|
|
|
|
|
gc.Cgen(nr, &n1)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&n1, nr.Type, nil)
|
|
|
|
|
gc.Cgen(nr, &n1)
|
|
|
|
|
gc.Regalloc(&n2, nl.Type, res)
|
|
|
|
|
gc.Cgen(nl, &n2)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// test for shift being 0
|
|
|
|
|
gins(arm.ATST, &n1, nil)
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
p3 := gc.Gbranch(arm.ABEQ, nil, -1)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// test and fix up large shifts
|
|
|
|
|
// TODO: if(!bounded), don't emit some of this.
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&n3, tr, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
gc.Nodconst(&t, gc.Types[gc.TUINT32], int64(w))
|
|
|
|
|
gmove(&t, &n3)
|
2015-03-18 17:26:36 -04:00
|
|
|
gins(arm.ACMP, &n1, &n3)
|
2015-02-13 14:40:36 -05:00
|
|
|
if op == gc.ORSH {
|
2015-02-23 16:07:24 -05:00
|
|
|
var p1 *obj.Prog
|
|
|
|
|
var p2 *obj.Prog
|
2015-03-01 07:54:01 +00:00
|
|
|
if gc.Issigned[nl.Type.Etype] {
|
2015-02-13 14:40:36 -05:00
|
|
|
p1 = gshift(arm.AMOVW, &n2, arm.SHIFT_AR, int32(w)-1, &n2)
|
|
|
|
|
p2 = gregshift(arm.AMOVW, &n2, arm.SHIFT_AR, &n1, &n2)
|
|
|
|
|
} else {
|
|
|
|
|
p1 = gins(arm.AEOR, &n2, &n2)
|
|
|
|
|
p2 = gregshift(arm.AMOVW, &n2, arm.SHIFT_LR, &n1, &n2)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p1.Scond = arm.C_SCOND_HS
|
|
|
|
|
p2.Scond = arm.C_SCOND_LO
|
|
|
|
|
} else {
|
2015-02-23 16:07:24 -05:00
|
|
|
p1 := gins(arm.AEOR, &n2, &n2)
|
|
|
|
|
p2 := gregshift(arm.AMOVW, &n2, arm.SHIFT_LL, &n1, &n2)
|
2015-02-13 14:40:36 -05:00
|
|
|
p1.Scond = arm.C_SCOND_HS
|
|
|
|
|
p2.Scond = arm.C_SCOND_LO
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regfree(&n3)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
gc.Patch(p3, gc.Pc)
|
|
|
|
|
|
|
|
|
|
// Left-shift of smaller word must be sign/zero-extended.
|
|
|
|
|
if w < 32 && op == gc.OLSH {
|
|
|
|
|
gins(optoas(gc.OAS, nl.Type), &n2, &n2)
|
|
|
|
|
}
|
|
|
|
|
gmove(&n2, res)
|
|
|
|
|
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regfree(&n1)
|
|
|
|
|
gc.Regfree(&n2)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func clearfat(nl *gc.Node) {
|
|
|
|
|
/* clear a fat object */
|
|
|
|
|
if gc.Debug['g'] != 0 {
|
|
|
|
|
gc.Dump("\nclearfat", nl)
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
w := uint32(nl.Type.Width)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// Avoid taking the address for simple enough types.
|
2015-03-18 12:29:40 -04:00
|
|
|
if gc.Componentgen(nil, nl) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
c := w % 4 // bytes
|
|
|
|
|
q := w / 4 // quads
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var r0 gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
r0.Op = gc.OREGISTER
|
|
|
|
|
|
2015-04-13 10:28:57 -07:00
|
|
|
r0.Reg = arm.REG_R0
|
2015-02-23 16:07:24 -05:00
|
|
|
var r1 gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
r1.Op = gc.OREGISTER
|
2015-04-13 10:28:57 -07:00
|
|
|
r1.Reg = arm.REG_R1
|
2015-02-23 16:07:24 -05:00
|
|
|
var dst gc.Node
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&dst, gc.Types[gc.Tptr], &r1)
|
|
|
|
|
gc.Agen(nl, &dst)
|
2015-02-23 16:07:24 -05:00
|
|
|
var nc gc.Node
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Nodconst(&nc, gc.Types[gc.TUINT32], 0)
|
2015-02-23 16:07:24 -05:00
|
|
|
var nz gc.Node
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&nz, gc.Types[gc.TUINT32], &r0)
|
|
|
|
|
gc.Cgen(&nc, &nz)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
if q > 128 {
|
2015-02-23 16:07:24 -05:00
|
|
|
var end gc.Node
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
|
2015-02-23 16:07:24 -05:00
|
|
|
p := gins(arm.AMOVW, &dst, &end)
|
2015-02-13 14:40:36 -05:00
|
|
|
p.From.Type = obj.TYPE_ADDR
|
|
|
|
|
p.From.Offset = int64(q) * 4
|
|
|
|
|
|
|
|
|
|
p = gins(arm.AMOVW, &nz, &dst)
|
|
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Offset = 4
|
|
|
|
|
p.Scond |= arm.C_PBIT
|
2015-02-23 16:07:24 -05:00
|
|
|
pl := p
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
p = gins(arm.ACMP, &dst, nil)
|
|
|
|
|
raddr(&end, p)
|
|
|
|
|
gc.Patch(gc.Gbranch(arm.ABNE, nil, 0), pl)
|
|
|
|
|
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regfree(&end)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else if q >= 4 && !gc.Nacl {
|
2015-02-23 16:07:24 -05:00
|
|
|
f := gc.Sysfunc("duffzero")
|
|
|
|
|
p := gins(obj.ADUFFZERO, nil, f)
|
2015-02-13 14:40:36 -05:00
|
|
|
gc.Afunclit(&p.To, f)
|
|
|
|
|
|
|
|
|
|
// 4 and 128 = magic constants: see ../../runtime/asm_arm.s
|
|
|
|
|
p.To.Offset = 4 * (128 - int64(q))
|
|
|
|
|
} else {
|
2015-02-23 16:07:24 -05:00
|
|
|
var p *obj.Prog
|
2015-02-13 14:40:36 -05:00
|
|
|
for q > 0 {
|
|
|
|
|
p = gins(arm.AMOVW, &nz, &dst)
|
|
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Offset = 4
|
|
|
|
|
p.Scond |= arm.C_PBIT
|
|
|
|
|
|
2015-05-27 10:40:47 -04:00
|
|
|
//print("1. %v\n", p);
|
2015-02-13 14:40:36 -05:00
|
|
|
q--
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var p *obj.Prog
|
2015-02-13 14:40:36 -05:00
|
|
|
for c > 0 {
|
|
|
|
|
p = gins(arm.AMOVB, &nz, &dst)
|
|
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Offset = 1
|
|
|
|
|
p.Scond |= arm.C_PBIT
|
|
|
|
|
|
2015-05-27 10:40:47 -04:00
|
|
|
//print("2. %v\n", p);
|
2015-02-13 14:40:36 -05:00
|
|
|
c--
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-18 17:26:36 -04:00
|
|
|
gc.Regfree(&dst)
|
|
|
|
|
gc.Regfree(&nz)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Called after regopt and peep have run.
|
|
|
|
|
// Expand CHECKNIL pseudo-op into actual nil pointer check.
|
|
|
|
|
func expandchecks(firstp *obj.Prog) {
|
|
|
|
|
var reg int
|
|
|
|
|
var p1 *obj.Prog
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
for p := firstp; p != nil; p = p.Link {
|
2015-02-13 14:40:36 -05:00
|
|
|
if p.As != obj.ACHECKNIL {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
|
2016-03-02 11:01:25 -08:00
|
|
|
gc.Warnl(p.Lineno, "generated nil check")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if p.From.Type != obj.TYPE_REG {
|
2015-08-30 23:10:03 +02:00
|
|
|
gc.Fatalf("invalid nil check %v", p)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
reg = int(p.From.Reg)
|
|
|
|
|
|
|
|
|
|
// check is
|
|
|
|
|
// CMP arg, $0
|
|
|
|
|
// MOV.EQ arg, 0(arg)
|
|
|
|
|
p1 = gc.Ctxt.NewProg()
|
|
|
|
|
|
|
|
|
|
gc.Clearp(p1)
|
|
|
|
|
p1.Link = p.Link
|
|
|
|
|
p.Link = p1
|
|
|
|
|
p1.Lineno = p.Lineno
|
|
|
|
|
p1.Pc = 9999
|
|
|
|
|
p1.As = arm.AMOVW
|
|
|
|
|
p1.From.Type = obj.TYPE_REG
|
|
|
|
|
p1.From.Reg = int16(reg)
|
|
|
|
|
p1.To.Type = obj.TYPE_MEM
|
|
|
|
|
p1.To.Reg = int16(reg)
|
|
|
|
|
p1.To.Offset = 0
|
|
|
|
|
p1.Scond = arm.C_SCOND_EQ
|
|
|
|
|
p.As = arm.ACMP
|
|
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Reg = 0
|
|
|
|
|
p.From.Offset = 0
|
|
|
|
|
p.Reg = int16(reg)
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-03-18 17:26:36 -04:00
|
|
|
|
|
|
|
|
func ginsnop() {
|
|
|
|
|
var r gc.Node
|
|
|
|
|
gc.Nodreg(&r, gc.Types[gc.TINT], arm.REG_R0)
|
|
|
|
|
p := gins(arm.AAND, &r, &r)
|
|
|
|
|
p.Scond = arm.C_SCOND_EQ
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* generate
|
|
|
|
|
* as $c, n
|
|
|
|
|
*/
|
|
|
|
|
func ginscon(as int, c int64, n *gc.Node) {
|
|
|
|
|
var n1 gc.Node
|
|
|
|
|
gc.Nodconst(&n1, gc.Types[gc.TINT32], c)
|
|
|
|
|
var n2 gc.Node
|
|
|
|
|
gc.Regalloc(&n2, gc.Types[gc.TINT32], nil)
|
|
|
|
|
gmove(&n1, &n2)
|
|
|
|
|
gins(as, &n2, n)
|
|
|
|
|
gc.Regfree(&n2)
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-24 23:21:18 +02:00
|
|
|
func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
|
2015-04-22 20:08:03 -07:00
|
|
|
if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && n1.Int() == 0 && n2.Op != gc.OLITERAL {
|
2015-05-12 15:51:22 -04:00
|
|
|
op = gc.Brrev(op)
|
|
|
|
|
n1, n2 = n2, n1
|
|
|
|
|
}
|
2015-05-06 12:28:19 -04:00
|
|
|
var r1, r2, g1, g2 gc.Node
|
|
|
|
|
gc.Regalloc(&r1, t, n1)
|
|
|
|
|
gc.Regalloc(&g1, n1.Type, &r1)
|
|
|
|
|
gc.Cgen(n1, &g1)
|
|
|
|
|
gmove(&g1, &r1)
|
2015-04-22 20:08:03 -07:00
|
|
|
if gc.Isint[t.Etype] && n2.Op == gc.OLITERAL && n2.Int() == 0 {
|
2015-05-12 15:51:22 -04:00
|
|
|
gins(arm.ACMP, &r1, 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)
|
|
|
|
|
gc.Regfree(&g2)
|
|
|
|
|
gc.Regfree(&r2)
|
|
|
|
|
}
|
2015-05-06 12:28:19 -04:00
|
|
|
gc.Regfree(&g1)
|
|
|
|
|
gc.Regfree(&r1)
|
|
|
|
|
return gc.Gbranch(optoas(op, t), nil, likely)
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-18 17:26:36 -04:00
|
|
|
// addr += index*width if possible.
|
|
|
|
|
func addindex(index *gc.Node, width int64, addr *gc.Node) bool {
|
|
|
|
|
switch width {
|
|
|
|
|
case 2:
|
|
|
|
|
gshift(arm.AADD, index, arm.SHIFT_LL, 1, addr)
|
|
|
|
|
return true
|
|
|
|
|
case 4:
|
|
|
|
|
gshift(arm.AADD, index, arm.SHIFT_LL, 2, addr)
|
|
|
|
|
return true
|
|
|
|
|
case 8:
|
|
|
|
|
gshift(arm.AADD, index, arm.SHIFT_LL, 3, addr)
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
2015-04-03 12:23:28 -04:00
|
|
|
|
|
|
|
|
// res = runtime.getg()
|
|
|
|
|
func getg(res *gc.Node) {
|
|
|
|
|
var n1 gc.Node
|
|
|
|
|
gc.Nodreg(&n1, res.Type, arm.REGG)
|
|
|
|
|
gmove(&n1, res)
|
|
|
|
|
}
|