Constants & Variables
ActualExprConstant
const
#
const ActualExprConstant ActualExprPropBits = *ast.BinaryExpr
ActualExprIsConcreteConvIface
const
#
const ActualExprIsConcreteConvIface
ActualExprIsFunc
const
#
const ActualExprIsFunc
ActualExprIsInlinableFunc
const
#
const ActualExprIsInlinableFunc
CallSiteInInitFunc
const
#
const CallSiteInInitFunc
CallSiteInLoop
const
#
const CallSiteInLoop CSPropBits = *ast.BinaryExpr
CallSiteOnPanicPath
const
#
const CallSiteOnPanicPath
FuncPropNeverReturns
const
#
const FuncPropNeverReturns FuncPropBits = *ast.BinaryExpr
ParamFeedsIfOrSwitch
const
#
const ParamFeedsIfOrSwitch
ParamFeedsIndirectCall
const
#
const ParamFeedsIndirectCall
ParamFeedsInterfaceMethodCall
const
#
const ParamFeedsInterfaceMethodCall ParamPropBits = *ast.BinaryExpr
ParamMayFeedIfOrSwitch
const
#
const ParamMayFeedIfOrSwitch
ParamMayFeedIndirectCall
const
#
const ParamMayFeedIndirectCall
ParamMayFeedInterfaceMethodCall
const
#
const ParamMayFeedInterfaceMethodCall ParamPropBits = *ast.BinaryExpr
ParamNoInfo
const
#
const ParamNoInfo ParamPropBits = 0
ResultAlwaysSameConstant
const
#
const ResultAlwaysSameConstant
ResultAlwaysSameFunc
const
#
const ResultAlwaysSameFunc
ResultAlwaysSameInlinableFunc
const
#
const ResultAlwaysSameInlinableFunc
ResultIsAllocatedMem
const
#
const ResultIsAllocatedMem ResultPropBits = *ast.BinaryExpr
ResultIsConcreteTypeConvertedToInterface
const
#
const ResultIsConcreteTypeConvertedToInterface
ResultNoInfo
const
#
const ResultNoInfo ResultPropBits = 0
_ActualExprPropBits_index
var
#
var _ActualExprPropBits_index = [...]uint8{...}
_ActualExprPropBits_name
const
#
const _ActualExprPropBits_name = "ActualExprConstantActualExprIsConcreteConvIfaceActualExprIsFuncActualExprIsInlinableFunc"
_ActualExprPropBits_value
var
#
var _ActualExprPropBits_value = [...]uint64{...}
_CSPropBits_index
var
#
var _CSPropBits_index = [...]uint8{...}
_CSPropBits_name
const
#
const _CSPropBits_name = "CallSiteInLoopCallSiteOnPanicPathCallSiteInInitFunc"
_CSPropBits_value
var
#
var _CSPropBits_value = [...]uint64{...}
_FuncPropBits_index
var
#
var _FuncPropBits_index = [...]uint8{...}
_FuncPropBits_name
const
#
const _FuncPropBits_name = "FuncPropNeverReturns"
_FuncPropBits_value
var
#
var _FuncPropBits_value = [...]uint64{...}
_ParamPropBits_index
var
#
var _ParamPropBits_index = [...]uint8{...}
_ParamPropBits_name
const
#
const _ParamPropBits_name = "ParamNoInfoParamFeedsInterfaceMethodCallParamMayFeedInterfaceMethodCallParamFeedsIndirectCallParamMayFeedIndirectCallParamFeedsIfOrSwitchParamMayFeedIfOrSwitch"
_ParamPropBits_value
var
#
var _ParamPropBits_value = [...]uint64{...}
_ResultPropBits_index
var
#
var _ResultPropBits_index = [...]uint8{...}
_ResultPropBits_name
const
#
const _ResultPropBits_name = "ResultNoInfoResultIsAllocatedMemResultIsConcreteTypeConvertedToInterfaceResultAlwaysSameConstantResultAlwaysSameFuncResultAlwaysSameInlinableFunc"
_ResultPropBits_value
var
#
var _ResultPropBits_value = [...]uint64{...}
_pstate_index
var
#
var _pstate_index = [...]uint8{...}
_pstate_name
const
#
const _pstate_name = "psNoInfopsCallsPanicpsMayReturnpsTop"
_scoreAdjustTyp_index
var
#
var _scoreAdjustTyp_index = [...]uint16{...}
_scoreAdjustTyp_name
const
#
const _scoreAdjustTyp_name = "panicPathAdjinitFuncAdjinLoopAdjpassConstToIfAdjpassConstToNestedIfAdjpassConcreteToItfCallAdjpassConcreteToNestedItfCallAdjpassFuncToIndCallAdjpassFuncToNestedIndCallAdjpassInlinableFuncToIndCallAdjpassInlinableFuncToNestedIndCallAdjreturnFeedsConstToIfAdjreturnFeedsFuncToIndCallAdjreturnFeedsInlinableFuncToIndCallAdjreturnFeedsConcreteToInterfaceCallAdj"
_scoreAdjustTyp_value
var
#
var _scoreAdjustTyp_value = [...]uint64{...}
adjValues
var
#
var adjValues = map[scoreAdjustTyp]int{...}
allCallSites
var
#
var allCallSites CallSiteTab
callSiteTab
var
#
var callSiteTab CallSiteTab
comDelimiter
const
#
const comDelimiter = ""
csAuxInlined
const
#
const csAuxInlined = *ast.BinaryExpr
csDelimiter
const
#
const csDelimiter = ""
debugTrace
var
#
var debugTrace = 0
debugTrace
const
#
const debugTrace = 0
debugTraceCalls
const
#
const debugTraceCalls
debugTraceExprClassify
const
#
const debugTraceExprClassify
debugTraceFuncFlags
const
#
const debugTraceFuncFlags
debugTraceFuncs
const
#
const debugTraceFuncs = *ast.BinaryExpr
debugTraceParams
const
#
const debugTraceParams
debugTraceResults
const
#
const debugTraceResults
debugTraceScoring
const
#
const debugTraceScoring
dumpBuffer
var
#
var dumpBuffer map[*ir.Func]fnInlHeur
exprLiterals
const
#
const exprLiterals
exprNoInfo
const
#
const exprNoInfo disp = iota
exprSimple
const
#
const exprSimple
fnDelimiter
const
#
const fnDelimiter = ""
fpmap
var
#
var fpmap = map[*ir.Func]fnInlHeur{...}
inLoopAdj
const
#
const inLoopAdj
initFuncAdj
const
#
const initFuncAdj
mayMustAdj
var
#
var mayMustAdj = [...]struct{...}{...}
panicPathAdj
const
#
const panicPathAdj scoreAdjustTyp = *ast.ParenExpr
paramFlagToPositiveAdj
var
#
var paramFlagToPositiveAdj map[ParamPropBits]scoreAdjustTyp
passConcreteToItfCallAdj
const
#
const passConcreteToItfCallAdj
passConcreteToNestedItfCallAdj
const
#
const passConcreteToNestedItfCallAdj
passConstToIfAdj
const
#
const passConstToIfAdj
passConstToNestedIfAdj
const
#
const passConstToNestedIfAdj
passFuncToIndCallAdj
const
#
const passFuncToIndCallAdj
passFuncToNestedIndCallAdj
const
#
const passFuncToNestedIndCallAdj
passInlinableFuncToIndCallAdj
const
#
const passInlinableFuncToIndCallAdj
passInlinableFuncToNestedIndCallAdj
const
#
const passInlinableFuncToNestedIndCallAdj
preambleDelimiter
const
#
const preambleDelimiter = ""
psCallsPanic
const
#
const psCallsPanic
psMayReturn
const
#
const psMayReturn
psNoInfo
const
#
const psNoInfo pstate = iota
psTop
const
#
const psTop
resultFlagToPositiveAdj
var
#
var resultFlagToPositiveAdj map[ResultPropBits]scoreAdjustTyp
returnFeedsConcreteToInterfaceCallAdj
const
#
const returnFeedsConcreteToInterfaceCallAdj
returnFeedsConstToIfAdj
const
#
const returnFeedsConstToIfAdj
returnFeedsFuncToIndCallAdj
const
#
const returnFeedsFuncToIndCallAdj
returnFeedsInlinableFuncToIndCallAdj
const
#
const returnFeedsInlinableFuncToIndCallAdj
scoreCallsCache
var
#
var scoreCallsCache scoreCallsCacheType
sentinelScoreAdj
const
#
const sentinelScoreAdj
Functions
AnalyzeFunc
function
#
AnalyzeFunc computes function properties for fn and its contained
closures, updating the global 'fpmap' table. It is assumed that
"CanInline" has been run on fn and on the closures that feed
directly into calls; other closures not directly called will also
be checked inlinability for inlinability here in case they are
returned as a result.
func AnalyzeFunc(fn *ir.Func, canInline func(*ir.Func), budgetForFunc func(*ir.Func) int32, inlineMaxBudget int)
BudgetExpansion
function
#
BudgetExpansion returns the amount to relax/expand the base
inlining budget when the new inliner is turned on; the inliner
will add the returned value to the hairiness budget.
Background: with the new inliner, the score for a given callsite
can be adjusted down by some amount due to heuristics, however we
won't know whether this is going to happen until much later after
the CanInline call. This function returns the amount to relax the
budget initially (to allow for a large score adjustment); later on
in RevisitInlinability we'll look at each individual function to
demote it if needed.
func BudgetExpansion(maxBudget int32) int32
DeserializeFromString
function
#
func DeserializeFromString(s string) *FuncProps
DumpFuncProps
function
#
DumpFuncProps computes and caches function properties for the func
'fn', writing out a description of the previously computed set of
properties to the file given in 'dumpfile'. Used for the
"-d=dumpinlfuncprops=..." command line flag, intended for use
primarily in unit testing.
func DumpFuncProps(fn *ir.Func, dumpfile string)
DumpInlCallSiteScores
function
#
DumpInlCallSiteScores is invoked by the inliner if the debug flag
"-d=dumpinlcallsitescores" is set; it dumps out a human-readable
summary of all (potentially) inlinable callsites in the package,
along with info on call site scoring and the adjustments made to a
given score. Here profile is the PGO profile in use (may be
nil), budgetCallback is a callback that can be invoked to find out
the original pre-adjustment hairiness limit for the function, and
inlineHotMaxBudget is the constant of the same name used in the
inliner. Sample output lines:
Score Adjustment Status Callee CallerPos ScoreFlags
115 40 DEMOTED cmd/compile/internal/abi.(*ABIParamAssignment).Offset expand_calls.go:1679:14|6 panicPathAdj
76 -5n PROMOTED runtime.persistentalloc mcheckmark.go:48:45|3 inLoopAdj
201 0 --- PGO unicode.DecodeRuneInString utf8.go:312:30|1
7 -5 --- PGO internal/abi.Name.DataChecked type.go:625:22|0 inLoopAdj
In the dump above, "Score" is the final score calculated for the
callsite, "Adjustment" is the amount added to or subtracted from
the original hairiness estimate to form the score. "Status" shows
whether anything changed with the site -- did the adjustment bump
it down just below the threshold ("PROMOTED") or instead bump it
above the threshold ("DEMOTED"); this will be blank ("---") if no
threshold was crossed as a result of the heuristics. Note that
"Status" also shows whether PGO was involved. "Callee" is the name
of the function called, "CallerPos" is the position of the
callsite, and "ScoreFlags" is a digest of the specific properties
we used to make adjustments to callsite score via heuristics.
func DumpInlCallSiteScores(profile *pgoir.Profile, budgetCallback func(fn *ir.Func, profile *pgoir.Profile) (int32, bool))
Enabled
function
#
func Enabled() bool
EncodeCallSiteKey
function
#
func EncodeCallSiteKey(cs *CallSite) string
GetCallSiteScore
function
#
GetCallSiteScore returns the previously calculated score for call
within fn.
func GetCallSiteScore(fn *ir.Func, call *ir.CallExpr) (int, bool)
LargestNegativeScoreAdjustment
function
#
LargestNegativeScoreAdjustment tries to estimate the largest possible
negative score adjustment that could be applied to a call of the
function with the specified props. Example:
func foo() { func bar(x int, p *int) int {
... if x < 0 { *p = x }
} return 99
}
Function 'foo' above on the left has no interesting properties,
thus as a result the most we'll adjust any call to is the value for
"call in loop". If the calculated cost of the function is 150, and
the in-loop adjustment is 5 (for example), then there is not much
point treating it as inlinable. On the other hand "bar" has a param
property (parameter "x" feeds unmodified to an "if" statement) and
a return property (always returns same constant) meaning that a
given call _could_ be rescored down as much as -35 points-- thus if
the size of "bar" is 100 (for example) then there is at least a
chance that scoring will enable inlining.
func LargestNegativeScoreAdjustment(fn *ir.Func, props *FuncProps) int
LargestPositiveScoreAdjustment
function
#
LargestPositiveScoreAdjustment tries to estimate the largest possible
positive score adjustment that could be applied to a given callsite.
At the moment we don't have very many positive score adjustments, so
this is just hard-coded, not table-driven.
func LargestPositiveScoreAdjustment(fn *ir.Func) int
ScoreCalls
function
#
ScoreCalls assigns numeric scores to each of the callsites in
function 'fn'; the lower the score, the more helpful we think it
will be to inline.
Unlike a lot of the other inline heuristics machinery, callsite
scoring can't be done as part of the CanInline call for a function,
due to fact that we may be working on a non-trivial SCC. So for
example with this SCC:
func foo(x int) { func bar(x int, f func()) {
if x != 0 { f()
bar(x, func(){}) foo(x-1)
} }
}
We don't want to perform scoring for the 'foo' call in "bar" until
after foo has been analyzed, but it's conceivable that CanInline
might visit bar before foo for this SCC.
func ScoreCalls(fn *ir.Func)
ScoreCallsCleanup
function
#
ScoreCallsCleanup resets the state of the callsite cache
once ScoreCalls is done with a function.
func ScoreCallsCleanup()
SerializeToString
method
#
func (funcProps *FuncProps) SerializeToString() string
SetupScoreAdjustments
function
#
SetupScoreAdjustments interprets the value of the -d=inlscoreadj
debugging option, if set. The value of this flag is expected to be
a series of "/"-separated clauses of the form adj1:value1. Example:
-d=inlscoreadj=inLoopAdj=0/passConstToIfAdj=-99
func SetupScoreAdjustments()
ShouldFoldIfNameConstant
function
#
ShouldFoldIfNameConstant analyzes expression tree 'e' to see
whether it contains only combinations of simple references to all
of the names in 'names' with selected constants + operators. The
intent is to identify expression that could be folded away to a
constant if the value of 'n' were available. Return value is TRUE
if 'e' does look foldable given the value of 'n', and given that
'e' actually makes reference to 'n'. Some examples where the type
of "n" is int64, type of "s" is string, and type of "p" is *byte:
Simple? Expr
yes n<10
yes n*n-100
yes (n < 10 || n > 100) && (n >= 12 || n <= 99 || n != 101)
yes s == "foo"
yes p == nil
no nm
no float32(n)<1.0
no *p == 1
no 1 + 100
no 1 / n
no 1 + unsafe.Sizeof(n)
To avoid complexities (e.g. nan, inf) we stay way from folding and
floating point or complex operations (integers, bools, and strings
only). We also try to be conservative about avoiding any operation
that might result in a panic at runtime, e.g. for "n" with type
int64:
1<<(n-9) < 100/(n<<9999)
we would return FALSE due to the negative shift count and/or
potential divide by zero.
func ShouldFoldIfNameConstant(n ir.Node, names []*ir.Name) bool
String
method
#
func (i ResultPropBits) String() string
String
method
#
func (i ActualExprPropBits) String() string
String
method
#
func (i ParamPropBits) String() string
String
method
#
func (d disp) String() string
String
method
#
func (i scoreAdjustTyp) String() string
String
method
#
func (pas propsAndScore) String() string
String
method
#
func (i pstate) String() string
String
method
#
func (i FuncPropBits) String() string
String
method
#
func (i CSPropBits) String() string
String
method
#
func (fp *FuncProps) String() string
TearDown
function
#
TearDown is invoked at the end of the main inlining pass; doing
function analysis and call site scoring is unlikely to help a lot
after this point, so nil out fpmap and other globals to reclaim
storage.
func TearDown()
ToString
method
#
func (fp *FuncProps) ToString(prefix string) string
UnitTesting
function
#
func UnitTesting() bool
UpdateCallsiteTable
function
#
UpdateCallsiteTable handles updating of callerfn's call site table
after an inlined has been carried out, e.g. the call at 'n' as been
turned into the inlined call expression 'ic' within function
callerfn. The chief thing of interest here is to make sure that any
call nodes within 'ic' are added to the call site table for
'callerfn' and scored appropriately.
func UpdateCallsiteTable(callerfn *ir.Func, n *ir.CallExpr, ic *ir.InlinedCallExpr)
Visit
method
#
Visit sets the classification for 'n' based on the previously
calculated classifications for n's children, as part of a bottom-up
walk over an expression tree.
func (ec *exprClassifier) Visit(n ir.Node)
_
function
#
func _()
_
function
#
func _()
_
function
#
func _()
_
function
#
func _()
_
function
#
func _()
_
function
#
func _()
_
function
#
func _()
addCallSite
method
#
func (cstb *callSiteTableBuilder) addCallSite(callee *ir.Func, call *ir.CallExpr)
addParamsAnalyzer
function
#
addParamsAnalyzer creates a new paramsAnalyzer 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 interesting
parameters then the analyzer list is returned unchanged, and the
params flags in "fp" are updated accordingly.
func addParamsAnalyzer(fn *ir.Func, analyzers []propAnalyzer, fp *FuncProps, nf *nameFinder) []propAnalyzer
addResultsAnalyzer
function
#
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
adjStringToVal
function
#
func adjStringToVal(s string) (scoreAdjustTyp, bool)
adjValue
function
#
func adjValue(x scoreAdjustTyp) int
adjustScore
function
#
func adjustScore(typ scoreAdjustTyp, score int, mask scoreAdjustTyp) (int, scoreAdjustTyp)
analyzeFunc
function
#
func analyzeFunc(fn *ir.Func, inlineMaxBudget int, nf *nameFinder) *FuncProps
analyzeResult
method
#
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)
argPropsForCall
method
#
argPropsForCall returns a slice of argument properties for the
expressions being passed to the callee in the specific call
expression; these will be stored in the CallSite object for a given
call and then consulted when scoring. If no arg has any interesting
properties we try to save some space and return a nil slice.
func (cstb *callSiteTableBuilder) argPropsForCall(ce *ir.CallExpr) []ActualExprPropBits
blockCombine
function
#
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:
case 1: case 2:
panic("foo") if q { return x } <-pred
return x panic("boo") <-succ
In case 1, since the pred state is "always panic" it doesn't matter
what the succ state is, hence the state for the combination of the
two blocks is "always panics". In case 2, because there is a path
to return that avoids the panic in succ, the state for the
combination of the two statements is "may return".
func blockCombine(pred pstate, succ pstate) pstate
branchCombine
function
#
branchCombine combines two states at a control flow branch point where
either p1 or p2 executes (as in an "if" statement).
func branchCombine(p1 pstate, p2 pstate) pstate
buildEncodedCallSiteTab
function
#
func buildEncodedCallSiteTab(tab CallSiteTab) encodedCallSiteTab
callCheckParams
method
#
callCheckParams examines the target of call expression 'ce' to see
if it is making a call to the value passed in for some parameter.
func (pa *paramsAnalyzer) callCheckParams(ce *ir.CallExpr)
callTargetCheckResults
method
#
callTargetCheckResults examines a given call to see whether the
callee expression is potentially an inlinable function returned
from a potentially inlinable call. Examples:
Scenario 1: named intermediate
fn1 := foo() conc := bar()
fn1("blah") conc.MyMethod()
Scenario 2: returned func or concrete object feeds directly to call
foo()("blah") bar().MyMethod()
In the second case although at the source level the result of the
direct call feeds right into the method call or indirect call,
we're relying on the front end having inserted an auto-temp to
capture the value.
func (rua *resultUseAnalyzer) callTargetCheckResults(call ir.Node)
captureFuncDumpEntry
function
#
captureFuncDumpEntry grabs the function properties object for 'fn'
and enqueues it for later dumping. Used for the
"-d=dumpinlfuncprops=..." command line flag, intended for use
primarily in unit testing.
func captureFuncDumpEntry(fn *ir.Func)
checkParams
method
#
paramsAnalyzer invokes function 'testf' on the specified expression
'x' for each parameter, and if the result is TRUE, or's 'flag' into
the flags for that param.
func (pa *paramsAnalyzer) checkParams(x ir.Node, flag ParamPropBits, mayflag ParamPropBits, testf testfType)
collectNamesUsed
function
#
func collectNamesUsed(expr ir.Node) []*ir.Name
computeCallSiteScore
method
#
computeCallSiteScore takes a given call site whose ir node is
'call' and callee function is 'callee' and with previously computed
call site properties 'csflags', then computes a score for the
callsite that combines the size cost of the callee with heuristics
based on previously computed argument and function properties,
then stores the score and the adjustment mask in the appropriate
fields in 'cs'
func (cs *CallSite) computeCallSiteScore(csa *callSiteAnalyzer, calleeProps *FuncProps)
computeCallSiteTable
function
#
computeCallSiteTable builds and returns a table of call sites for
the specified region in function fn. A region here corresponds to a
specific subtree within the AST for a function. The main intended
use cases are for 'region' to be either A) an entire function body,
or B) an inlined call expression.
func computeCallSiteTable(fn *ir.Func, region ir.Nodes, cstab CallSiteTab, ptab map[ir.Node]pstate, loopNestingLevel int, nf *nameFinder) CallSiteTab
computeFuncProps
function
#
computeFuncProps examines the Go function 'fn' and computes for it
a function "properties" object, to be used to drive inlining
heuristics. See comments on the FuncProps type for more info.
func computeFuncProps(fn *ir.Func, inlineMaxBudget int, nf *nameFinder) (*FuncProps, CallSiteTab)
constValue
method
#
constValue returns the underlying constant.Value for an AST node n
if n is itself a constant value/expr, or if n is a singly assigned
local containing constant expr/value (or nil not constant).
func (nf *nameFinder) constValue(n ir.Node) constant.Value
containingAssignment
method
#
containingAssignment returns the top-level assignment statement
for a statement level function call "n". Examples:
x := foo()
x, y := bar(z, baz())
if blah() { ...
Here the top-level assignment statement for the foo() call is the
statement assigning to "x"; the top-level assignment for "bar()"
call is the assignment to x,y. For the baz() and blah() calls,
there is no top level assignment statement.
The unstated goal here is that we want to use the containing
assignment to establish a connection between a given call and the
variables to which its results/returns are being assigned.
Note that for the "bar" command above, the front end sometimes
decomposes this into two assignments, the first one assigning the
call to a pair of auto-temps, then the second one assigning the
auto-temps to the user-visible vars. This helper will return the
second (outer) of these two.
func (cstb *callSiteTableBuilder) containingAssignment(n ir.Node) ir.Node
deriveFlagsFromCallee
method
#
deriveFlagsFromCallee tries to derive flags for the current
function based on a call this function makes to some other
function. Example:
/* Simple */ /* Derived from callee
func foo(f func(int)) { func foo(f func(int)) {
f(2) bar(32, f)
} }
func bar(x int, f func()) {
f(x)
}
Here we can set the "param feeds indirect call" flag for
foo's param 'f' since we know that bar has that flag set for
its second param, and we're passing that param a function.
func (pa *paramsAnalyzer) deriveFlagsFromCallee(ce *ir.CallExpr, callee *ir.Func)
deriveReturnFlagsFromCallee
method
#
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)
determinePanicPathBits
method
#
determinePanicPathBits updates the CallSiteOnPanicPath bit within
"r" if we think this call is on an unconditional path to
panic/exit. Do this by walking back up the node stack to see if we
can find either A) an enclosing panic, or B) a statement node that
we've determined leads to a panic/exit.
func (cstb *callSiteTableBuilder) determinePanicPathBits(call ir.Node, r CSPropBits) CSPropBits
disableDebugTrace
function
#
func disableDebugTrace()
disableDebugTrace
function
#
func disableDebugTrace()
dispmeet
method
#
dispmeet performs a "meet" operation on the data flow states of
node x and y (where the term "meet" is being drawn from traditional
lattice-theoretical data flow analysis terminology).
func (ec *exprClassifier) dispmeet(x ir.Node, y ir.Node) disp
dumpFilePreamble
function
#
dumpFilePreamble writes out a file-level preamble for a given
Go function as part of a function properties dump.
func dumpFilePreamble(w io.Writer)
dumpFnPreamble
function
#
dumpFnPreamble writes out a function-level preamble for a given
Go function as part of a function properties dump. See the
README.txt file in testdata/props for more on the format of
this preamble.
func dumpFnPreamble(w io.Writer, funcInlHeur *fnInlHeur, ecst encodedCallSiteTab, idx uint, atl uint) error
emitDumpToFile
function
#
emitDumpToFile writes out the buffer function property dump entries
to a file, for unit testing. Dump entries need to be sorted by
definition line, and due to generics we need to account for the
possibility that several ir.Func's will have the same def line.
func emitDumpToFile(dumpfile string)
enableDebugTrace
function
#
func enableDebugTrace(x int)
enableDebugTrace
function
#
func enableDebugTrace(x int)
enableDebugTraceIfEnv
function
#
func enableDebugTraceIfEnv()
enableDebugTraceIfEnv
function
#
func enableDebugTraceIfEnv()
examineCallResults
method
#
func (csa *callSiteAnalyzer) examineCallResults(cs *CallSite, resultNameTab map[*ir.Name]resultPropAndCS) map[*ir.Name]resultPropAndCS
findParamIdx
method
#
func (pa *paramsAnalyzer) findParamIdx(n *ir.Name) int
flagSliceToSB
function
#
func flagSliceToSB(sb *strings.Builder, sl []T, prefix string, tag string)
flagsForNode
method
#
func (cstb *callSiteTableBuilder) flagsForNode(call *ir.CallExpr) CSPropBits
fmtFullPos
function
#
func fmtFullPos(p src.XPos) string
fnFileLine
function
#
func fnFileLine(fn *ir.Func) (string, uint)
foldCheckParams
method
#
foldCheckParams checks expression 'x' (an 'if' condition or
'switch' stmt expr) to see if the expr would fold away if a
specific parameter had a constant value.
func (pa *paramsAnalyzer) foldCheckParams(x ir.Node)
foldCheckResults
method
#
foldCheckResults examines the specified if/switch condition 'cond'
to see if it refers to locals defined by a (potentially inlinable)
function call at call site C, and if so, whether 'cond' contains
only combinations of simple references to all of the names in
'names' with selected constants + operators. If these criteria are
met, then we adjust the score for call site C to reflect the
fact that inlining will enable deadcode and/or constant propagation.
Note: for this heuristic to kick in, the names in question have to
be all from the same callsite. Examples:
q, r := baz() x, y := foo()
switch q+r { a, b, c := bar()
... if x && y && a && b && c {
} ...
}
For the call to "baz" above we apply a score adjustment, but not
for the calls to "foo" or "bar".
func (rua *resultUseAnalyzer) foldCheckResults(cond ir.Node)
funcName
method
#
funcName returns the *ir.Name for the func or method
corresponding to node 'n', or nil if n can't be proven
to contain a function value.
func (nf *nameFinder) funcName(n ir.Node) *ir.Name
getCallResultName
method
#
func (rua *resultUseAnalyzer) getCallResultName(ce *ir.CallExpr) *ir.Name
getParams
function
#
getParams returns an *ir.Name slice containing all params for the
function (plus rcvr as well if applicable).
func getParams(fn *ir.Func) []*ir.Name
getState
method
#
func (ffa *funcFlagsAnalyzer) getState(n ir.Node) pstate
getdisp
method
#
func (ec *exprClassifier) getdisp(x ir.Node) disp
hasTopLevelLoopBodyReturnOrBreak
function
#
hasTopLevelLoopBodyReturnOrBreak examines the body of a "for" or
"range" loop to try to verify that it is a real loop, as opposed to
a construct that is syntactically loopy but doesn't actually iterate
multiple times, like:
for {
blah()
return 1
}
[Remark: the pattern above crops up quite a bit in the source code
for the compiler itself, e.g. the auto-generated rewrite code]
Note that we don't look for GOTO statements here, so it's possible
we'll get the wrong result for a loop with complicated control
jumps via gotos.
func hasTopLevelLoopBodyReturnOrBreak(loopBody ir.Nodes) bool
isAllocatedMem
method
#
isAllocatedMem returns true if node n corresponds to a memory
allocation expression (make, new, or equivalent).
func (nf *nameFinder) isAllocatedMem(n ir.Node) bool
isConcreteConvIface
method
#
func (nf *nameFinder) isConcreteConvIface(n ir.Node) bool
isExitCall
function
#
isExitCall reports TRUE if the node itself is an unconditional
call to os.Exit(), a panic, or a function that does likewise.
func isExitCall(n ir.Node) bool
isMainMain
function
#
func isMainMain(fn *ir.Func) bool
isMay
function
#
func isMay(x scoreAdjustTyp) bool
isMust
function
#
func isMust(x scoreAdjustTyp) bool
isNil
method
#
isNil returns whether n is nil (or singly
assigned local containing nil).
func (nf *nameFinder) isNil(n ir.Node) bool
isSameFuncName
function
#
func isSameFuncName(v1 *ir.Name, v2 *ir.Name) bool
isWellKnownFunc
function
#
func isWellKnownFunc(s *types.Sym, pkg string, name string) bool
loopBody
function
#
func loopBody(n ir.Node) ir.Nodes
makeCallSiteAnalyzer
function
#
func makeCallSiteAnalyzer(fn *ir.Func) *callSiteAnalyzer
makeCallSiteTableBuilder
function
#
func makeCallSiteTableBuilder(fn *ir.Func, cstab CallSiteTab, ptab map[ir.Node]pstate, loopNestingLevel int, nf *nameFinder) *callSiteTableBuilder
makeExprClassifier
function
#
func makeExprClassifier(names []*ir.Name) *exprClassifier
makeFuncFlagsAnalyzer
function
#
func makeFuncFlagsAnalyzer(fn *ir.Func) *funcFlagsAnalyzer
makeParamsAnalyzer
function
#
makeParamsAnalyzer creates a new helper object to analyze parameters
of function fn. If the function doesn't have any interesting
params, a nil helper is returned along with a set of default param
flags for the func.
func makeParamsAnalyzer(fn *ir.Func, nf *nameFinder) (*paramsAnalyzer, []ParamPropBits)
makeResultsAnalyzer
function
#
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)
mayToMust
function
#
func mayToMust(x scoreAdjustTyp) scoreAdjustTyp
merge
method
#
func (cst CallSiteTab) merge(other CallSiteTab) error
mustToMay
function
#
func mustToMay(x scoreAdjustTyp) scoreAdjustTyp
namesDefined
function
#
namesDefined returns a list of ir.Name's corresponding to locals
that receive the results from the call at site 'cs', plus the
properties object for the called function. If a given result
isn't cleanly assigned to a newly defined local, the
slot for that result in the returned list will be nil. Example:
call returned name list
x := foo() [ x ]
z, y := bar() [ nil, nil ]
_, q := baz() [ nil, q ]
In the case of a multi-return call, such as "x, y := foo()",
the pattern we see from the front end will be a call op
assigning to auto-temps, and then an assignment of the auto-temps
to the user-level variables. In such cases we return
first the user-level variable (in the first func result)
and then the auto-temp name in the second result.
func namesDefined(cs *CallSite) ([]*ir.Name, []*ir.Name, *FuncProps)
newNameFinder
function
#
newNameFinder returns a new nameFinder object with a reassignment
oracle initialized based on the function fn, or if fn is nil,
without an underlying ReassignOracle.
func newNameFinder(fn *ir.Func) *nameFinder
nodeVisitPost
method
#
nodeVisitPost helps implement the propAnalyzer interface; when
called on a given node, it decides the disposition of that node
based on the state(s) of the node's children.
func (ffa *funcFlagsAnalyzer) nodeVisitPost(n ir.Node)
nodeVisitPost
method
#
func (pa *paramsAnalyzer) nodeVisitPost(n ir.Node)
nodeVisitPost
method
#
func (rua *resultUseAnalyzer) nodeVisitPost(n ir.Node)
nodeVisitPost
method
#
func (ra *resultsAnalyzer) nodeVisitPost(n ir.Node)
nodeVisitPost
method
#
func (cstb *callSiteTableBuilder) nodeVisitPost(n ir.Node)
nodeVisitPre
method
#
func (pa *paramsAnalyzer) nodeVisitPre(n ir.Node)
nodeVisitPre
method
#
func (ffa *funcFlagsAnalyzer) nodeVisitPre(n ir.Node)
nodeVisitPre
method
#
func (rua *resultUseAnalyzer) nodeVisitPre(n ir.Node)
nodeVisitPre
method
#
func (ra *resultsAnalyzer) nodeVisitPre(n ir.Node)
nodeVisitPre
method
#
func (cstb *callSiteTableBuilder) nodeVisitPre(n ir.Node)
panicPathTable
method
#
func (ffa *funcFlagsAnalyzer) panicPathTable() map[ir.Node]pstate
parseScoreAdj
function
#
func parseScoreAdj(val string) error
pessimize
method
#
func (ra *resultsAnalyzer) pessimize()
pessimize
method
#
pessimize is called to record the fact that we saw something in the
function that renders it entirely impossible to analyze.
func (ffa *funcFlagsAnalyzer) pessimize()
post
method
#
func (c *condLevelTracker) post(n ir.Node)
pre
method
#
func (c *condLevelTracker) pre(n ir.Node)
propsForArg
method
#
propsForArg returns property bits for a given call argument expression arg.
func (cstb *callSiteTableBuilder) propsForArg(arg ir.Node) ActualExprPropBits
propsForFunc
function
#
func propsForFunc(fn *ir.Func) *FuncProps
readULEB128
function
#
func readULEB128(sl []byte) (value uint64, rsl []byte)
reassigned
method
#
func (nf *nameFinder) reassigned(n *ir.Name) bool
rescoreBasedOnCallResultUses
method
#
rescoreBasedOnCallResultUses examines how call results are used,
and tries to update the scores of calls based on how their results
are used in the function.
func (csa *callSiteAnalyzer) rescoreBasedOnCallResultUses(fn *ir.Func, resultNameTab map[*ir.Name]resultPropAndCS, cstab CallSiteTab)
returnHasProp
method
#
func (rua *resultUseAnalyzer) returnHasProp(name *ir.Name, prop ResultPropBits) *CallSite
revisitInlinability
function
#
revisitInlinability revisits the question of whether to continue to
treat function 'fn' as an inline candidate based on the set of
properties we've computed for it. If (for example) it has an
initial size score of 150 and no interesting properties to speak
of, then there isn't really any point to moving ahead with it as an
inline candidate.
func revisitInlinability(fn *ir.Func, funcProps *FuncProps, budgetForFunc func(*ir.Func) int32)
runAnalyzersOnFunction
function
#
func runAnalyzersOnFunction(fn *ir.Func, analyzers []propAnalyzer)
scoreCallsRegion
method
#
scoreCallsRegion assigns numeric scores to each of the callsites in
region 'region' within function 'fn'. This can be called on
an entire function, or with 'region' set to a chunk of
code corresponding to an inlined call.
func (csa *callSiteAnalyzer) scoreCallsRegion(fn *ir.Func, region ir.Nodes, cstab CallSiteTab, doCallResults bool, ic *ir.InlinedCallExpr)
setResults
method
#
setResults transfers func flag results to 'funcProps'.
func (ffa *funcFlagsAnalyzer) setResults(funcProps *FuncProps)
setResults
method
#
func (pa *paramsAnalyzer) setResults(funcProps *FuncProps)
setResults
method
#
setResults transfers the calculated result properties for this
function to 'funcProps'.
func (ra *resultsAnalyzer) setResults(funcProps *FuncProps)
setState
method
#
func (ffa *funcFlagsAnalyzer) setState(n ir.Node, st pstate)
setupFlagToAdjMaps
function
#
func setupFlagToAdjMaps()
shouldVisit
function
#
shouldVisit reports TRUE if this is an interesting node from the
perspective of computing function flags. NB: due to the fact that
ir.CallExpr implements the Stmt interface, we wind up visiting
a lot of nodes that we don't really need to, but these can
simply be screened out as part of the visit.
func shouldVisit(n ir.Node) bool
sortFnInlHeurSlice
function
#
sortFnInlHeurSlice sorts a slice of fnInlHeur based on
the starting line of the function definition, then by name.
func sortFnInlHeurSlice(sl []fnInlHeur) []fnInlHeur
stateForList
method
#
stateForList walks through a list of statements and computes the
state/disposition for the entire list as a whole, as well
as updating disposition of intermediate nodes.
func (ffa *funcFlagsAnalyzer) stateForList(list ir.Nodes) pstate
staticValue
method
#
func (nf *nameFinder) staticValue(n ir.Node) ir.Node
updateState
method
#
func (ffa *funcFlagsAnalyzer) updateState(n ir.Node, st pstate)
writeUleb128
function
#
func writeUleb128(sb *strings.Builder, v uint64)