Commit b9602632 authored by Russ Cox's avatar Russ Cox

cmd/internal/gc: move componentgen into portable code

Change-Id: I652cc7a33a186d1041f62f6e7581421496832a27
Reviewed-on: https://go-review.googlesource.com/7747Reviewed-by: 's avatarJosh Bleecher Snyder <josharian@gmail.com>
parent d47fe809
......@@ -1530,7 +1530,7 @@ func sgen(n *gc.Node, res *gc.Node, w int64) {
}
// Avoid taking the address for simple enough types.
if componentgen(n, res) {
if gc.Componentgen(n, res) {
return
}
......@@ -1725,268 +1725,3 @@ func sgen(n *gc.Node, res *gc.Node, w int64) {
regfree(&src)
regfree(&tmp)
}
func cadable(n *gc.Node) bool {
if n.Addable == 0 {
// dont know how it happens,
// but it does
return false
}
switch n.Op {
case gc.ONAME:
return true
}
return false
}
/*
* copy a composite value by moving its individual components.
* Slices, strings and interfaces are supported.
* Small structs or arrays with elements of basic type are
* also supported.
* nr is N when assigning a zero value.
* return 1 if can do, 0 if cant.
*/
func componentgen(nr *gc.Node, nl *gc.Node) bool {
var nodl gc.Node
var nodr gc.Node
freel := 0
freer := 0
switch nl.Type.Etype {
default:
goto no
case gc.TARRAY:
t := nl.Type
// Slices are ok.
if gc.Isslice(t) {
break
}
// Small arrays are ok.
if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) {
break
}
goto no
// Small structs with non-fat types are ok.
// Zero-sized structs are treated separately elsewhere.
case gc.TSTRUCT:
fldcount := int64(0)
for t := nl.Type.Type; t != nil; t = t.Down {
if gc.Isfat(t.Type) {
goto no
}
if t.Etype != gc.TFIELD {
gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong))
}
fldcount++
}
if fldcount == 0 || fldcount > 4 {
goto no
}
case gc.TSTRING,
gc.TINTER:
break
}
nodl = *nl
if !cadable(nl) {
if nr != nil && !cadable(nr) {
goto no
}
igen(nl, &nodl, nil)
freel = 1
}
if nr != nil {
nodr = *nr
if !cadable(nr) {
igen(nr, &nodr, nil)
freer = 1
}
} else {
// When zeroing, prepare a register containing zero.
var tmp gc.Node
gc.Nodconst(&tmp, nl.Type, 0)
regalloc(&nodr, gc.Types[gc.TUINT], nil)
gmove(&tmp, &nodr)
freer = 1
}
// nl and nr are 'cadable' which basically means they are names (variables) now.
// If they are the same variable, don't generate any code, because the
// VARDEF we generate will mark the old value as dead incorrectly.
// (And also the assignments are useless.)
if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr {
goto yes
}
switch nl.Type.Etype {
// componentgen for arrays.
case gc.TARRAY:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
t := nl.Type
if !gc.Isslice(t) {
nodl.Type = t.Type
nodr.Type = nodl.Type
for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
if nr == nil {
gc.Clearslim(&nodl)
} else {
gmove(&nodr, &nodl)
}
nodl.Xoffset += t.Type.Width
nodr.Xoffset += t.Type.Width
}
goto yes
}
// componentgen for slices.
nodl.Xoffset += int64(gc.Array_array)
nodl.Type = gc.Ptrto(nl.Type.Type)
if nr != nil {
nodr.Xoffset += int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
if nr != nil {
nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
if nr != nil {
nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
goto yes
case gc.TSTRING:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
nodl.Xoffset += int64(gc.Array_array)
nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
if nr != nil {
nodr.Xoffset += int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
if nr != nil {
nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
goto yes
case gc.TINTER:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
nodl.Xoffset += int64(gc.Array_array)
nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
if nr != nil {
nodr.Xoffset += int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
if nr != nil {
nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
goto yes
case gc.TSTRUCT:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
loffset := nodl.Xoffset
roffset := nodr.Xoffset
// funarg structs may not begin at offset zero.
if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
loffset -= nl.Type.Type.Width
}
if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
roffset -= nr.Type.Type.Width
}
for t := nl.Type.Type; t != nil; t = t.Down {
nodl.Xoffset = loffset + t.Width
nodl.Type = t.Type
if nr == nil {
gc.Clearslim(&nodl)
} else {
nodr.Xoffset = roffset + t.Width
nodr.Type = nodl.Type
gmove(&nodr, &nodl)
}
}
goto yes
}
no:
if freer != 0 {
regfree(&nodr)
}
if freel != 0 {
regfree(&nodl)
}
return false
yes:
if freer != 0 {
regfree(&nodr)
}
if freel != 0 {
regfree(&nodl)
}
return true
}
......@@ -61,6 +61,7 @@ func main() {
gc.Thearch.Ginit = ginit
gc.Thearch.Gins = gins
gc.Thearch.Ginscall = ginscall
gc.Thearch.Gmove = gmove
gc.Thearch.Igen = igen
gc.Thearch.Linkarchinit = linkarchinit
gc.Thearch.Peep = peep
......
......@@ -657,7 +657,7 @@ func clearfat(nl *gc.Node) {
w := uint32(nl.Type.Width)
// Avoid taking the address for simple enough types.
if componentgen(nil, nl) {
if gc.Componentgen(nil, nl) {
return
}
......
......@@ -1441,7 +1441,7 @@ func sgen(n *gc.Node, ns *gc.Node, w int64) {
}
// Avoid taking the address for simple enough types.
if componentgen(n, ns) {
if gc.Componentgen(n, ns) {
return
}
......@@ -1612,268 +1612,3 @@ func sgen(n *gc.Node, ns *gc.Node, w int64) {
restx(&cx, &oldcx)
}
func cadable(n *gc.Node) bool {
if n.Addable == 0 {
// dont know how it happens,
// but it does
return false
}
switch n.Op {
case gc.ONAME:
return true
}
return false
}
/*
* copy a composite value by moving its individual components.
* Slices, strings and interfaces are supported.
* Small structs or arrays with elements of basic type are
* also supported.
* nr is N when assigning a zero value.
* return 1 if can do, 0 if can't.
*/
func componentgen(nr *gc.Node, nl *gc.Node) bool {
var nodl gc.Node
var nodr gc.Node
freel := 0
freer := 0
switch nl.Type.Etype {
default:
goto no
case gc.TARRAY:
t := nl.Type
// Slices are ok.
if gc.Isslice(t) {
break
}
// Small arrays are ok.
if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) {
break
}
goto no
// Small structs with non-fat types are ok.
// Zero-sized structs are treated separately elsewhere.
case gc.TSTRUCT:
fldcount := int64(0)
for t := nl.Type.Type; t != nil; t = t.Down {
if gc.Isfat(t.Type) && !gc.Isslice(t) {
goto no
}
if t.Etype != gc.TFIELD {
gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong))
}
fldcount++
}
if fldcount == 0 || fldcount > 4 {
goto no
}
case gc.TSTRING,
gc.TINTER:
break
}
nodl = *nl
if !cadable(nl) {
if nr != nil && !cadable(nr) {
goto no
}
igen(nl, &nodl, nil)
freel = 1
}
if nr != nil {
nodr = *nr
if !cadable(nr) {
igen(nr, &nodr, nil)
freer = 1
}
} else {
// When zeroing, prepare a register containing zero.
var tmp gc.Node
gc.Nodconst(&tmp, nl.Type, 0)
regalloc(&nodr, gc.Types[gc.TUINT], nil)
gmove(&tmp, &nodr)
freer = 1
}
// nl and nr are 'cadable' which basically means they are names (variables) now.
// If they are the same variable, don't generate any code, because the
// VARDEF we generate will mark the old value as dead incorrectly.
// (And also the assignments are useless.)
if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr {
goto yes
}
switch nl.Type.Etype {
// componentgen for arrays.
case gc.TARRAY:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
t := nl.Type
if !gc.Isslice(t) {
nodl.Type = t.Type
nodr.Type = nodl.Type
for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
if nr == nil {
gc.Clearslim(&nodl)
} else {
gmove(&nodr, &nodl)
}
nodl.Xoffset += t.Type.Width
nodr.Xoffset += t.Type.Width
}
goto yes
}
// componentgen for slices.
nodl.Xoffset += int64(gc.Array_array)
nodl.Type = gc.Ptrto(nl.Type.Type)
if nr != nil {
nodr.Xoffset += int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
if nr != nil {
nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
if nr != nil {
nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
goto yes
case gc.TSTRING:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
nodl.Xoffset += int64(gc.Array_array)
nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
if nr != nil {
nodr.Xoffset += int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
if nr != nil {
nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
goto yes
case gc.TINTER:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
nodl.Xoffset += int64(gc.Array_array)
nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
if nr != nil {
nodr.Xoffset += int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
if nr != nil {
nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
goto yes
case gc.TSTRUCT:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
loffset := nodl.Xoffset
roffset := nodr.Xoffset
// funarg structs may not begin at offset zero.
if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
loffset -= nl.Type.Type.Width
}
if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
roffset -= nr.Type.Type.Width
}
for t := nl.Type.Type; t != nil; t = t.Down {
nodl.Xoffset = loffset + t.Width
nodl.Type = t.Type
if nr == nil {
gc.Clearslim(&nodl)
} else {
nodr.Xoffset = roffset + t.Width
nodr.Type = nodl.Type
gmove(&nodr, &nodl)
}
}
goto yes
}
no:
if freer != 0 {
regfree(&nodr)
}
if freel != 0 {
regfree(&nodl)
}
return false
yes:
if freer != 0 {
regfree(&nodr)
}
if freel != 0 {
regfree(&nodl)
}
return true
}
......@@ -86,6 +86,7 @@ func main() {
gc.Thearch.Ginit = ginit
gc.Thearch.Gins = gins
gc.Thearch.Ginscall = ginscall
gc.Thearch.Gmove = gmove
gc.Thearch.Igen = igen
gc.Thearch.Linkarchinit = linkarchinit
gc.Thearch.Peep = peep
......
......@@ -950,7 +950,7 @@ func clearfat(nl *gc.Node) {
w := nl.Type.Width
// Avoid taking the address for simple enough types.
if componentgen(nil, nl) {
if gc.Componentgen(nil, nl) {
return
}
......
......@@ -1424,8 +1424,10 @@ func sgen(n *gc.Node, ns *gc.Node, w int64) {
}
// Avoid taking the address for simple enough types.
//if(componentgen(n, ns))
// return;
//if gc.Componentgen(n, ns) {
// return
//}
if w == 0 {
// evaluate side effects only.
var dst gc.Node
......@@ -1598,268 +1600,3 @@ func sgen(n *gc.Node, ns *gc.Node, w int64) {
regfree(&src)
regfree(&tmp)
}
func cadable(n *gc.Node) bool {
if n.Addable == 0 {
// dont know how it happens,
// but it does
return false
}
switch n.Op {
case gc.ONAME:
return true
}
return false
}
/*
* copy a composite value by moving its individual components.
* Slices, strings and interfaces are supported.
* Small structs or arrays with elements of basic type are
* also supported.
* nr is N when assigning a zero value.
* return 1 if can do, 0 if can't.
*/
func componentgen(nr *gc.Node, nl *gc.Node) bool {
var nodl gc.Node
var nodr gc.Node
freel := 0
freer := 0
switch nl.Type.Etype {
default:
goto no
case gc.TARRAY:
t := nl.Type
// Slices are ok.
if gc.Isslice(t) {
break
}
// Small arrays are ok.
if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) {
break
}
goto no
// Small structs with non-fat types are ok.
// Zero-sized structs are treated separately elsewhere.
case gc.TSTRUCT:
fldcount := int64(0)
for t := nl.Type.Type; t != nil; t = t.Down {
if gc.Isfat(t.Type) {
goto no
}
if t.Etype != gc.TFIELD {
gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong))
}
fldcount++
}
if fldcount == 0 || fldcount > 4 {
goto no
}
case gc.TSTRING,
gc.TINTER:
break
}
nodl = *nl
if !cadable(nl) {
if nr != nil && !cadable(nr) {
goto no
}
igen(nl, &nodl, nil)
freel = 1
}
if nr != nil {
nodr = *nr
if !cadable(nr) {
igen(nr, &nodr, nil)
freer = 1
}
} else {
// When zeroing, prepare a register containing zero.
var tmp gc.Node
gc.Nodconst(&tmp, nl.Type, 0)
regalloc(&nodr, gc.Types[gc.TUINT], nil)
gmove(&tmp, &nodr)
freer = 1
}
// nl and nr are 'cadable' which basically means they are names (variables) now.
// If they are the same variable, don't generate any code, because the
// VARDEF we generate will mark the old value as dead incorrectly.
// (And also the assignments are useless.)
if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr {
goto yes
}
switch nl.Type.Etype {
// componentgen for arrays.
case gc.TARRAY:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
t := nl.Type
if !gc.Isslice(t) {
nodl.Type = t.Type
nodr.Type = nodl.Type
for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
if nr == nil {
gc.Clearslim(&nodl)
} else {
gmove(&nodr, &nodl)
}
nodl.Xoffset += t.Type.Width
nodr.Xoffset += t.Type.Width
}
goto yes
}
// componentgen for slices.
nodl.Xoffset += int64(gc.Array_array)
nodl.Type = gc.Ptrto(nl.Type.Type)
if nr != nil {
nodr.Xoffset += int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
if nr != nil {
nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
if nr != nil {
nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
goto yes
case gc.TSTRING:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
nodl.Xoffset += int64(gc.Array_array)
nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
if nr != nil {
nodr.Xoffset += int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
if nr != nil {
nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
goto yes
case gc.TINTER:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
nodl.Xoffset += int64(gc.Array_array)
nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
if nr != nil {
nodr.Xoffset += int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
if nr != nil {
nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
goto yes
case gc.TSTRUCT:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
loffset := nodl.Xoffset
roffset := nodr.Xoffset
// funarg structs may not begin at offset zero.
if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
loffset -= nl.Type.Type.Width
}
if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
roffset -= nr.Type.Type.Width
}
for t := nl.Type.Type; t != nil; t = t.Down {
nodl.Xoffset = loffset + t.Width
nodl.Type = t.Type
if nr == nil {
gc.Clearslim(&nodl)
} else {
nodr.Xoffset = roffset + t.Width
nodr.Type = nodl.Type
gmove(&nodr, &nodl)
}
}
goto yes
}
no:
if freer != 0 {
regfree(&nodr)
}
if freel != 0 {
regfree(&nodl)
}
return false
yes:
if freer != 0 {
regfree(&nodr)
}
if freel != 0 {
regfree(&nodl)
}
return true
}
......@@ -60,6 +60,7 @@ func main() {
gc.Thearch.Ginit = ginit
gc.Thearch.Gins = gins
gc.Thearch.Ginscall = ginscall
gc.Thearch.Gmove = gmove
gc.Thearch.Igen = igen
gc.Thearch.Linkarchinit = linkarchinit
gc.Thearch.Peep = peep
......
......@@ -720,8 +720,9 @@ func clearfat(nl *gc.Node) {
w := uint64(uint64(nl.Type.Width))
// Avoid taking the address for simple enough types.
//if(componentgen(N, nl))
// return;
//if gc.Componentgen(nil, nl) {
// return
//}
c := uint64(w % 8) // bytes
q := uint64(w / 8) // dwords
......
......@@ -1332,7 +1332,7 @@ func sgen(n *gc.Node, res *gc.Node, w int64) {
}
// Avoid taking the address for simple enough types.
if componentgen(n, res) {
if gc.Componentgen(n, res) {
return
}
......@@ -1462,268 +1462,3 @@ func sgen(n *gc.Node, res *gc.Node, w int64) {
}
}
}
func cadable(n *gc.Node) bool {
if n.Addable == 0 {
// dont know how it happens,
// but it does
return false
}
switch n.Op {
case gc.ONAME:
return true
}
return false
}
/*
* copy a composite value by moving its individual components.
* Slices, strings and interfaces are supported.
* Small structs or arrays with elements of basic type are
* also supported.
* nr is N when assigning a zero value.
* return 1 if can do, 0 if can't.
*/
func componentgen(nr *gc.Node, nl *gc.Node) bool {
var nodl gc.Node
var nodr gc.Node
freel := 0
freer := 0
switch nl.Type.Etype {
default:
goto no
case gc.TARRAY:
t := nl.Type
// Slices are ok.
if gc.Isslice(t) {
break
}
// Small arrays are ok.
if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) {
break
}
goto no
// Small structs with non-fat types are ok.
// Zero-sized structs are treated separately elsewhere.
case gc.TSTRUCT:
fldcount := int64(0)
for t := nl.Type.Type; t != nil; t = t.Down {
if gc.Isfat(t.Type) {
goto no
}
if t.Etype != gc.TFIELD {
gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong))
}
fldcount++
}
if fldcount == 0 || fldcount > 4 {
goto no
}
case gc.TSTRING,
gc.TINTER:
break
}
nodl = *nl
if !cadable(nl) {
if nr != nil && !cadable(nr) {
goto no
}
igen(nl, &nodl, nil)
freel = 1
}
if nr != nil {
nodr = *nr
if !cadable(nr) {
igen(nr, &nodr, nil)
freer = 1
}
} else {
// When zeroing, prepare a register containing zero.
var tmp gc.Node
gc.Nodconst(&tmp, nl.Type, 0)
regalloc(&nodr, gc.Types[gc.TUINT], nil)
gmove(&tmp, &nodr)
freer = 1
}
// nl and nr are 'cadable' which basically means they are names (variables) now.
// If they are the same variable, don't generate any code, because the
// VARDEF we generate will mark the old value as dead incorrectly.
// (And also the assignments are useless.)
if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr {
goto yes
}
switch nl.Type.Etype {
// componentgen for arrays.
case gc.TARRAY:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
t := nl.Type
if !gc.Isslice(t) {
nodl.Type = t.Type
nodr.Type = nodl.Type
for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
if nr == nil {
gc.Clearslim(&nodl)
} else {
gmove(&nodr, &nodl)
}
nodl.Xoffset += t.Type.Width
nodr.Xoffset += t.Type.Width
}
goto yes
}
// componentgen for slices.
nodl.Xoffset += int64(gc.Array_array)
nodl.Type = gc.Ptrto(nl.Type.Type)
if nr != nil {
nodr.Xoffset += int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
if nr != nil {
nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
if nr != nil {
nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
goto yes
case gc.TSTRING:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
nodl.Xoffset += int64(gc.Array_array)
nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
if nr != nil {
nodr.Xoffset += int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
if nr != nil {
nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
goto yes
case gc.TINTER:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
nodl.Xoffset += int64(gc.Array_array)
nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
if nr != nil {
nodr.Xoffset += int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
if nr != nil {
nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
goto yes
case gc.TSTRUCT:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
loffset := nodl.Xoffset
roffset := nodr.Xoffset
// funarg structs may not begin at offset zero.
if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
loffset -= nl.Type.Type.Width
}
if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
roffset -= nr.Type.Type.Width
}
for t := nl.Type.Type; t != nil; t = t.Down {
nodl.Xoffset = loffset + t.Width
nodl.Type = t.Type
if nr == nil {
gc.Clearslim(&nodl)
} else {
nodr.Xoffset = roffset + t.Width
nodr.Type = nodl.Type
gmove(&nodr, &nodl)
}
}
goto yes
}
no:
if freer != 0 {
regfree(&nodr)
}
if freel != 0 {
regfree(&nodl)
}
return false
yes:
if freer != 0 {
regfree(&nodr)
}
if freel != 0 {
regfree(&nodl)
}
return true
}
......@@ -61,6 +61,7 @@ func main() {
gc.Thearch.Ginit = ginit
gc.Thearch.Gins = gins
gc.Thearch.Ginscall = ginscall
gc.Thearch.Gmove = gmove
gc.Thearch.Igen = igen
gc.Thearch.Linkarchinit = linkarchinit
gc.Thearch.Peep = peep
......
......@@ -112,7 +112,7 @@ func clearfat(nl *gc.Node) {
w := uint32(nl.Type.Width)
// Avoid taking the address for simple enough types.
if componentgen(nil, nl) {
if gc.Componentgen(nil, nl) {
return
}
......
......@@ -1445,8 +1445,10 @@ func sgen(n *gc.Node, ns *gc.Node, w int64) {
}
// Avoid taking the address for simple enough types.
//if(componentgen(n, ns))
// return;
if gc.Componentgen(n, ns) {
return
}
if w == 0 {
// evaluate side effects only.
var dst gc.Node
......@@ -1615,268 +1617,3 @@ func sgen(n *gc.Node, ns *gc.Node, w int64) {
regfree(&src)
regfree(&tmp)
}
func cadable(n *gc.Node) bool {
if n.Addable == 0 {
// dont know how it happens,
// but it does
return false
}
switch n.Op {
case gc.ONAME:
return true
}
return false
}
/*
* copy a composite value by moving its individual components.
* Slices, strings and interfaces are supported.
* Small structs or arrays with elements of basic type are
* also supported.
* nr is N when assigning a zero value.
* return 1 if can do, 0 if can't.
*/
func componentgen(nr *gc.Node, nl *gc.Node) bool {
var nodl gc.Node
var nodr gc.Node
freel := 0
freer := 0
switch nl.Type.Etype {
default:
goto no
case gc.TARRAY:
t := nl.Type
// Slices are ok.
if gc.Isslice(t) {
break
}
// Small arrays are ok.
if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) {
break
}
goto no
// Small structs with non-fat types are ok.
// Zero-sized structs are treated separately elsewhere.
case gc.TSTRUCT:
fldcount := int64(0)
for t := nl.Type.Type; t != nil; t = t.Down {
if gc.Isfat(t.Type) {
goto no
}
if t.Etype != gc.TFIELD {
gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong))
}
fldcount++
}
if fldcount == 0 || fldcount > 4 {
goto no
}
case gc.TSTRING,
gc.TINTER:
break
}
nodl = *nl
if !cadable(nl) {
if nr != nil && !cadable(nr) {
goto no
}
igen(nl, &nodl, nil)
freel = 1
}
if nr != nil {
nodr = *nr
if !cadable(nr) {
igen(nr, &nodr, nil)
freer = 1
}
} else {
// When zeroing, prepare a register containing zero.
var tmp gc.Node
gc.Nodconst(&tmp, nl.Type, 0)
regalloc(&nodr, gc.Types[gc.TUINT], nil)
gmove(&tmp, &nodr)
freer = 1
}
// nl and nr are 'cadable' which basically means they are names (variables) now.
// If they are the same variable, don't generate any code, because the
// VARDEF we generate will mark the old value as dead incorrectly.
// (And also the assignments are useless.)
if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr {
goto yes
}
switch nl.Type.Etype {
// componentgen for arrays.
case gc.TARRAY:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
t := nl.Type
if !gc.Isslice(t) {
nodl.Type = t.Type
nodr.Type = nodl.Type
for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
if nr == nil {
gc.Clearslim(&nodl)
} else {
gmove(&nodr, &nodl)
}
nodl.Xoffset += t.Type.Width
nodr.Xoffset += t.Type.Width
}
goto yes
}
// componentgen for slices.
nodl.Xoffset += int64(gc.Array_array)
nodl.Type = gc.Ptrto(nl.Type.Type)
if nr != nil {
nodr.Xoffset += int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
if nr != nil {
nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
if nr != nil {
nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
goto yes
case gc.TSTRING:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
nodl.Xoffset += int64(gc.Array_array)
nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
if nr != nil {
nodr.Xoffset += int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
if nr != nil {
nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
goto yes
case gc.TINTER:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
nodl.Xoffset += int64(gc.Array_array)
nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
if nr != nil {
nodr.Xoffset += int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
if nr != nil {
nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
nodr.Type = nodl.Type
}
gmove(&nodr, &nodl)
goto yes
case gc.TSTRUCT:
if nl.Op == gc.ONAME {
gc.Gvardef(nl)
}
loffset := nodl.Xoffset
roffset := nodr.Xoffset
// funarg structs may not begin at offset zero.
if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
loffset -= nl.Type.Type.Width
}
if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
roffset -= nr.Type.Type.Width
}
for t := nl.Type.Type; t != nil; t = t.Down {
nodl.Xoffset = loffset + t.Width
nodl.Type = t.Type
if nr == nil {
gc.Clearslim(&nodl)
} else {
nodr.Xoffset = roffset + t.Width
nodr.Type = nodl.Type
gmove(&nodr, &nodl)
}
}
goto yes
}
no:
if freer != 0 {
regfree(&nodr)
}
if freel != 0 {
regfree(&nodl)
}
return false
yes:
if freer != 0 {
regfree(&nodr)
}
if freel != 0 {
regfree(&nodl)
}
return true
}
......@@ -69,6 +69,7 @@ func main() {
gc.Thearch.Ginit = ginit
gc.Thearch.Gins = gins
gc.Thearch.Ginscall = ginscall
gc.Thearch.Gmove = gmove
gc.Thearch.Igen = igen
gc.Thearch.Linkarchinit = linkarchinit
gc.Thearch.Peep = peep
......
......@@ -734,8 +734,9 @@ func clearfat(nl *gc.Node) {
w := uint64(uint64(nl.Type.Width))
// Avoid taking the address for simple enough types.
//if(componentgen(N, nl))
// return;
if gc.Componentgen(nil, nl) {
return
}
c := uint64(w % 8) // bytes
q := uint64(w / 8) // dwords
......
......@@ -956,3 +956,268 @@ func checklabels() {
}
}
}
/*
* copy a composite value by moving its individual components.
* Slices, strings and interfaces are supported.
* Small structs or arrays with elements of basic type are
* also supported.
* nr is N when assigning a zero value.
* return 1 if can do, 0 if can't.
*/
func Componentgen(nr *Node, nl *Node) bool {
var nodl Node
var nodr Node
freel := 0
freer := 0
switch nl.Type.Etype {
default:
goto no
case TARRAY:
t := nl.Type
// Slices are ok.
if Isslice(t) {
break
}
// Small arrays are ok.
if t.Bound > 0 && t.Bound <= 3 && !Isfat(t.Type) {
break
}
goto no
// Small structs with non-fat types are ok.
// Zero-sized structs are treated separately elsewhere.
case TSTRUCT:
fldcount := int64(0)
for t := nl.Type.Type; t != nil; t = t.Down {
if Isfat(t.Type) && !Isslice(t) {
goto no
}
if t.Etype != TFIELD {
Fatal("componentgen: not a TFIELD: %v", Tconv(t, obj.FmtLong))
}
fldcount++
}
if fldcount == 0 || fldcount > 4 {
goto no
}
case TSTRING,
TINTER:
break
}
nodl = *nl
if !cadable(nl) {
if nr != nil && !cadable(nr) {
goto no
}
Thearch.Igen(nl, &nodl, nil)
freel = 1
}
if nr != nil {
nodr = *nr
if !cadable(nr) {
Thearch.Igen(nr, &nodr, nil)
freer = 1
}
} else {
// When zeroing, prepare a register containing zero.
var tmp Node
Nodconst(&tmp, nl.Type, 0)
Thearch.Regalloc(&nodr, Types[TUINT], nil)
Thearch.Gmove(&tmp, &nodr)
freer = 1
}
// nl and nr are 'cadable' which basically means they are names (variables) now.
// If they are the same variable, don't generate any code, because the
// VARDEF we generate will mark the old value as dead incorrectly.
// (And also the assignments are useless.)
if nr != nil && nl.Op == ONAME && nr.Op == ONAME && nl == nr {
goto yes
}
switch nl.Type.Etype {
// componentgen for arrays.
case TARRAY:
if nl.Op == ONAME {
Gvardef(nl)
}
t := nl.Type
if !Isslice(t) {
nodl.Type = t.Type
nodr.Type = nodl.Type
for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
if nr == nil {
Clearslim(&nodl)
} else {
Thearch.Gmove(&nodr, &nodl)
}
nodl.Xoffset += t.Type.Width
nodr.Xoffset += t.Type.Width
}
goto yes
}
// componentgen for slices.
nodl.Xoffset += int64(Array_array)
nodl.Type = Ptrto(nl.Type.Type)
if nr != nil {
nodr.Xoffset += int64(Array_array)
nodr.Type = nodl.Type
}
Thearch.Gmove(&nodr, &nodl)
nodl.Xoffset += int64(Array_nel) - int64(Array_array)
nodl.Type = Types[Simtype[TUINT]]
if nr != nil {
nodr.Xoffset += int64(Array_nel) - int64(Array_array)
nodr.Type = nodl.Type
}
Thearch.Gmove(&nodr, &nodl)
nodl.Xoffset += int64(Array_cap) - int64(Array_nel)
nodl.Type = Types[Simtype[TUINT]]
if nr != nil {
nodr.Xoffset += int64(Array_cap) - int64(Array_nel)
nodr.Type = nodl.Type
}
Thearch.Gmove(&nodr, &nodl)
goto yes
case TSTRING:
if nl.Op == ONAME {
Gvardef(nl)
}
nodl.Xoffset += int64(Array_array)
nodl.Type = Ptrto(Types[TUINT8])
if nr != nil {
nodr.Xoffset += int64(Array_array)
nodr.Type = nodl.Type
}
Thearch.Gmove(&nodr, &nodl)
nodl.Xoffset += int64(Array_nel) - int64(Array_array)
nodl.Type = Types[Simtype[TUINT]]
if nr != nil {
nodr.Xoffset += int64(Array_nel) - int64(Array_array)
nodr.Type = nodl.Type
}
Thearch.Gmove(&nodr, &nodl)
goto yes
case TINTER:
if nl.Op == ONAME {
Gvardef(nl)
}
nodl.Xoffset += int64(Array_array)
nodl.Type = Ptrto(Types[TUINT8])
if nr != nil {
nodr.Xoffset += int64(Array_array)
nodr.Type = nodl.Type
}
Thearch.Gmove(&nodr, &nodl)
nodl.Xoffset += int64(Array_nel) - int64(Array_array)
nodl.Type = Ptrto(Types[TUINT8])
if nr != nil {
nodr.Xoffset += int64(Array_nel) - int64(Array_array)
nodr.Type = nodl.Type
}
Thearch.Gmove(&nodr, &nodl)
goto yes
case TSTRUCT:
if nl.Op == ONAME {
Gvardef(nl)
}
loffset := nodl.Xoffset
roffset := nodr.Xoffset
// funarg structs may not begin at offset zero.
if nl.Type.Etype == TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
loffset -= nl.Type.Type.Width
}
if nr != nil && nr.Type.Etype == TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
roffset -= nr.Type.Type.Width
}
for t := nl.Type.Type; t != nil; t = t.Down {
nodl.Xoffset = loffset + t.Width
nodl.Type = t.Type
if nr == nil {
Clearslim(&nodl)
} else {
nodr.Xoffset = roffset + t.Width
nodr.Type = nodl.Type
Thearch.Gmove(&nodr, &nodl)
}
}
goto yes
}
no:
if freer != 0 {
Thearch.Regfree(&nodr)
}
if freel != 0 {
Thearch.Regfree(&nodl)
}
return false
yes:
if freer != 0 {
Thearch.Regfree(&nodr)
}
if freel != 0 {
Thearch.Regfree(&nodl)
}
return true
}
func cadable(n *Node) bool {
if n.Addable == 0 {
// dont know how it happens,
// but it does
return false
}
switch n.Op {
case ONAME:
return true
}
return false
}
......@@ -790,6 +790,7 @@ type Arch struct {
Ginit func()
Gins func(int, *Node, *Node) *obj.Prog
Ginscall func(*Node, int)
Gmove func(*Node, *Node)
Igen func(*Node, *Node, *Node)
Linkarchinit func()
Peep func(*obj.Prog)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment