]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/cmd/compile/internal/inline/inlheur/analyze_func_flags.go
cmd/compile/internal/inline: fix buglet in panic path scoring
[gostls13.git] / src / cmd / compile / internal / inline / inlheur / analyze_func_flags.go
index 41c31a4607c956307d680612ac76c4f37ec22afe..588d2f4f598da746371bced9e863b11f1fb503e9 100644 (file)
@@ -40,8 +40,8 @@ func makeFuncFlagsAnalyzer(fn *ir.Func) *funcFlagsAnalyzer {
        }
 }
 
-// setResults transfers func flag results to 'fp'.
-func (ffa *funcFlagsAnalyzer) setResults(fp *FuncProps) {
+// setResults transfers func flag results to 'funcProps'.
+func (ffa *funcFlagsAnalyzer) setResults(funcProps *FuncProps) {
        var rv FuncPropBits
        if !ffa.noInfo && ffa.stateForList(ffa.fn.Body) == psCallsPanic {
                rv = FuncPropNeverReturns
@@ -63,7 +63,7 @@ func (ffa *funcFlagsAnalyzer) setResults(fp *FuncProps) {
        if isMainMain(ffa.fn) {
                rv &^= FuncPropNeverReturns
        }
-       fp.Flags = rv
+       funcProps.Flags = rv
 }
 
 func (ffa *funcFlagsAnalyzer) getstate(n ir.Node) pstate {
@@ -82,10 +82,22 @@ func (ffa *funcFlagsAnalyzer) setstate(n ir.Node, st pstate) {
        }
 }
 
+func (ffa *funcFlagsAnalyzer) updatestate(n ir.Node, st pstate) {
+       if _, ok := ffa.nstate[n]; !ok {
+               base.Fatalf("funcFlagsAnalyzer: fn %q internal error, expected existing setting for node:\n%+v\n", ffa.fn.Sym().Name, n)
+       } else {
+               ffa.nstate[n] = st
+       }
+}
+
 func (ffa *funcFlagsAnalyzer) setstateSoft(n ir.Node, st pstate) {
        ffa.nstate[n] = st
 }
 
+func (ffa *funcFlagsAnalyzer) panicPathTable() map[ir.Node]pstate {
+       return ffa.nstate
+}
+
 // blockCombine merges together states as part of a linear sequence of
 // statements, where 'pred' and 'succ' are analysis results for a pair
 // of consecutive statements. Examples:
@@ -132,17 +144,33 @@ func branchCombine(p1, p2 pstate) pstate {
 }
 
 // stateForList walks through a list of statements and computes the
-// state/diposition for the entire list as a whole.
+// state/diposition for the entire list as a whole, as well
+// as updating disposition of intermediate nodes.
 func (ffa *funcFlagsAnalyzer) stateForList(list ir.Nodes) pstate {
        st := psTop
-       for i := range list {
+       // Walk the list backwards so that we can update the state for
+       // earlier list elements based on what we find out about their
+       // successors. Example:
+       //
+       //        if ... {
+       //  L10:    foo()
+       //  L11:    <stmt>
+       //  L12:    panic(...)
+       //        }
+       //
+       // After combining the dispositions for line 11 and 12, we want to
+       // update the state for the call at line 10 based on that combined
+       // disposition (if L11 has no path to "return", then the call at
+       // line 10 will be on a panic path).
+       for i := len(list) - 1; i >= 0; i-- {
                n := list[i]
                psi := ffa.getstate(n)
                if debugTrace&debugTraceFuncFlags != 0 {
                        fmt.Fprintf(os.Stderr, "=-= %v: stateForList n=%s ps=%s\n",
                                ir.Line(n), n.Op().String(), psi.String())
                }
-               st = blockCombine(st, psi)
+               st = blockCombine(psi, st)
+               ffa.updatestate(n, st)
        }
        if st == psTop {
                st = psNoInfo
@@ -166,7 +194,7 @@ func isExitCall(n ir.Node) bool {
                return false
        }
        cx := n.(*ir.CallExpr)
-       name := ir.StaticCalleeName(cx.X)
+       name := ir.StaticCalleeName(cx.Fun)
        if name == nil {
                return false
        }
@@ -175,10 +203,12 @@ func isExitCall(n ir.Node) bool {
                isWellKnownFunc(s, "runtime", "throw") {
                return true
        }
-       // FIXME: consult results of flags computation for
-       // previously analyzed Go functions, including props
-       // read from export data for functions in other packages.
-       return false
+       if funcProps := propsForFunc(name.Func); funcProps != nil {
+               if funcProps.Flags&FuncPropNeverReturns != 0 {
+                       return true
+               }
+       }
+       return name.Func.NeverReturns()
 }
 
 // pessimize is called to record the fact that we saw something in the
@@ -314,7 +344,7 @@ func (ffa *funcFlagsAnalyzer) nodeVisitPost(n ir.Node) {
        case ir.OFALL:
                // Not important.
        case ir.ODCLFUNC, ir.ORECOVER, ir.OAS, ir.OAS2, ir.OAS2FUNC, ir.OASOP,
-               ir.OPRINTN, ir.OPRINT, ir.OLABEL, ir.OCALLINTER, ir.ODEFER,
+               ir.OPRINTLN, ir.OPRINT, ir.OLABEL, ir.OCALLINTER, ir.ODEFER,
                ir.OSEND, ir.ORECV, ir.OSELRECV2, ir.OGO, ir.OAPPEND, ir.OAS2DOTTYPE,
                ir.OAS2MAPR, ir.OGETG, ir.ODELETE, ir.OINLMARK, ir.OAS2RECV,
                ir.OMIN, ir.OMAX, ir.OMAKE, ir.ORECOVERFP, ir.OGETCALLERSP: