1
0
mirror of https://github.com/golang/go synced 2024-11-14 06:30:22 -07:00

[dev.regabi] cmd/compile: merge OBLOCK and OEMPTY

OEMPTY is an empty *statement*, but it confusingly
gets handled as an expression in a few places.
More confusingly, OEMPTY often has an init list,
making it not empty at all. Replace uses and analysis
of OEMPTY with OBLOCK instead.

Passes buildall w/ toolstash -cmp.

Change-Id: I8d4fcef151e4f441fa19b1b96da5272d778131d6
Reviewed-on: https://go-review.googlesource.com/c/go/+/274594
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Russ Cox 2020-11-30 21:56:24 -05:00
parent c769d393de
commit ec5f349b22
13 changed files with 53 additions and 48 deletions

View File

@ -302,7 +302,7 @@ func (e *Escape) stmt(n ir.Node) {
default: default:
base.Fatalf("unexpected stmt: %v", n) base.Fatalf("unexpected stmt: %v", n)
case ir.ODCLCONST, ir.ODCLTYPE, ir.OEMPTY, ir.OFALL, ir.OINLMARK: case ir.ODCLCONST, ir.ODCLTYPE, ir.OFALL, ir.OINLMARK:
// nop // nop
case ir.OBREAK, ir.OCONTINUE, ir.OGOTO: case ir.OBREAK, ir.OCONTINUE, ir.OGOTO:

View File

@ -1048,6 +1048,17 @@ func (w *exportWriter) stmt(n ir.Node) {
} }
switch op := n.Op(); op { switch op := n.Op(); op {
case ir.OBLOCK:
// No OBLOCK in export data.
// Inline content into this statement list,
// like the init list above.
// (At the moment neither the parser nor the typechecker
// generate OBLOCK nodes except to denote an empty
// function body, although that may change.)
for _, n := range n.List().Slice() {
w.stmt(n)
}
case ir.ODCL: case ir.ODCL:
w.op(ir.ODCL) w.op(ir.ODCL)
w.pos(n.Left().Pos()) w.pos(n.Left().Pos())
@ -1129,9 +1140,6 @@ func (w *exportWriter) stmt(n ir.Node) {
w.op(ir.OFALL) w.op(ir.OFALL)
w.pos(n.Pos()) w.pos(n.Pos())
case ir.OEMPTY:
// nothing to emit
case ir.OBREAK, ir.OCONTINUE, ir.OGOTO, ir.OLABEL: case ir.OBREAK, ir.OCONTINUE, ir.OGOTO, ir.OLABEL:
w.op(op) w.op(op)
w.pos(n.Pos()) w.pos(n.Pos())

View File

@ -742,7 +742,9 @@ func (r *importReader) stmtList() []ir.Node {
if n == nil { if n == nil {
break break
} }
// OBLOCK nodes may be created when importing ODCL nodes - unpack them // OBLOCK nodes are not written to the import data directly,
// but the handling of ODCL calls liststmt, which creates one.
// Inline them into the statement list.
if n.Op() == ir.OBLOCK { if n.Op() == ir.OBLOCK {
list = append(list, n.List().Slice()...) list = append(list, n.List().Slice()...)
} else { } else {

View File

@ -88,9 +88,11 @@ func fninit(n []ir.Node) {
s := lookupN("init.", i) s := lookupN("init.", i)
fn := ir.AsNode(s.Def).Name().Defn fn := ir.AsNode(s.Def).Name().Defn
// Skip init functions with empty bodies. // Skip init functions with empty bodies.
if fn.Body().Len() == 1 && fn.Body().First().Op() == ir.OEMPTY { if fn.Body().Len() == 1 {
if stmt := fn.Body().First(); stmt.Op() == ir.OBLOCK && stmt.List().Len() == 0 {
continue continue
} }
}
fns = append(fns, s.Linksym()) fns = append(fns, s.Linksym())
} }

View File

@ -396,7 +396,7 @@ func (v *hairyVisitor) visit(n ir.Node) bool {
case ir.OAPPEND: case ir.OAPPEND:
v.budget -= inlineExtraAppendCost v.budget -= inlineExtraAppendCost
case ir.ODCLCONST, ir.OEMPTY, ir.OFALL: case ir.ODCLCONST, ir.OFALL:
// These nodes don't produce code; omit from inlining budget. // These nodes don't produce code; omit from inlining budget.
return false return false
@ -425,6 +425,11 @@ func (v *hairyVisitor) visit(n ir.Node) bool {
v.usedLocals[n] = true v.usedLocals[n] = true
} }
case ir.OBLOCK:
// The only OBLOCK we should see at this point is an empty one.
// In any event, let the visitList(n.List()) below take care of the statements,
// and don't charge for the OBLOCK itself. The ++ undoes the -- below.
v.budget++
} }
v.budget-- v.budget--

View File

@ -164,7 +164,7 @@ func (p *noder) funcBody(fn *ir.Func, block *syntax.BlockStmt) {
if block != nil { if block != nil {
body := p.stmts(block.List) body := p.stmts(block.List)
if body == nil { if body == nil {
body = []ir.Node{ir.Nod(ir.OEMPTY, nil, nil)} body = []ir.Node{ir.Nod(ir.OBLOCK, nil, nil)}
} }
fn.PtrBody().Set(body) fn.PtrBody().Set(body)
@ -967,7 +967,9 @@ func (p *noder) stmtsFall(stmts []syntax.Stmt, fallOK bool) []ir.Node {
for i, stmt := range stmts { for i, stmt := range stmts {
s := p.stmtFall(stmt, fallOK && i+1 == len(stmts)) s := p.stmtFall(stmt, fallOK && i+1 == len(stmts))
if s == nil { if s == nil {
} else if s.Op() == ir.OBLOCK && s.Init().Len() == 0 { } else if s.Op() == ir.OBLOCK && s.List().Len() > 0 {
// Inline non-empty block.
// Empty blocks must be preserved for checkreturn.
nodes = append(nodes, s.List().Slice()...) nodes = append(nodes, s.List().Slice()...)
} else { } else {
nodes = append(nodes, s) nodes = append(nodes, s)
@ -991,7 +993,7 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) ir.Node {
l := p.blockStmt(stmt) l := p.blockStmt(stmt)
if len(l) == 0 { if len(l) == 0 {
// TODO(mdempsky): Line number? // TODO(mdempsky): Line number?
return ir.Nod(ir.OEMPTY, nil, nil) return ir.Nod(ir.OBLOCK, nil, nil)
} }
return liststmt(l) return liststmt(l)
case *syntax.ExprStmt: case *syntax.ExprStmt:
@ -1166,7 +1168,7 @@ func (p *noder) ifStmt(stmt *syntax.IfStmt) ir.Node {
n.PtrBody().Set(p.blockStmt(stmt.Then)) n.PtrBody().Set(p.blockStmt(stmt.Then))
if stmt.Else != nil { if stmt.Else != nil {
e := p.stmt(stmt.Else) e := p.stmt(stmt.Else)
if e.Op() == ir.OBLOCK && e.Init().Len() == 0 { if e.Op() == ir.OBLOCK {
n.PtrRlist().Set(e.List().Slice()) n.PtrRlist().Set(e.List().Slice())
} else { } else {
n.PtrRlist().Set1(e) n.PtrRlist().Set1(e)
@ -1319,7 +1321,7 @@ func (p *noder) labeledStmt(label *syntax.LabeledStmt, fallOK bool) ir.Node {
l := []ir.Node{lhs} l := []ir.Node{lhs}
if ls != nil { if ls != nil {
if ls.Op() == ir.OBLOCK && ls.Init().Len() == 0 { if ls.Op() == ir.OBLOCK {
l = append(l, ls.List().Slice()...) l = append(l, ls.List().Slice()...)
} else { } else {
l = append(l, ls) l = append(l, ls)

View File

@ -676,7 +676,7 @@ func (o *Order) stmt(n ir.Node) {
o.cleanTemp(t) o.cleanTemp(t)
// Special: does not save n onto out. // Special: does not save n onto out.
case ir.OBLOCK, ir.OEMPTY: case ir.OBLOCK:
o.stmtList(n.List()) o.stmtList(n.List())
// Special: n->left is not an expression; save as is. // Special: n->left is not an expression; save as is.

View File

@ -1071,7 +1071,7 @@ func (s *state) stmt(n ir.Node) {
s.stmtList(n.List()) s.stmtList(n.List())
// No-ops // No-ops
case ir.OEMPTY, ir.ODCLCONST, ir.ODCLTYPE, ir.OFALL: case ir.ODCLCONST, ir.ODCLTYPE, ir.OFALL:
// Expression statements // Expression statements
case ir.OCALLFUNC: case ir.OCALLFUNC:

View File

@ -1950,13 +1950,16 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
case ir.OBREAK, case ir.OBREAK,
ir.OCONTINUE, ir.OCONTINUE,
ir.ODCL, ir.ODCL,
ir.OEMPTY,
ir.OGOTO, ir.OGOTO,
ir.OFALL, ir.OFALL,
ir.OVARKILL, ir.OVARKILL,
ir.OVARLIVE: ir.OVARLIVE:
ok |= ctxStmt ok |= ctxStmt
case ir.OBLOCK:
ok |= ctxStmt
typecheckslice(n.List().Slice(), ctxStmt)
case ir.OLABEL: case ir.OLABEL:
ok |= ctxStmt ok |= ctxStmt
decldepth++ decldepth++
@ -1964,7 +1967,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
// Empty identifier is valid but useless. // Empty identifier is valid but useless.
// Eliminate now to simplify life later. // Eliminate now to simplify life later.
// See issues 7538, 11589, 11593. // See issues 7538, 11589, 11593.
n = ir.NodAt(n.Pos(), ir.OEMPTY, nil, nil) n = ir.NodAt(n.Pos(), ir.OBLOCK, nil, nil)
} }
case ir.ODEFER: case ir.ODEFER:
@ -3808,7 +3811,7 @@ func deadcode(fn *ir.Func) {
} }
} }
fn.PtrBody().Set([]ir.Node{ir.Nod(ir.OEMPTY, nil, nil)}) fn.PtrBody().Set([]ir.Node{ir.Nod(ir.OBLOCK, nil, nil)})
} }
func deadcodeslice(nn *ir.Nodes) { func deadcodeslice(nn *ir.Nodes) {

View File

@ -142,7 +142,6 @@ func walkstmt(n ir.Node) ir.Node {
ir.OPRINT, ir.OPRINT,
ir.OPRINTN, ir.OPRINTN,
ir.OPANIC, ir.OPANIC,
ir.OEMPTY,
ir.ORECOVER, ir.ORECOVER,
ir.OGETG: ir.OGETG:
if n.Typecheck() == 0 { if n.Typecheck() == 0 {
@ -155,7 +154,7 @@ func walkstmt(n ir.Node) ir.Node {
if wascopy && n.Op() == ir.ONAME { if wascopy && n.Op() == ir.ONAME {
// copy rewrote to a statement list and a temp for the length. // copy rewrote to a statement list and a temp for the length.
// Throw away the temp to avoid plain values as statements. // Throw away the temp to avoid plain values as statements.
n = ir.NodAt(n.Pos(), ir.OEMPTY, nil, nil) n = ir.NodAt(n.Pos(), ir.OBLOCK, nil, nil)
} }
n = addinit(n, init.Slice()) n = addinit(n, init.Slice())
@ -470,7 +469,7 @@ opswitch:
ir.Dump("walk", n) ir.Dump("walk", n)
base.Fatalf("walkexpr: switch 1 unknown op %+S", n) base.Fatalf("walkexpr: switch 1 unknown op %+S", n)
case ir.ONONAME, ir.OEMPTY, ir.OGETG, ir.ONEWOBJ, ir.OMETHEXPR: case ir.ONONAME, ir.OGETG, ir.ONEWOBJ, ir.OMETHEXPR:
case ir.OTYPE, ir.ONAME, ir.OLITERAL, ir.ONIL: case ir.OTYPE, ir.ONAME, ir.OLITERAL, ir.ONIL:
// TODO(mdempsky): Just return n; see discussion on CL 38655. // TODO(mdempsky): Just return n; see discussion on CL 38655.
@ -609,7 +608,7 @@ opswitch:
} }
if oaslit(n, init) { if oaslit(n, init) {
n = ir.NodAt(n.Pos(), ir.OEMPTY, nil, nil) n = ir.NodAt(n.Pos(), ir.OBLOCK, nil, nil)
break break
} }
@ -2032,10 +2031,10 @@ func walkprint(nn ir.Node, init *ir.Nodes) ir.Node {
typecheckslice(calls, ctxStmt) typecheckslice(calls, ctxStmt)
walkexprlist(calls, init) walkexprlist(calls, init)
r := ir.Nod(ir.OEMPTY, nil, nil) r := ir.Nod(ir.OBLOCK, nil, nil)
r = typecheck(r, ctxStmt) r = typecheck(r, ctxStmt)
r = walkexpr(r, init) r = walkstmt(r)
r.PtrInit().Set(calls) r.PtrList().Set(calls)
return r return r
} }

View File

@ -942,6 +942,11 @@ func stmtFmt(n Node, s fmt.State, mode FmtMode) {
mode.Fprintf(s, "%.v = %.v", n.List(), n.Rlist()) mode.Fprintf(s, "%.v = %.v", n.List(), n.Rlist())
} }
case OBLOCK:
if n.List().Len() != 0 {
mode.Fprintf(s, "%v", n.List())
}
case ORETURN: case ORETURN:
mode.Fprintf(s, "return %.v", n.List()) mode.Fprintf(s, "return %.v", n.List())
@ -1044,9 +1049,6 @@ func stmtFmt(n Node, s fmt.State, mode FmtMode) {
mode.Fprintf(s, "%#v", n.Op()) mode.Fprintf(s, "%#v", n.Op())
} }
case OEMPTY:
break
case OLABEL: case OLABEL:
mode.Fprintf(s, "%v: ", n.Sym()) mode.Fprintf(s, "%v: ", n.Sym())
} }
@ -1155,12 +1157,12 @@ var OpPrec = []int{
OAS2MAPR: -1, OAS2MAPR: -1,
OAS2RECV: -1, OAS2RECV: -1,
OASOP: -1, OASOP: -1,
OBLOCK: -1,
OBREAK: -1, OBREAK: -1,
OCASE: -1, OCASE: -1,
OCONTINUE: -1, OCONTINUE: -1,
ODCL: -1, ODCL: -1,
ODEFER: -1, ODEFER: -1,
OEMPTY: -1,
OFALL: -1, OFALL: -1,
OFOR: -1, OFOR: -1,
OFORUNTIL: -1, OFORUNTIL: -1,

View File

@ -301,7 +301,7 @@ const (
OCASE OCASE
OCONTINUE // continue [Sym] OCONTINUE // continue [Sym]
ODEFER // defer Left (Left must be call) ODEFER // defer Left (Left must be call)
OEMPTY // no-op (empty statement) OEMPTY // TODO(rsc): Delete. (Use OBLOCK instead.)
OFALL // fallthrough OFALL // fallthrough
OFOR // for Ninit; Left; Right { Nbody } OFOR // for Ninit; Left; Right { Nbody }
// OFORUNTIL is like OFOR, but the test (Left) is applied after the body: // OFORUNTIL is like OFOR, but the test (Left) is applied after the body:
@ -781,8 +781,6 @@ func NodAt(pos src.XPos, op Op, nleft, nright Node) Node {
n := NewTypeAssertExpr(pos, nleft, typ) n := NewTypeAssertExpr(pos, nleft, typ)
n.SetOp(op) n.SetOp(op)
return n return n
case OEMPTY:
return NewEmptyStmt(pos)
case OFOR: case OFOR:
return NewForStmt(pos, nil, nleft, nright, nil) return NewForStmt(pos, nil, nleft, nright, nil)
case OGO: case OGO:

View File

@ -266,22 +266,6 @@ func (n *DeferStmt) rawCopy() Node { c := *n; return &c }
func (n *DeferStmt) Left() Node { return n.Call } func (n *DeferStmt) Left() Node { return n.Call }
func (n *DeferStmt) SetLeft(x Node) { n.Call = x } func (n *DeferStmt) SetLeft(x Node) { n.Call = x }
// An EmptyStmt is an empty statement
type EmptyStmt struct {
miniStmt
}
func NewEmptyStmt(pos src.XPos) *EmptyStmt {
n := &EmptyStmt{}
n.pos = pos
n.op = OEMPTY
return n
}
func (n *EmptyStmt) String() string { return fmt.Sprint(n) }
func (n *EmptyStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
func (n *EmptyStmt) rawCopy() Node { c := *n; return &c }
// A ForStmt is a non-range for loop: for Init; Cond; Post { Body } // A ForStmt is a non-range for loop: for Init; Cond; Post { Body }
// Op can be OFOR or OFORUNTIL (!Cond). // Op can be OFOR or OFORUNTIL (!Cond).
type ForStmt struct { type ForStmt struct {