cmd/internal/gc: inline runtime.getg
This more closely restores what the old C runtime did.
(In C, g was an 'extern register' with the same effective
implementation as in this CL.)
On a late 2012 MacBookPro10,2, best of 5 old vs best of 5 new:
benchmark old ns/op new ns/op delta
BenchmarkBinaryTree17 4981312777 4463426605 -10.40%
BenchmarkFannkuch11 3046495712 3006819428 -1.30%
BenchmarkFmtFprintfEmpty 89.3 79.8 -10.64%
BenchmarkFmtFprintfString 284 262 -7.75%
BenchmarkFmtFprintfInt 282 262 -7.09%
BenchmarkFmtFprintfIntInt 480 448 -6.67%
BenchmarkFmtFprintfPrefixedInt 382 358 -6.28%
BenchmarkFmtFprintfFloat 529 486 -8.13%
BenchmarkFmtManyArgs 1849 1773 -4.11%
BenchmarkGobDecode 12835963 11794385 -8.11%
BenchmarkGobEncode 10527170 10288422 -2.27%
BenchmarkGzip 436109569 438422516 +0.53%
BenchmarkGunzip 110121663 109843648 -0.25%
BenchmarkHTTPClientServer 81930 85446 +4.29%
BenchmarkJSONEncode 24638574 24280603 -1.45%
BenchmarkJSONDecode 93022423 85753546 -7.81%
BenchmarkMandelbrot200 4703899 4735407 +0.67%
BenchmarkGoParse 5319853 5086843 -4.38%
BenchmarkRegexpMatchEasy0_32 151 151 +0.00%
BenchmarkRegexpMatchEasy0_1K 452 453 +0.22%
BenchmarkRegexpMatchEasy1_32 131 132 +0.76%
BenchmarkRegexpMatchEasy1_1K 761 722 -5.12%
BenchmarkRegexpMatchMedium_32 228 224 -1.75%
BenchmarkRegexpMatchMedium_1K 63751 64296 +0.85%
BenchmarkRegexpMatchHard_32 3188 3238 +1.57%
BenchmarkRegexpMatchHard_1K 95396 96756 +1.43%
BenchmarkRevcomp 661587262 687107364 +3.86%
BenchmarkTemplate 108312598 104008540 -3.97%
BenchmarkTimeParse 453 459 +1.32%
BenchmarkTimeFormat 475 441 -7.16%
The garbage benchmark from the benchmarks subrepo gets 2.6% faster as well.
Change-Id: I320aeda332db81012688b26ffab23f6581c59cfa
Reviewed-on: https://go-review.googlesource.com/8460
Reviewed-by: Rick Hudson <rlh@golang.org>
Run-TryBot: Rick Hudson <rlh@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
diff --git a/src/cmd/internal/gc/cgen.go b/src/cmd/internal/gc/cgen.go
index 3b628ac..886a2d1 100644
--- a/src/cmd/internal/gc/cgen.go
+++ b/src/cmd/internal/gc/cgen.go
@@ -418,6 +418,10 @@
Regfree(&n1)
return
+ case OGETG:
+ Thearch.Getg(res)
+ return
+
// symmetric binary
case OAND,
OOR,
diff --git a/src/cmd/internal/gc/fmt.go b/src/cmd/internal/gc/fmt.go
index 38e358a..589f20c 100644
--- a/src/cmd/internal/gc/fmt.go
+++ b/src/cmd/internal/gc/fmt.go
@@ -976,6 +976,7 @@
OCONV: 8,
OCOPY: 8,
ODELETE: 8,
+ OGETG: 8,
OLEN: 8,
OLITERAL: 8,
OMAKESLICE: 8,
@@ -1363,7 +1364,7 @@
}
return fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
- case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH:
+ case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
var f string
f += exprfmt(n.Left, nprec)
if n.Isddd {
diff --git a/src/cmd/internal/gc/gen.go b/src/cmd/internal/gc/gen.go
index e52ff65..4b7344a 100644
--- a/src/cmd/internal/gc/gen.go
+++ b/src/cmd/internal/gc/gen.go
@@ -1002,6 +1002,10 @@
case ORETURN, ORETJMP:
cgen_ret(n)
+ // Function calls turned into compiler intrinsics.
+ // At top level, can just ignore the call and make sure to preserve side effects in the argument, if any.
+ case OGETG:
+ // nothing
case OSQRT:
cgen_discard(n.Left)
diff --git a/src/cmd/internal/gc/go.go b/src/cmd/internal/gc/go.go
index 027ad28..a6faaa5 100644
--- a/src/cmd/internal/gc/go.go
+++ b/src/cmd/internal/gc/go.go
@@ -798,6 +798,7 @@
Dodiv func(int, *Node, *Node, *Node)
Excise func(*Flow)
Expandchecks func(*obj.Prog)
+ Getg func(*Node)
Gins func(int, *Node, *Node) *obj.Prog
Ginscon func(int, int64, *Node)
Ginsnop func()
diff --git a/src/cmd/internal/gc/syntax.go b/src/cmd/internal/gc/syntax.go
index 736c7af..11cdf29 100644
--- a/src/cmd/internal/gc/syntax.go
+++ b/src/cmd/internal/gc/syntax.go
@@ -304,6 +304,7 @@
ORETJMP // return to other function
OPS // compare parity set (for x86 NaN check)
OSQRT // sqrt(float64), on systems that have hw support
+ OGETG // runtime.getg() (read g pointer)
OEND
)
diff --git a/src/cmd/internal/gc/typecheck.go b/src/cmd/internal/gc/typecheck.go
index 4399164..08262b1 100644
--- a/src/cmd/internal/gc/typecheck.go
+++ b/src/cmd/internal/gc/typecheck.go
@@ -1366,6 +1366,17 @@
t = t.Type
}
n.Type = t
+
+ if n.Op == OCALLFUNC && n.Left.Op == ONAME && (compiling_runtime != 0 || n.Left.Sym.Pkg == Runtimepkg) && n.Left.Sym.Name == "getg" {
+ // Emit code for runtime.getg() directly instead of calling function.
+ // Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
+ // so that the ordering pass can make sure to preserve the semantics of the original code
+ // (in particular, the exact time of the function call) by introducing temporaries.
+ // In this case, we know getg() always returns the same result within a given function
+ // and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
+ n.Op = OGETG
+ }
+
break OpSwitch
}
@@ -1376,6 +1387,7 @@
}
n.Type = getoutargx(l.Type)
+
break OpSwitch
case OCAP, OLEN, OREAL, OIMAG:
diff --git a/src/cmd/internal/gc/walk.go b/src/cmd/internal/gc/walk.go
index bf91116..1012aa0 100644
--- a/src/cmd/internal/gc/walk.go
+++ b/src/cmd/internal/gc/walk.go
@@ -179,7 +179,8 @@
OPRINTN,
OPANIC,
OEMPTY,
- ORECOVER:
+ ORECOVER,
+ OGETG:
if n.Typecheck == 0 {
Fatal("missing typecheck: %v", Nconv(n, obj.FmtSign))
}
@@ -424,7 +425,8 @@
ONONAME,
OINDREG,
OEMPTY,
- OPARAM:
+ OPARAM,
+ OGETG:
goto ret
case ONOT,