diff --git a/demo1.go b/demo1.go new file mode 100644 index 00000000000000..79f680d7880afa --- /dev/null +++ b/demo1.go @@ -0,0 +1,15 @@ +package main + +import ( + "fmt" +) + +func main() { + for i := 8; i <= 20; i += 4 { + if !(i%8 == 0) { + fmt.Println(i, "is not divisible by 8") + continue + } + fmt.Println(i, "is divisible by 8") + } +} diff --git a/demo2.go b/demo2.go new file mode 100644 index 00000000000000..64a2bdea7f9398 --- /dev/null +++ b/demo2.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" +) + +func main() { + four i := 8; i <= 20; i++ { + unless i%8 == 0 { + fmt.Println(i, "is not divisible by 8") + continue + } + fmt.Println(i, "is divisible by 8") + } +} + diff --git a/demo3.go b/demo3.go new file mode 100644 index 00000000000000..65971c1cc55b90 --- /dev/null +++ b/demo3.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" +) + +func f() { + fmt.Println("number is divisible by 8") +} + +func g() { + fmt.Println("number is not divisible by 8") +} + +func main() { + four i := 8; i <= 20; i++ { + unless i%8 == 0 { + g() + continue + } + f() + } +} diff --git a/src/cmd/compile/internal/escape/stmt.go b/src/cmd/compile/internal/escape/stmt.go index b766864a306f82..6c337293905492 100644 --- a/src/cmd/compile/internal/escape/stmt.go +++ b/src/cmd/compile/internal/escape/stmt.go @@ -87,6 +87,19 @@ func (e *escape) stmt(n ir.Node) { e.block(n.Body) e.loopDepth-- + case ir.OFOUR: + n := n.(*ir.FourStmt) + e.loopDepth++ + e.discard(n.Cond) + e.stmt(n.Post) + e.block(n.Body) + e.loopDepth-- + + case ir.OUNLESS: + n := n.(*ir.UnlessStmt) + e.discard(n.Cond) + e.block(n.Body) + case ir.ORANGE: // for Key, Value = range X { Body } n := n.(*ir.RangeStmt) diff --git a/src/cmd/compile/internal/ir/fmt.go b/src/cmd/compile/internal/ir/fmt.go index 31c610348bcd80..05de70db312139 100644 --- a/src/cmd/compile/internal/ir/fmt.go +++ b/src/cmd/compile/internal/ir/fmt.go @@ -49,6 +49,8 @@ var OpNames = []string{ OEQ: "==", OFALL: "fallthrough", OFOR: "for", + OFOUR: "four", + OUNLESS: "unless", OGE: ">=", OGOTO: "goto", OGT: ">", @@ -279,6 +281,8 @@ var OpPrec = []int{ ODEFER: -1, OFALL: -1, OFOR: -1, + OFOUR: -1, + OUNLESS: -1, OGOTO: -1, OIF: -1, OLABEL: -1, @@ -294,7 +298,7 @@ var OpPrec = []int{ // StmtWithInit reports whether op is a statement with an explicit init list. func StmtWithInit(op Op) bool { switch op { - case OIF, OFOR, OSWITCH: + case OIF, OFOR, OSWITCH, OFOUR, OUNLESS: return true } return false @@ -434,6 +438,40 @@ func stmtFmt(n Node, s fmt.State) { fmt.Fprintf(s, " { %v }", n.Body) + case OUNLESS: + n := n.(*UnlessStmt) + if simpleinit { + fmt.Fprintf(s, "unless %v; %v { %v }", n.Init()[0], n.Cond, n.Body) + } else { + fmt.Fprintf(s, "unless %v { %v }", n.Cond, n.Body) + } + + case OFOUR: + n := n.(*FourStmt) + if !exportFormat { // TODO maybe only if FmtShort, same below + fmt.Fprintf(s, "four loop") + break + } + + fmt.Fprint(s, "four") + if simpleinit { + fmt.Fprintf(s, " %v;", n.Init()[0]) + } else if n.Post != nil { + fmt.Fprint(s, " ;") + } + + if n.Cond != nil { + fmt.Fprintf(s, " %v", n.Cond) + } + + if n.Post != nil { + fmt.Fprintf(s, "; %v", n.Post) + } else if simpleinit { + fmt.Fprint(s, ";") + } + + fmt.Fprintf(s, " { %v }", n.Body) + case ORANGE: n := n.(*RangeStmt) if !exportFormat { diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go index 6513386f03f2f9..44cd35d7aedab2 100644 --- a/src/cmd/compile/internal/ir/node.go +++ b/src/cmd/compile/internal/ir/node.go @@ -265,6 +265,8 @@ const ( ODEFER // defer Call OFALL // fallthrough OFOR // for Init; Cond; Post { Body } + OFOUR // four Init; Cond; Post { Body } + OUNLESS // unless Init; Cond { Body } OGOTO // goto Label OIF // if Init; Cond { Then } else { Else } OLABEL // Label: diff --git a/src/cmd/compile/internal/ir/node_gen.go b/src/cmd/compile/internal/ir/node_gen.go index fc28067629d6a0..6b10e753e1798b 100644 --- a/src/cmd/compile/internal/ir/node_gen.go +++ b/src/cmd/compile/internal/ir/node_gen.go @@ -301,6 +301,9 @@ func (n *CallExpr) doChildren(do func(Node) bool) bool { if doNodes(n.Args, do) { return true } + if n.DeferAt != nil && do(n.DeferAt) { + return true + } if doNames(n.KeepAlive, do) { return true } @@ -312,6 +315,9 @@ func (n *CallExpr) editChildren(edit func(Node) Node) { n.Fun = edit(n.Fun).(Node) } editNodes(n.Args, edit) + if n.DeferAt != nil { + n.DeferAt = edit(n.DeferAt).(Node) + } editNames(n.KeepAlive, edit) } func (n *CallExpr) editChildrenWithHidden(edit func(Node) Node) { @@ -320,6 +326,9 @@ func (n *CallExpr) editChildrenWithHidden(edit func(Node) Node) { n.Fun = edit(n.Fun).(Node) } editNodes(n.Args, edit) + if n.DeferAt != nil { + n.DeferAt = edit(n.DeferAt).(Node) + } if n.RType != nil { n.RType = edit(n.RType).(Node) } @@ -668,6 +677,49 @@ func (n *ForStmt) editChildrenWithHidden(edit func(Node) Node) { editNodes(n.Body, edit) } +func (n *FourStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) } +func (n *FourStmt) copy() Node { + c := *n + c.init = copyNodes(c.init) + c.Body = copyNodes(c.Body) + return &c +} +func (n *FourStmt) doChildren(do func(Node) bool) bool { + if doNodes(n.init, do) { + return true + } + if n.Cond != nil && do(n.Cond) { + return true + } + if n.Post != nil && do(n.Post) { + return true + } + if doNodes(n.Body, do) { + return true + } + return false +} +func (n *FourStmt) editChildren(edit func(Node) Node) { + editNodes(n.init, edit) + if n.Cond != nil { + n.Cond = edit(n.Cond).(Node) + } + if n.Post != nil { + n.Post = edit(n.Post).(Node) + } + editNodes(n.Body, edit) +} +func (n *FourStmt) editChildrenWithHidden(edit func(Node) Node) { + editNodes(n.init, edit) + if n.Cond != nil { + n.Cond = edit(n.Cond).(Node) + } + if n.Post != nil { + n.Post = edit(n.Post).(Node) + } + editNodes(n.Body, edit) +} + func (n *Func) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) } func (n *GoDeferStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) } @@ -683,6 +735,9 @@ func (n *GoDeferStmt) doChildren(do func(Node) bool) bool { if n.Call != nil && do(n.Call) { return true } + if n.DeferAt != nil && do(n.DeferAt) { + return true + } return false } func (n *GoDeferStmt) editChildren(edit func(Node) Node) { @@ -690,12 +745,18 @@ func (n *GoDeferStmt) editChildren(edit func(Node) Node) { if n.Call != nil { n.Call = edit(n.Call).(Node) } + if n.DeferAt != nil { + n.DeferAt = edit(n.DeferAt).(Expr) + } } func (n *GoDeferStmt) editChildrenWithHidden(edit func(Node) Node) { editNodes(n.init, edit) if n.Call != nil { n.Call = edit(n.Call).(Node) } + if n.DeferAt != nil { + n.DeferAt = edit(n.DeferAt).(Expr) + } } func (n *Ident) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) } @@ -866,6 +927,9 @@ func (n *InterfaceSwitchStmt) doChildren(do func(Node) bool) bool { if n.RuntimeType != nil && do(n.RuntimeType) { return true } + if n.Hash != nil && do(n.Hash) { + return true + } return false } func (n *InterfaceSwitchStmt) editChildren(edit func(Node) Node) { @@ -879,6 +943,9 @@ func (n *InterfaceSwitchStmt) editChildren(edit func(Node) Node) { if n.RuntimeType != nil { n.RuntimeType = edit(n.RuntimeType).(Node) } + if n.Hash != nil { + n.Hash = edit(n.Hash).(Node) + } } func (n *InterfaceSwitchStmt) editChildrenWithHidden(edit func(Node) Node) { editNodes(n.init, edit) @@ -891,6 +958,9 @@ func (n *InterfaceSwitchStmt) editChildrenWithHidden(edit func(Node) Node) { if n.RuntimeType != nil { n.RuntimeType = edit(n.RuntimeType).(Node) } + if n.Hash != nil { + n.Hash = edit(n.Hash).(Node) + } } func (n *JumpTableStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) } @@ -1699,6 +1769,40 @@ func (n *UnaryExpr) editChildrenWithHidden(edit func(Node) Node) { } } +func (n *UnlessStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) } +func (n *UnlessStmt) copy() Node { + c := *n + c.init = copyNodes(c.init) + c.Body = copyNodes(c.Body) + return &c +} +func (n *UnlessStmt) doChildren(do func(Node) bool) bool { + if doNodes(n.init, do) { + return true + } + if n.Cond != nil && do(n.Cond) { + return true + } + if doNodes(n.Body, do) { + return true + } + return false +} +func (n *UnlessStmt) editChildren(edit func(Node) Node) { + editNodes(n.init, edit) + if n.Cond != nil { + n.Cond = edit(n.Cond).(Node) + } + editNodes(n.Body, edit) +} +func (n *UnlessStmt) editChildrenWithHidden(edit func(Node) Node) { + editNodes(n.init, edit) + if n.Cond != nil { + n.Cond = edit(n.Cond).(Node) + } + editNodes(n.Body, edit) +} + func (n *typeNode) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) } func (n *typeNode) copy() Node { c := *n diff --git a/src/cmd/compile/internal/ir/op_string.go b/src/cmd/compile/internal/ir/op_string.go index fb97ac68f45904..91858e61573aa9 100644 --- a/src/cmd/compile/internal/ir/op_string.go +++ b/src/cmd/compile/internal/ir/op_string.go @@ -131,40 +131,42 @@ func _() { _ = x[ODEFER-120] _ = x[OFALL-121] _ = x[OFOR-122] - _ = x[OGOTO-123] - _ = x[OIF-124] - _ = x[OLABEL-125] - _ = x[OGO-126] - _ = x[ORANGE-127] - _ = x[ORETURN-128] - _ = x[OSELECT-129] - _ = x[OSWITCH-130] - _ = x[OTYPESW-131] - _ = x[OINLCALL-132] - _ = x[OMAKEFACE-133] - _ = x[OITAB-134] - _ = x[OIDATA-135] - _ = x[OSPTR-136] - _ = x[OCFUNC-137] - _ = x[OCHECKNIL-138] - _ = x[ORESULT-139] - _ = x[OINLMARK-140] - _ = x[OLINKSYMOFFSET-141] - _ = x[OJUMPTABLE-142] - _ = x[OINTERFACESWITCH-143] - _ = x[ODYNAMICDOTTYPE-144] - _ = x[ODYNAMICDOTTYPE2-145] - _ = x[ODYNAMICTYPE-146] - _ = x[OTAILCALL-147] - _ = x[OGETG-148] - _ = x[OGETCALLERPC-149] - _ = x[OGETCALLERSP-150] - _ = x[OEND-151] + _ = x[OFOUR-123] + _ = x[OUNLESS-124] + _ = x[OGOTO-125] + _ = x[OIF-126] + _ = x[OLABEL-127] + _ = x[OGO-128] + _ = x[ORANGE-129] + _ = x[ORETURN-130] + _ = x[OSELECT-131] + _ = x[OSWITCH-132] + _ = x[OTYPESW-133] + _ = x[OINLCALL-134] + _ = x[OMAKEFACE-135] + _ = x[OITAB-136] + _ = x[OIDATA-137] + _ = x[OSPTR-138] + _ = x[OCFUNC-139] + _ = x[OCHECKNIL-140] + _ = x[ORESULT-141] + _ = x[OINLMARK-142] + _ = x[OLINKSYMOFFSET-143] + _ = x[OJUMPTABLE-144] + _ = x[OINTERFACESWITCH-145] + _ = x[ODYNAMICDOTTYPE-146] + _ = x[ODYNAMICDOTTYPE2-147] + _ = x[ODYNAMICTYPE-148] + _ = x[OTAILCALL-149] + _ = x[OGETG-150] + _ = x[OGETCALLERPC-151] + _ = x[OGETCALLERSP-152] + _ = x[OEND-153] } -const _Op_name = "XXXNAMENONAMETYPELITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLEARCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERSTRINGHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2MINMAXREALIMAGCOMPLEXUNSAFEADDUNSAFESLICEUNSAFESLICEDATAUNSAFESTRINGUNSAFESTRINGDATAMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWINLCALLMAKEFACEITABIDATASPTRCFUNCCHECKNILRESULTINLMARKLINKSYMOFFSETJUMPTABLEINTERFACESWITCHDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERPCGETCALLERSPEND" +const _Op_name = "XXXNAMENONAMETYPELITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLEARCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTLNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERSTRINGHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2MINMAXREALIMAGCOMPLEXUNSAFEADDUNSAFESLICEUNSAFESLICEDATAUNSAFESTRINGUNSAFESTRINGDATAMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORFOURUNLESSGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWINLCALLMAKEFACEITABIDATASPTRCFUNCCHECKNILRESULTINLMARKLINKSYMOFFSETJUMPTABLEINTERFACESWITCHDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERPCGETCALLERSPEND" -var _Op_index = [...]uint16{0, 3, 7, 13, 17, 24, 27, 30, 33, 35, 38, 44, 48, 54, 60, 69, 81, 90, 99, 111, 120, 129, 141, 143, 146, 156, 163, 170, 177, 181, 185, 193, 201, 210, 213, 218, 223, 230, 237, 243, 252, 260, 268, 274, 278, 287, 294, 298, 301, 308, 314, 317, 323, 330, 338, 342, 349, 357, 359, 361, 363, 365, 367, 369, 374, 379, 387, 390, 399, 402, 406, 414, 421, 430, 443, 446, 449, 452, 455, 458, 461, 467, 470, 473, 479, 483, 486, 490, 495, 500, 506, 511, 515, 520, 528, 536, 542, 551, 562, 574, 581, 590, 594, 601, 609, 612, 615, 619, 623, 630, 639, 650, 665, 677, 693, 701, 710, 715, 720, 724, 732, 737, 741, 744, 748, 750, 755, 757, 762, 768, 774, 780, 786, 793, 801, 805, 810, 814, 819, 827, 833, 840, 853, 862, 877, 891, 906, 917, 925, 929, 940, 951, 954} +var _Op_index = [...]uint16{0, 3, 7, 13, 17, 24, 27, 30, 33, 35, 38, 44, 48, 54, 60, 69, 81, 90, 99, 111, 120, 129, 141, 143, 146, 156, 163, 170, 177, 181, 185, 193, 201, 210, 213, 218, 223, 230, 237, 243, 252, 260, 268, 274, 278, 287, 294, 298, 301, 308, 314, 317, 323, 330, 338, 342, 349, 357, 359, 361, 363, 365, 367, 369, 374, 379, 387, 390, 399, 402, 406, 414, 421, 430, 443, 446, 449, 452, 455, 458, 461, 467, 470, 473, 479, 483, 486, 490, 495, 500, 507, 512, 516, 521, 529, 537, 543, 552, 563, 575, 582, 591, 595, 602, 610, 613, 616, 620, 624, 631, 640, 651, 666, 678, 694, 702, 711, 716, 721, 725, 733, 738, 742, 745, 749, 755, 759, 761, 766, 768, 773, 779, 785, 791, 797, 804, 812, 816, 821, 825, 830, 838, 844, 851, 864, 873, 888, 902, 917, 928, 936, 940, 951, 962, 965} func (i Op) String() string { if i >= Op(len(_Op_index)-1) { diff --git a/src/cmd/compile/internal/ir/stmt.go b/src/cmd/compile/internal/ir/stmt.go index 0801ecdd9e8722..a97ed5424c8612 100644 --- a/src/cmd/compile/internal/ir/stmt.go +++ b/src/cmd/compile/internal/ir/stmt.go @@ -236,6 +236,40 @@ func NewForStmt(pos src.XPos, init Node, cond, post Node, body []Node, distinctV return n } +type FourStmt struct { + miniStmt + Label *types.Sym + Cond Node + Post Node + Body Nodes +} + +func NewFourStmt(pos src.XPos, init Node, cond, post Node, body []Node) *FourStmt { + n := &FourStmt{Cond: cond, Post: post} + n.pos = pos + n.op = OFOUR + if init != nil { + n.init = []Node{init} + } + n.Body = body + return n +} + +type UnlessStmt struct { + miniStmt + Cond Node + Body Nodes + Likely bool // code layout hint +} + +func NewUnlessStmt(pos src.XPos, cond Node, body []Node) *UnlessStmt { + n := &UnlessStmt{Cond: cond} + n.pos = pos + n.op = OUNLESS + n.Body = body + return n +} + // A GoDeferStmt is a go or defer statement: go Call / defer Call. // // The two opcodes use a single syntax because the implementations diff --git a/src/cmd/compile/internal/noder/codes.go b/src/cmd/compile/internal/noder/codes.go index 8bdbfc9a8800b8..2027b89890332d 100644 --- a/src/cmd/compile/internal/noder/codes.go +++ b/src/cmd/compile/internal/noder/codes.go @@ -26,6 +26,8 @@ const ( stmtReturn stmtIf stmtFor + stmtFour + stmtUnless stmtSwitch stmtSelect ) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 2dddd201659024..bee74c9ead8454 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -1693,6 +1693,12 @@ func (r *reader) stmt1(tag codeStmt, out *ir.Nodes) ir.Node { case stmtFor: return r.forStmt(label) + case stmtFour: + return r.fourStmt(label) + + case stmtUnless: + return r.unlessStmt() + case stmtIf: return r.ifStmt() @@ -1819,6 +1825,37 @@ func (r *reader) forStmt(label *types.Sym) ir.Node { return stmt } +func (r *reader) fourStmt(label *types.Sym) ir.Node { + r.Sync(pkgbits.SyncFourStmt) + + r.openScope() + + pos := r.pos() + init := r.stmt() + cond := r.optExpr() + post := r.stmt() + body := r.blockStmt() + r.closeAnotherScope() + + stmt := ir.NewFourStmt(pos, init, cond, post, body) + stmt.Label = label + return stmt +} + +func (r *reader) unlessStmt() ir.Node { + r.Sync(pkgbits.SyncUnlessStmt) + r.openScope() + pos := r.pos() + init := r.stmts() + cond := r.expr() + then := r.blockStmt() + r.closeAnotherScope() + + n := ir.NewUnlessStmt(pos, cond, then) + n.SetInit(init) + return n +} + func (r *reader) ifStmt() ir.Node { r.Sync(pkgbits.SyncIfStmt) r.openScope() diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index e5894c950543ae..32091e5788f138 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -1288,6 +1288,14 @@ func (w *writer) stmt1(stmt syntax.Stmt) { w.Code(stmtFor) w.forStmt(stmt) + case *syntax.FourStmt: + w.Code(stmtFour) + w.fourStmt(stmt) + + case *syntax.UnlessStmt: + w.Code(stmtUnless) + w.unlessStmt(stmt) + case *syntax.IfStmt: w.Code(stmtIf) w.ifStmt(stmt) @@ -1497,6 +1505,30 @@ func (w *writer) distinctVars(stmt *syntax.ForStmt) bool { return is122 || lv > 0 && lv != 3 } +func (w *writer) fourStmt(stmt *syntax.FourStmt) { + w.Sync(pkgbits.SyncFourStmt) + w.openScope(stmt.Pos()) + + w.pos(stmt) + w.stmt(stmt.Init) + w.optExpr(stmt.Cond) + w.stmt(stmt.Post) + + w.blockStmt(stmt.Body) + w.Bool(base.Debug.LoopVar > 0) + w.closeAnotherScope() +} + +func (w *writer) unlessStmt(stmt *syntax.UnlessStmt) { + w.Sync(pkgbits.SyncUnlessStmt) + w.openScope(stmt.Pos()) + w.pos(stmt) + w.stmt(stmt.Init) + w.expr(stmt.Cond) + w.blockStmt(stmt.Then) + w.closeAnotherScope() +} + func (w *writer) ifStmt(stmt *syntax.IfStmt) { cond := w.p.staticBool(&stmt.Cond) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index c794d6ffd9d783..2710fa422bd96a 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -1874,6 +1874,105 @@ func (s *state) stmt(n ir.Node) { s.startBlock(bEnd) + case ir.OFOUR: + // OFOUR: four Ninit; Left; Right { Nbody } + // cond (Left); body (Nbody); incr (Right) + n := n.(*ir.FourStmt) + bCond := s.f.NewBlock(ssa.BlockPlain) + bBody := s.f.NewBlock(ssa.BlockPlain) + bIncr := s.f.NewBlock(ssa.BlockPlain) + bEnd := s.f.NewBlock(ssa.BlockPlain) + + // ensure empty for loops have correct position; issue #30167 + bBody.Pos = n.Pos() + + // first, jump to condition test + b := s.endBlock() + b.AddEdgeTo(bCond) + + // generate code to test condition + s.startBlock(bCond) + if n.Cond != nil { + s.condBranch(n.Cond, bBody, bEnd, 1) + } else { + b := s.endBlock() + b.Kind = ssa.BlockPlain + b.AddEdgeTo(bBody) + } + + // set up for continue/break in body + prevContinue := s.continueTo + prevBreak := s.breakTo + s.continueTo = bIncr + s.breakTo = bEnd + var lab *ssaLabel + if sym := n.Label; sym != nil { + // labeled for loop + lab = s.label(sym) + lab.continueTarget = bIncr + lab.breakTarget = bEnd + } + + // generate body + s.startBlock(bBody) + s.stmtList(n.Body) + + // tear down continue/break + s.continueTo = prevContinue + s.breakTo = prevBreak + if lab != nil { + lab.continueTarget = nil + lab.breakTarget = nil + } + + // done with body, goto incr + if b := s.endBlock(); b != nil { + b.AddEdgeTo(bIncr) + } + + // generate incr + s.startBlock(bIncr) + if n.Post != nil { + for i := 0; i < 4; i++ { + s.stmt(n.Post) + } + } + if b := s.endBlock(); b != nil { + b.AddEdgeTo(bCond) + // It can happen that bIncr ends in a block containing only VARKILL, + // and that muddles the debugging experience. + if b.Pos == src.NoXPos { + b.Pos = bCond.Pos + } + } + + s.startBlock(bEnd) + + case ir.OUNLESS: + n := n.(*ir.UnlessStmt) + + bEnd := s.f.NewBlock(ssa.BlockPlain) + var likely int8 + if n.Likely { + likely = 1 + } + var bThen *ssa.Block + if len(n.Body) != 0 { + bThen = s.f.NewBlock(ssa.BlockPlain) + } else { + bThen = bEnd + } + s.condBranch(n.Cond, bEnd, bThen, likely) + + if len(n.Body) != 0 { + s.startBlock(bThen) + s.stmtList(n.Body) + if b := s.endBlock(); b != nil { + b.AddEdgeTo(bEnd) + } + } + s.startBlock(bEnd) + case ir.OSWITCH, ir.OSELECT: // These have been mostly rewritten by the front end into their Nbody fields. // Our main task is to correctly hook up any break statements. diff --git a/src/cmd/compile/internal/syntax/nodes.go b/src/cmd/compile/internal/syntax/nodes.go index de277fc3d8cdab..881eac26ee4b69 100644 --- a/src/cmd/compile/internal/syntax/nodes.go +++ b/src/cmd/compile/internal/syntax/nodes.go @@ -418,6 +418,21 @@ type ( stmt } + FourStmt struct { + Init SimpleStmt + Cond Expr + Post SimpleStmt + Body *BlockStmt + stmt + } + + UnlessStmt struct { + Init SimpleStmt + Cond Expr + Then *BlockStmt + stmt + } + SwitchStmt struct { Init SimpleStmt Tag Expr // incl. *TypeSwitchGuard diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index 1569b5e9872e1e..b51f0c2814060d 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -315,6 +315,8 @@ const stopset uint64 = 1<<_Break | 1<<_Defer | 1<<_Fallthrough | 1<<_For | + 1<<_Four | + 1<<_Unless | 1<<_Go | 1<<_Goto | 1<<_If | @@ -2290,6 +2292,36 @@ func (p *parser) forStmt() Stmt { return s } +func (p *parser) fourStmt() Stmt { + if trace { + defer p.trace("fourStmt")() + } + + s := new(FourStmt) + s.pos = p.pos() + + s.Init, s.Cond, s.Post = p.header(_Four) + s.Body = p.blockStmt("four clause") + + // Fdump(os.Stderr, s) + + return s +} + +func (p *parser) unlessStmt() *UnlessStmt { + if trace { + defer p.trace("unlessStmt")() + } + + s := new(UnlessStmt) + s.pos = p.pos() + + s.Init, s.Cond, _ = p.header(_Unless) + s.Then = p.blockStmt("unless clause") + + return s +} + func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleStmt) { p.want(keyword) @@ -2297,6 +2329,9 @@ func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleS if keyword == _If { p.syntaxError("missing condition in if statement") cond = p.badExpr() + } else if keyword == _Unless { + p.syntaxError("missing condition in unless statement") + cond = p.badExpr() } return } @@ -2350,6 +2385,21 @@ func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleS p.syntaxErrorAt(a.Pos(), "cannot declare in post statement of for loop") } } + } else if keyword == _Four { + if p.tok != _Semi { + if p.tok == _Lbrace { + p.syntaxError("expected four loop condition") + goto done + } + condStmt = p.simpleStmt(nil, 0 /* range not permitted */) + } + p.want(_Semi) + if p.tok != _Lbrace { + post = p.simpleStmt(nil, 0 /* range not permitted */) + if a, _ := post.(*AssignStmt); a != nil && a.Op == Def { + p.syntaxErrorAt(a.Pos(), "cannot declare in post statement of four loop") + } + } } else if p.tok != _Lbrace { condStmt = p.simpleStmt(nil, keyword) } @@ -2371,6 +2421,15 @@ done: b := new(BadExpr) b.pos = semi.pos cond = b + } else if keyword == _Unless && semi.pos.IsKnown() { + if semi.lit != "semicolon" { + p.syntaxErrorAt(semi.pos, fmt.Sprintf("unexpected %s, expected { after unless clause", semi.lit)) + } else { + p.syntaxErrorAt(semi.pos, "missing condition in unless statement") + } + b := new(BadExpr) + b.pos = semi.pos + cond = b } case *ExprStmt: cond = s.X @@ -2595,6 +2654,12 @@ func (p *parser) stmtOrNil() Stmt { case _For: return p.forStmt() + case _Four: + return p.fourStmt() + + case _Unless: + return p.unlessStmt() + case _Switch: return p.switchStmt() @@ -2655,7 +2720,6 @@ func (p *parser) stmtList() (l []Stmt) { if trace { defer p.trace("stmtList")() } - for p.tok != _EOF && p.tok != _Rbrace && p.tok != _Case && p.tok != _Default { s := p.stmtOrNil() p.clearPragma() diff --git a/src/cmd/compile/internal/syntax/scanner.go b/src/cmd/compile/internal/syntax/scanner.go index 807d8383866dcb..5836da84b2731e 100644 --- a/src/cmd/compile/internal/syntax/scanner.go +++ b/src/cmd/compile/internal/syntax/scanner.go @@ -421,7 +421,7 @@ func hash(s []byte) uint { return (uint(s[0])<<4 ^ uint(s[1]) + uint(len(s))) & uint(len(keywordMap)-1) } -var keywordMap [1 << 6]token // size must be power of two +var keywordMap [1 << 7]token // size must be power of two func init() { // populate keywordMap diff --git a/src/cmd/compile/internal/syntax/token_string.go b/src/cmd/compile/internal/syntax/token_string.go index ef295eb24b2bc9..f1f8a8398339e0 100644 --- a/src/cmd/compile/internal/syntax/token_string.go +++ b/src/cmd/compile/internal/syntax/token_string.go @@ -39,27 +39,29 @@ func _() { _ = x[_Else-29] _ = x[_Fallthrough-30] _ = x[_For-31] - _ = x[_Func-32] - _ = x[_Go-33] - _ = x[_Goto-34] - _ = x[_If-35] - _ = x[_Import-36] - _ = x[_Interface-37] - _ = x[_Map-38] - _ = x[_Package-39] - _ = x[_Range-40] - _ = x[_Return-41] - _ = x[_Select-42] - _ = x[_Struct-43] - _ = x[_Switch-44] - _ = x[_Type-45] - _ = x[_Var-46] - _ = x[tokenCount-47] + _ = x[_Four-32] + _ = x[_Unless-33] + _ = x[_Func-34] + _ = x[_Go-35] + _ = x[_Goto-36] + _ = x[_If-37] + _ = x[_Import-38] + _ = x[_Interface-39] + _ = x[_Map-40] + _ = x[_Package-41] + _ = x[_Range-42] + _ = x[_Return-43] + _ = x[_Select-44] + _ = x[_Struct-45] + _ = x[_Switch-46] + _ = x[_Type-47] + _ = x[_Var-48] + _ = x[tokenCount-49] } -const _token_name = "EOFnameliteralopop=opop=:=<-*([{)]},;:....breakcasechanconstcontinuedefaultdeferelsefallthroughforfuncgogotoifimportinterfacemappackagerangereturnselectstructswitchtypevar" +const _token_name = "EOFnameliteralopop=opop=:=<-*([{)]},;:....breakcasechanconstcontinuedefaultdeferelsefallthroughforfourunlessfuncgogotoifimportinterfacemappackagerangereturnselectstructswitchtypevar" -var _token_index = [...]uint8{0, 3, 7, 14, 16, 19, 23, 24, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 42, 47, 51, 55, 60, 68, 75, 80, 84, 95, 98, 102, 104, 108, 110, 116, 125, 128, 135, 140, 146, 152, 158, 164, 168, 171, 171} +var _token_index = [...]uint8{0, 3, 7, 14, 16, 19, 23, 24, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 42, 47, 51, 55, 60, 68, 75, 80, 84, 95, 98, 102, 108, 112, 114, 118, 120, 126, 135, 138, 145, 150, 156, 162, 168, 174, 178, 181, 181} func (i token) String() string { i -= 1 diff --git a/src/cmd/compile/internal/syntax/tokens.go b/src/cmd/compile/internal/syntax/tokens.go index b08f699582fb65..3ca311db411a7c 100644 --- a/src/cmd/compile/internal/syntax/tokens.go +++ b/src/cmd/compile/internal/syntax/tokens.go @@ -52,6 +52,8 @@ const ( _Else // else _Fallthrough // fallthrough _For // for + _Four // four + _Unless // unless _Func // func _Go // go _Goto // goto diff --git a/src/cmd/compile/internal/syntax/walk.go b/src/cmd/compile/internal/syntax/walk.go index b03a7c14b0d14e..83a1987f7db94d 100644 --- a/src/cmd/compile/internal/syntax/walk.go +++ b/src/cmd/compile/internal/syntax/walk.go @@ -273,6 +273,25 @@ func (w walker) node(n Node) { } w.node(n.Body) + case *FourStmt: + if n.Init != nil { + w.node(n.Init) + } + if n.Cond != nil { + w.node(n.Cond) + } + if n.Post != nil { + w.node(n.Post) + } + w.node(n.Body) + + case *UnlessStmt: + if n.Init != nil { + w.node(n.Init) + } + w.node(n.Cond) + w.node(n.Then) + case *SwitchStmt: if n.Init != nil { w.node(n.Init) diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go index 8d792485d863c4..9e4a4675620b9d 100644 --- a/src/cmd/compile/internal/typecheck/stmt.go +++ b/src/cmd/compile/internal/typecheck/stmt.go @@ -198,6 +198,35 @@ func tcFor(n *ir.ForStmt) ir.Node { return n } +func tcFour(n *ir.FourStmt) ir.Node { + Stmts(n.Init()) + n.Cond = Expr(n.Cond) + n.Cond = DefaultLit(n.Cond, nil) + if n.Cond != nil { + t := n.Cond.Type() + if t != nil && !t.IsBoolean() { + base.Errorf("non-bool %L used as four condition", n.Cond) + } + } + n.Post = Stmt(n.Post) + Stmts(n.Body) + return n +} + +func tcUnless(n *ir.UnlessStmt) ir.Node { + Stmts(n.Init()) + n.Cond = Expr(n.Cond) + n.Cond = DefaultLit(n.Cond, nil) + if n.Cond != nil { + t := n.Cond.Type() + if t != nil && !t.IsBoolean() { + base.Errorf("non-bool %L used as unless condition", n.Cond) + } + } + Stmts(n.Body) + return n +} + // tcGoDefer typechecks (normalizes) an OGO/ODEFER statement. func tcGoDefer(n *ir.GoDeferStmt) { call := normalizeGoDeferCall(n.Pos(), n.Op(), n.Call, n.PtrInit()) diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index b22e45358ea831..3935ce5e327621 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -550,6 +550,14 @@ func typecheck1(n ir.Node, top int) ir.Node { n := n.(*ir.ForStmt) return tcFor(n) + case ir.OFOUR: + n := n.(*ir.FourStmt) + return tcFour(n) + + case ir.OUNLESS: + n := n.(*ir.UnlessStmt) + return tcUnless(n) + case ir.OIF: n := n.(*ir.IfStmt) return tcIf(n) diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index c9713dac6fe7ff..281ef6adb15eaf 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -667,6 +667,41 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { } check.stmt(inner, s.Body) + case *syntax.FourStmt: + inner |= breakOk | continueOk + + check.openScope(s, "four") + defer check.closeScope() + + check.simpleStmt(s.Init) + if s.Cond != nil { + var x operand + check.expr(nil, &x, s.Cond) + if x.mode != invalid && !allBoolean(x.typ) { + check.error(s.Cond, InvalidCond, "non-boolean condition in four statement") + } + } + check.simpleStmt(s.Post) + // spec: "The init statement may be a short variable + // declaration, but the post statement must not." + if s, _ := s.Post.(*syntax.AssignStmt); s != nil && s.Op == syntax.Def { + // The parser already reported an error. + check.use(s.Lhs) // avoid follow-up errors + } + check.stmt(inner, s.Body) + + case *syntax.UnlessStmt: + check.openScope(s, "unless") + defer check.closeScope() + + check.simpleStmt(s.Init) + var x operand + check.expr(nil, &x, s.Cond) + if x.mode != invalid && !allBoolean(x.typ) { + check.error(s.Cond, InvalidCond, "non-boolean condition in unless statement") + } + check.stmt(inner, s.Then) + default: check.error(s, InvalidSyntaxTree, "invalid statement") } diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go index 179fbdb99e9872..070b920330369b 100644 --- a/src/cmd/compile/internal/walk/order.go +++ b/src/cmd/compile/internal/walk/order.go @@ -835,6 +835,23 @@ func (o *orderState) stmt(n ir.Node) { o.out = append(o.out, n) o.popTemp(t) + case ir.OFOUR: + n := n.(*ir.FourStmt) + t := o.markTemp() + n.Cond = o.exprInPlace(n.Cond) + orderBlock(&n.Body, o.free) + n.Post = orderStmtInPlace(n.Post, o.free) + o.out = append(o.out, n) + o.popTemp(t) + + case ir.OUNLESS: + n := n.(*ir.UnlessStmt) + t := o.markTemp() + n.Cond = o.exprInPlace(n.Cond) + o.popTemp(t) + orderBlock(&n.Body, o.free) + o.out = append(o.out, n) + // Clean temporaries from condition at // beginning of both branches. case ir.OIF: diff --git a/src/cmd/compile/internal/walk/stmt.go b/src/cmd/compile/internal/walk/stmt.go index b2a226e0789fbb..8c1d0420db9671 100644 --- a/src/cmd/compile/internal/walk/stmt.go +++ b/src/cmd/compile/internal/walk/stmt.go @@ -127,6 +127,14 @@ func walkStmt(n ir.Node) ir.Node { n := n.(*ir.ForStmt) return walkFor(n) + case ir.OFOUR: + n := n.(*ir.FourStmt) + return walkFour(n) + + case ir.OUNLESS: + n := n.(*ir.UnlessStmt) + return walkUnless(n) + case ir.OIF: n := n.(*ir.IfStmt) return walkIf(n) @@ -191,6 +199,25 @@ func walkFor(n *ir.ForStmt) ir.Node { return n } +func walkFour(n *ir.FourStmt) ir.Node { + if n.Cond != nil { + init := ir.TakeInit(n.Cond) + walkStmtList(init) + n.Cond = walkExpr(n.Cond, &init) + n.Cond = ir.InitExpr(init, n.Cond) + } + n.Post = walkStmt(n.Post) + walkStmtList(n.Body) + return n +} + +func walkUnless(n *ir.UnlessStmt) ir.Node { + n.Cond = walkExpr(n.Cond, n.PtrInit()) + n.Cond = ir.NewUnaryExpr(n.Pos(), ir.ONOT, n.Cond) + walkStmtList(n.Body) + return ir.NewIfStmt(n.Pos(), n.Cond, n.Body, []ir.Node{}) +} + // validGoDeferCall reports whether call is a valid call to appear in // a go or defer statement; that is, whether it's a regular function // call without arguments or results. diff --git a/src/internal/pkgbits/sync.go b/src/internal/pkgbits/sync.go index 1520b73afb9e96..39f8b367db4811 100644 --- a/src/internal/pkgbits/sync.go +++ b/src/internal/pkgbits/sync.go @@ -115,6 +115,8 @@ const ( SyncBlockStmt SyncIfStmt SyncForStmt + SyncFourStmt + SyncUnlessStmt SyncSwitchStmt SyncRangeStmt SyncCaseClause diff --git a/src/internal/pkgbits/syncmarker_string.go b/src/internal/pkgbits/syncmarker_string.go index 582ad56d3e09f3..a92256997e411e 100644 --- a/src/internal/pkgbits/syncmarker_string.go +++ b/src/internal/pkgbits/syncmarker_string.go @@ -60,28 +60,30 @@ func _() { _ = x[SyncBlockStmt-50] _ = x[SyncIfStmt-51] _ = x[SyncForStmt-52] - _ = x[SyncSwitchStmt-53] - _ = x[SyncRangeStmt-54] - _ = x[SyncCaseClause-55] - _ = x[SyncCommClause-56] - _ = x[SyncSelectStmt-57] - _ = x[SyncDecls-58] - _ = x[SyncLabeledStmt-59] - _ = x[SyncUseObjLocal-60] - _ = x[SyncAddLocal-61] - _ = x[SyncLinkname-62] - _ = x[SyncStmt1-63] - _ = x[SyncStmtsEnd-64] - _ = x[SyncLabel-65] - _ = x[SyncOptLabel-66] - _ = x[SyncMultiExpr-67] - _ = x[SyncRType-68] - _ = x[SyncConvRTTI-69] + _ = x[SyncFourStmt-53] + _ = x[SyncUnlessStmt-54] + _ = x[SyncSwitchStmt-55] + _ = x[SyncRangeStmt-56] + _ = x[SyncCaseClause-57] + _ = x[SyncCommClause-58] + _ = x[SyncSelectStmt-59] + _ = x[SyncDecls-60] + _ = x[SyncLabeledStmt-61] + _ = x[SyncUseObjLocal-62] + _ = x[SyncAddLocal-63] + _ = x[SyncLinkname-64] + _ = x[SyncStmt1-65] + _ = x[SyncStmtsEnd-66] + _ = x[SyncLabel-67] + _ = x[SyncOptLabel-68] + _ = x[SyncMultiExpr-69] + _ = x[SyncRType-70] + _ = x[SyncConvRTTI-71] } -const _SyncMarker_name = "EOFBoolInt64Uint64StringValueValRelocsRelocUseRelocPublicPosPosBaseObjectObject1PkgPkgDefMethodTypeTypeIdxTypeParamNamesSignatureParamsParamCodeObjSymLocalIdentSelectorPrivateFuncExtVarExtTypeExtPragmaExprListExprsExprExprTypeAssignOpFuncLitCompLitDeclFuncBodyOpenScopeCloseScopeCloseAnotherScopeDeclNamesDeclNameStmtsBlockStmtIfStmtForStmtSwitchStmtRangeStmtCaseClauseCommClauseSelectStmtDeclsLabeledStmtUseObjLocalAddLocalLinknameStmt1StmtsEndLabelOptLabelMultiExprRTypeConvRTTI" +const _SyncMarker_name = "EOFBoolInt64Uint64StringValueValRelocsRelocUseRelocPublicPosPosBaseObjectObject1PkgPkgDefMethodTypeTypeIdxTypeParamNamesSignatureParamsParamCodeObjSymLocalIdentSelectorPrivateFuncExtVarExtTypeExtPragmaExprListExprsExprExprTypeAssignOpFuncLitCompLitDeclFuncBodyOpenScopeCloseScopeCloseAnotherScopeDeclNamesDeclNameStmtsBlockStmtIfStmtForStmtFourStmtUnlessStmtSwitchStmtRangeStmtCaseClauseCommClauseSelectStmtDeclsLabeledStmtUseObjLocalAddLocalLinknameStmt1StmtsEndLabelOptLabelMultiExprRTypeConvRTTI" -var _SyncMarker_index = [...]uint16{0, 3, 7, 12, 18, 24, 29, 32, 38, 43, 51, 57, 60, 67, 73, 80, 83, 89, 95, 99, 106, 120, 129, 135, 140, 147, 150, 160, 168, 175, 182, 188, 195, 201, 209, 214, 218, 226, 232, 234, 241, 248, 252, 260, 269, 279, 296, 305, 313, 318, 327, 333, 340, 350, 359, 369, 379, 389, 394, 405, 416, 424, 432, 437, 445, 450, 458, 467, 472, 480} +var _SyncMarker_index = [...]uint16{0, 3, 7, 12, 18, 24, 29, 32, 38, 43, 51, 57, 60, 67, 73, 80, 83, 89, 95, 99, 106, 120, 129, 135, 140, 147, 150, 160, 168, 175, 182, 188, 195, 201, 209, 214, 218, 226, 232, 234, 241, 248, 252, 260, 269, 279, 296, 305, 313, 318, 327, 333, 340, 348, 358, 368, 377, 387, 397, 407, 412, 423, 434, 442, 450, 455, 463, 468, 476, 485, 490, 498} func (i SyncMarker) String() string { i -= 1 diff --git a/ssa.html b/ssa.html new file mode 100644 index 00000000000000..7c010a5b7f49eb --- /dev/null +++ b/ssa.html @@ -0,0 +1,722 @@ +
+ + + + + ++Click on a value or block to toggle highlighting of that value/block +and its uses. (Values and blocks are highlighted by ID, and IDs of +dead items may be reused, so not all highlights necessarily correspond +to the clicked item.) +
+ ++Faded out values and blocks are dead code that has not been eliminated. +
+ ++Values printed in italics have a dependency cycle. +
+ ++CFG: Dashed edge is for unlikely branches. Blue color is for backward edges. +Edge with a dot means that this edge follows the order in which blocks were laidout. +
+ +sources | sources
|
+AST | ASTbuildssa-body . DCL # demo3.go:16:7 . . NAME-main.i esc(no) Class:PAUTO Offset:0 OnStack Used int tc(1) # demo3.go:16:7 . AS Def tc(1) # demo3.go:16:9 . . NAME-main.i esc(no) Class:PAUTO Offset:0 OnStack Used int tc(1) # demo3.go:16:7 . . LITERAL-8 int tc(1) # demo3.go:16:12 . FOUR tc(1) # demo3.go:16:2 . FOUR-Cond . . LE bool tc(1) # demo3.go:16:17 . . . NAME-main.i esc(no) Class:PAUTO Offset:0 OnStack Used int tc(1) # demo3.go:16:7 . . . LITERAL-20 int tc(1) # demo3.go:16:20 . FOUR-Post . . BLOCK # demo3.go:16:25 . . BLOCK-List . . . AS tc(1) # demo3.go:16:25 . . . . NAME-main.i esc(no) Class:PAUTO Offset:0 OnStack Used int tc(1) # demo3.go:16:7 . . . . ADD int tc(1) # demo3.go:16:25 . . . . . NAME-main.i esc(no) Class:PAUTO Offset:0 OnStack Used int tc(1) # demo3.go:16:7 . . . . . LITERAL-1 int tc(1) # demo3.go:16:25 . FOUR-Body . . IF # demo3.go:17:3 . . IF-Cond . . . NOT # demo3.go:17:3 . . . . EQ bool tc(1) # demo3.go:17:14 . . . . . MOD int tc(1) # demo3.go:17:11 . . . . . . NAME-main.i esc(no) Class:PAUTO Offset:0 OnStack Used int tc(1) # demo3.go:16:7 . . . . . . LITERAL-8 int tc(1) # demo3.go:17:12 . . . . . LITERAL-0 int tc(1) # demo3.go:17:17 . . IF-Body . . . CALLFUNC Walked tc(1) # demo3.go:18:5 . . . CALLFUNC-Fun . . . . NAME-main.g Class:PFUNC Offset:0 Used FUNC-func() tc(1) # demo3.go:11:6 . . . CONTINUE tc(1) # demo3.go:19:4 . . CALLFUNC Walked tc(1) # demo3.go:21:4 . . CALLFUNC-Fun . . . NAME-main.f Class:PFUNC Offset:0 Used FUNC-func() tc(1) # demo3.go:7:6 |
+before insert phis | before insert phis |
+start | start |
+number lines | number lines [4100 ns] |
+early phielim | early phielim [1800 ns] |
+early copyelim | early copyelim [1000 ns] |
+early deadcode | early deadcode [5300 ns] |
+short circuit + decompose user + pre-opt deadcode + opt | short circuit [1100 ns]decompose user [500 ns]pre-opt deadcode [2500 ns]opt [18900 ns] |
+zero arg cse | zero arg cse [3300 ns] |
+opt deadcode | opt deadcode [3900 ns] |
+generic cse + phiopt + gcse deadcode + nilcheckelim + prove | generic cse [7100 ns]phiopt [700 ns]gcse deadcode [2200 ns]nilcheckelim [4300 ns]prove [41200 ns] |
+early fuse + expand calls | early fuse [500 ns]expand calls [3600 ns] |
+decompose builtin + softfloat + late opt | decompose builtin [5400 ns]softfloat [100 ns]late opt [5600 ns] |
+dead auto elim + sccp | dead auto elim [1900 ns]sccp [18100 ns] |
+generic deadcode | generic deadcode [4500 ns] |
+check bce + branchelim + late fuse | check bce [300 ns]branchelim [1000 ns]late fuse [1900 ns] |
+dse + memcombine + writebarrier + lower | dse [3200 ns]memcombine [1100 ns]writebarrier [1800 ns]lower [18900 ns] |
+addressing modes + late lower + lowered deadcode for cse + lowered cse + elim unread autos + tighten tuple selectors + lowered deadcode + checkLower + late phielim + late copyelim + tighten + late deadcode + critical + phi tighten + likelyadjust + layout | addressing modes [1200 ns]late lower [1400 ns]lowered deadcode for cse [2100 ns]lowered cse [2100 ns]elim unread autos [300 ns]tighten tuple selectors [1100 ns]lowered deadcode [1600 ns]checkLower [300 ns]late phielim [400 ns]late copyelim [500 ns]tighten [7900 ns]late deadcode [1300 ns]critical [900 ns]phi tighten [300 ns]likelyadjust [900 ns]layout [2800 ns] |
+schedule + late nilcheck + flagalloc + regalloc | schedule [6600 ns]late nilcheck [1700 ns]flagalloc [3100 ns]regalloc [37500 ns] |
+loop rotate | loop rotate [2200 ns] |
+trim | trim [400 ns] |
+genssa | genssa |
+