1
0
mirror of https://github.com/golang/go synced 2024-11-23 20:20:01 -07:00

[dev.unified] cmd/compile: add RType fields

This CL adds RType/ITab fields to IR nodes that (may) ultimately
become runtime calls that require a *runtime._type or *runtime.itab
argument. It also updates the corresponding reflectdata IR helpers to
use these fields in preference of calling TypePtr/ITabAddr.

Subsequent CLs will start updating the GOEXPERIMENT=unified frontend
to set the RType fields, and incrementally switch the reflectdata
helpers to require them.

Passes toolstash -cmp.

Change-Id: I30e31d91f0a53961e3d6d872d7b5f9df2ec5074c
Reviewed-on: https://go-review.googlesource.com/c/go/+/413358
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Matthew Dempsky 2022-06-20 23:21:16 -07:00
parent 5e0258c700
commit 5960f4ec10
4 changed files with 70 additions and 8 deletions

View File

@ -119,8 +119,9 @@ func (n *BasicLit) SetVal(val constant.Value) { n.val = val }
// or Op(X, Y) for builtin functions that do not become calls. // or Op(X, Y) for builtin functions that do not become calls.
type BinaryExpr struct { type BinaryExpr struct {
miniExpr miniExpr
X Node X Node
Y Node Y Node
RType Node `mknode:"-"` // see reflectdata/helpers.go
} }
func NewBinaryExpr(pos src.XPos, op Op, x, y Node) *BinaryExpr { func NewBinaryExpr(pos src.XPos, op Op, x, y Node) *BinaryExpr {
@ -148,6 +149,7 @@ type CallExpr struct {
origNode origNode
X Node X Node
Args Nodes Args Nodes
RType Node `mknode:"-"` // see reflectdata/helpers.go
KeepAlive []*Name // vars to be kept alive until call returns KeepAlive []*Name // vars to be kept alive until call returns
IsDDD bool IsDDD bool
NoInline bool NoInline bool
@ -247,6 +249,17 @@ type ConvExpr struct {
miniExpr miniExpr
X Node X Node
// For implementing OCONVIFACE expressions.
//
// TypeWord is an expression yielding a *runtime._type or
// *runtime.itab value to go in the type word of the iface/eface
// result. See reflectdata.ConvIfaceTypeWord for further details.
//
// SrcRType is an expression yielding a *runtime._type value for X,
// if it's not pointer-shaped and needs to be heap allocated.
TypeWord Node `mknode:"-"`
SrcRType Node `mknode:"-"`
// For -d=checkptr instrumentation of conversions from // For -d=checkptr instrumentation of conversions from
// unsafe.Pointer to *Elem or *[Len]Elem. // unsafe.Pointer to *Elem or *[Len]Elem.
// //
@ -285,6 +298,7 @@ type IndexExpr struct {
miniExpr miniExpr
X Node X Node
Index Node Index Node
RType Node `mknode:"-"` // see reflectdata/helpers.go
Assigned bool Assigned bool
} }
@ -395,8 +409,9 @@ func (n *LogicalExpr) SetOp(op Op) {
// but *not* OMAKE (that's a pre-typechecking CallExpr). // but *not* OMAKE (that's a pre-typechecking CallExpr).
type MakeExpr struct { type MakeExpr struct {
miniExpr miniExpr
Len Node RType Node `mknode:"-"` // see reflectdata/helpers.go
Cap Node Len Node
Cap Node
} }
func NewMakeExpr(pos src.XPos, op Op, len, cap Node) *MakeExpr { func NewMakeExpr(pos src.XPos, op Op, len, cap Node) *MakeExpr {
@ -633,7 +648,7 @@ type TypeAssertExpr struct {
// Runtime type information provided by walkDotType for // Runtime type information provided by walkDotType for
// assertions from non-empty interface to concrete type. // assertions from non-empty interface to concrete type.
ITab *AddrExpr `mknode:"-"` // *runtime.itab for Type implementing X's type ITab Node `mknode:"-"` // *runtime.itab for Type implementing X's type
} }
func NewTypeAssertExpr(pos src.XPos, x Node, typ *types.Type) *TypeAssertExpr { func NewTypeAssertExpr(pos src.XPos, x Node, typ *types.Type) *TypeAssertExpr {

View File

@ -333,6 +333,7 @@ type RangeStmt struct {
Label *types.Sym Label *types.Sym
Def bool Def bool
X Node X Node
RType Node `mknode:"-"` // see reflectdata/helpers.go
Key Node Key Node
Value Node Value Node
Body Nodes Body Nodes

View File

@ -11,6 +11,16 @@ import (
"cmd/internal/src" "cmd/internal/src"
) )
func haveRType(n, rtype ir.Node, fieldName string, required bool) bool {
if rtype != nil {
return true
}
if base.Debug.Unified != 0 && required {
base.FatalfAt(n.Pos(), "missing %s: %+v", fieldName, n)
}
return false
}
// assertOp asserts that n is an op. // assertOp asserts that n is an op.
func assertOp(n ir.Node, op ir.Op) { func assertOp(n ir.Node, op ir.Op) {
base.AssertfAt(n.Op() == op, n.Pos(), "want %v, have %v", op, n) base.AssertfAt(n.Op() == op, n.Pos(), "want %v, have %v", op, n)
@ -61,6 +71,9 @@ func concreteRType(pos src.XPos, typ *types.Type) ir.Node {
// representing the result slice type's element type. // representing the result slice type's element type.
func AppendElemRType(pos src.XPos, n *ir.CallExpr) ir.Node { func AppendElemRType(pos src.XPos, n *ir.CallExpr) ir.Node {
assertOp(n, ir.OAPPEND) assertOp(n, ir.OAPPEND)
if haveRType(n, n.RType, "RType", false) {
return n.RType
}
return sliceElemRType(pos, n.Type()) return sliceElemRType(pos, n.Type())
} }
@ -71,6 +84,9 @@ func AppendElemRType(pos src.XPos, n *ir.CallExpr) ir.Node {
func CompareRType(pos src.XPos, n *ir.BinaryExpr) ir.Node { func CompareRType(pos src.XPos, n *ir.BinaryExpr) ir.Node {
assertOp2(n, ir.OEQ, ir.ONE) assertOp2(n, ir.OEQ, ir.ONE)
base.AssertfAt(n.X.Type().IsInterface() != n.Y.Type().IsInterface(), n.Pos(), "expect mixed interface and non-interface, have %L and %L", n.X, n.Y) base.AssertfAt(n.X.Type().IsInterface() != n.Y.Type().IsInterface(), n.Pos(), "expect mixed interface and non-interface, have %L and %L", n.X, n.Y)
if haveRType(n, n.RType, "RType", false) {
return n.RType
}
typ := n.X.Type() typ := n.X.Type()
if typ.IsInterface() { if typ.IsInterface() {
typ = n.Y.Type() typ = n.Y.Type()
@ -89,6 +105,9 @@ func ConvIfaceTypeWord(pos src.XPos, n *ir.ConvExpr) ir.Node {
assertOp(n, ir.OCONVIFACE) assertOp(n, ir.OCONVIFACE)
src, dst := n.X.Type(), n.Type() src, dst := n.X.Type(), n.Type()
base.AssertfAt(dst.IsInterface(), n.Pos(), "want interface type, have %L", n) base.AssertfAt(dst.IsInterface(), n.Pos(), "want interface type, have %L", n)
if haveRType(n, n.TypeWord, "TypeWord", false) {
return n.TypeWord
}
if dst.IsEmptyInterface() { if dst.IsEmptyInterface() {
return concreteRType(pos, src) // direct eface construction return concreteRType(pos, src) // direct eface construction
} }
@ -98,12 +117,15 @@ func ConvIfaceTypeWord(pos src.XPos, n *ir.ConvExpr) ir.Node {
return TypePtrAt(pos, dst) // convI2I return TypePtrAt(pos, dst) // convI2I
} }
// ConvIfaceDataWordRType asserts that n is a conversion from // ConvIfaceSrcRType asserts that n is a conversion from
// non-interface type to interface type (or OCONVIDATA operation), and // non-interface type to interface type (or OCONVIDATA operation), and
// returns an expression that yields the *runtime._type for copying // returns an expression that yields the *runtime._type for copying
// the convertee value to the heap. // the convertee value to the heap.
func ConvIfaceDataWordRType(pos src.XPos, n *ir.ConvExpr) ir.Node { func ConvIfaceSrcRType(pos src.XPos, n *ir.ConvExpr) ir.Node {
assertOp2(n, ir.OCONVIFACE, ir.OCONVIDATA) assertOp2(n, ir.OCONVIFACE, ir.OCONVIDATA)
if haveRType(n, n.SrcRType, "SrcRType", false) {
return n.SrcRType
}
return concreteRType(pos, n.X.Type()) return concreteRType(pos, n.X.Type())
} }
@ -112,6 +134,9 @@ func ConvIfaceDataWordRType(pos src.XPos, n *ir.ConvExpr) ir.Node {
// destination slice type's element type. // destination slice type's element type.
func CopyElemRType(pos src.XPos, n *ir.BinaryExpr) ir.Node { func CopyElemRType(pos src.XPos, n *ir.BinaryExpr) ir.Node {
assertOp(n, ir.OCOPY) assertOp(n, ir.OCOPY)
if haveRType(n, n.RType, "RType", false) {
return n.RType
}
return sliceElemRType(pos, n.X.Type()) return sliceElemRType(pos, n.X.Type())
} }
@ -120,6 +145,9 @@ func CopyElemRType(pos src.XPos, n *ir.BinaryExpr) ir.Node {
// map type. // map type.
func DeleteMapRType(pos src.XPos, n *ir.CallExpr) ir.Node { func DeleteMapRType(pos src.XPos, n *ir.CallExpr) ir.Node {
assertOp(n, ir.ODELETE) assertOp(n, ir.ODELETE)
if haveRType(n, n.RType, "RType", false) {
return n.RType
}
return mapRType(pos, n.Args[0].Type()) return mapRType(pos, n.Args[0].Type())
} }
@ -128,6 +156,9 @@ func DeleteMapRType(pos src.XPos, n *ir.CallExpr) ir.Node {
// map type. // map type.
func IndexMapRType(pos src.XPos, n *ir.IndexExpr) ir.Node { func IndexMapRType(pos src.XPos, n *ir.IndexExpr) ir.Node {
assertOp(n, ir.OINDEXMAP) assertOp(n, ir.OINDEXMAP)
if haveRType(n, n.RType, "RType", false) {
return n.RType
}
return mapRType(pos, n.X.Type()) return mapRType(pos, n.X.Type())
} }
@ -136,6 +167,9 @@ func IndexMapRType(pos src.XPos, n *ir.IndexExpr) ir.Node {
// value representing that channel type. // value representing that channel type.
func MakeChanRType(pos src.XPos, n *ir.MakeExpr) ir.Node { func MakeChanRType(pos src.XPos, n *ir.MakeExpr) ir.Node {
assertOp(n, ir.OMAKECHAN) assertOp(n, ir.OMAKECHAN)
if haveRType(n, n.RType, "RType", false) {
return n.RType
}
return chanRType(pos, n.Type()) return chanRType(pos, n.Type())
} }
@ -144,6 +178,9 @@ func MakeChanRType(pos src.XPos, n *ir.MakeExpr) ir.Node {
// representing that map type. // representing that map type.
func MakeMapRType(pos src.XPos, n *ir.MakeExpr) ir.Node { func MakeMapRType(pos src.XPos, n *ir.MakeExpr) ir.Node {
assertOp(n, ir.OMAKEMAP) assertOp(n, ir.OMAKEMAP)
if haveRType(n, n.RType, "RType", false) {
return n.RType
}
return mapRType(pos, n.Type()) return mapRType(pos, n.Type())
} }
@ -152,6 +189,9 @@ func MakeMapRType(pos src.XPos, n *ir.MakeExpr) ir.Node {
// value representing that slice type's element type. // value representing that slice type's element type.
func MakeSliceElemRType(pos src.XPos, n *ir.MakeExpr) ir.Node { func MakeSliceElemRType(pos src.XPos, n *ir.MakeExpr) ir.Node {
assertOp2(n, ir.OMAKESLICE, ir.OMAKESLICECOPY) assertOp2(n, ir.OMAKESLICE, ir.OMAKESLICECOPY)
if haveRType(n, n.RType, "RType", false) {
return n.RType
}
return sliceElemRType(pos, n.Type()) return sliceElemRType(pos, n.Type())
} }
@ -160,6 +200,9 @@ func MakeSliceElemRType(pos src.XPos, n *ir.MakeExpr) ir.Node {
// representing that map type. // representing that map type.
func RangeMapRType(pos src.XPos, n *ir.RangeStmt) ir.Node { func RangeMapRType(pos src.XPos, n *ir.RangeStmt) ir.Node {
assertOp(n, ir.ORANGE) assertOp(n, ir.ORANGE)
if haveRType(n, n.RType, "RType", false) {
return n.RType
}
return mapRType(pos, n.X.Type()) return mapRType(pos, n.X.Type())
} }
@ -168,5 +211,8 @@ func RangeMapRType(pos src.XPos, n *ir.RangeStmt) ir.Node {
// representing the result slice type's element type. // representing the result slice type's element type.
func UnsafeSliceElemRType(pos src.XPos, n *ir.BinaryExpr) ir.Node { func UnsafeSliceElemRType(pos src.XPos, n *ir.BinaryExpr) ir.Node {
assertOp(n, ir.OUNSAFESLICE) assertOp(n, ir.OUNSAFESLICE)
if haveRType(n, n.RType, "RType", false) {
return n.RType
}
return sliceElemRType(pos, n.Type()) return sliceElemRType(pos, n.Type())
} }

View File

@ -170,7 +170,7 @@ func dataWord(conv *ir.ConvExpr, init *ir.Nodes) ir.Node {
n = copyExpr(n, fromType, init) n = copyExpr(n, fromType, init)
} }
fn = typecheck.SubstArgTypes(fn, fromType) fn = typecheck.SubstArgTypes(fn, fromType)
args = []ir.Node{reflectdata.ConvIfaceDataWordRType(base.Pos, conv), typecheck.NodAddr(n)} args = []ir.Node{reflectdata.ConvIfaceSrcRType(base.Pos, conv), typecheck.NodAddr(n)}
} else { } else {
// Use a specialized conversion routine that takes the type being // Use a specialized conversion routine that takes the type being
// converted by value, not by pointer. // converted by value, not by pointer.