cmd/compile: add variable length TRESULTS type for SSA use.

This type is very much like TTUPLE, but not just for pairs.
Used to describe results of a pre-expansion function call.
(will later probably also be used to describe the incoming args).

Change-Id: I811850cfcc2b3de85085eb4c2eca217c04c330b3
Reviewed-on: https://go-review.googlesource.com/c/go/+/242360
Trust: David Chase <drchase@google.com>
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index 43e501d..d4af451 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -711,6 +711,17 @@
 		return
 	}
 
+	if t.Etype == types.TRESULTS {
+		tys := t.Extra.(*types.Results).Types
+		for i, et := range tys {
+			if i > 0 {
+				b.WriteByte(',')
+			}
+			b.WriteString(et.String())
+		}
+		return
+	}
+
 	flag, mode = flag.update(mode)
 	if mode == FTypeIdName {
 		flag |= FmtUnsigned
diff --git a/src/cmd/compile/internal/types/etype_string.go b/src/cmd/compile/internal/types/etype_string.go
index 0ff05a8..14fd5b7 100644
--- a/src/cmd/compile/internal/types/etype_string.go
+++ b/src/cmd/compile/internal/types/etype_string.go
@@ -44,12 +44,13 @@
 	_ = x[TCHANARGS-33]
 	_ = x[TSSA-34]
 	_ = x[TTUPLE-35]
-	_ = x[NTYPE-36]
+	_ = x[TRESULTS-36]
+	_ = x[NTYPE-37]
 }
 
-const _EType_name = "xxxINT8UINT8INT16UINT16INT32UINT32INT64UINT64INTUINTUINTPTRCOMPLEX64COMPLEX128FLOAT32FLOAT64BOOLPTRFUNCSLICEARRAYSTRUCTCHANMAPINTERFORWANYSTRINGUNSAFEPTRIDEALNILBLANKFUNCARGSCHANARGSSSATUPLENTYPE"
+const _EType_name = "xxxINT8UINT8INT16UINT16INT32UINT32INT64UINT64INTUINTUINTPTRCOMPLEX64COMPLEX128FLOAT32FLOAT64BOOLPTRFUNCSLICEARRAYSTRUCTCHANMAPINTERFORWANYSTRINGUNSAFEPTRIDEALNILBLANKFUNCARGSCHANARGSSSATUPLERESULTSNTYPE"
 
-var _EType_index = [...]uint8{0, 3, 7, 12, 17, 23, 28, 34, 39, 45, 48, 52, 59, 68, 78, 85, 92, 96, 99, 103, 108, 113, 119, 123, 126, 131, 135, 138, 144, 153, 158, 161, 166, 174, 182, 185, 190, 195}
+var _EType_index = [...]uint8{0, 3, 7, 12, 17, 23, 28, 34, 39, 45, 48, 52, 59, 68, 78, 85, 92, 96, 99, 103, 108, 113, 119, 123, 126, 131, 135, 138, 144, 153, 158, 161, 166, 174, 182, 185, 190, 197, 202}
 
 func (i EType) String() string {
 	if i >= EType(len(_EType_index)-1) {
diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go
index a777a5f..9b05aef 100644
--- a/src/cmd/compile/internal/types/type.go
+++ b/src/cmd/compile/internal/types/type.go
@@ -66,8 +66,9 @@
 	TCHANARGS
 
 	// SSA backend types
-	TSSA   // internal types used by SSA backend (flags, memory, etc.)
-	TTUPLE // a pair of types, used by SSA backend
+	TSSA     // internal types used by SSA backend (flags, memory, etc.)
+	TTUPLE   // a pair of types, used by SSA backend
+	TRESULTS // multiuple types; the resulting of calling a function or method, plus a memory at the end.
 
 	NTYPE
 )
@@ -330,6 +331,11 @@
 	// Any tuple with a memory type must put that memory type second.
 }
 
+type Results struct {
+	Types []*Type
+	// Any Results with a memory type must put that memory type last.
+}
+
 // Array contains Type fields specific to array types.
 type Array struct {
 	Elem  *Type // element type
@@ -466,6 +472,8 @@
 		t.Extra = new(Chan)
 	case TTUPLE:
 		t.Extra = new(Tuple)
+	case TRESULTS:
+		t.Extra = new(Results)
 	}
 	return t
 }
@@ -512,6 +520,12 @@
 	return t
 }
 
+func NewResults(types []*Type) *Type {
+	t := New(TRESULTS)
+	t.Extra.(*Results).Types = types
+	return t
+}
+
 func newSSA(name string) *Type {
 	t := New(TSSA)
 	t.Extra = name
@@ -688,7 +702,7 @@
 	case TARRAY:
 		x := *t.Extra.(*Array)
 		nt.Extra = &x
-	case TTUPLE, TSSA:
+	case TTUPLE, TSSA, TRESULTS:
 		Fatalf("ssa types cannot be copied")
 	}
 	// TODO(mdempsky): Find out why this is necessary and explain.
@@ -1051,6 +1065,23 @@
 		}
 		return ttup.second.Compare(xtup.second)
 
+	case TRESULTS:
+		xResults := x.Extra.(*Results)
+		tResults := t.Extra.(*Results)
+		xl, tl := len(xResults.Types), len(tResults.Types)
+		if tl != xl {
+			if tl < xl {
+				return CMPlt
+			}
+			return CMPgt
+		}
+		for i := 0; i < tl; i++ {
+			if c := tResults.Types[i].Compare(xResults.Types[i]); c != CMPeq {
+				return c
+			}
+		}
+		return CMPeq
+
 	case TMAP:
 		if c := t.Key().cmp(x.Key()); c != CMPeq {
 			return c
@@ -1305,6 +1336,9 @@
 			panic("bad tuple index")
 		}
 	}
+	if t.Etype == TRESULTS {
+		return t.Extra.(*Results).Types[i]
+	}
 	return t.Field(i).Type
 }
 func (t *Type) FieldOff(i int) int64 {
@@ -1382,11 +1416,20 @@
 }
 
 func (t *Type) IsMemory() bool {
-	return t == TypeMem || t.Etype == TTUPLE && t.Extra.(*Tuple).second == TypeMem
+	if t == TypeMem || t.Etype == TTUPLE && t.Extra.(*Tuple).second == TypeMem {
+		return true
+	}
+	if t.Etype == TRESULTS {
+		if types := t.Extra.(*Results).Types; len(types) > 0 && types[len(types)-1] == TypeMem {
+			return true
+		}
+	}
+	return false
 }
-func (t *Type) IsFlags() bool { return t == TypeFlags }
-func (t *Type) IsVoid() bool  { return t == TypeVoid }
-func (t *Type) IsTuple() bool { return t.Etype == TTUPLE }
+func (t *Type) IsFlags() bool   { return t == TypeFlags }
+func (t *Type) IsVoid() bool    { return t == TypeVoid }
+func (t *Type) IsTuple() bool   { return t.Etype == TTUPLE }
+func (t *Type) IsResults() bool { return t.Etype == TRESULTS }
 
 // IsUntyped reports whether t is an untyped type.
 func (t *Type) IsUntyped() bool {
@@ -1431,6 +1474,15 @@
 	case TTUPLE:
 		ttup := t.Extra.(*Tuple)
 		return ttup.first.HasPointers() || ttup.second.HasPointers()
+
+	case TRESULTS:
+		types := t.Extra.(*Results).Types
+		for _, et := range types {
+			if et.HasPointers() {
+				return true
+			}
+		}
+		return false
 	}
 
 	return true