diff --git a/src/cmd/compile/internal/gc/op_string.go b/src/cmd/compile/internal/gc/op_string.go index fe80e39064d781..f45163aef79396 100644 --- a/src/cmd/compile/internal/gc/op_string.go +++ b/src/cmd/compile/internal/gc/op_string.go @@ -4,9 +4,9 @@ package gc import "strconv" -const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESASAS2AS2FUNCAS2RECVAS2MAPRAS2DOTTYPEASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASEXCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDDDDARGINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVEINDREGSPRETJMPGETGEND" +const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESASAS2AS2FUNCAS2RECVAS2MAPRAS2DOTTYPEASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASEXCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWUNREACHABLETCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDDDDARGINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVEINDREGSPINLMARKRETJMPGETGEND" -var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 70, 82, 91, 100, 112, 121, 123, 126, 133, 140, 147, 157, 161, 165, 173, 181, 190, 198, 201, 206, 213, 220, 226, 235, 243, 251, 257, 261, 270, 277, 281, 284, 291, 299, 307, 314, 320, 323, 329, 336, 344, 348, 355, 363, 365, 367, 369, 371, 373, 375, 380, 385, 393, 396, 405, 408, 412, 420, 427, 436, 439, 442, 445, 448, 451, 454, 460, 463, 466, 472, 476, 479, 483, 488, 493, 499, 504, 508, 513, 521, 529, 535, 544, 555, 562, 566, 573, 580, 588, 592, 596, 600, 607, 614, 622, 628, 633, 638, 642, 647, 655, 660, 665, 669, 672, 680, 684, 686, 691, 693, 698, 704, 710, 716, 722, 727, 731, 738, 744, 749, 755, 758, 764, 771, 776, 780, 785, 789, 799, 804, 812, 818, 825, 832, 840, 846, 850, 853} +var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 70, 82, 91, 100, 112, 121, 123, 126, 133, 140, 147, 157, 161, 165, 173, 181, 190, 198, 201, 206, 213, 220, 226, 235, 243, 251, 257, 261, 270, 277, 281, 284, 291, 299, 307, 314, 320, 323, 329, 336, 344, 348, 355, 363, 365, 367, 369, 371, 373, 375, 380, 385, 393, 396, 405, 408, 412, 420, 427, 436, 439, 442, 445, 448, 451, 454, 460, 463, 466, 472, 476, 479, 483, 488, 493, 499, 504, 508, 513, 521, 529, 535, 544, 555, 562, 566, 573, 580, 588, 592, 596, 600, 607, 614, 622, 628, 633, 638, 642, 647, 655, 660, 665, 669, 672, 680, 684, 686, 691, 693, 698, 704, 710, 716, 722, 733, 738, 742, 749, 755, 760, 766, 769, 775, 782, 787, 791, 796, 800, 810, 815, 823, 829, 836, 843, 851, 858, 864, 868, 871} func (i Op) String() string { if i >= Op(len(_Op_index)-1) { diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go index 4848a02bb6a8c4..fbdfa3cd575aa5 100644 --- a/src/cmd/compile/internal/gc/order.go +++ b/src/cmd/compile/internal/gc/order.go @@ -553,7 +553,7 @@ func (o *Order) stmt(n *Node) { default: Fatalf("orderstmt %v", n.Op) - case OVARKILL, OVARLIVE, OINLMARK: + case OVARKILL, OVARLIVE, OINLMARK, OUNREACHABLE: o.out = append(o.out, n) case OAS: diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 95904edd6a063d..fc647df6597cd2 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -804,6 +804,12 @@ func (s *state) stmt(n *Node) { // go through SSA. } } + case OUNREACHABLE: + m := s.mem() + b := s.endBlock() + b.Kind = ssa.BlockExit + b.Aux = "unreachable" // TODO: new block kind instead of this hack + b.SetControl(m) case ODEFER: s.call(n.Left, callDefer) case OGO: diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go index 5f07c6c52ad25e..b59116561ee325 100644 --- a/src/cmd/compile/internal/gc/syntax.go +++ b/src/cmd/compile/internal/gc/syntax.go @@ -728,6 +728,8 @@ const ( OSWITCH // switch Ninit; Left { List } (List is a list of OXCASE or OCASE) OTYPESW // Left = Right.(type) (appears as .Left of OSWITCH) + OUNREACHABLE // unsafe.Unreachable() + // types OTCHAN // chan int OTMAP // map[string]int diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 69ba9ef52a0412..0762b1ce0438b4 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -1405,6 +1405,13 @@ func typecheck1(n *Node, top int) (res *Node) { // any side effects disappear; ignore init setintconst(n, evalunsafe(n)) + case OUNREACHABLE: + ok |= ctxStmt + if !zeroargs(n, "unsafe.Unreachable") { + n.Type = nil + return n + } + case OCAP, OLEN: ok |= ctxExpr if !onearg(n, "%v", n.Op) { @@ -2369,6 +2376,14 @@ func implicitstar(n *Node) *Node { return n } +func zeroargs(n *Node, f string) bool { + if n.List.Len() != 0 { + yyerror("too many arguments to %s: %v", f, n) + return false + } + return true +} + func onearg(n *Node, f string, args ...interface{}) bool { if n.Left != nil { return true diff --git a/src/cmd/compile/internal/gc/universe.go b/src/cmd/compile/internal/gc/universe.go index 104c6bab23d328..f3fdff58892995 100644 --- a/src/cmd/compile/internal/gc/universe.go +++ b/src/cmd/compile/internal/gc/universe.go @@ -83,6 +83,7 @@ var unsafeFuncs = [...]struct { {"Alignof", OALIGNOF}, {"Offsetof", OOFFSETOF}, {"Sizeof", OSIZEOF}, + {"Unreachable", OUNREACHABLE}, } // initUniverse initializes the universe block. diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 41a9d8e9dcc470..55f6b2e7d1c511 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -122,12 +122,12 @@ func walkstmt(n *Node) *Node { switch n.Op { default: + Dump("nottop", n) if n.Op == ONAME { - yyerror("%v is not a top level statement", n.Sym) + Fatalf("%v is not a top level statement", n.Sym) } else { - yyerror("%v is not a top level statement", n.Op) + Fatalf("%v is not a top level statement", n.Op) } - Dump("nottop", n) case OAS, OASOP, @@ -187,7 +187,8 @@ func walkstmt(n *Node) *Node { OCHECKNIL, OVARDEF, OVARKILL, - OVARLIVE: + OVARLIVE, + OUNREACHABLE: break case ODCL: diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index 38f12abf1858cf..066f089e9fa072 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -393,6 +393,7 @@ var passes = [...]pass{ {name: "phiopt", fn: phiopt}, {name: "nilcheckelim", fn: nilcheckelim}, {name: "prove", fn: prove}, + {name: "unreachable", fn: unreachable}, // TODO: is this in the right place? TODO: flag to disable? {name: "fuse plain", fn: fusePlain}, {name: "decompose builtin", fn: decomposeBuiltIn, required: true}, {name: "softfloat", fn: softfloat, required: true}, @@ -447,6 +448,8 @@ var passOrder = [...]constraint{ {"generic cse", "prove"}, // deadcode after prove to eliminate all new dead blocks. {"prove", "generic deadcode"}, + // unreachable after prove so that prove can use unreachability information + {"prove", "unreachable"}, // common-subexpression before dead-store elim, so that we recognize // when two address expressions are the same. {"generic cse", "dse"}, diff --git a/src/cmd/compile/internal/ssa/unreachable.go b/src/cmd/compile/internal/ssa/unreachable.go new file mode 100644 index 00000000000000..e2eaa7a1f01486 --- /dev/null +++ b/src/cmd/compile/internal/ssa/unreachable.go @@ -0,0 +1,46 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssa + +// unreachable removes blocks generated by unsafe.Unreachable. +func unreachable(f *Func) { + // if os.Getenv("J") == "" { + // return + // } + changed := false + for _, b := range f.Blocks { + // TODO: this is a hack. + // We should probably explicitly represent unsafe.Unreachable + // with its own block kind. + if b.Aux != "unreachable" { + continue + } + if b == f.Entry { + // TODO: what here? + continue + } + for _, e := range b.Preds { + p := e.b + if len(p.Succs) != 2 { + // TODO: is this possible? if so, handle. + continue + } + p.removeSucc(e.i) + p.Kind = BlockPlain + p.Likely = BranchUnknown + p.SetControl(nil) + + // trash b, just in case + b.Kind = BlockInvalid + b.Values = nil + b.Preds = nil + b.Succs = nil + changed = true + } + } + if changed { + f.invalidateCFG() + } +} diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index ece6d4f530cfe5..029b064a03af4c 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -586,6 +586,9 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b x.typ = Typ[Uintptr] // result is constant - no need to record signature + case _Unreachable: + x.mode = novalue + case _Sizeof: // unsafe.Sizeof(x T) uintptr check.assignment(x, nil, "argument to unsafe.Sizeof") diff --git a/src/go/types/universe.go b/src/go/types/universe.go index 7af6dab320edd1..1e53032e92d4f8 100644 --- a/src/go/types/universe.go +++ b/src/go/types/universe.go @@ -130,6 +130,7 @@ const ( _Alignof _Offsetof _Sizeof + _Unreachable // testing support _Assert @@ -158,9 +159,10 @@ var predeclaredFuncs = [...]struct { _Real: {"real", 1, false, expression}, _Recover: {"recover", 0, false, statement}, - _Alignof: {"Alignof", 1, false, expression}, - _Offsetof: {"Offsetof", 1, false, expression}, - _Sizeof: {"Sizeof", 1, false, expression}, + _Alignof: {"Alignof", 1, false, expression}, + _Offsetof: {"Offsetof", 1, false, expression}, + _Sizeof: {"Sizeof", 1, false, expression}, + _Unreachable: {"Unreachable", 0, false, statement}, _Assert: {"assert", 1, false, statement}, _Trace: {"trace", 0, true, statement},