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:
parent
c769d393de
commit
ec5f349b22
@ -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:
|
||||||
|
@ -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())
|
||||||
|
@ -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 {
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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--
|
||||||
|
@ -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)
|
||||||
|
@ -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.
|
||||||
|
@ -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:
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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:
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user