aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/noder/reader.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/noder/reader.go')
-rw-r--r--src/cmd/compile/internal/noder/reader.go19
1 files changed, 14 insertions, 5 deletions
diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index 1dae4da167..ce4cc1cc4e 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -3971,14 +3971,23 @@ func addTailCall(pos src.XPos, fn *ir.Func, recv ir.Node, method *types.Field) {
args[i] = param.Nname.(*ir.Name)
}
- // TODO(mdempsky): Support creating OTAILCALL, when possible. See reflectdata.methodWrapper.
- // Not urgent though, because tail calls are currently incompatible with regabi anyway.
-
- fn.SetWrapper(true) // TODO(mdempsky): Leave unset for tail calls?
-
dot := typecheck.XDotMethod(pos, recv, method.Sym, true)
call := typecheck.Call(pos, dot, args, method.Type.IsVariadic()).(*ir.CallExpr)
+ if recv.Type() != nil && recv.Type().IsPtr() && method.Type.Recv().Type.IsPtr() &&
+ method.Embedded != 0 && !types.IsInterfaceMethod(method.Type) &&
+ !unifiedHaveInlineBody(ir.MethodExprName(dot).Func) &&
+ !(base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) {
+ if base.Debug.TailCall != 0 {
+ base.WarnfAt(fn.Nname.Type().Recv().Type.Elem().Pos(), "tail call emitted for the method %v wrapper", method.Nname)
+ }
+ // Prefer OTAILCALL to reduce code size (except the case when the called method can be inlined).
+ fn.Body.Append(ir.NewTailCallStmt(pos, call))
+ return
+ }
+
+ fn.SetWrapper(true)
+
if method.Type.NumResults() == 0 {
fn.Body.Append(call)
return