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

cmd/compile: make translation to calls for SSA look more "value-oriented"

The existing translation assumes an in-memory return values, thus it returns
the address of the result(s).  Most consumers immediately load from the
address to get the value, and in late call expansion that is the favored idiom,
and it is also the favored idiom when arguments and results use registers
instead of memory.

Change-Id: Ie0ccc70f399682a42509d847b330ef3956462d56
Reviewed-on: https://go-review.googlesource.com/c/go/+/240186
Trust: David Chase <drchase@google.com>
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
David Chase 2020-06-26 18:19:01 -04:00
parent 39da81da5e
commit 396688af7e

View File

@ -1076,7 +1076,7 @@ func (s *state) stmt(n *Node) {
fallthrough fallthrough
case OCALLMETH, OCALLINTER: case OCALLMETH, OCALLINTER:
s.call(n, callNormal) s.callAddr(n, callNormal)
if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class() == PFUNC { if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class() == PFUNC {
if fn := n.Left.Sym.Name; compiling_runtime && fn == "throw" || if fn := n.Left.Sym.Name; compiling_runtime && fn == "throw" ||
n.Left.Sym.Pkg == Runtimepkg && (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block" || fn == "panicmakeslicelen" || fn == "panicmakeslicecap") { n.Left.Sym.Pkg == Runtimepkg && (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block" || fn == "panicmakeslicelen" || fn == "panicmakeslicecap") {
@ -1108,10 +1108,10 @@ func (s *state) stmt(n *Node) {
if n.Esc == EscNever { if n.Esc == EscNever {
d = callDeferStack d = callDeferStack
} }
s.call(n.Left, d) s.callAddr(n.Left, d)
} }
case OGO: case OGO:
s.call(n.Left, callGo) s.callAddr(n.Left, callGo)
case OAS2DOTTYPE: case OAS2DOTTYPE:
res, resok := s.dottype(n.Right, true) res, resok := s.dottype(n.Right, true)
@ -2715,8 +2715,7 @@ func (s *state) expr(n *Node) *ssa.Value {
fallthrough fallthrough
case OCALLINTER, OCALLMETH: case OCALLINTER, OCALLMETH:
a := s.call(n, callNormal) return s.callResult(n, callNormal)
return s.load(n.Type, a)
case OGETG: case OGETG:
return s.newValue1(ssa.OpGetG, n.Type, s.mem()) return s.newValue1(ssa.OpGetG, n.Type, s.mem())
@ -3589,8 +3588,7 @@ func init() {
addF("math", "FMA", addF("math", "FMA",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value { func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
if !s.config.UseFMA { if !s.config.UseFMA {
a := s.call(n, callNormal) s.vars[n] = s.callResult(n, callNormal) // types.Types[TFLOAT64]
s.vars[n] = s.load(types.Types[TFLOAT64], a)
return s.variable(n, types.Types[TFLOAT64]) return s.variable(n, types.Types[TFLOAT64])
} }
v := s.entryNewValue0A(ssa.OpHasCPUFeature, types.Types[TBOOL], x86HasFMA) v := s.entryNewValue0A(ssa.OpHasCPUFeature, types.Types[TBOOL], x86HasFMA)
@ -3611,8 +3609,7 @@ func init() {
// Call the pure Go version. // Call the pure Go version.
s.startBlock(bFalse) s.startBlock(bFalse)
a := s.call(n, callNormal) s.vars[n] = s.callResult(n, callNormal) // types.Types[TFLOAT64]
s.vars[n] = s.load(types.Types[TFLOAT64], a)
s.endBlock().AddEdgeTo(bEnd) s.endBlock().AddEdgeTo(bEnd)
// Merge results. // Merge results.
@ -3623,8 +3620,7 @@ func init() {
addF("math", "FMA", addF("math", "FMA",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value { func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
if !s.config.UseFMA { if !s.config.UseFMA {
a := s.call(n, callNormal) s.vars[n] = s.callResult(n, callNormal) // types.Types[TFLOAT64]
s.vars[n] = s.load(types.Types[TFLOAT64], a)
return s.variable(n, types.Types[TFLOAT64]) return s.variable(n, types.Types[TFLOAT64])
} }
addr := s.entryNewValue1A(ssa.OpAddr, types.Types[TBOOL].PtrTo(), armHasVFPv4, s.sb) addr := s.entryNewValue1A(ssa.OpAddr, types.Types[TBOOL].PtrTo(), armHasVFPv4, s.sb)
@ -3646,8 +3642,7 @@ func init() {
// Call the pure Go version. // Call the pure Go version.
s.startBlock(bFalse) s.startBlock(bFalse)
a := s.call(n, callNormal) s.vars[n] = s.callResult(n, callNormal) // types.Types[TFLOAT64]
s.vars[n] = s.load(types.Types[TFLOAT64], a)
s.endBlock().AddEdgeTo(bEnd) s.endBlock().AddEdgeTo(bEnd)
// Merge results. // Merge results.
@ -3676,8 +3671,7 @@ func init() {
// Call the pure Go version. // Call the pure Go version.
s.startBlock(bFalse) s.startBlock(bFalse)
a := s.call(n, callNormal) s.vars[n] = s.callResult(n, callNormal) // types.Types[TFLOAT64]
s.vars[n] = s.load(types.Types[TFLOAT64], a)
s.endBlock().AddEdgeTo(bEnd) s.endBlock().AddEdgeTo(bEnd)
// Merge results. // Merge results.
@ -3887,8 +3881,7 @@ func init() {
// Call the pure Go version. // Call the pure Go version.
s.startBlock(bFalse) s.startBlock(bFalse)
a := s.call(n, callNormal) s.vars[n] = s.callResult(n, callNormal) // types.Types[TINT]
s.vars[n] = s.load(types.Types[TINT], a)
s.endBlock().AddEdgeTo(bEnd) s.endBlock().AddEdgeTo(bEnd)
// Merge results. // Merge results.
@ -4336,9 +4329,17 @@ func (s *state) openDeferExit() {
} }
} }
func (s *state) callResult(n *Node, k callKind) *ssa.Value {
return s.call(n, k, false)
}
func (s *state) callAddr(n *Node, k callKind) *ssa.Value {
return s.call(n, k, true)
}
// Calls the function n using the specified call type. // Calls the function n using the specified call type.
// Returns the address of the return value (or nil if none). // Returns the address of the return value (or nil if none).
func (s *state) call(n *Node, k callKind) *ssa.Value { func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
var sym *types.Sym // target symbol (if static) var sym *types.Sym // target symbol (if static)
var closure *ssa.Value // ptr to closure to run (if dynamic) var closure *ssa.Value // ptr to closure to run (if dynamic)
var codeptr *ssa.Value // ptr to target code (if dynamic) var codeptr *ssa.Value // ptr to target code (if dynamic)
@ -4547,8 +4548,11 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
return nil return nil
} }
fp := res.Field(0) fp := res.Field(0)
if returnResultAddr {
return s.constOffPtrSP(types.NewPtr(fp.Type), fp.Offset+Ctxt.FixedFrameSize()) return s.constOffPtrSP(types.NewPtr(fp.Type), fp.Offset+Ctxt.FixedFrameSize())
} }
return s.load(n.Type, s.constOffPtrSP(types.NewPtr(fp.Type), fp.Offset+Ctxt.FixedFrameSize()))
}
// maybeNilCheckClosure checks if a nil check of a closure is needed in some // maybeNilCheckClosure checks if a nil check of a closure is needed in some
// architecture-dependent situations and, if so, emits the nil check. // architecture-dependent situations and, if so, emits the nil check.
@ -4676,7 +4680,7 @@ func (s *state) addr(n *Node) *ssa.Value {
addr := s.addr(n.Left) addr := s.addr(n.Left)
return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
case OCALLFUNC, OCALLINTER, OCALLMETH: case OCALLFUNC, OCALLINTER, OCALLMETH:
return s.call(n, callNormal) return s.callAddr(n, callNormal)
case ODOTTYPE: case ODOTTYPE:
v, _ := s.dottype(n, false) v, _ := s.dottype(n, false)
if v.Op != ssa.OpLoad { if v.Op != ssa.OpLoad {