Файловый менеджер - Редактировать - /usr/local/go/src/cmd/compile/internal/inline/inlheur/analyze_func_returns.go
Ðазад
// Copyright 2023 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 inlheur import ( "cmd/compile/internal/ir" "fmt" "go/constant" "go/token" "os" ) // resultsAnalyzer stores state information for the process of // computing flags/properties for the return values of a specific Go // function, as part of inline heuristics synthesis. type resultsAnalyzer struct { fname string props []ResultPropBits values []resultVal inlineMaxBudget int *nameFinder } // resultVal captures information about a specific result returned from // the function we're analyzing; we are interested in cases where // the func always returns the same constant, or always returns // the same function, etc. This container stores info on a the specific // scenarios we're looking for. type resultVal struct { cval constant.Value fn *ir.Name fnClo bool top bool derived bool // see deriveReturnFlagsFromCallee below } // addResultsAnalyzer creates a new resultsAnalyzer helper object for // the function fn, appends it to the analyzers list, and returns the // new list. If the function in question doesn't have any returns (or // any interesting returns) then the analyzer list is left as is, and // the result flags in "fp" are updated accordingly. func addResultsAnalyzer(fn *ir.Func, analyzers []propAnalyzer, fp *FuncProps, inlineMaxBudget int, nf *nameFinder) []propAnalyzer { ra, props := makeResultsAnalyzer(fn, inlineMaxBudget, nf) if ra != nil { analyzers = append(analyzers, ra) } else { fp.ResultFlags = props } return analyzers } // makeResultsAnalyzer creates a new helper object to analyze results // in function fn. If the function doesn't have any interesting // results, a nil helper is returned along with a set of default // result flags for the func. func makeResultsAnalyzer(fn *ir.Func, inlineMaxBudget int, nf *nameFinder) (*resultsAnalyzer, []ResultPropBits) { results := fn.Type().Results() if len(results) == 0 { return nil, nil } props := make([]ResultPropBits, len(results)) if fn.Inl == nil { return nil, props } vals := make([]resultVal, len(results)) interestingToAnalyze := false for i := range results { rt := results[i].Type if !rt.IsScalar() && !rt.HasNil() { // existing properties not applicable here (for things // like structs, arrays, slices, etc). continue } // set the "top" flag (as in "top element of data flow lattice") // meaning "we have no info yet, but we might later on". vals[i].top = true interestingToAnalyze = true } if !interestingToAnalyze { return nil, props } ra := &resultsAnalyzer{ props: props, values: vals, inlineMaxBudget: inlineMaxBudget, nameFinder: nf, } return ra, nil } // setResults transfers the calculated result properties for this // function to 'funcProps'. func (ra *resultsAnalyzer) setResults(funcProps *FuncProps) { // Promote ResultAlwaysSameFunc to ResultAlwaysSameInlinableFunc for i := range ra.values { if ra.props[i] == ResultAlwaysSameFunc && !ra.values[i].derived { f := ra.values[i].fn.Func // HACK: in order to allow for call site score // adjustments, we used a relaxed inline budget in // determining inlinability. For the check below, however, // we want to know is whether the func in question is // likely to be inlined, as opposed to whether it might // possibly be inlined if all the right score adjustments // happened, so do a simple check based on the cost. if f.Inl != nil && f.Inl.Cost <= int32(ra.inlineMaxBudget) { ra.props[i] = ResultAlwaysSameInlinableFunc } } } funcProps.ResultFlags = ra.props } func (ra *resultsAnalyzer) pessimize() { for i := range ra.props { ra.props[i] = ResultNoInfo } } func (ra *resultsAnalyzer) nodeVisitPre(n ir.Node) { } func (ra *resultsAnalyzer) nodeVisitPost(n ir.Node) { if len(ra.values) == 0 { return } if n.Op() != ir.ORETURN { return } if debugTrace&debugTraceResults != 0 { fmt.Fprintf(os.Stderr, "=+= returns nodevis %v %s\n", ir.Line(n), n.Op().String()) } // No support currently for named results, so if we see an empty // "return" stmt, be conservative. rs := n.(*ir.ReturnStmt) if len(rs.Results) != len(ra.values) { ra.pessimize() return } for i, r := range rs.Results { ra.analyzeResult(i, r) } } // analyzeResult examines the expression 'n' being returned as the // 'ii'th argument in some return statement to see whether has // interesting characteristics (for example, returns a constant), then // applies a dataflow "meet" operation to combine this result with any // previous result (for the given return slot) that we've already // processed. func (ra *resultsAnalyzer) analyzeResult(ii int, n ir.Node) { isAllocMem := ra.isAllocatedMem(n) isConcConvItf := ra.isConcreteConvIface(n) constVal := ra.constValue(n) isConst := (constVal != nil) isNil := ra.isNil(n) rfunc := ra.funcName(n) isFunc := (rfunc != nil) isClo := (rfunc != nil && rfunc.Func.OClosure != nil) curp := ra.props[ii] dprops, isDerivedFromCall := ra.deriveReturnFlagsFromCallee(n) newp := ResultNoInfo var newcval constant.Value var newfunc *ir.Name if debugTrace&debugTraceResults != 0 { fmt.Fprintf(os.Stderr, "=-= %v: analyzeResult n=%s ismem=%v isconcconv=%v isconst=%v isnil=%v isfunc=%v isclo=%v\n", ir.Line(n), n.Op().String(), isAllocMem, isConcConvItf, isConst, isNil, isFunc, isClo) } if ra.values[ii].top { ra.values[ii].top = false // this is the first return we've seen; record // whatever properties it has. switch { case isAllocMem: newp = ResultIsAllocatedMem case isConcConvItf: newp = ResultIsConcreteTypeConvertedToInterface case isFunc: newp = ResultAlwaysSameFunc newfunc = rfunc case isConst: newp = ResultAlwaysSameConstant newcval = constVal case isNil: newp = ResultAlwaysSameConstant newcval = nil case isDerivedFromCall: newp = dprops ra.values[ii].derived = true } } else { if !ra.values[ii].derived { // this is not the first return we've seen; apply // what amounts of a "meet" operator to combine // the properties we see here with what we saw on // the previous returns. switch curp { case ResultIsAllocatedMem: if isAllocMem { newp = ResultIsAllocatedMem } case ResultIsConcreteTypeConvertedToInterface: if isConcConvItf { newp = ResultIsConcreteTypeConvertedToInterface } case ResultAlwaysSameConstant: if isNil && ra.values[ii].cval == nil { newp = ResultAlwaysSameConstant newcval = nil } else if isConst && constant.Compare(constVal, token.EQL, ra.values[ii].cval) { newp = ResultAlwaysSameConstant newcval = constVal } case ResultAlwaysSameFunc: if isFunc && isSameFuncName(rfunc, ra.values[ii].fn) { newp = ResultAlwaysSameFunc newfunc = rfunc } } } } ra.values[ii].fn = newfunc ra.values[ii].fnClo = isClo ra.values[ii].cval = newcval ra.props[ii] = newp if debugTrace&debugTraceResults != 0 { fmt.Fprintf(os.Stderr, "=-= %v: analyzeResult newp=%s\n", ir.Line(n), newp) } } // deriveReturnFlagsFromCallee tries to set properties for a given // return result where we're returning call expression; return value // is a return property value and a boolean indicating whether the // prop is valid. Examples: // // func foo() int { return bar() } // func bar() int { return 42 } // func blix() int { return 43 } // func two(y int) int { // if y < 0 { return bar() } else { return blix() } // } // // Since "foo" always returns the result of a call to "bar", we can // set foo's return property to that of bar. In the case of "two", however, // even though each return path returns a constant, we don't know // whether the constants are identical, hence we need to be conservative. func (ra *resultsAnalyzer) deriveReturnFlagsFromCallee(n ir.Node) (ResultPropBits, bool) { if n.Op() != ir.OCALLFUNC { return 0, false } ce := n.(*ir.CallExpr) if ce.Fun.Op() != ir.ONAME { return 0, false } called := ir.StaticValue(ce.Fun) if called.Op() != ir.ONAME { return 0, false } cname := ra.funcName(called) if cname == nil { return 0, false } calleeProps := propsForFunc(cname.Func) if calleeProps == nil { return 0, false } if len(calleeProps.ResultFlags) != 1 { return 0, false } return calleeProps.ResultFlags[0], true }
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0 |
proxy
|
phpinfo
|
ÐаÑтройка