1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
7 // This file implements the CFG construction pass.
17 mayReturn func(*ast.CallExpr) bool
19 lblocks map[*ast.Object]*lblock // labeled blocks
20 targets *targets // linked stack of branch targets
23 func (b *builder) stmt(_s ast.Stmt) {
24 // The label of the current statement. If non-nil, its _goto
25 // target is always set; its _break and _continue are set only
26 // within the body of switch/typeswitch/select/for/range.
27 // It is effectively an additional default-nil parameter of stmt().
30 switch s := _s.(type) {
38 // No effect on control flow.
43 if call, ok := s.X.(*ast.CallExpr); ok && !b.mayReturn(call) {
44 // Calls to panic, os.Exit, etc, never return.
45 b.current = b.newBlock("unreachable.call")
49 // Treat each var ValueSpec as a separate statement.
50 d := s.Decl.(*ast.GenDecl)
51 if d.Tok == token.VAR {
52 for _, spec := range d.Specs {
53 if spec, ok := spec.(*ast.ValueSpec); ok {
59 case *ast.LabeledStmt:
60 label = b.labeledBlock(s.Label)
62 b.current = label._goto
64 goto start // effectively: tailcall stmt(g, s.Stmt, label)
68 b.current = b.newBlock("unreachable.return")
80 then := b.newBlock("if.then")
81 done := b.newBlock("if.done")
84 _else = b.newBlock("if.else")
100 case *ast.SwitchStmt:
101 b.switchStmt(s, label)
103 case *ast.TypeSwitchStmt:
104 b.typeSwitchStmt(s, label)
106 case *ast.SelectStmt:
107 b.selectStmt(s, label)
113 b.rangeStmt(s, label)
116 panic(fmt.Sprintf("unexpected statement kind: %T", s))
120 func (b *builder) stmtList(list []ast.Stmt) {
121 for _, s := range list {
126 func (b *builder) branchStmt(s *ast.BranchStmt) {
131 if lb := b.labeledBlock(s.Label); lb != nil {
135 for t := b.targets; t != nil && block == nil; t = t.tail {
142 if lb := b.labeledBlock(s.Label); lb != nil {
146 for t := b.targets; t != nil && block == nil; t = t.tail {
151 case token.FALLTHROUGH:
152 for t := b.targets; t != nil && block == nil; t = t.tail {
153 block = t._fallthrough
158 block = b.labeledBlock(s.Label)._goto
162 block = b.newBlock("undefined.branch")
165 b.current = b.newBlock("unreachable.branch")
168 func (b *builder) switchStmt(s *ast.SwitchStmt, label *lblock) {
175 done := b.newBlock("switch.done")
179 // We pull the default case (if present) down to the end.
180 // But each fallthrough label must point to the next
181 // body block in source order, so we preallocate a
182 // body block (fallthru) for the next case.
183 // Unfortunately this makes for a confusing block order.
184 var defaultBody *[]ast.Stmt
185 var defaultFallthrough *Block
186 var fallthru, defaultBlock *Block
187 ncases := len(s.Body.List)
188 for i, clause := range s.Body.List {
191 body = b.newBlock("switch.body") // first case only
194 // Preallocate body block for the next case.
197 fallthru = b.newBlock("switch.body")
200 cc := clause.(*ast.CaseClause)
203 defaultBody = &cc.Body
204 defaultFallthrough = fallthru
210 for _, cond := range cc.List {
211 nextCond = b.newBlock("switch.next")
212 b.add(cond) // one half of the tag==cond condition
213 b.ifelse(body, nextCond)
217 b.targets = &targets{
220 _fallthrough: fallthru,
223 b.targets = b.targets.tail
227 if defaultBlock != nil {
229 b.current = defaultBlock
230 b.targets = &targets{
233 _fallthrough: defaultFallthrough,
235 b.stmtList(*defaultBody)
236 b.targets = b.targets.tail
242 func (b *builder) typeSwitchStmt(s *ast.TypeSwitchStmt, label *lblock) {
250 done := b.newBlock("typeswitch.done")
254 var default_ *ast.CaseClause
255 for _, clause := range s.Body.List {
256 cc := clause.(*ast.CaseClause)
261 body := b.newBlock("typeswitch.body")
263 for _, casetype := range cc.List {
264 next = b.newBlock("typeswitch.next")
265 // casetype is a type, so don't call b.add(casetype).
266 // This block logically contains a type assertion,
267 // x.(casetype), but it's unclear how to represent x.
273 b.typeCaseBody(cc, done)
277 b.typeCaseBody(default_, done)
284 func (b *builder) typeCaseBody(cc *ast.CaseClause, done *Block) {
285 b.targets = &targets{
290 b.targets = b.targets.tail
294 func (b *builder) selectStmt(s *ast.SelectStmt, label *lblock) {
295 // First evaluate channel expressions.
296 // TODO(adonovan): fix: evaluate only channel exprs here.
297 for _, clause := range s.Body.List {
298 if comm := clause.(*ast.CommClause).Comm; comm != nil {
303 done := b.newBlock("select.done")
308 var defaultBody *[]ast.Stmt
309 for _, cc := range s.Body.List {
310 clause := cc.(*ast.CommClause)
311 if clause.Comm == nil {
312 defaultBody = &clause.Body
315 body := b.newBlock("select.body")
316 next := b.newBlock("select.next")
319 b.targets = &targets{
323 switch comm := clause.Comm.(type) {
324 case *ast.ExprStmt: // <-ch
326 case *ast.AssignStmt: // x := <-states[state].Chan
329 b.stmtList(clause.Body)
330 b.targets = b.targets.tail
334 if defaultBody != nil {
335 b.targets = &targets{
339 b.stmtList(*defaultBody)
340 b.targets = b.targets.tail
346 func (b *builder) forStmt(s *ast.ForStmt, label *lblock) {
350 // if cond goto body else done
354 // post: (target of continue)
357 // done: (target of break)
361 body := b.newBlock("for.body")
362 done := b.newBlock("for.done") // target of 'break'
363 loop := body // target of back-edge
365 loop = b.newBlock("for.loop")
367 cont := loop // target of 'continue'
369 cont = b.newBlock("for.post")
373 label._continue = cont
382 b.targets = &targets{
388 b.targets = b.targets.tail
394 b.jump(loop) // back-edge
399 func (b *builder) rangeStmt(s *ast.RangeStmt, label *lblock) {
410 // loop: (target of continue)
411 // if ... goto body else done
415 // done: (target of break)
417 loop := b.newBlock("range.loop")
421 body := b.newBlock("range.body")
422 done := b.newBlock("range.done")
428 label._continue = loop
430 b.targets = &targets{
436 b.targets = b.targets.tail
437 b.jump(loop) // back-edge
441 // -------- helpers --------
443 // Destinations associated with unlabeled for/switch/select stmts.
444 // We push/pop one of these as we enter/leave each construct and for
445 // each BranchStmt we scan for the innermost target of the right type.
447 type targets struct {
448 tail *targets // rest of stack
454 // Destinations associated with a labeled block.
455 // We populate these as labels are encountered in forward gotos or
456 // labeled statements.
464 // labeledBlock returns the branch target associated with the
465 // specified label, creating it if needed.
467 func (b *builder) labeledBlock(label *ast.Ident) *lblock {
468 lb := b.lblocks[label.Obj]
470 lb = &lblock{_goto: b.newBlock(label.Name)}
471 if b.lblocks == nil {
472 b.lblocks = make(map[*ast.Object]*lblock)
474 b.lblocks[label.Obj] = lb
479 // newBlock appends a new unconnected basic block to b.cfg's block
480 // slice and returns it.
481 // It does not automatically become the current block.
482 // comment is an optional string for more readable debugging output.
483 func (b *builder) newBlock(comment string) *Block {
486 Index: int32(len(g.Blocks)),
489 block.Succs = block.succs2[:0]
490 g.Blocks = append(g.Blocks, block)
494 func (b *builder) add(n ast.Node) {
495 b.current.Nodes = append(b.current.Nodes, n)
498 // jump adds an edge from the current block to the target block,
499 // and sets b.current to nil.
500 func (b *builder) jump(target *Block) {
501 b.current.Succs = append(b.current.Succs, target)
505 // ifelse emits edges from the current block to the t and f blocks,
506 // and sets b.current to nil.
507 func (b *builder) ifelse(t, f *Block) {
508 b.current.Succs = append(b.current.Succs, t, f)