func (b *builder) switchStmt(fn *Function, s *ast.SwitchStmt, label *lblock) {
	// We treat SwitchStmt like a sequential if-else chain.
	// Multiway dispatch can be recovered later by ssautil.Switches()
	// to those cases that are free of side effects.
	if s.Init != nil {
		b.stmt(fn, s.Init)
	}
	var tag Value = vTrue
	if s.Tag != nil {
		tag = b.expr(fn, s.Tag)
	}
	done := fn.newBasicBlock("switch.done")
	if label != nil {
		label._break = done
	}
	// We pull the default case (if present) down to the end.
	// But each fallthrough label must point to the next
	// body block in source order, so we preallocate a
	// body block (fallthru) for the next case.
	// Unfortunately this makes for a confusing block order.
	var dfltBody *[]ast.Stmt
	var dfltFallthrough *BasicBlock
	var fallthru, dfltBlock *BasicBlock
	ncases := len(s.Body.List)
	for i, clause := range s.Body.List {
		body := fallthru
		if body == nil {
			body = fn.newBasicBlock("switch.body") // first case only
		}

		// Preallocate body block for the next case.
		fallthru = done
		if i+1 < ncases {
			fallthru = fn.newBasicBlock("switch.body")
		}

		cc := clause.(*ast.CaseClause)
		if cc.List == nil {
			// Default case.
			dfltBody = &cc.Body
			dfltFallthrough = fallthru
			dfltBlock = body
			continue
		}

		var nextCond *BasicBlock
		for _, cond := range cc.List {
			nextCond = fn.newBasicBlock("switch.next")
			// TODO(adonovan): opt: when tag==vTrue, we'd
			// get better code if we use b.cond(cond)
			// instead of BinOp(EQL, tag, b.expr(cond))
			// followed by If.  Don't forget conversions
			// though.
			cond := emitCompare(fn, token.EQL, tag, b.expr(fn, cond), cond.Pos())
			emitIf(fn, cond, body, nextCond)
			fn.currentBlock = nextCond
		}
		fn.currentBlock = body
		fn.targets = &targets{
			tail:         fn.targets,
			_break:       done,
			_fallthrough: fallthru,
		}
		b.stmtList(fn, cc.Body)
		fn.targets = fn.targets.tail
		emitJump(fn, done)
		fn.currentBlock = nextCond
	}
	if dfltBlock != nil {
		emitJump(fn, dfltBlock)
		fn.currentBlock = dfltBlock
		fn.targets = &targets{
			tail:         fn.targets,
			_break:       done,
			_fallthrough: dfltFallthrough,
		}
		b.stmtList(fn, *dfltBody)
		fn.targets = fn.targets.tail
	}
	emitJump(fn, done)
	fn.currentBlock = done
}
func (b *builder) switchStmt(fn *Function, s *ast.SwitchStmt, label *lblock) {
	
	
	
	if s.Init != nil {
		b.stmt(fn, s.Init)
	}
	var tag Value = vTrue
	if s.Tag != nil {
		tag = b.expr(fn, s.Tag)
	}
	done := fn.newBasicBlock("switch.done")
	if label != nil {
		label._break = done
	}
	
	
	
	
	
	var dfltBody *[]ast.Stmt
	var dfltFallthrough *BasicBlock
	var fallthru, dfltBlock *BasicBlock
	ncases := len(s.Body.List)
	for i, clause := range s.Body.List {
		body := fallthru
		if body == nil {
			body = fn.newBasicBlock("switch.body") 
		}

		
		fallthru = done
		if i+1 < ncases {
			fallthru = fn.newBasicBlock("switch.body")
		}

		cc := clause.(*ast.CaseClause)
		if cc.List == nil {
			
			dfltBody = &cc.Body
			dfltFallthrough = fallthru
			dfltBlock = body
			continue
		}

		var nextCond *BasicBlock
		for _, cond := range cc.List {
			nextCond = fn.newBasicBlock("switch.next")
			
			
			
			
			
			cond := emitCompare(fn, token.EQL, tag, b.expr(fn, cond), cond.Pos())
			emitIf(fn, cond, body, nextCond)
			fn.currentBlock = nextCond
		}
		fn.currentBlock = body
		fn.targets = &targets{
			tail:         fn.targets,
			_break:       done,
			_fallthrough: fallthru,
		}
		b.stmtList(fn, cc.Body)
		fn.targets = fn.targets.tail
		emitJump(fn, done)
		fn.currentBlock = nextCond
	}
	if dfltBlock != nil {
		emitJump(fn, dfltBlock)
		fn.currentBlock = dfltBlock
		fn.targets = &targets{
			tail:         fn.targets,
			_break:       done,
			_fallthrough: dfltFallthrough,
		}
		b.stmtList(fn, *dfltBody)
		fn.targets = fn.targets.tail
	}
	emitJump(fn, done)
	fn.currentBlock = done
}
func ( b * builder ) switchStmt ( fn * Function , s * ast . SwitchStmt , label * lblock ) { // We treat SwitchStmt like a sequential if-else chain. // Multiway dispatch can be recovered later by ssautil.Switches() // to those cases that are free of side effects. if s . Init != nil { b . stmt ( fn , s . Init ) } var tag Value = vTrue if s . Tag != nil { tag = b . expr ( fn , s . Tag ) } done := fn . newBasicBlock ( " " ) if label != nil { label . _break = done } // We pull the default case (if present) down to the end. // But each fallthrough label must point to the next // body block in source order, so we preallocate a // body block (fallthru) for the next case. // Unfortunately this makes for a confusing block order. var dfltBody * [ ] ast . Stmt var dfltFallthrough * BasicBlock var fallthru , dfltBlock * BasicBlock ncases := len ( s . Body . List ) for i , clause := range s . Body . List { body := fallthru if body == nil { body = fn . newBasicBlock ( " " ) // first case only } // Preallocate body block for the next case. fallthru = done if i + 1 < ncases { fallthru = fn . newBasicBlock ( " " ) } cc := clause . ( * ast . CaseClause ) if cc . List == nil { // Default case. dfltBody = & cc . Body dfltFallthrough = fallthru dfltBlock = body continue } var nextCond * BasicBlock for _ , cond := range cc . List { nextCond = fn . newBasicBlock ( " " ) // TODO(adonovan): opt: when tag==vTrue, we'd // get better code if we use b.cond(cond) // instead of BinOp(EQL, tag, b.expr(cond)) // followed by If.  Don't forget conversions // though. cond := emitCompare ( fn , token . EQL , tag , b . expr ( fn , cond ) , cond . Pos ( ) ) emitIf ( fn , cond , body , nextCond ) fn . currentBlock = nextCond } fn . currentBlock = body fn . targets = & targets { tail : fn . targets , _break : done , _fallthrough : fallthru , } b . stmtList ( fn , cc . Body ) fn . targets = fn . targets . tail emitJump ( fn , done ) fn . currentBlock = nextCond } if dfltBlock != nil { emitJump ( fn , dfltBlock ) fn . currentBlock = dfltBlock fn . targets = & targets { tail : fn . targets , _break : done , _fallthrough : dfltFallthrough , } b . stmtList ( fn , * dfltBody ) fn . targets = fn . targets . tail } emitJump ( fn , done ) fn . currentBlock = done }
// switchStmt emits to fn code for the switch statement s, optionally
// labelled by label.
//
switchStmt emits to fn code for the switch statement s optionally labelled by label .