Skip to content

Commit 1aa3362

Browse files
committed
Revert "cmd/compile: Enable inlining of tail calls"
This reverts CL 650455 and CL 655816. Reason for revert: it causes #73747. Properly fixing it gets into trickiness with defer/recover, wrapper, and inlining. We're late in the Go 1.25 release cycle. Fixes #73747. Change-Id: Ifb343d522b18fec3fec73a7c886678032ac8e4df Reviewed-on: https://go-review.googlesource.com/c/go/+/678575 Reviewed-by: Carlos Amedee <carlos@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
1 parent f537061 commit 1aa3362

File tree

10 files changed

+25
-32
lines changed

10 files changed

+25
-32
lines changed

‎src/cmd/compile/internal/inline/inl.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,7 @@ func inlineCallCheck(callerfn *ir.Func, call *ir.CallExpr) (bool, bool) {
785785
if call.Op() != ir.OCALLFUNC {
786786
return false, false
787787
}
788-
if call.GoDefer {
788+
if call.GoDefer || call.NoInline {
789789
return false, false
790790
}
791791

‎src/cmd/compile/internal/inline/interleaved/interleaved.go

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,12 @@ func (s *inlClosureState) mark(n ir.Node) ir.Node {
279279

280280
ok := match(n)
281281

282-
ir.EditChildren(n, s.mark)
282+
// can't wrap TailCall's child into ParenExpr
283+
if t, ok := n.(*ir.TailCallStmt); ok {
284+
ir.EditChildren(t.Call, s.mark)
285+
} else {
286+
ir.EditChildren(n, s.mark)
287+
}
283288

284289
if ok {
285290
if p == nil {
@@ -317,23 +322,6 @@ func (s *inlClosureState) unparenthesize() {
317322
n = paren.X
318323
}
319324
ir.EditChildren(n, unparen)
320-
// special case for tail calls: if the tail call was inlined, transform
321-
// the tail call to a return stmt if the inlined function was not void,
322-
// otherwise replace it with the inlined expression followed by a return.
323-
if tail, ok := n.(*ir.TailCallStmt); ok {
324-
if inl, done := tail.Call.(*ir.InlinedCallExpr); done {
325-
if len(inl.ReturnVars) != 0 {
326-
ret := ir.NewReturnStmt(tail.Pos(), []ir.Node{inl})
327-
if len(inl.ReturnVars) > 1 {
328-
typecheck.RewriteMultiValueCall(ret, inl)
329-
}
330-
n = ret
331-
} else {
332-
ret := ir.NewReturnStmt(tail.Pos(), nil)
333-
n = ir.NewBlockStmt(tail.Pos(), []ir.Node{inl, ret})
334-
}
335-
}
336-
}
337325
return n
338326
}
339327
ir.EditChildren(s.fn, unparen)
@@ -370,9 +358,11 @@ func (s *inlClosureState) fixpoint() bool {
370358
}
371359

372360
func match(n ir.Node) bool {
373-
switch n.(type) {
361+
switch n := n.(type) {
374362
case *ir.CallExpr:
375363
return true
364+
case *ir.TailCallStmt:
365+
n.Call.NoInline = true // can't inline yet
376366
}
377367
return false
378368
}

‎src/cmd/compile/internal/ir/expr.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ type CallExpr struct {
191191
KeepAlive []*Name // vars to be kept alive until call returns
192192
IsDDD bool
193193
GoDefer bool // whether this call is part of a go or defer statement
194+
NoInline bool // whether this call must not be inlined
194195
}
195196

196197
func NewCallExpr(pos src.XPos, op Op, fun Node, args []Node) *CallExpr {

‎src/cmd/compile/internal/ir/node_gen.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/cmd/compile/internal/ir/stmt.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ func NewSwitchStmt(pos src.XPos, tag Node, cases []*CaseClause) *SwitchStmt {
479479
// code generation to jump directly to another function entirely.
480480
type TailCallStmt struct {
481481
miniStmt
482-
Call Node // the underlying call
482+
Call *CallExpr // the underlying call
483483
}
484484

485485
func NewTailCallStmt(pos src.XPos, call *CallExpr) *TailCallStmt {

‎src/cmd/compile/internal/noder/reader.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3996,11 +3996,12 @@ func addTailCall(pos src.XPos, fn *ir.Func, recv ir.Node, method *types.Field) {
39963996

39973997
if recv.Type() != nil && recv.Type().IsPtr() && method.Type.Recv().Type.IsPtr() &&
39983998
method.Embedded != 0 && !types.IsInterfaceMethod(method.Type) &&
3999+
!unifiedHaveInlineBody(ir.MethodExprName(dot).Func) &&
39994000
!(base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) {
40004001
if base.Debug.TailCall != 0 {
40014002
base.WarnfAt(fn.Nname.Type().Recv().Type.Elem().Pos(), "tail call emitted for the method %v wrapper", method.Nname)
40024003
}
4003-
// Prefer OTAILCALL to reduce code size (the called method can be inlined).
4004+
// Prefer OTAILCALL to reduce code size (except the case when the called method can be inlined).
40044005
fn.Body.Append(ir.NewTailCallStmt(pos, call))
40054006
return
40064007
}

‎src/cmd/compile/internal/ssagen/ssa.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1921,7 +1921,7 @@ func (s *state) stmt(n ir.Node) {
19211921

19221922
case ir.OTAILCALL:
19231923
n := n.(*ir.TailCallStmt)
1924-
s.callResult(n.Call.(*ir.CallExpr), callTail)
1924+
s.callResult(n.Call, callTail)
19251925
call := s.mem()
19261926
b := s.endBlock()
19271927
b.Kind = ssa.BlockRetJmp // could use BlockExit. BlockRetJmp is mostly for clarity.

‎src/cmd/compile/internal/typecheck/stmt.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ assignOK:
137137
if cr > len(rhs) {
138138
stmt := stmt.(*ir.AssignListStmt)
139139
stmt.SetOp(ir.OAS2FUNC)
140-
r := rhs[0]
140+
r := rhs[0].(*ir.CallExpr)
141141
rtyp := r.Type()
142142

143143
mismatched := false

‎src/cmd/compile/internal/walk/stmt.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,7 @@ func walkStmt(n ir.Node) ir.Node {
139139
n := n.(*ir.TailCallStmt)
140140

141141
var init ir.Nodes
142-
call := n.Call.(*ir.CallExpr)
143-
call.Fun = walkExpr(call.Fun, &init)
142+
n.Call.Fun = walkExpr(n.Call.Fun, &init)
144143

145144
if len(init) > 0 {
146145
init.Append(n)

‎test/tailcall.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@
77
package p
88

99
// Test that when generating wrappers for methods, we generate a tail call to the pointer version of
10-
// the method.
10+
// the method, if that method is not inlineable. We use go:noinline here to force the non-inlineability
11+
// condition.
1112

12-
func (f *Foo) Get2Vals() [2]int { return [2]int{f.Val, f.Val + 1} }
13-
func (f *Foo) Get3Vals() (int, int, int) { return f.Val, f.Val + 1, f.Val + 2 }
13+
//go:noinline
14+
func (f *Foo) Get2Vals() [2]int { return [2]int{f.Val, f.Val + 1} }
15+
func (f *Foo) Get3Vals() [3]int { return [3]int{f.Val, f.Val + 1, f.Val + 2} }
1416

1517
type Foo struct{ Val int }
1618

17-
type Bar struct { // ERROR "tail call emitted for the method \(\*Foo\).Get2Vals wrapper" "tail call emitted for the method \(\*Foo\).Get3Vals wrapper"
19+
type Bar struct { // ERROR "tail call emitted for the method \(\*Foo\).Get2Vals wrapper"
1820
int64
1921
*Foo // needs a method wrapper
2022
string

0 commit comments

Comments
 (0)