cmd/internal/gc: move componentgen into portable code
Change-Id: I652cc7a33a186d1041f62f6e7581421496832a27
Reviewed-on: https://go-review.googlesource.com/7747
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
diff --git a/src/cmd/internal/gc/gen.go b/src/cmd/internal/gc/gen.go
index 3777cc3..314f6c1 100644
--- a/src/cmd/internal/gc/gen.go
+++ b/src/cmd/internal/gc/gen.go
@@ -956,3 +956,268 @@
}
}
}
+
+/*
+ * 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
+}