cmd/internal/gc: inline x := y.(*T) and x, ok := y.(*T)
These can be implemented with just a compare and a move instruction.
Do so, avoiding the overhead of a call into the runtime.
These assertions are a significant cost in Go code that uses interface{}
as a safe alternative to C's void* (or unsafe.Pointer), such as the
current version of the Go compiler.
*T here includes pointer to T but also any Go type represented as
a single pointer (chan, func, map). It does not include [1]*T or struct{*int}.
That requires more work in other parts of the compiler; there is a TODO.
Change-Id: I7ff681c20d2c3eb6ad11dd7b3a37b1f3dda23965
Reviewed-on: https://go-review.googlesource.com/7862
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/src/cmd/internal/gc/cgen.go b/src/cmd/internal/gc/cgen.go
index 610f251..7566dda 100644
--- a/src/cmd/internal/gc/cgen.go
+++ b/src/cmd/internal/gc/cgen.go
@@ -54,6 +54,10 @@
Cgen_eface(n, res)
}
return
+
+ case ODOTTYPE:
+ cgen_dottype(n, res, nil)
+ return
}
if n.Ullman >= UINF {
@@ -1224,12 +1228,19 @@
Agenr(nl, &n3, res)
} else {
if nl.Addable == 0 {
+ if res != nil && res.Op == OREGISTER { // give up res, which we don't need yet.
+ Regfree(res)
+ }
+
// igen will need an addressable node.
var tmp2 Node
Tempname(&tmp2, nl.Type)
-
Cgen(nl, &tmp2)
nl = &tmp2
+
+ if res != nil && res.Op == OREGISTER { // reacquire res
+ Regrealloc(res)
+ }
}
Igen(nl, &nlen, res)
@@ -1448,16 +1459,10 @@
cgen_call(n, 0)
cgen_aret(n, res)
- case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
+ case OEFACE, ODOTTYPE, OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
var n1 Node
Tempname(&n1, n.Type)
- Cgen_slice(n, &n1)
- Agen(&n1, res)
-
- case OEFACE:
- var n1 Node
- Tempname(&n1, n.Type)
- Cgen_eface(n, &n1)
+ Cgen(n, &n1)
Agen(&n1, res)
case OINDEX:
@@ -1520,15 +1525,12 @@
Regfree(&n2)
}
-/*
- * 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.
- */
+// Igen computes the address &n, stores it in a register r,
+// and rewrites a to refer to *r. The chosen r may be the
+// stack pointer, it may be borrowed from res, or it may
+// be a newly allocated register. The caller must call Regfree(a)
+// to free r when the address is no longer needed.
+// The generated code ensures that &n is not nil.
func Igen(n *Node, a *Node, res *Node) {
if Debug['g'] != 0 {
Dump("\nigen-n", n)