cmd/internal/gc: move cgen, regalloc, et al to portable code
This CL moves the bulk of the code that has been copy-and-pasted
since the initial 386 port back into a shared place, cutting 5 copies to 1.
The motivation here is not cleanup per se but instead to reduce the
cost of introducing changes in shared concepts like regalloc or general
expression evaluation. For example, a change after this one will
implement x.(*T) without a call into the runtime. This CL makes that
followup work 5x easier.
The single copy still has more special cases for architecture details
than I'd like, but having them called out explicitly like this at least
opens the door to generalizing the conditions and smoothing out
the distinctions in the future.
This is a LARGE CL. I started by trying to pull in one function at a time
in a sequence of CLs and it became clear that everything was so
interrelated that it had to be moved as a whole. Apologies for the size.
It is not clear how many more releases this code will matter for;
eventually it will be replaced by Keith's SSA work. But as noted above,
the deduplication was necessary to reduce the cost of working on
the current code while we have it.
Passes tests on amd64, 386, arm, and ppc64le.
Can build arm64 binaries but not tested there.
Being able to build binaries means it is probably very close.
Change-Id: I735977f04c0614f80215fb12966dfe9bbd1f5861
Reviewed-on: https://go-review.googlesource.com/7853
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/cmd/8g/cgen.go b/src/cmd/8g/cgen.go
index 2a10e49..5546aba3 100644
--- a/src/cmd/8g/cgen.go
+++ b/src/cmd/8g/cgen.go
@@ -8,507 +8,21 @@
"cmd/internal/gc"
"cmd/internal/obj"
"cmd/internal/obj/x86"
- "fmt"
)
/*
- * reg.c
- */
-
-/*
- * peep.c
- */
-func mgen(n *gc.Node, n1 *gc.Node, rg *gc.Node) {
- n1.Op = gc.OEMPTY
-
- if n.Addable != 0 {
- *n1 = *n
- if n1.Op == gc.OREGISTER || n1.Op == gc.OINDREG {
- reg[n.Val.U.Reg]++
- }
- return
- }
-
- gc.Tempname(n1, n.Type)
- cgen(n, n1)
- if n.Type.Width <= int64(gc.Widthptr) || gc.Isfloat[n.Type.Etype] {
- n2 := *n1
- regalloc(n1, n.Type, rg)
- gmove(&n2, n1)
- }
-}
-
-func mfree(n *gc.Node) {
- if n.Op == gc.OREGISTER {
- regfree(n)
- }
-}
-
-/*
- * generate:
- * res = n;
- * simplifies and calls gmove.
- *
- * TODO:
- * sudoaddable
- */
-func cgen(n *gc.Node, res *gc.Node) {
- if gc.Debug['g'] != 0 {
- gc.Dump("\ncgen-n", n)
- gc.Dump("cgen-res", res)
- }
-
- if n == nil || n.Type == nil {
- gc.Fatal("cgen: n nil")
- }
- if res == nil || res.Type == nil {
- gc.Fatal("cgen: res nil")
- }
-
- switch n.Op {
- case gc.OSLICE,
- gc.OSLICEARR,
- gc.OSLICESTR,
- gc.OSLICE3,
- gc.OSLICE3ARR:
- if res.Op != gc.ONAME || res.Addable == 0 {
- var n1 gc.Node
- gc.Tempname(&n1, n.Type)
- gc.Cgen_slice(n, &n1)
- cgen(&n1, res)
- } else {
- gc.Cgen_slice(n, res)
- }
- return
-
- case gc.OEFACE:
- if res.Op != gc.ONAME || res.Addable == 0 {
- var n1 gc.Node
- gc.Tempname(&n1, n.Type)
- gc.Cgen_eface(n, &n1)
- cgen(&n1, res)
- } else {
- gc.Cgen_eface(n, res)
- }
- return
- }
-
- for n.Op == gc.OCONVNOP {
- n = n.Left
- }
-
- // function calls on both sides? introduce temporary
- if n.Ullman >= gc.UINF && res.Ullman >= gc.UINF {
- var n1 gc.Node
- gc.Tempname(&n1, n.Type)
- cgen(n, &n1)
- cgen(&n1, res)
- return
- }
-
- // structs etc get handled specially
- if gc.Isfat(n.Type) {
- if n.Type.Width < 0 {
- gc.Fatal("forgot to compute width for %v", gc.Tconv(n.Type, 0))
- }
- sgen(n, res, n.Type.Width)
- return
- }
-
- // update addressability for string, slice
- // can't do in walk because n->left->addable
- // changes if n->left is an escaping local variable.
- switch n.Op {
- case gc.OSPTR,
- gc.OLEN:
- if gc.Isslice(n.Left.Type) || gc.Istype(n.Left.Type, gc.TSTRING) {
- n.Addable = n.Left.Addable
- }
-
- case gc.OCAP:
- if gc.Isslice(n.Left.Type) {
- n.Addable = n.Left.Addable
- }
-
- case gc.OITAB:
- n.Addable = n.Left.Addable
- }
-
- // if both are addressable, move
- if n.Addable != 0 && res.Addable != 0 {
- gmove(n, res)
- return
- }
-
- // if both are not addressable, use a temporary.
- if n.Addable == 0 && res.Addable == 0 {
- // could use regalloc here sometimes,
- // but have to check for ullman >= UINF.
- var n1 gc.Node
- gc.Tempname(&n1, n.Type)
-
- cgen(n, &n1)
- cgen(&n1, res)
- return
- }
-
- // if result is not addressable directly but n is,
- // compute its address and then store via the address.
- if res.Addable == 0 {
- var n1 gc.Node
- igen(res, &n1, nil)
- cgen(n, &n1)
- regfree(&n1)
- return
- }
-
- // complex types
- if gc.Complexop(n, res) {
- gc.Complexgen(n, res)
- return
- }
-
- // otherwise, the result is addressable but n is not.
- // let's do some computation.
-
- // use ullman to pick operand to eval first.
- nl := n.Left
-
- nr := n.Right
- if nl != nil && nl.Ullman >= gc.UINF {
- if nr != nil && nr.Ullman >= gc.UINF {
- // both are hard
- var n1 gc.Node
- gc.Tempname(&n1, nl.Type)
-
- cgen(nl, &n1)
- n2 := *n
- n2.Left = &n1
- cgen(&n2, res)
- return
- }
- }
-
- // 64-bit ops are hard on 32-bit machine.
- if gc.Is64(n.Type) || gc.Is64(res.Type) || n.Left != nil && gc.Is64(n.Left.Type) {
- switch n.Op {
- // math goes to cgen64.
- case gc.OMINUS,
- gc.OCOM,
- gc.OADD,
- gc.OSUB,
- gc.OMUL,
- gc.OLROT,
- gc.OLSH,
- gc.ORSH,
- gc.OAND,
- gc.OOR,
- gc.OXOR:
- cgen64(n, res)
-
- return
- }
- }
-
- if nl != nil && gc.Isfloat[n.Type.Etype] && gc.Isfloat[nl.Type.Etype] {
- cgen_float(n, res)
- return
- }
-
- var a int
- switch n.Op {
- default:
- gc.Dump("cgen", n)
- gc.Fatal("cgen %v", gc.Oconv(int(n.Op), 0))
-
- case gc.OREAL,
- gc.OIMAG,
- gc.OCOMPLEX:
- gc.Fatal("unexpected complex")
- return
-
- // these call bgen to get a bool value
- case gc.OOROR,
- gc.OANDAND,
- gc.OEQ,
- gc.ONE,
- gc.OLT,
- gc.OLE,
- gc.OGE,
- gc.OGT,
- gc.ONOT:
- p1 := gc.Gbranch(obj.AJMP, nil, 0)
-
- p2 := gc.Pc
- gmove(gc.Nodbool(true), res)
- p3 := gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p1, gc.Pc)
- bgen(n, true, 0, p2)
- gmove(gc.Nodbool(false), res)
- gc.Patch(p3, gc.Pc)
- return
-
- case gc.OPLUS:
- cgen(nl, res)
- return
-
- case gc.OMINUS,
- gc.OCOM:
- a := optoas(int(n.Op), nl.Type)
- // unary
- var n1 gc.Node
- gc.Tempname(&n1, nl.Type)
-
- cgen(nl, &n1)
- gins(a, nil, &n1)
- gmove(&n1, res)
- return
-
- // symmetric binary
- case gc.OAND,
- gc.OOR,
- gc.OXOR,
- gc.OADD,
- gc.OMUL:
- a = optoas(int(n.Op), nl.Type)
-
- if a == x86.AIMULB {
- cgen_bmul(int(n.Op), nl, nr, res)
- break
- }
-
- // symmetric binary
- if nl.Ullman < nr.Ullman || nl.Op == gc.OLITERAL {
- r := nl
- nl = nr
- nr = r
- }
- goto abop
-
- // asymmetric binary
- case gc.OSUB:
- a = optoas(int(n.Op), nl.Type)
-
- goto abop
-
- case gc.OHMUL:
- cgen_hmul(nl, nr, res)
-
- case gc.OCONV:
- if gc.Eqtype(n.Type, nl.Type) || gc.Noconv(n.Type, nl.Type) {
- cgen(nl, res)
- break
- }
-
- var n2 gc.Node
- gc.Tempname(&n2, n.Type)
- var n1 gc.Node
- mgen(nl, &n1, res)
- gmove(&n1, &n2)
- gmove(&n2, res)
- mfree(&n1)
-
- case gc.ODOT,
- gc.ODOTPTR,
- gc.OINDEX,
- gc.OIND,
- gc.ONAME: // PHEAP or PPARAMREF var
- var n1 gc.Node
- igen(n, &n1, res)
-
- gmove(&n1, res)
- regfree(&n1)
-
- case gc.OITAB:
- var n1 gc.Node
- igen(nl, &n1, res)
- n1.Type = gc.Ptrto(gc.Types[gc.TUINTPTR])
- gmove(&n1, res)
- regfree(&n1)
-
- // pointer is the first word of string or slice.
- case gc.OSPTR:
- if gc.Isconst(nl, gc.CTSTR) {
- var n1 gc.Node
- regalloc(&n1, gc.Types[gc.Tptr], res)
- p1 := gins(x86.ALEAL, nil, &n1)
- gc.Datastring(nl.Val.U.Sval, &p1.From)
- gmove(&n1, res)
- regfree(&n1)
- break
- }
-
- var n1 gc.Node
- igen(nl, &n1, res)
- n1.Type = n.Type
- gmove(&n1, res)
- regfree(&n1)
-
- case gc.OLEN:
- if gc.Istype(nl.Type, gc.TMAP) || gc.Istype(nl.Type, gc.TCHAN) {
- // map has len in the first 32-bit word.
- // a zero pointer means zero length
- var n1 gc.Node
- gc.Tempname(&n1, gc.Types[gc.Tptr])
-
- cgen(nl, &n1)
- var n2 gc.Node
- regalloc(&n2, gc.Types[gc.Tptr], nil)
- gmove(&n1, &n2)
- n1 = n2
-
- gc.Nodconst(&n2, gc.Types[gc.Tptr], 0)
- gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2)
- p1 := gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, -1)
-
- n2 = n1
- n2.Op = gc.OINDREG
- n2.Type = gc.Types[gc.TINT32]
- gmove(&n2, &n1)
-
- gc.Patch(p1, gc.Pc)
-
- gmove(&n1, res)
- regfree(&n1)
- break
- }
-
- if gc.Istype(nl.Type, gc.TSTRING) || gc.Isslice(nl.Type) {
- // both slice and string have len one pointer into the struct.
- var n1 gc.Node
- igen(nl, &n1, res)
-
- n1.Type = gc.Types[gc.TUINT32]
- n1.Xoffset += int64(gc.Array_nel)
- gmove(&n1, res)
- regfree(&n1)
- break
- }
-
- gc.Fatal("cgen: OLEN: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong))
-
- case gc.OCAP:
- if gc.Istype(nl.Type, gc.TCHAN) {
- // chan has cap in the second 32-bit word.
- // a zero pointer means zero length
- var n1 gc.Node
- gc.Tempname(&n1, gc.Types[gc.Tptr])
-
- cgen(nl, &n1)
- var n2 gc.Node
- regalloc(&n2, gc.Types[gc.Tptr], nil)
- gmove(&n1, &n2)
- n1 = n2
-
- gc.Nodconst(&n2, gc.Types[gc.Tptr], 0)
- gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2)
- p1 := gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, -1)
-
- n2 = n1
- n2.Op = gc.OINDREG
- n2.Xoffset = 4
- n2.Type = gc.Types[gc.TINT32]
- gmove(&n2, &n1)
-
- gc.Patch(p1, gc.Pc)
-
- gmove(&n1, res)
- regfree(&n1)
- break
- }
-
- if gc.Isslice(nl.Type) {
- var n1 gc.Node
- igen(nl, &n1, res)
- n1.Type = gc.Types[gc.TUINT32]
- n1.Xoffset += int64(gc.Array_cap)
- gmove(&n1, res)
- regfree(&n1)
- break
- }
-
- gc.Fatal("cgen: OCAP: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong))
-
- case gc.OADDR:
- agen(nl, res)
-
- case gc.OCALLMETH:
- gc.Cgen_callmeth(n, 0)
- cgen_callret(n, res)
-
- case gc.OCALLINTER:
- cgen_callinter(n, res, 0)
- cgen_callret(n, res)
-
- case gc.OCALLFUNC:
- cgen_call(n, 0)
- cgen_callret(n, res)
-
- case gc.OMOD,
- gc.ODIV:
- cgen_div(int(n.Op), nl, nr, res)
-
- case gc.OLSH,
- gc.ORSH,
- gc.OLROT:
- cgen_shift(int(n.Op), n.Bounded, nl, nr, res)
- }
-
- return
-
-abop: // asymmetric binary
- if gc.Smallintconst(nr) {
- var n1 gc.Node
- mgen(nl, &n1, res)
- var n2 gc.Node
- regalloc(&n2, nl.Type, &n1)
- gmove(&n1, &n2)
- gins(a, nr, &n2)
- gmove(&n2, res)
- regfree(&n2)
- mfree(&n1)
- } else if nl.Ullman >= nr.Ullman {
- var nt gc.Node
- gc.Tempname(&nt, nl.Type)
- cgen(nl, &nt)
- var n2 gc.Node
- mgen(nr, &n2, nil)
- var n1 gc.Node
- regalloc(&n1, nl.Type, res)
- gmove(&nt, &n1)
- gins(a, &n2, &n1)
- gmove(&n1, res)
- regfree(&n1)
- mfree(&n2)
- } else {
- var n2 gc.Node
- regalloc(&n2, nr.Type, res)
- cgen(nr, &n2)
- var n1 gc.Node
- regalloc(&n1, nl.Type, nil)
- cgen(nl, &n1)
- gins(a, &n2, &n1)
- regfree(&n2)
- gmove(&n1, res)
- regfree(&n1)
- }
-
- return
-}
-
-/*
* generate an addressable node in res, containing the value of n.
* n is an array index, and might be any size; res width is <= 32-bit.
* returns Prog* to patch to panic call.
*/
-func igenindex(n *gc.Node, res *gc.Node, bounded int) *obj.Prog {
+func igenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog {
if !gc.Is64(n.Type) {
if n.Addable != 0 {
// nothing to do.
*res = *n
} else {
gc.Tempname(res, gc.Types[gc.TUINT32])
- cgen(n, res)
+ gc.Cgen(n, res)
}
return nil
@@ -516,13 +30,13 @@
var tmp gc.Node
gc.Tempname(&tmp, gc.Types[gc.TINT64])
- cgen(n, &tmp)
+ gc.Cgen(n, &tmp)
var lo gc.Node
var hi gc.Node
split64(&tmp, &lo, &hi)
gc.Tempname(res, gc.Types[gc.TUINT32])
gmove(&lo, res)
- if bounded != 0 {
+ if bounded {
splitclean()
return nil
}
@@ -534,826 +48,7 @@
return gc.Gbranch(x86.AJNE, nil, +1)
}
-/*
- * address gen
- * res = &n;
- * The generated code checks that the result is not nil.
- */
-func agen(n *gc.Node, res *gc.Node) {
- if gc.Debug['g'] != 0 {
- gc.Dump("\nagen-res", res)
- gc.Dump("agen-r", n)
- }
-
- if n == nil || n.Type == nil || res == nil || res.Type == nil {
- gc.Fatal("agen")
- }
-
- for n.Op == gc.OCONVNOP {
- n = n.Left
- }
-
- if gc.Isconst(n, gc.CTNIL) && n.Type.Width > int64(gc.Widthptr) {
- // Use of a nil interface or nil slice.
- // Create a temporary we can take the address of and read.
- // The generated code is just going to panic, so it need not
- // be terribly efficient. See issue 3670.
- var n1 gc.Node
- gc.Tempname(&n1, n.Type)
-
- gc.Gvardef(&n1)
- clearfat(&n1)
- var n2 gc.Node
- regalloc(&n2, gc.Types[gc.Tptr], res)
- gins(x86.ALEAL, &n1, &n2)
- gmove(&n2, res)
- regfree(&n2)
- return
- }
-
- // addressable var is easy
- if n.Addable != 0 {
- if n.Op == gc.OREGISTER {
- gc.Fatal("agen OREGISTER")
- }
- var n1 gc.Node
- regalloc(&n1, gc.Types[gc.Tptr], res)
- gins(x86.ALEAL, n, &n1)
- gmove(&n1, res)
- regfree(&n1)
- return
- }
-
- // let's compute
- nl := n.Left
-
- nr := n.Right
-
- switch n.Op {
- default:
- gc.Fatal("agen %v", gc.Oconv(int(n.Op), 0))
-
- case gc.OCALLMETH:
- gc.Cgen_callmeth(n, 0)
- cgen_aret(n, res)
-
- case gc.OCALLINTER:
- cgen_callinter(n, res, 0)
- cgen_aret(n, res)
-
- case gc.OCALLFUNC:
- cgen_call(n, 0)
- cgen_aret(n, res)
-
- case gc.OSLICE,
- gc.OSLICEARR,
- gc.OSLICESTR,
- gc.OSLICE3,
- gc.OSLICE3ARR:
- var n1 gc.Node
- gc.Tempname(&n1, n.Type)
- gc.Cgen_slice(n, &n1)
- agen(&n1, res)
-
- case gc.OEFACE:
- var n1 gc.Node
- gc.Tempname(&n1, n.Type)
- gc.Cgen_eface(n, &n1)
- agen(&n1, res)
-
- case gc.OINDEX:
- var p2 *obj.Prog // to be patched to panicindex.
- w := uint32(n.Type.Width)
- bounded := gc.Debug['B'] != 0 || n.Bounded
- var n3 gc.Node
- var tmp gc.Node
- var n1 gc.Node
- if nr.Addable != 0 {
- // Generate &nl first, and move nr into register.
- if !gc.Isconst(nl, gc.CTSTR) {
- igen(nl, &n3, res)
- }
- if !gc.Isconst(nr, gc.CTINT) {
- p2 = igenindex(nr, &tmp, bool2int(bounded))
- regalloc(&n1, tmp.Type, nil)
- gmove(&tmp, &n1)
- }
- } else if nl.Addable != 0 {
- // Generate nr first, and move &nl into register.
- if !gc.Isconst(nr, gc.CTINT) {
- p2 = igenindex(nr, &tmp, bool2int(bounded))
- regalloc(&n1, tmp.Type, nil)
- gmove(&tmp, &n1)
- }
-
- if !gc.Isconst(nl, gc.CTSTR) {
- igen(nl, &n3, res)
- }
- } else {
- p2 = igenindex(nr, &tmp, bool2int(bounded))
- nr = &tmp
- if !gc.Isconst(nl, gc.CTSTR) {
- igen(nl, &n3, res)
- }
- regalloc(&n1, tmp.Type, nil)
- gins(optoas(gc.OAS, tmp.Type), &tmp, &n1)
- }
-
- // For fixed array we really want the pointer in n3.
- var n2 gc.Node
- if gc.Isfixedarray(nl.Type) {
- regalloc(&n2, gc.Types[gc.Tptr], &n3)
- agen(&n3, &n2)
- regfree(&n3)
- n3 = n2
- }
-
- // &a[0] is in n3 (allocated in res)
- // i is in n1 (if not constant)
- // len(a) is in nlen (if needed)
- // w is width
-
- // constant index
- if gc.Isconst(nr, gc.CTINT) {
- if gc.Isconst(nl, gc.CTSTR) {
- gc.Fatal("constant string constant index") // front end should handle
- }
- v := uint64(gc.Mpgetfix(nr.Val.U.Xval))
- if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
- if gc.Debug['B'] == 0 && !n.Bounded {
- nlen := n3
- nlen.Type = gc.Types[gc.TUINT32]
- nlen.Xoffset += int64(gc.Array_nel)
- gc.Nodconst(&n2, gc.Types[gc.TUINT32], int64(v))
- gins(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &nlen, &n2)
- p1 := gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TUINT32]), nil, +1)
- ginscall(gc.Panicindex, -1)
- gc.Patch(p1, gc.Pc)
- }
- }
-
- // Load base pointer in n2 = n3.
- regalloc(&n2, gc.Types[gc.Tptr], &n3)
-
- n3.Type = gc.Types[gc.Tptr]
- n3.Xoffset += int64(gc.Array_array)
- gmove(&n3, &n2)
- regfree(&n3)
- if v*uint64(w) != 0 {
- gc.Nodconst(&n1, gc.Types[gc.Tptr], int64(v*uint64(w)))
- gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n1, &n2)
- }
-
- gmove(&n2, res)
- regfree(&n2)
- break
- }
-
- // i is in register n1, extend to 32 bits.
- t := gc.Types[gc.TUINT32]
-
- if gc.Issigned[n1.Type.Etype] {
- t = gc.Types[gc.TINT32]
- }
-
- regalloc(&n2, t, &n1) // i
- gmove(&n1, &n2)
- regfree(&n1)
-
- if gc.Debug['B'] == 0 && !n.Bounded {
- // check bounds
- t := gc.Types[gc.TUINT32]
-
- var nlen gc.Node
- if gc.Isconst(nl, gc.CTSTR) {
- gc.Nodconst(&nlen, t, int64(len(nl.Val.U.Sval)))
- } else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
- nlen = n3
- nlen.Type = t
- nlen.Xoffset += int64(gc.Array_nel)
- } else {
- gc.Nodconst(&nlen, t, nl.Type.Bound)
- }
-
- gins(optoas(gc.OCMP, t), &n2, &nlen)
- p1 := gc.Gbranch(optoas(gc.OLT, t), nil, +1)
- if p2 != nil {
- gc.Patch(p2, gc.Pc)
- }
- ginscall(gc.Panicindex, -1)
- gc.Patch(p1, gc.Pc)
- }
-
- if gc.Isconst(nl, gc.CTSTR) {
- regalloc(&n3, gc.Types[gc.Tptr], res)
- p1 := gins(x86.ALEAL, nil, &n3)
- gc.Datastring(nl.Val.U.Sval, &p1.From)
- p1.From.Scale = 1
- p1.From.Index = n2.Val.U.Reg
- goto indexdone
- }
-
- // Load base pointer in n3.
- regalloc(&tmp, gc.Types[gc.Tptr], &n3)
-
- if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING {
- n3.Type = gc.Types[gc.Tptr]
- n3.Xoffset += int64(gc.Array_array)
- gmove(&n3, &tmp)
- }
-
- regfree(&n3)
- n3 = tmp
-
- if w == 0 {
- } else // nothing to do
- if w == 1 || w == 2 || w == 4 || w == 8 {
- // LEAL (n3)(n2*w), n3
- p1 := gins(x86.ALEAL, &n2, &n3)
-
- p1.From.Scale = int16(w)
- p1.From.Type = obj.TYPE_MEM
- p1.From.Index = p1.From.Reg
- p1.From.Reg = p1.To.Reg
- } else {
- gc.Nodconst(&tmp, gc.Types[gc.TUINT32], int64(w))
- gins(optoas(gc.OMUL, gc.Types[gc.TUINT32]), &tmp, &n2)
- gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3)
- }
-
- indexdone:
- gmove(&n3, res)
- regfree(&n2)
- regfree(&n3)
-
- // should only get here with names in this func.
- case gc.ONAME:
- if n.Funcdepth > 0 && n.Funcdepth != gc.Funcdepth {
- gc.Dump("bad agen", n)
- gc.Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, gc.Funcdepth)
- }
-
- // should only get here for heap vars or paramref
- if n.Class&gc.PHEAP == 0 && n.Class != gc.PPARAMREF {
- gc.Dump("bad agen", n)
- gc.Fatal("agen: bad ONAME class %#x", n.Class)
- }
-
- cgen(n.Heapaddr, res)
- if n.Xoffset != 0 {
- var n1 gc.Node
- gc.Nodconst(&n1, gc.Types[gc.Tptr], n.Xoffset)
- gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n1, res)
- }
-
- case gc.OIND:
- cgen(nl, res)
- gc.Cgen_checknil(res)
-
- case gc.ODOT:
- agen(nl, res)
- if n.Xoffset != 0 {
- var n1 gc.Node
- gc.Nodconst(&n1, gc.Types[gc.Tptr], n.Xoffset)
- gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n1, res)
- }
-
- case gc.ODOTPTR:
- t := nl.Type
- if !gc.Isptr[t.Etype] {
- gc.Fatal("agen: not ptr %v", gc.Nconv(n, 0))
- }
- cgen(nl, res)
- gc.Cgen_checknil(res)
- if n.Xoffset != 0 {
- var n1 gc.Node
- gc.Nodconst(&n1, gc.Types[gc.Tptr], n.Xoffset)
- gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n1, res)
- }
- }
-}
-
-/*
- * generate:
- * newreg = &n;
- * res = newreg
- *
- * on exit, a has been changed to be *newreg.
- * caller must regfree(a).
- * The generated code checks that the result is not *nil.
- */
-func igen(n *gc.Node, a *gc.Node, res *gc.Node) {
- if gc.Debug['g'] != 0 {
- gc.Dump("\nigen-n", n)
- }
-
- switch n.Op {
- case gc.ONAME:
- if (n.Class&gc.PHEAP != 0) || n.Class == gc.PPARAMREF {
- break
- }
- *a = *n
- return
-
- // Increase the refcount of the register so that igen's caller
- // has to call regfree.
- case gc.OINDREG:
- if n.Val.U.Reg != x86.REG_SP {
- reg[n.Val.U.Reg]++
- }
- *a = *n
- return
-
- case gc.ODOT:
- igen(n.Left, a, res)
- a.Xoffset += n.Xoffset
- a.Type = n.Type
- return
-
- case gc.ODOTPTR:
- switch n.Left.Op {
- // igen-able nodes.
- case gc.ODOT,
- gc.ODOTPTR,
- gc.OCALLFUNC,
- gc.OCALLMETH,
- gc.OCALLINTER:
- var n1 gc.Node
- igen(n.Left, &n1, res)
-
- regalloc(a, gc.Types[gc.Tptr], &n1)
- gmove(&n1, a)
- regfree(&n1)
-
- default:
- regalloc(a, gc.Types[gc.Tptr], res)
- cgen(n.Left, a)
- }
-
- gc.Cgen_checknil(a)
- a.Op = gc.OINDREG
- a.Xoffset += n.Xoffset
- a.Type = n.Type
- return
-
- case gc.OCALLFUNC,
- gc.OCALLMETH,
- gc.OCALLINTER:
- switch n.Op {
- case gc.OCALLFUNC:
- cgen_call(n, 0)
-
- case gc.OCALLMETH:
- gc.Cgen_callmeth(n, 0)
-
- case gc.OCALLINTER:
- cgen_callinter(n, nil, 0)
- }
-
- var flist gc.Iter
- fp := gc.Structfirst(&flist, gc.Getoutarg(n.Left.Type))
- *a = gc.Node{}
- a.Op = gc.OINDREG
- a.Val.U.Reg = x86.REG_SP
- a.Addable = 1
- a.Xoffset = fp.Width
- a.Type = n.Type
- return
-
- // Index of fixed-size array by constant can
- // put the offset in the addressing.
- // Could do the same for slice except that we need
- // to use the real index for the bounds checking.
- case gc.OINDEX:
- if gc.Isfixedarray(n.Left.Type) || (gc.Isptr[n.Left.Type.Etype] && gc.Isfixedarray(n.Left.Left.Type)) {
- if gc.Isconst(n.Right, gc.CTINT) {
- // Compute &a.
- if !gc.Isptr[n.Left.Type.Etype] {
- igen(n.Left, a, res)
- } else {
- var n1 gc.Node
- igen(n.Left, &n1, res)
- gc.Cgen_checknil(&n1)
- regalloc(a, gc.Types[gc.Tptr], res)
- gmove(&n1, a)
- regfree(&n1)
- a.Op = gc.OINDREG
- }
-
- // Compute &a[i] as &a + i*width.
- a.Type = n.Type
-
- a.Xoffset += gc.Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width
- return
- }
- }
- }
-
- // release register for now, to avoid
- // confusing tempname.
- if res != nil && res.Op == gc.OREGISTER {
- reg[res.Val.U.Reg]--
- }
- var n1 gc.Node
- gc.Tempname(&n1, gc.Types[gc.Tptr])
- agen(n, &n1)
- if res != nil && res.Op == gc.OREGISTER {
- reg[res.Val.U.Reg]++
- }
- regalloc(a, gc.Types[gc.Tptr], res)
- gmove(&n1, a)
- a.Op = gc.OINDREG
- a.Type = n.Type
-}
-
-/*
- * branch gen
- * if(n == true) goto to;
- */
-func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) {
- if gc.Debug['g'] != 0 {
- gc.Dump("\nbgen", n)
- }
-
- if n == nil {
- n = gc.Nodbool(true)
- }
-
- if n.Ninit != nil {
- gc.Genlist(n.Ninit)
- }
-
- if n.Type == nil {
- gc.Convlit(&n, gc.Types[gc.TBOOL])
- if n.Type == nil {
- return
- }
- }
-
- et := int(n.Type.Etype)
- if et != gc.TBOOL {
- gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0))
- gc.Patch(gins(obj.AEND, nil, nil), to)
- return
- }
-
- for n.Op == gc.OCONVNOP {
- n = n.Left
- if n.Ninit != nil {
- gc.Genlist(n.Ninit)
- }
- }
-
- nl := n.Left
- var nr *gc.Node
-
- if nl != nil && gc.Isfloat[nl.Type.Etype] {
- bgen_float(n, bool2int(true_), likely, to)
- return
- }
-
- switch n.Op {
- default:
- goto def
-
- // need to ask if it is bool?
- case gc.OLITERAL:
- if !true_ == (n.Val.U.Bval == 0) {
- gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to)
- }
- return
-
- case gc.ONAME:
- if n.Addable == 0 {
- goto def
- }
- var n1 gc.Node
- gc.Nodconst(&n1, n.Type, 0)
- gins(optoas(gc.OCMP, n.Type), n, &n1)
- a := x86.AJNE
- if !true_ {
- a = x86.AJEQ
- }
- gc.Patch(gc.Gbranch(a, n.Type, likely), to)
- return
-
- case gc.OANDAND,
- gc.OOROR:
- if (n.Op == gc.OANDAND) == true_ {
- p1 := gc.Gbranch(obj.AJMP, nil, 0)
- p2 := gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p1, gc.Pc)
- bgen(n.Left, !true_, -likely, p2)
- bgen(n.Right, !true_, -likely, p2)
- p1 = gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p1, to)
- gc.Patch(p2, gc.Pc)
- } else {
- bgen(n.Left, true_, likely, to)
- bgen(n.Right, true_, likely, to)
- }
-
- return
-
- case gc.OEQ,
- gc.ONE,
- gc.OLT,
- gc.OGT,
- gc.OLE,
- gc.OGE:
- nr = n.Right
- if nr == nil || nr.Type == nil {
- return
- }
- fallthrough
-
- case gc.ONOT: // unary
- nl = n.Left
-
- if nl == nil || nl.Type == nil {
- return
- }
- }
-
- switch n.Op {
- case gc.ONOT:
- bgen(nl, !true_, likely, to)
-
- case gc.OEQ,
- gc.ONE,
- gc.OLT,
- gc.OGT,
- gc.OLE,
- gc.OGE:
- a := int(n.Op)
- if !true_ {
- a = gc.Brcom(a)
- true_ = !true_
- }
-
- // make simplest on right
- if nl.Op == gc.OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < gc.UINF) {
- a = gc.Brrev(a)
- r := nl
- nl = nr
- nr = r
- }
-
- if gc.Isslice(nl.Type) {
- // front end should only leave cmp to literal nil
- if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL {
- gc.Yyerror("illegal slice comparison")
- break
- }
-
- a = optoas(a, gc.Types[gc.Tptr])
- var n1 gc.Node
- igen(nl, &n1, nil)
- n1.Xoffset += int64(gc.Array_array)
- n1.Type = gc.Types[gc.Tptr]
- var tmp gc.Node
- gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0)
- gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp)
- gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to)
- regfree(&n1)
- break
- }
-
- if gc.Isinter(nl.Type) {
- // front end should only leave cmp to literal nil
- if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL {
- gc.Yyerror("illegal interface comparison")
- break
- }
-
- a = optoas(a, gc.Types[gc.Tptr])
- var n1 gc.Node
- igen(nl, &n1, nil)
- n1.Type = gc.Types[gc.Tptr]
- var tmp gc.Node
- gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0)
- gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp)
- gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to)
- regfree(&n1)
- break
- }
-
- if gc.Iscomplex[nl.Type.Etype] {
- gc.Complexbool(a, nl, nr, true_, likely, to)
- break
- }
-
- if gc.Is64(nr.Type) {
- if nl.Addable == 0 || gc.Isconst(nl, gc.CTINT) {
- var n1 gc.Node
- gc.Tempname(&n1, nl.Type)
- cgen(nl, &n1)
- nl = &n1
- }
-
- if nr.Addable == 0 {
- var n2 gc.Node
- gc.Tempname(&n2, nr.Type)
- cgen(nr, &n2)
- nr = &n2
- }
-
- cmp64(nl, nr, a, likely, to)
- break
- }
-
- var n2 gc.Node
- if nr.Ullman >= gc.UINF {
- if nl.Addable == 0 {
- var n1 gc.Node
- gc.Tempname(&n1, nl.Type)
- cgen(nl, &n1)
- nl = &n1
- }
-
- if nr.Addable == 0 {
- var tmp gc.Node
- gc.Tempname(&tmp, nr.Type)
- cgen(nr, &tmp)
- nr = &tmp
- }
-
- var n2 gc.Node
- regalloc(&n2, nr.Type, nil)
- cgen(nr, &n2)
- nr = &n2
- goto cmp
- }
-
- if nl.Addable == 0 {
- var n1 gc.Node
- gc.Tempname(&n1, nl.Type)
- cgen(nl, &n1)
- nl = &n1
- }
-
- if gc.Smallintconst(nr) {
- gins(optoas(gc.OCMP, nr.Type), nl, nr)
- gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to)
- break
- }
-
- if nr.Addable == 0 {
- var tmp gc.Node
- gc.Tempname(&tmp, nr.Type)
- cgen(nr, &tmp)
- nr = &tmp
- }
-
- regalloc(&n2, nr.Type, nil)
- gmove(nr, &n2)
- nr = &n2
-
- cmp:
- gins(optoas(gc.OCMP, nr.Type), nl, nr)
- gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to)
-
- if nl.Op == gc.OREGISTER {
- regfree(nl)
- }
- regfree(nr)
- }
-
- return
-
-def:
- var n1 gc.Node
- regalloc(&n1, n.Type, nil)
- cgen(n, &n1)
- var n2 gc.Node
- gc.Nodconst(&n2, n.Type, 0)
- gins(optoas(gc.OCMP, n.Type), &n1, &n2)
- a := x86.AJNE
- if !true_ {
- a = x86.AJEQ
- }
- gc.Patch(gc.Gbranch(a, n.Type, likely), to)
- regfree(&n1)
- return
-}
-
-/*
- * n is on stack, either local variable
- * or return value from function call.
- * return n's offset from SP.
- */
-func stkof(n *gc.Node) int32 {
- switch n.Op {
- case gc.OINDREG:
- return int32(n.Xoffset)
-
- case gc.ODOT:
- t := n.Left.Type
- if gc.Isptr[t.Etype] {
- break
- }
- off := stkof(n.Left)
- if off == -1000 || off == 1000 {
- return off
- }
- return int32(int64(off) + n.Xoffset)
-
- case gc.OINDEX:
- t := n.Left.Type
- if !gc.Isfixedarray(t) {
- break
- }
- off := stkof(n.Left)
- if off == -1000 || off == 1000 {
- return off
- }
- if gc.Isconst(n.Right, gc.CTINT) {
- return int32(int64(off) + t.Type.Width*gc.Mpgetfix(n.Right.Val.U.Xval))
- }
- return 1000
-
- case gc.OCALLMETH,
- gc.OCALLINTER,
- gc.OCALLFUNC:
- t := n.Left.Type
- if gc.Isptr[t.Etype] {
- t = t.Type
- }
-
- var flist gc.Iter
- t = gc.Structfirst(&flist, gc.Getoutarg(t))
- if t != nil {
- return int32(t.Width)
- }
- }
-
- // botch - probably failing to recognize address
- // arithmetic on the above. eg INDEX and DOT
- return -1000
-}
-
-/*
- * struct gen
- * memmove(&res, &n, w);
- */
-func sgen(n *gc.Node, res *gc.Node, w int64) {
- if gc.Debug['g'] != 0 {
- fmt.Printf("\nsgen w=%d\n", w)
- gc.Dump("r", n)
- gc.Dump("res", res)
- }
-
- if n.Ullman >= gc.UINF && res.Ullman >= gc.UINF {
- gc.Fatal("sgen UINF")
- }
-
- if w < 0 || int64(int32(w)) != w {
- gc.Fatal("sgen copy %d", w)
- }
-
- if w == 0 {
- // evaluate side effects only.
- var tdst gc.Node
- gc.Tempname(&tdst, gc.Types[gc.Tptr])
-
- agen(res, &tdst)
- agen(n, &tdst)
- return
- }
-
- // If copying .args, that's all the results, so record definition sites
- // for them for the liveness analysis.
- if res.Op == gc.ONAME && res.Sym.Name == ".args" {
- for l := gc.Curfn.Dcl; l != nil; l = l.Next {
- if l.N.Class == gc.PPARAMOUT {
- gc.Gvardef(l.N)
- }
- }
- }
-
- // Avoid taking the address for simple enough types.
- if gc.Componentgen(n, res) {
- return
- }
-
- // offset on the stack
- osrc := stkof(n)
-
- odst := stkof(res)
-
- if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) {
- // osrc and odst both on stack, and at least one is in
- // an unknown position. Could generate code to test
- // for forward/backward copy, but instead just copy
- // to a temporary location first.
- var tsrc gc.Node
- gc.Tempname(&tsrc, n.Type)
-
- sgen(n, &tsrc, w)
- sgen(&tsrc, res, w)
- return
- }
-
+func stackcopy(n, res *gc.Node, osrc, odst, w int64) {
var dst gc.Node
gc.Nodreg(&dst, gc.Types[gc.Tptr], x86.REG_DI)
var src gc.Node
@@ -1364,13 +59,13 @@
var tdst gc.Node
gc.Tempname(&tdst, gc.Types[gc.Tptr])
if n.Addable == 0 {
- agen(n, &tsrc)
+ gc.Agen(n, &tsrc)
}
if res.Addable == 0 {
- agen(res, &tdst)
+ gc.Agen(res, &tdst)
}
if n.Addable != 0 {
- agen(n, &src)
+ gc.Agen(n, &src)
} else {
gmove(&tsrc, &src)
}
@@ -1380,7 +75,7 @@
}
if res.Addable != 0 {
- agen(res, &dst)
+ gc.Agen(res, &dst)
} else {
gmove(&tdst, &dst)
}
diff --git a/src/cmd/8g/cgen64.go b/src/cmd/8g/cgen64.go
index 4c435f6..ee04bdb 100644
--- a/src/cmd/8g/cgen64.go
+++ b/src/cmd/8g/cgen64.go
@@ -27,7 +27,7 @@
gc.Fatal("cgen64 %v", gc.Oconv(int(n.Op), 0))
case gc.OMINUS:
- cgen(n.Left, res)
+ gc.Cgen(n.Left, res)
var hi1 gc.Node
var lo1 gc.Node
split64(res, &lo1, &hi1)
@@ -38,7 +38,7 @@
return
case gc.OCOM:
- cgen(n.Left, res)
+ gc.Cgen(n.Left, res)
var lo1 gc.Node
var hi1 gc.Node
split64(res, &lo1, &hi1)
@@ -66,14 +66,14 @@
if l.Addable == 0 {
var t1 gc.Node
gc.Tempname(&t1, l.Type)
- cgen(l, &t1)
+ gc.Cgen(l, &t1)
l = &t1
}
if r != nil && r.Addable == 0 {
var t2 gc.Node
gc.Tempname(&t2, r.Type)
- cgen(r, &t2)
+ gc.Cgen(r, &t2)
r = &t2
}
@@ -116,10 +116,10 @@
// let's call the next two EX and FX.
case gc.OMUL:
var ex gc.Node
- regalloc(&ex, gc.Types[gc.TPTR32], nil)
+ gc.Regalloc(&ex, gc.Types[gc.TPTR32], nil)
var fx gc.Node
- regalloc(&fx, gc.Types[gc.TPTR32], nil)
+ gc.Regalloc(&fx, gc.Types[gc.TPTR32], nil)
// load args into DX:AX and EX:CX.
gins(x86.AMOVL, &lo1, &ax)
@@ -148,8 +148,8 @@
gins(x86.AADDL, &fx, &dx)
gc.Patch(p2, gc.Pc)
- regfree(&ex)
- regfree(&fx)
+ gc.Regfree(&ex)
+ gc.Regfree(&fx)
// We only rotate by a constant c in [0,64).
// if c >= 32:
@@ -523,10 +523,10 @@
if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL {
gins(x86.ACMPL, &hi1, &hi2)
} else {
- regalloc(&rr, gc.Types[gc.TINT32], nil)
+ gc.Regalloc(&rr, gc.Types[gc.TINT32], nil)
gins(x86.AMOVL, &hi1, &rr)
gins(x86.ACMPL, &rr, &hi2)
- regfree(&rr)
+ gc.Regfree(&rr)
}
var br *obj.Prog
@@ -580,10 +580,10 @@
if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL {
gins(x86.ACMPL, &lo1, &lo2)
} else {
- regalloc(&rr, gc.Types[gc.TINT32], nil)
+ gc.Regalloc(&rr, gc.Types[gc.TINT32], nil)
gins(x86.AMOVL, &lo1, &rr)
gins(x86.ACMPL, &rr, &lo2)
- regfree(&rr)
+ gc.Regfree(&rr)
}
// jump again
diff --git a/src/cmd/8g/galign.go b/src/cmd/8g/galign.go
index f0c878a..f5ff825 100644
--- a/src/cmd/8g/galign.go
+++ b/src/cmd/8g/galign.go
@@ -45,33 +45,44 @@
gc.Thearch.Typedefs = typedefs
gc.Thearch.REGSP = x86.REGSP
gc.Thearch.REGCTXT = x86.REGCTXT
+ gc.Thearch.REGCALLX = x86.REG_BX
+ gc.Thearch.REGCALLX2 = x86.REG_AX
+ gc.Thearch.REGRETURN = x86.REG_AX
+ gc.Thearch.REGMIN = x86.REG_AX
+ gc.Thearch.REGMAX = x86.REG_DI
+ gc.Thearch.FREGMIN = x86.REG_X0
+ gc.Thearch.FREGMAX = x86.REG_X7
gc.Thearch.MAXWIDTH = MAXWIDTH
- gc.Thearch.Anyregalloc = anyregalloc
+ gc.Thearch.ReservedRegs = resvd
+
gc.Thearch.Betypeinit = betypeinit
- gc.Thearch.Bgen = bgen
- gc.Thearch.Cgen = cgen
- gc.Thearch.Cgen_call = cgen_call
- gc.Thearch.Cgen_callinter = cgen_callinter
- gc.Thearch.Cgen_ret = cgen_ret
+ gc.Thearch.Bgen_float = bgen_float
+ gc.Thearch.Cgen64 = cgen64
+ gc.Thearch.Cgen_bmul = cgen_bmul
+ gc.Thearch.Cgen_float = cgen_float
+ gc.Thearch.Cgen_hmul = cgen_hmul
+ gc.Thearch.Cgen_shift = cgen_shift
gc.Thearch.Clearfat = clearfat
+ gc.Thearch.Cmp64 = cmp64
gc.Thearch.Defframe = defframe
+ gc.Thearch.Dodiv = cgen_div
gc.Thearch.Excise = excise
gc.Thearch.Expandchecks = expandchecks
- gc.Thearch.Gclean = gclean
- gc.Thearch.Ginit = ginit
gc.Thearch.Gins = gins
- gc.Thearch.Ginscall = ginscall
+ gc.Thearch.Ginscon = ginscon
+ gc.Thearch.Ginsnop = ginsnop
gc.Thearch.Gmove = gmove
- gc.Thearch.Igen = igen
+ gc.Thearch.Igenindex = igenindex
gc.Thearch.Linkarchinit = linkarchinit
gc.Thearch.Peep = peep
gc.Thearch.Proginfo = proginfo
- gc.Thearch.Regalloc = regalloc
- gc.Thearch.Regfree = regfree
gc.Thearch.Regtyp = regtyp
gc.Thearch.Sameaddr = sameaddr
gc.Thearch.Smallindir = smallindir
gc.Thearch.Stackaddr = stackaddr
+ gc.Thearch.Stackcopy = stackcopy
+ gc.Thearch.Sudoaddable = sudoaddable
+ gc.Thearch.Sudoclean = sudoclean
gc.Thearch.Excludedregs = excludedregs
gc.Thearch.RtoB = RtoB
gc.Thearch.FtoB = FtoB
diff --git a/src/cmd/8g/ggen.go b/src/cmd/8g/ggen.go
index 3a197cd..69c6028 100644
--- a/src/cmd/8g/ggen.go
+++ b/src/cmd/8g/ggen.go
@@ -127,9 +127,9 @@
// NOTE: Must use agen, not igen, so that optimizer sees address
// being taken. We are not writing on field boundaries.
var n1 gc.Node
- regalloc(&n1, gc.Types[gc.Tptr], nil)
+ gc.Regalloc(&n1, gc.Types[gc.Tptr], nil)
- agen(nl, &n1)
+ gc.Agen(nl, &n1)
n1.Op = gc.OINDREG
var z gc.Node
gc.Nodconst(&z, gc.Types[gc.TUINT64], 0)
@@ -156,13 +156,13 @@
n1.Xoffset++
}
- regfree(&n1)
+ gc.Regfree(&n1)
return
}
var n1 gc.Node
gc.Nodreg(&n1, gc.Types[gc.Tptr], x86.REG_DI)
- agen(nl, &n1)
+ gc.Agen(nl, &n1)
gconreg(x86.AMOVL, 0, x86.REG_AX)
if q > 128 || (q >= 4 && gc.Nacl) {
@@ -190,312 +190,6 @@
}
/*
- * generate:
- * call f
- * proc=-1 normal call but no return
- * proc=0 normal call
- * proc=1 goroutine run in new proc
- * proc=2 defer call save away stack
- * proc=3 normal call to C pointer (not Go func value)
-*/
-func ginscall(f *gc.Node, proc int) {
- if f.Type != nil {
- extra := int32(0)
- if proc == 1 || proc == 2 {
- extra = 2 * int32(gc.Widthptr)
- }
- gc.Setmaxarg(f.Type, extra)
- }
-
- switch proc {
- default:
- gc.Fatal("ginscall: bad proc %d", proc)
-
- case 0, // normal call
- -1: // normal call but no return
- if f.Op == gc.ONAME && f.Class == gc.PFUNC {
- if f == gc.Deferreturn {
- // Deferred calls will appear to be returning to
- // the CALL deferreturn(SB) that we are about to emit.
- // However, the stack trace code will show the line
- // of the instruction byte before the return PC.
- // To avoid that being an unrelated instruction,
- // insert an x86 NOP that we will have the right line number.
- // x86 NOP 0x90 is really XCHG AX, AX; use that description
- // because the NOP pseudo-instruction will be removed by
- // the linker.
- var reg gc.Node
- gc.Nodreg(®, gc.Types[gc.TINT], x86.REG_AX)
-
- gins(x86.AXCHGL, ®, ®)
- }
-
- p := gins(obj.ACALL, nil, f)
- gc.Afunclit(&p.To, f)
- if proc == -1 || gc.Noreturn(p) {
- gins(obj.AUNDEF, nil, nil)
- }
- break
- }
-
- var reg gc.Node
- gc.Nodreg(®, gc.Types[gc.Tptr], x86.REG_DX)
- var r1 gc.Node
- gc.Nodreg(&r1, gc.Types[gc.Tptr], x86.REG_BX)
- gmove(f, ®)
- reg.Op = gc.OINDREG
- gmove(®, &r1)
- reg.Op = gc.OREGISTER
- gins(obj.ACALL, ®, &r1)
-
- case 3: // normal call of c function pointer
- gins(obj.ACALL, nil, f)
-
- case 1, // call in new proc (go)
- 2: // deferred call (defer)
- var stk gc.Node
-
- stk.Op = gc.OINDREG
- stk.Val.U.Reg = x86.REG_SP
- stk.Xoffset = 0
-
- // size of arguments at 0(SP)
- var con gc.Node
- gc.Nodconst(&con, gc.Types[gc.TINT32], int64(gc.Argsize(f.Type)))
-
- gins(x86.AMOVL, &con, &stk)
-
- // FuncVal* at 4(SP)
- stk.Xoffset = int64(gc.Widthptr)
-
- gins(x86.AMOVL, f, &stk)
-
- if proc == 1 {
- ginscall(gc.Newproc, 0)
- } else {
- ginscall(gc.Deferproc, 0)
- }
- if proc == 2 {
- var reg gc.Node
- gc.Nodreg(®, gc.Types[gc.TINT32], x86.REG_AX)
- gins(x86.ATESTL, ®, ®)
- p := gc.Gbranch(x86.AJEQ, nil, +1)
- cgen_ret(nil)
- gc.Patch(p, gc.Pc)
- }
- }
-}
-
-/*
- * n is call to interface method.
- * generate res = n.
- */
-func cgen_callinter(n *gc.Node, res *gc.Node, proc int) {
- i := n.Left
- if i.Op != gc.ODOTINTER {
- gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0))
- }
-
- f := i.Right // field
- if f.Op != gc.ONAME {
- gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0))
- }
-
- i = i.Left // interface
-
- if i.Addable == 0 {
- var tmpi gc.Node
- gc.Tempname(&tmpi, i.Type)
- cgen(i, &tmpi)
- i = &tmpi
- }
-
- gc.Genlist(n.List) // assign the args
-
- // i is now addable, prepare an indirected
- // register to hold its address.
- var nodi gc.Node
- igen(i, &nodi, res) // REG = &inter
-
- var nodsp gc.Node
- gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], x86.REG_SP)
-
- nodsp.Xoffset = 0
- if proc != 0 {
- nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn
- }
- nodi.Type = gc.Types[gc.Tptr]
- nodi.Xoffset += int64(gc.Widthptr)
- cgen(&nodi, &nodsp) // {0 or 8}(SP) = 4(REG) -- i.data
-
- var nodo gc.Node
- regalloc(&nodo, gc.Types[gc.Tptr], res)
-
- nodi.Type = gc.Types[gc.Tptr]
- nodi.Xoffset -= int64(gc.Widthptr)
- cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab
- regfree(&nodi)
-
- var nodr gc.Node
- regalloc(&nodr, gc.Types[gc.Tptr], &nodo)
- if n.Left.Xoffset == gc.BADWIDTH {
- gc.Fatal("cgen_callinter: badwidth")
- }
- gc.Cgen_checknil(&nodo)
- nodo.Op = gc.OINDREG
- nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8
-
- if proc == 0 {
- // plain call: use direct c function pointer - more efficient
- cgen(&nodo, &nodr) // REG = 20+offset(REG) -- i.tab->fun[f]
- proc = 3
- } else {
- // go/defer. generate go func value.
- gins(x86.ALEAL, &nodo, &nodr) // REG = &(20+offset(REG)) -- i.tab->fun[f]
- }
-
- nodr.Type = n.Left.Type
- ginscall(&nodr, proc)
-
- regfree(&nodr)
- regfree(&nodo)
-}
-
-/*
- * generate function call;
- * proc=0 normal call
- * proc=1 goroutine run in new proc
- * proc=2 defer call save away stack
- */
-func cgen_call(n *gc.Node, proc int) {
- if n == nil {
- return
- }
-
- var afun gc.Node
- if n.Left.Ullman >= gc.UINF {
- // if name involves a fn call
- // precompute the address of the fn
- gc.Tempname(&afun, gc.Types[gc.Tptr])
-
- cgen(n.Left, &afun)
- }
-
- gc.Genlist(n.List) // assign the args
- t := n.Left.Type
-
- // call tempname pointer
- if n.Left.Ullman >= gc.UINF {
- var nod gc.Node
- regalloc(&nod, gc.Types[gc.Tptr], nil)
- gc.Cgen_as(&nod, &afun)
- nod.Type = t
- ginscall(&nod, proc)
- regfree(&nod)
- return
- }
-
- // call pointer
- if n.Left.Op != gc.ONAME || n.Left.Class != gc.PFUNC {
- var nod gc.Node
- regalloc(&nod, gc.Types[gc.Tptr], nil)
- gc.Cgen_as(&nod, n.Left)
- nod.Type = t
- ginscall(&nod, proc)
- regfree(&nod)
- return
- }
-
- // call direct
- n.Left.Method = 1
-
- ginscall(n.Left, proc)
-}
-
-/*
- * call to n has already been generated.
- * generate:
- * res = return value from call.
- */
-func cgen_callret(n *gc.Node, res *gc.Node) {
- t := n.Left.Type
- if t.Etype == gc.TPTR32 || t.Etype == gc.TPTR64 {
- t = t.Type
- }
-
- var flist gc.Iter
- fp := gc.Structfirst(&flist, gc.Getoutarg(t))
- if fp == nil {
- gc.Fatal("cgen_callret: nil")
- }
-
- var nod gc.Node
- nod.Op = gc.OINDREG
- nod.Val.U.Reg = x86.REG_SP
- nod.Addable = 1
-
- nod.Xoffset = fp.Width
- nod.Type = fp.Type
- gc.Cgen_as(res, &nod)
-}
-
-/*
- * call to n has already been generated.
- * generate:
- * res = &return value from call.
- */
-func cgen_aret(n *gc.Node, res *gc.Node) {
- t := n.Left.Type
- if gc.Isptr[t.Etype] {
- t = t.Type
- }
-
- var flist gc.Iter
- fp := gc.Structfirst(&flist, gc.Getoutarg(t))
- if fp == nil {
- gc.Fatal("cgen_aret: nil")
- }
-
- var nod1 gc.Node
- nod1.Op = gc.OINDREG
- nod1.Val.U.Reg = x86.REG_SP
- nod1.Addable = 1
-
- nod1.Xoffset = fp.Width
- nod1.Type = fp.Type
-
- if res.Op != gc.OREGISTER {
- var nod2 gc.Node
- regalloc(&nod2, gc.Types[gc.Tptr], res)
- gins(x86.ALEAL, &nod1, &nod2)
- gins(x86.AMOVL, &nod2, res)
- regfree(&nod2)
- } else {
- gins(x86.ALEAL, &nod1, res)
- }
-}
-
-/*
- * generate return.
- * n->left is assignments to return values.
- */
-func cgen_ret(n *gc.Node) {
- if n != nil {
- gc.Genlist(n.List) // copy out args
- }
- if gc.Hasdefer != 0 {
- ginscall(gc.Deferreturn, 0)
- }
- gc.Genlist(gc.Curfn.Exit)
- p := gins(obj.ARET, nil, nil)
- if n != nil && n.Op == gc.ORETJMP {
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_EXTERN
- p.To.Sym = gc.Linksym(n.Left.Sym)
- }
-}
-
-/*
* generate division.
* caller must set:
* ax = allocated AX register
@@ -545,23 +239,23 @@
gc.Tempname(&t3, t0)
var t4 gc.Node
gc.Tempname(&t4, t0)
- cgen(nl, &t3)
- cgen(nr, &t4)
+ gc.Cgen(nl, &t3)
+ gc.Cgen(nr, &t4)
// Convert.
gmove(&t3, &t1)
gmove(&t4, &t2)
} else {
- cgen(nl, &t1)
- cgen(nr, &t2)
+ gc.Cgen(nl, &t1)
+ gc.Cgen(nr, &t2)
}
var n1 gc.Node
if !gc.Samereg(ax, res) && !gc.Samereg(dx, res) {
- regalloc(&n1, t, res)
+ gc.Regalloc(&n1, t, res)
} else {
- regalloc(&n1, t, nil)
+ gc.Regalloc(&n1, t, nil)
}
gmove(&t2, &n1)
gmove(&t1, ax)
@@ -578,7 +272,7 @@
if panicdiv == nil {
panicdiv = gc.Sysfunc("panicdivide")
}
- ginscall(panicdiv, -1)
+ gc.Ginscall(panicdiv, -1)
gc.Patch(p1, gc.Pc)
}
@@ -610,7 +304,7 @@
gins(optoas(gc.OEXTEND, t), nil, nil)
}
gins(optoas(op, t), &n1, nil)
- regfree(&n1)
+ gc.Regfree(&n1)
if op == gc.ODIV {
gmove(ax, res)
@@ -635,11 +329,11 @@
gmove(x, oldx)
}
- regalloc(x, t, x)
+ gc.Regalloc(x, t, x)
}
func restx(x *gc.Node, oldx *gc.Node) {
- regfree(x)
+ gc.Regfree(x)
if oldx.Op != 0 {
x.Type = gc.Types[gc.TINT32]
@@ -691,9 +385,9 @@
if nr.Op == gc.OLITERAL {
var n2 gc.Node
gc.Tempname(&n2, nl.Type)
- cgen(nl, &n2)
+ gc.Cgen(nl, &n2)
var n1 gc.Node
- regalloc(&n1, nl.Type, res)
+ gc.Regalloc(&n1, nl.Type, res)
gmove(&n2, &n1)
sc := uint64(gc.Mpgetfix(nr.Val.U.Xval))
if sc >= uint64(nl.Type.Width*8) {
@@ -705,7 +399,7 @@
gins(a, nr, &n1)
}
gmove(&n1, res)
- regfree(&n1)
+ gc.Regfree(&n1)
return
}
@@ -724,21 +418,21 @@
n1 = nt
} else {
gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_CX)
- regalloc(&n1, nr.Type, &n1) // to hold the shift type in CX
+ gc.Regalloc(&n1, nr.Type, &n1) // to hold the shift type in CX
}
var n2 gc.Node
if gc.Samereg(&cx, res) {
- regalloc(&n2, nl.Type, nil)
+ gc.Regalloc(&n2, nl.Type, nil)
} else {
- regalloc(&n2, nl.Type, res)
+ gc.Regalloc(&n2, nl.Type, res)
}
if nl.Ullman >= nr.Ullman {
- cgen(nl, &n2)
- cgen(nr, &n1)
+ gc.Cgen(nl, &n2)
+ gc.Cgen(nr, &n1)
} else {
- cgen(nr, &n1)
- cgen(nl, &n2)
+ gc.Cgen(nr, &n1)
+ gc.Cgen(nl, &n2)
}
// test and fix up large shifts
@@ -747,7 +441,7 @@
// delayed reg alloc
gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_CX)
- regalloc(&n1, gc.Types[gc.TUINT32], &n1) // to hold the shift type in CX
+ gc.Regalloc(&n1, gc.Types[gc.TUINT32], &n1) // to hold the shift type in CX
var lo gc.Node
var hi gc.Node
split64(&nt, &lo, &hi)
@@ -760,7 +454,7 @@
// delayed reg alloc
gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_CX)
- regalloc(&n1, gc.Types[gc.TUINT32], &n1) // to hold the shift type in CX
+ gc.Regalloc(&n1, gc.Types[gc.TUINT32], &n1) // to hold the shift type in CX
var lo gc.Node
var hi gc.Node
split64(&nt, &lo, &hi)
@@ -793,8 +487,8 @@
gmove(&n2, res)
- regfree(&n1)
- regfree(&n2)
+ gc.Regfree(&n1)
+ gc.Regfree(&n2)
}
/*
@@ -803,7 +497,11 @@
* there is no 2-operand byte multiply instruction so
* we do a full-width multiplication and truncate afterwards.
*/
-func cgen_bmul(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
+func cgen_bmul(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) bool {
+ if optoas(op, nl.Type) != x86.AIMULB {
+ return false
+ }
+
// copy from byte to full registers
t := gc.Types[gc.TUINT32]
@@ -820,18 +518,20 @@
var nt gc.Node
gc.Tempname(&nt, nl.Type)
- cgen(nl, &nt)
+ gc.Cgen(nl, &nt)
var n1 gc.Node
- regalloc(&n1, t, res)
- cgen(nr, &n1)
+ gc.Regalloc(&n1, t, res)
+ gc.Cgen(nr, &n1)
var n2 gc.Node
- regalloc(&n2, t, nil)
+ gc.Regalloc(&n2, t, nil)
gmove(&nt, &n2)
a := optoas(op, t)
gins(a, &n2, &n1)
- regfree(&n2)
+ gc.Regfree(&n2)
gmove(&n1, res)
- regfree(&n1)
+ gc.Regfree(&n1)
+
+ return true
}
/*
@@ -850,19 +550,19 @@
// gen nl in n1.
gc.Tempname(&n1, t)
- cgen(nl, &n1)
+ gc.Cgen(nl, &n1)
// gen nr in n2.
- regalloc(&n2, t, res)
+ gc.Regalloc(&n2, t, res)
- cgen(nr, &n2)
+ gc.Cgen(nr, &n2)
// multiply.
gc.Nodreg(&ax, t, x86.REG_AX)
gmove(&n2, &ax)
gins(a, &n1, nil)
- regfree(&n2)
+ gc.Regfree(&n2)
if t.Width == 1 {
// byte multiply behaves differently.
@@ -892,28 +592,28 @@
gmove(gc.Nodbool(true), res)
p3 := gc.Gbranch(obj.AJMP, nil, 0)
gc.Patch(p1, gc.Pc)
- bgen(n, true, 0, p2)
+ gc.Bgen(n, true, 0, p2)
gmove(gc.Nodbool(false), res)
gc.Patch(p3, gc.Pc)
return
case gc.OPLUS:
- cgen(nl, res)
+ gc.Cgen(nl, res)
return
case gc.OCONV:
if gc.Eqtype(n.Type, nl.Type) || gc.Noconv(n.Type, nl.Type) {
- cgen(nl, res)
+ gc.Cgen(nl, res)
return
}
var n2 gc.Node
gc.Tempname(&n2, n.Type)
var n1 gc.Node
- mgen(nl, &n1, res)
+ gc.Mgen(nl, &n1, res)
gmove(&n1, &n2)
gmove(&n2, res)
- mfree(&n1)
+ gc.Mfree(&n1)
return
}
@@ -936,19 +636,19 @@
if nr != nil {
// binary
if nl.Ullman >= nr.Ullman {
- cgen(nl, &f0)
+ gc.Cgen(nl, &f0)
if nr.Addable != 0 {
gins(foptoas(int(n.Op), n.Type, 0), nr, &f0)
} else {
- cgen(nr, &f0)
+ gc.Cgen(nr, &f0)
gins(foptoas(int(n.Op), n.Type, Fpop), &f0, &f1)
}
} else {
- cgen(nr, &f0)
+ gc.Cgen(nr, &f0)
if nl.Addable != 0 {
gins(foptoas(int(n.Op), n.Type, Frev), nl, &f0)
} else {
- cgen(nl, &f0)
+ gc.Cgen(nl, &f0)
gins(foptoas(int(n.Op), n.Type, Frev|Fpop), &f0, &f1)
}
}
@@ -958,7 +658,7 @@
}
// unary
- cgen(nl, &f0)
+ gc.Cgen(nl, &f0)
if n.Op != gc.OCONV && n.Op != gc.OPLUS {
gins(foptoas(int(n.Op), n.Type, 0), nil, nil)
@@ -1012,27 +712,27 @@
if nl.Ullman >= nr.Ullman {
var nt gc.Node
gc.Tempname(&nt, nl.Type)
- cgen(nl, &nt)
+ gc.Cgen(nl, &nt)
var n2 gc.Node
- mgen(nr, &n2, nil)
+ gc.Mgen(nr, &n2, nil)
var n1 gc.Node
- regalloc(&n1, nl.Type, res)
+ gc.Regalloc(&n1, nl.Type, res)
gmove(&nt, &n1)
gins(a, &n2, &n1)
gmove(&n1, res)
- regfree(&n1)
- mfree(&n2)
+ gc.Regfree(&n1)
+ gc.Mfree(&n2)
} else {
var n2 gc.Node
- regalloc(&n2, nr.Type, res)
- cgen(nr, &n2)
+ gc.Regalloc(&n2, nr.Type, res)
+ gc.Cgen(nr, &n2)
var n1 gc.Node
- regalloc(&n1, nl.Type, nil)
- cgen(nl, &n1)
+ gc.Regalloc(&n1, nl.Type, nil)
+ gc.Cgen(nl, &n1)
gins(a, &n2, &n1)
- regfree(&n2)
+ gc.Regfree(&n2)
gmove(&n1, res)
- regfree(&n1)
+ gc.Regfree(&n1)
}
return
@@ -1065,25 +765,25 @@
if nl.Addable == 0 {
var n1 gc.Node
gc.Tempname(&n1, nl.Type)
- cgen(nl, &n1)
+ gc.Cgen(nl, &n1)
nl = &n1
}
if nr.Addable == 0 {
var tmp gc.Node
gc.Tempname(&tmp, nr.Type)
- cgen(nr, &tmp)
+ gc.Cgen(nr, &tmp)
nr = &tmp
}
var n2 gc.Node
- regalloc(&n2, nr.Type, nil)
+ gc.Regalloc(&n2, nr.Type, nil)
gmove(nr, &n2)
nr = &n2
if nl.Op != gc.OREGISTER {
var n3 gc.Node
- regalloc(&n3, nl.Type, nil)
+ gc.Regalloc(&n3, nl.Type, nil)
gmove(nl, &n3)
nl = &n3
}
@@ -1099,9 +799,9 @@
gins(foptoas(gc.OCMP, nr.Type, 0), nl, nr)
if nl.Op == gc.OREGISTER {
- regfree(nl)
+ gc.Regfree(nl)
}
- regfree(nr)
+ gc.Regfree(nr)
goto ret
} else {
goto x87
@@ -1124,12 +824,12 @@
et = gc.Simsimtype(nr.Type)
if et == gc.TFLOAT64 {
if nl.Ullman > nr.Ullman {
- cgen(nl, &tmp)
- cgen(nr, &tmp)
+ gc.Cgen(nl, &tmp)
+ gc.Cgen(nr, &tmp)
gins(x86.AFXCHD, &tmp, &n2)
} else {
- cgen(nr, &tmp)
- cgen(nl, &tmp)
+ gc.Cgen(nr, &tmp)
+ gc.Cgen(nl, &tmp)
}
gins(x86.AFUCOMIP, &tmp, &n2)
@@ -1146,8 +846,8 @@
var t2 gc.Node
gc.Tempname(&t2, gc.Types[gc.TFLOAT32])
- cgen(nr, &t1)
- cgen(nl, &t2)
+ gc.Cgen(nr, &t1)
+ gc.Cgen(nl, &t2)
gmove(&t2, &tmp)
gins(x86.AFCOMFP, &t1, &tmp)
gins(x86.AFSTSW, nil, &ax)
@@ -1230,3 +930,17 @@
p2.To.Offset = 0
}
}
+
+// addr += index*width if possible.
+func addindex(index *gc.Node, width int64, addr *gc.Node) bool {
+ switch width {
+ case 1, 2, 4, 8:
+ p1 := gins(x86.ALEAL, index, addr)
+ p1.From.Type = obj.TYPE_MEM
+ p1.From.Scale = int16(width)
+ p1.From.Index = p1.From.Reg
+ p1.From.Reg = p1.To.Reg
+ return true
+ }
+ return false
+}
diff --git a/src/cmd/8g/gsubr.go b/src/cmd/8g/gsubr.go
index cc5efdf..fa28b6d 100644
--- a/src/cmd/8g/gsubr.go
+++ b/src/cmd/8g/gsubr.go
@@ -550,184 +550,6 @@
x86.REG_CX, // for shift
x86.REG_DX, // for divide
x86.REG_SP, // for stack
-
- x86.REG_BL, // because REG_BX can be allocated
- x86.REG_BH,
-}
-
-func ginit() {
- for i := 0; i < len(reg); i++ {
- reg[i] = 1
- }
- for i := x86.REG_AX; i <= x86.REG_DI; i++ {
- reg[i] = 0
- }
- for i := x86.REG_X0; i <= x86.REG_X7; i++ {
- reg[i] = 0
- }
- for i := 0; i < len(resvd); i++ {
- reg[resvd[i]]++
- }
-}
-
-var regpc [x86.MAXREG]uint32
-
-func gclean() {
- for i := 0; i < len(resvd); i++ {
- reg[resvd[i]]--
- }
-
- for i := x86.REG_AX; i <= x86.REG_DI; i++ {
- if reg[i] != 0 {
- gc.Yyerror("reg %v left allocated at %x", obj.Rconv(i), regpc[i])
- }
- }
- for i := x86.REG_X0; i <= x86.REG_X7; i++ {
- if reg[i] != 0 {
- gc.Yyerror("reg %v left allocated\n", obj.Rconv(i))
- }
- }
-}
-
-func anyregalloc() bool {
- var j int
-
- for i := x86.REG_AX; i <= x86.REG_DI; i++ {
- if reg[i] == 0 {
- goto ok
- }
- for j = 0; j < len(resvd); j++ {
- if resvd[j] == i {
- goto ok
- }
- }
- return true
- ok:
- }
-
- for i := x86.REG_X0; i <= x86.REG_X7; i++ {
- if reg[i] != 0 {
- return true
- }
- }
- return false
-}
-
-/*
- * allocate register of type t, leave in n.
- * if o != N, o is desired fixed register.
- * caller must regfree(n).
- */
-func regalloc(n *gc.Node, t *gc.Type, o *gc.Node) {
- if t == nil {
- gc.Fatal("regalloc: t nil")
- }
- et := int(gc.Simtype[t.Etype])
-
- var i int
- switch et {
- case gc.TINT64,
- gc.TUINT64:
- gc.Fatal("regalloc64")
-
- case gc.TINT8,
- gc.TUINT8,
- gc.TINT16,
- gc.TUINT16,
- gc.TINT32,
- gc.TUINT32,
- gc.TPTR32,
- gc.TPTR64,
- gc.TBOOL:
- if o != nil && o.Op == gc.OREGISTER {
- i = int(o.Val.U.Reg)
- if i >= x86.REG_AX && i <= x86.REG_DI {
- goto out
- }
- }
-
- for i = x86.REG_AX; i <= x86.REG_DI; i++ {
- if reg[i] == 0 {
- goto out
- }
- }
-
- fmt.Printf("registers allocated at\n")
- for i := x86.REG_AX; i <= x86.REG_DI; i++ {
- fmt.Printf("\t%v\t%#x\n", obj.Rconv(i), regpc[i])
- }
- gc.Fatal("out of fixed registers")
- goto err
-
- case gc.TFLOAT32,
- gc.TFLOAT64:
- if gc.Use_sse == 0 {
- i = x86.REG_F0
- goto out
- }
-
- if o != nil && o.Op == gc.OREGISTER {
- i = int(o.Val.U.Reg)
- if i >= x86.REG_X0 && i <= x86.REG_X7 {
- goto out
- }
- }
-
- for i = x86.REG_X0; i <= x86.REG_X7; i++ {
- if reg[i] == 0 {
- goto out
- }
- }
- fmt.Printf("registers allocated at\n")
- for i := x86.REG_X0; i <= x86.REG_X7; i++ {
- fmt.Printf("\t%v\t%#x\n", obj.Rconv(i), regpc[i])
- }
- gc.Fatal("out of floating registers")
- }
-
- gc.Yyerror("regalloc: unknown type %v", gc.Tconv(t, 0))
-
-err:
- gc.Nodreg(n, t, 0)
- return
-
-out:
- if i == x86.REG_SP {
- fmt.Printf("alloc SP\n")
- }
- if reg[i] == 0 {
- regpc[i] = uint32(obj.Getcallerpc(&n))
- if i == x86.REG_AX || i == x86.REG_CX || i == x86.REG_DX || i == x86.REG_SP {
- gc.Dump("regalloc-o", o)
- gc.Fatal("regalloc %v", obj.Rconv(i))
- }
- }
-
- reg[i]++
- gc.Nodreg(n, t, i)
-}
-
-func regfree(n *gc.Node) {
- if n.Op == gc.ONAME {
- return
- }
- if n.Op != gc.OREGISTER && n.Op != gc.OINDREG {
- gc.Fatal("regfree: not a register")
- }
- i := int(n.Val.U.Reg)
- if i == x86.REG_SP {
- return
- }
- if i < 0 || i >= len(reg) {
- gc.Fatal("regfree: reg out of range")
- }
- if reg[i] <= 0 {
- gc.Fatal("regfree: reg not allocated")
- }
- reg[i]--
- if reg[i] == 0 && (i == x86.REG_AX || i == x86.REG_CX || i == x86.REG_DX || i == x86.REG_SP) {
- gc.Fatal("regfree %v", obj.Rconv(i))
- }
}
/*
@@ -744,6 +566,16 @@
}
/*
+ * generate
+ * as $c, n
+ */
+func ginscon(as int, c int64, n2 *gc.Node) {
+ var n1 gc.Node
+ gc.Nodconst(&n1, gc.Types[gc.TINT32], c)
+ gins(as, &n1, n2)
+}
+
+/*
* swap node contents
*/
func nswap(a *gc.Node, b *gc.Node) {
@@ -790,7 +622,7 @@
default:
var n1 gc.Node
if !dotaddable(n, &n1) {
- igen(n, &n1, nil)
+ gc.Igen(n, &n1, nil)
sclean[nsclean-1] = n1
}
@@ -799,7 +631,7 @@
case gc.ONAME:
if n.Class == gc.PPARAMREF {
var n1 gc.Node
- cgen(n.Heapaddr, &n1)
+ gc.Cgen(n.Heapaddr, &n1)
sclean[nsclean-1] = n1
n = &n1
}
@@ -839,7 +671,7 @@
}
nsclean--
if sclean[nsclean].Op != gc.OEMPTY {
- regfree(&sclean[nsclean])
+ gc.Regfree(&sclean[nsclean])
}
}
@@ -1139,31 +971,31 @@
// requires register source
rsrc:
- regalloc(&r1, f.Type, t)
+ gc.Regalloc(&r1, f.Type, t)
gmove(f, &r1)
gins(a, &r1, t)
- regfree(&r1)
+ gc.Regfree(&r1)
return
// requires register destination
rdst:
{
- regalloc(&r1, t.Type, t)
+ gc.Regalloc(&r1, t.Type, t)
gins(a, f, &r1)
gmove(&r1, t)
- regfree(&r1)
+ gc.Regfree(&r1)
return
}
// requires register intermediate
hard:
- regalloc(&r1, cvt, t)
+ gc.Regalloc(&r1, cvt, t)
gmove(f, &r1)
gmove(&r1, t)
- regfree(&r1)
+ gc.Regfree(&r1)
return
}
@@ -1408,11 +1240,11 @@
// requires register intermediate
hard:
- regalloc(&r1, cvt, t)
+ gc.Regalloc(&r1, cvt, t)
gmove(f, &r1)
gmove(&r1, t)
- regfree(&r1)
+ gc.Regfree(&r1)
return
// requires memory intermediate
@@ -1652,11 +1484,11 @@
// requires register intermediate
hard:
- regalloc(&r1, cvt, t)
+ gc.Regalloc(&r1, cvt, t)
gmove(f, &r1)
gmove(&r1, t)
- regfree(&r1)
+ gc.Regfree(&r1)
return
// requires memory intermediate
@@ -1774,11 +1606,11 @@
// requires register intermediate
hard:
- regalloc(&r1, cvt, t)
+ gc.Regalloc(&r1, cvt, t)
gmove(f, &r1)
gmove(&r1, t)
- regfree(&r1)
+ gc.Regfree(&r1)
return
// requires memory intermediate
@@ -1791,11 +1623,11 @@
// requires register destination
rdst:
- regalloc(&r1, t.Type, t)
+ gc.Regalloc(&r1, t.Type, t)
gins(a, f, &r1)
gmove(&r1, t)
- regfree(&r1)
+ gc.Regfree(&r1)
return
}
@@ -1830,6 +1662,15 @@
gc.Fatal("gins MOVSD into F0")
}
+ if as == x86.AMOVL && f != nil && f.Op == gc.OADDR && f.Left.Op == gc.ONAME && f.Left.Class != gc.PEXTERN && f.Left.Class != gc.PFUNC {
+ // Turn MOVL $xxx(FP/SP) 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.
+ as = x86.ALEAL
+ f = f.Left
+ }
+
switch as {
case x86.AMOVB,
x86.AMOVW,
@@ -1877,6 +1718,12 @@
return p
}
+func ginsnop() {
+ var reg gc.Node
+ gc.Nodreg(®, gc.Types[gc.TINT], x86.REG_AX)
+ gins(x86.AXCHGL, ®, ®)
+}
+
func dotaddable(n *gc.Node, n1 *gc.Node) bool {
if n.Op != gc.ODOT {
return false
diff --git a/src/cmd/8g/peep.go b/src/cmd/8g/peep.go
index 91055fd..e309aea7 100644
--- a/src/cmd/8g/peep.go
+++ b/src/cmd/8g/peep.go
@@ -672,7 +672,7 @@
if regtyp(v) {
return true
}
- if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
+ if (v.Type == obj.TYPE_MEM || v.Type == obj.TYPE_ADDR) && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
if v.Offset == a.Offset {
return true
}
@@ -687,7 +687,7 @@
if regtyp(v) {
return true
}
- if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
+ if (v.Type == obj.TYPE_MEM || v.Type == obj.TYPE_ADDR) && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
if v.Offset == a.Offset {
return true
}
@@ -703,7 +703,7 @@
return true
}
if regtyp(v) {
- if a.Type == obj.TYPE_MEM && a.Reg == v.Reg {
+ if (a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && a.Reg == v.Reg {
return true
}
if a.Index == v.Reg {
@@ -732,7 +732,7 @@
if regtyp(v) {
reg := int(v.Reg)
- if a.Type == obj.TYPE_MEM && int(a.Reg) == reg {
+ if (a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && int(a.Reg) == reg {
if (s.Reg == x86.REG_BP) && a.Index != obj.TYPE_NONE {
return 1 /* can't use BP-base with index */
}