mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.regabi] cmd/compile: add ir.TailCallStmt
This CL splits out ORETJMP as a new TailCallStmt node, separate from the other BranchStmt nodes. In doing so, this allows us to change it from identifying a function by *types.Sym to identifying one by directly pointing to the *ir.Func. While here, also rename the operation to OTAILCALL. Passes toolstash -cmp. Change-Id: I273e6ea5d92bf3005ae02fb59b3240a190a6cf1b Reviewed-on: https://go-review.googlesource.com/c/go/+/284227 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
parent
e3027c6828
commit
87845d14f9
14 changed files with 63 additions and 27 deletions
|
|
@ -75,7 +75,7 @@ func stmts(nn *ir.Nodes) {
|
||||||
// might be the target of a goto. See issue 28616.
|
// might be the target of a goto. See issue 28616.
|
||||||
if body := body; len(body) != 0 {
|
if body := body; len(body) != 0 {
|
||||||
switch body[(len(body) - 1)].Op() {
|
switch body[(len(body) - 1)].Op() {
|
||||||
case ir.ORETURN, ir.ORETJMP, ir.OPANIC:
|
case ir.ORETURN, ir.OTAILCALL, ir.OPANIC:
|
||||||
if i > lastLabel {
|
if i > lastLabel {
|
||||||
cut = true
|
cut = true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -534,8 +534,8 @@ func (e *escape) stmt(n ir.Node) {
|
||||||
e.stmts(n.Call.Init())
|
e.stmts(n.Call.Init())
|
||||||
e.call(nil, n.Call, n)
|
e.call(nil, n.Call, n)
|
||||||
|
|
||||||
case ir.ORETJMP:
|
case ir.OTAILCALL:
|
||||||
// TODO(mdempsky): What do? esc.go just ignores it.
|
// TODO(mdempsky): Treat like a normal call? esc.go used to just ignore it.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -359,7 +359,7 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
|
||||||
ir.OGO,
|
ir.OGO,
|
||||||
ir.ODEFER,
|
ir.ODEFER,
|
||||||
ir.ODCLTYPE, // can't print yet
|
ir.ODCLTYPE, // can't print yet
|
||||||
ir.ORETJMP:
|
ir.OTAILCALL:
|
||||||
return errors.New("unhandled op " + n.Op().String())
|
return errors.New("unhandled op " + n.Op().String())
|
||||||
|
|
||||||
case ir.OAPPEND:
|
case ir.OAPPEND:
|
||||||
|
|
|
||||||
|
|
@ -378,9 +378,9 @@ func stmtFmt(n Node, s fmt.State) {
|
||||||
n := n.(*ReturnStmt)
|
n := n.(*ReturnStmt)
|
||||||
fmt.Fprintf(s, "return %.v", n.Results)
|
fmt.Fprintf(s, "return %.v", n.Results)
|
||||||
|
|
||||||
case ORETJMP:
|
case OTAILCALL:
|
||||||
n := n.(*BranchStmt)
|
n := n.(*TailCallStmt)
|
||||||
fmt.Fprintf(s, "retjmp %v", n.Label)
|
fmt.Fprintf(s, "tailcall %v", n.Target)
|
||||||
|
|
||||||
case OINLMARK:
|
case OINLMARK:
|
||||||
n := n.(*InlineMarkStmt)
|
n := n.(*InlineMarkStmt)
|
||||||
|
|
|
||||||
|
|
@ -306,8 +306,8 @@ const (
|
||||||
OLINKSYMOFFSET // offset within a name
|
OLINKSYMOFFSET // offset within a name
|
||||||
|
|
||||||
// arch-specific opcodes
|
// arch-specific opcodes
|
||||||
ORETJMP // return to other function
|
OTAILCALL // tail call to another function
|
||||||
OGETG // runtime.getg() (read g pointer)
|
OGETG // runtime.getg() (read g pointer)
|
||||||
|
|
||||||
OEND
|
OEND
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1227,6 +1227,28 @@ func (n *SwitchStmt) editChildren(edit func(Node) Node) {
|
||||||
editNodes(n.Compiled, edit)
|
editNodes(n.Compiled, edit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *TailCallStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||||
|
func (n *TailCallStmt) copy() Node {
|
||||||
|
c := *n
|
||||||
|
c.init = copyNodes(c.init)
|
||||||
|
return &c
|
||||||
|
}
|
||||||
|
func (n *TailCallStmt) doChildren(do func(Node) bool) bool {
|
||||||
|
if doNodes(n.init, do) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if n.Target != nil && do(n.Target) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func (n *TailCallStmt) editChildren(edit func(Node) Node) {
|
||||||
|
editNodes(n.init, edit)
|
||||||
|
if n.Target != nil {
|
||||||
|
n.Target = edit(n.Target).(*Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (n *TypeAssertExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
func (n *TypeAssertExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||||
func (n *TypeAssertExpr) copy() Node {
|
func (n *TypeAssertExpr) copy() Node {
|
||||||
c := *n
|
c := *n
|
||||||
|
|
|
||||||
|
|
@ -157,14 +157,14 @@ func _() {
|
||||||
_ = x[ORESULT-146]
|
_ = x[ORESULT-146]
|
||||||
_ = x[OINLMARK-147]
|
_ = x[OINLMARK-147]
|
||||||
_ = x[OLINKSYMOFFSET-148]
|
_ = x[OLINKSYMOFFSET-148]
|
||||||
_ = x[ORETJMP-149]
|
_ = x[OTAILCALL-149]
|
||||||
_ = x[OGETG-150]
|
_ = x[OGETG-150]
|
||||||
_ = x[OEND-151]
|
_ = x[OEND-151]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _Op_name = "XXXNAMENONAMETYPEPACKLITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFMETHEXPRSTMTEXPRBLOCKBREAKCASECONTINUEDEFERFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYTSLICEINLCALLEFACEITABIDATASPTRCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKLINKSYMOFFSETRETJMPGETGEND"
|
const _Op_name = "XXXNAMENONAMETYPEPACKLITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFMETHEXPRSTMTEXPRBLOCKBREAKCASECONTINUEDEFERFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYTSLICEINLCALLEFACEITABIDATASPTRCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKLINKSYMOFFSETTAILCALLGETGEND"
|
||||||
|
|
||||||
var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 37, 39, 42, 48, 52, 58, 64, 73, 85, 94, 103, 115, 124, 126, 129, 139, 146, 153, 160, 164, 168, 176, 184, 193, 201, 204, 209, 216, 223, 229, 238, 246, 254, 260, 264, 273, 280, 284, 287, 294, 302, 309, 315, 318, 324, 331, 339, 343, 350, 358, 360, 362, 364, 366, 368, 370, 375, 380, 388, 391, 400, 403, 407, 415, 422, 431, 444, 447, 450, 453, 456, 459, 462, 468, 471, 474, 480, 484, 487, 491, 496, 501, 507, 512, 516, 521, 529, 537, 543, 552, 563, 570, 574, 581, 589, 593, 597, 601, 608, 615, 623, 629, 637, 645, 650, 655, 659, 667, 672, 676, 679, 687, 691, 693, 698, 700, 705, 711, 717, 723, 729, 734, 738, 745, 751, 756, 762, 768, 775, 780, 784, 789, 793, 798, 806, 812, 819, 826, 832, 839, 852, 858, 862, 865}
|
var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 37, 39, 42, 48, 52, 58, 64, 73, 85, 94, 103, 115, 124, 126, 129, 139, 146, 153, 160, 164, 168, 176, 184, 193, 201, 204, 209, 216, 223, 229, 238, 246, 254, 260, 264, 273, 280, 284, 287, 294, 302, 309, 315, 318, 324, 331, 339, 343, 350, 358, 360, 362, 364, 366, 368, 370, 375, 380, 388, 391, 400, 403, 407, 415, 422, 431, 444, 447, 450, 453, 456, 459, 462, 468, 471, 474, 480, 484, 487, 491, 496, 501, 507, 512, 516, 521, 529, 537, 543, 552, 563, 570, 574, 581, 589, 593, 597, 601, 608, 615, 623, 629, 637, 645, 650, 655, 659, 667, 672, 676, 679, 687, 691, 693, 698, 700, 705, 711, 717, 723, 729, 734, 738, 745, 751, 756, 762, 768, 775, 780, 784, 789, 793, 798, 806, 812, 819, 826, 832, 839, 852, 860, 864, 867}
|
||||||
|
|
||||||
func (i Op) String() string {
|
func (i Op) String() string {
|
||||||
if i >= Op(len(_Op_index)-1) {
|
if i >= Op(len(_Op_index)-1) {
|
||||||
|
|
|
||||||
|
|
@ -144,9 +144,6 @@ func NewBlockStmt(pos src.XPos, list []Node) *BlockStmt {
|
||||||
}
|
}
|
||||||
|
|
||||||
// A BranchStmt is a break, continue, fallthrough, or goto statement.
|
// A BranchStmt is a break, continue, fallthrough, or goto statement.
|
||||||
//
|
|
||||||
// For back-end code generation, Op may also be RETJMP (return+jump),
|
|
||||||
// in which case the label names another function entirely.
|
|
||||||
type BranchStmt struct {
|
type BranchStmt struct {
|
||||||
miniStmt
|
miniStmt
|
||||||
Label *types.Sym // label if present
|
Label *types.Sym // label if present
|
||||||
|
|
@ -154,7 +151,7 @@ type BranchStmt struct {
|
||||||
|
|
||||||
func NewBranchStmt(pos src.XPos, op Op, label *types.Sym) *BranchStmt {
|
func NewBranchStmt(pos src.XPos, op Op, label *types.Sym) *BranchStmt {
|
||||||
switch op {
|
switch op {
|
||||||
case OBREAK, OCONTINUE, OFALL, OGOTO, ORETJMP:
|
case OBREAK, OCONTINUE, OFALL, OGOTO:
|
||||||
// ok
|
// ok
|
||||||
default:
|
default:
|
||||||
panic("NewBranch " + op.String())
|
panic("NewBranch " + op.String())
|
||||||
|
|
@ -384,6 +381,23 @@ func NewSwitchStmt(pos src.XPos, tag Node, cases []*CaseClause) *SwitchStmt {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A TailCallStmt is a tail call statement, which is used for back-end
|
||||||
|
// code generation to jump directly to another function entirely.
|
||||||
|
type TailCallStmt struct {
|
||||||
|
miniStmt
|
||||||
|
Target *Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTailCallStmt(pos src.XPos, target *Name) *TailCallStmt {
|
||||||
|
if target.Op() != ONAME || target.Class != PFUNC {
|
||||||
|
base.FatalfAt(pos, "tail call to non-func %v", target)
|
||||||
|
}
|
||||||
|
n := &TailCallStmt{Target: target}
|
||||||
|
n.pos = pos
|
||||||
|
n.op = OTAILCALL
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
// A TypeSwitchGuard is the [Name :=] X.(type) in a type switch.
|
// A TypeSwitchGuard is the [Name :=] X.(type) in a type switch.
|
||||||
type TypeSwitchGuard struct {
|
type TypeSwitchGuard struct {
|
||||||
miniNode
|
miniNode
|
||||||
|
|
|
||||||
|
|
@ -1794,7 +1794,7 @@ func methodWrapper(rcvr *types.Type, method *types.Field) *obj.LSym {
|
||||||
}
|
}
|
||||||
as := ir.NewAssignStmt(base.Pos, nthis, typecheck.ConvNop(left, rcvr))
|
as := ir.NewAssignStmt(base.Pos, nthis, typecheck.ConvNop(left, rcvr))
|
||||||
fn.Body.Append(as)
|
fn.Body.Append(as)
|
||||||
fn.Body.Append(ir.NewBranchStmt(base.Pos, ir.ORETJMP, ir.MethodSym(methodrcvr, method.Sym)))
|
fn.Body.Append(ir.NewTailCallStmt(base.Pos, method.Nname.(*ir.Name)))
|
||||||
} else {
|
} else {
|
||||||
fn.SetWrapper(true) // ignore frame for panic+recover matching
|
fn.SetWrapper(true) // ignore frame for panic+recover matching
|
||||||
call := ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil)
|
call := ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil)
|
||||||
|
|
|
||||||
|
|
@ -303,7 +303,7 @@ func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) {
|
||||||
var tail ir.Node
|
var tail ir.Node
|
||||||
if tfn.Type().NumResults() == 0 && tfn.Type().NumParams() == 0 && tfn.Type().NumRecvs() == 0 && !(base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) {
|
if tfn.Type().NumResults() == 0 && tfn.Type().NumParams() == 0 && tfn.Type().NumRecvs() == 0 && !(base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) {
|
||||||
|
|
||||||
tail = ir.NewBranchStmt(base.Pos, ir.ORETJMP, f.Nname.Sym())
|
tail = ir.NewTailCallStmt(base.Pos, f.Nname)
|
||||||
} else {
|
} else {
|
||||||
call := ir.NewCallExpr(base.Pos, ir.OCALL, f.Nname, nil)
|
call := ir.NewCallExpr(base.Pos, ir.OCALL, f.Nname, nil)
|
||||||
call.Args = ir.ParamNames(tfn.Type())
|
call.Args = ir.ParamNames(tfn.Type())
|
||||||
|
|
|
||||||
|
|
@ -1580,11 +1580,11 @@ func (s *state) stmt(n ir.Node) {
|
||||||
b := s.exit()
|
b := s.exit()
|
||||||
b.Pos = s.lastPos.WithIsStmt()
|
b.Pos = s.lastPos.WithIsStmt()
|
||||||
|
|
||||||
case ir.ORETJMP:
|
case ir.OTAILCALL:
|
||||||
n := n.(*ir.BranchStmt)
|
n := n.(*ir.TailCallStmt)
|
||||||
b := s.exit()
|
b := s.exit()
|
||||||
b.Kind = ssa.BlockRetJmp // override BlockRet
|
b.Kind = ssa.BlockRetJmp // override BlockRet
|
||||||
b.Aux = callTargetLSym(n.Label, s.curfn.LSym)
|
b.Aux = callTargetLSym(n.Target.Sym(), s.curfn.LSym)
|
||||||
|
|
||||||
case ir.OCONTINUE, ir.OBREAK:
|
case ir.OCONTINUE, ir.OBREAK:
|
||||||
n := n.(*ir.BranchStmt)
|
n := n.(*ir.BranchStmt)
|
||||||
|
|
|
||||||
|
|
@ -857,8 +857,8 @@ func typecheck1(n ir.Node, top int) ir.Node {
|
||||||
n := n.(*ir.ReturnStmt)
|
n := n.(*ir.ReturnStmt)
|
||||||
return tcReturn(n)
|
return tcReturn(n)
|
||||||
|
|
||||||
case ir.ORETJMP:
|
case ir.OTAILCALL:
|
||||||
n := n.(*ir.BranchStmt)
|
n := n.(*ir.TailCallStmt)
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OSELECT:
|
case ir.OSELECT:
|
||||||
|
|
@ -2023,7 +2023,7 @@ func isTermNode(n ir.Node) bool {
|
||||||
n := n.(*ir.BlockStmt)
|
n := n.(*ir.BlockStmt)
|
||||||
return isTermNodes(n.List)
|
return isTermNodes(n.List)
|
||||||
|
|
||||||
case ir.OGOTO, ir.ORETURN, ir.ORETJMP, ir.OPANIC, ir.OFALL:
|
case ir.OGOTO, ir.ORETURN, ir.OTAILCALL, ir.OPANIC, ir.OFALL:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case ir.OFOR, ir.OFORUNTIL:
|
case ir.OFOR, ir.OFORUNTIL:
|
||||||
|
|
|
||||||
|
|
@ -692,7 +692,7 @@ func (o *orderState) stmt(n ir.Node) {
|
||||||
ir.OFALL,
|
ir.OFALL,
|
||||||
ir.OGOTO,
|
ir.OGOTO,
|
||||||
ir.OLABEL,
|
ir.OLABEL,
|
||||||
ir.ORETJMP:
|
ir.OTAILCALL:
|
||||||
o.out = append(o.out, n)
|
o.out = append(o.out, n)
|
||||||
|
|
||||||
// Special: handle call arguments.
|
// Special: handle call arguments.
|
||||||
|
|
|
||||||
|
|
@ -136,8 +136,8 @@ func walkStmt(n ir.Node) ir.Node {
|
||||||
n := n.(*ir.ReturnStmt)
|
n := n.(*ir.ReturnStmt)
|
||||||
return walkReturn(n)
|
return walkReturn(n)
|
||||||
|
|
||||||
case ir.ORETJMP:
|
case ir.OTAILCALL:
|
||||||
n := n.(*ir.BranchStmt)
|
n := n.(*ir.TailCallStmt)
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OINLMARK:
|
case ir.OINLMARK:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue