inlheur

Imports

Imports #

"strings"
"os"
"strconv"
"cmd/compile/internal/ir"
"cmd/compile/internal/pgoir"
"cmd/compile/internal/typecheck"
"fmt"
"os"
"strings"
"cmd/compile/internal/ir"
"fmt"
"os"
"cmd/compile/internal/ir"
"fmt"
"os"
"strconv"
"bytes"
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmp"
"encoding/json"
"fmt"
"internal/buildcfg"
"io"
"os"
"path/filepath"
"slices"
"strings"
"cmd/compile/internal/ir"
"go/constant"
"bytes"
"strconv"
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types"
"fmt"
"os"
"cmd/compile/internal/ir"
"fmt"
"go/constant"
"go/token"
"os"
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/internal/src"
"fmt"
"io"
"path/filepath"
"sort"
"strings"
"strconv"
"bytes"
"fmt"
"strings"
"bytes"
"strconv"
"bytes"
"strconv"
"strconv"
"bytes"
"strconv"
"cmd/compile/internal/ir"
"fmt"
"os"
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/pgoir"
"cmd/compile/internal/types"
"cmp"
"fmt"
"os"
"slices"
"strconv"
"strings"

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 #

Function always panics or invokes os.Exit() or a func that does likewise.

const FuncPropNeverReturns FuncPropBits = *ast.BinaryExpr

ParamFeedsIfOrSwitch const #

Parameter value feeds unmodified into a top level "switch" statement or "if" statement simple expressions (see more on "simple" expression classification below).

const ParamFeedsIfOrSwitch

ParamFeedsIndirectCall const #

Parameter value feeds unmodified into a top level indirect function call (assumes parameter is of function type).

const ParamFeedsIndirectCall

ParamFeedsInterfaceMethodCall const #

Parameter value feeds unmodified into a top-level interface call (this assumes the parameter is of interface type).

const ParamFeedsInterfaceMethodCall ParamPropBits = *ast.BinaryExpr

ParamMayFeedIfOrSwitch const #

Parameter value feeds unmodified into a "switch" or "if" statement simple expressions (see more on "simple" expression classification below), where the if/switch is conditional/nested.

const ParamMayFeedIfOrSwitch

ParamMayFeedIndirectCall const #

Parameter value feeds unmodified into an indirect function call that is conditional/nested (not guaranteed to execute). Assumes parameter is of function type.

const ParamMayFeedIndirectCall

ParamMayFeedInterfaceMethodCall const #

Parameter value feeds unmodified into an interface call that may be conditional/nested and not always executed (this assumes the parameter is of interface type).

const ParamMayFeedInterfaceMethodCall ParamPropBits = *ast.BinaryExpr

ParamNoInfo const #

No info about this param

const ParamNoInfo ParamPropBits = 0

ResultAlwaysSameConstant const #

Result is always the same non-composite compile time constant.

const ResultAlwaysSameConstant

ResultAlwaysSameFunc const #

Result is always the same function or closure.

const ResultAlwaysSameFunc

ResultAlwaysSameInlinableFunc const #

Result is always the same (potentially) inlinable function or closure.

const ResultAlwaysSameInlinableFunc

ResultIsAllocatedMem const #

This result always contains allocated memory.

const ResultIsAllocatedMem ResultPropBits = *ast.BinaryExpr

ResultIsConcreteTypeConvertedToInterface const #

This result is always a single concrete type that is implicitly converted to interface.

const ResultIsConcreteTypeConvertedToInterface

ResultNoInfo const #

No info about this result

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 #

callSiteTab contains entries for each call in the function currently being processed by InlineCalls; this variable will either be set to 'cstabCache' below (for non-inlinable routines) or to the local 'cstab' entry in the fnInlHeur object for inlinable routines. NOTE: this assumes that inlining operations are happening in a serial, single-threaded fashion,f which is true today but probably won't hold in the future (for example, we might want to score the callsites in multiple functions in parallel); if the inliner evolves in this direction we'll need to come up with a different approach here.

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 #

dumpBuffer stores up function properties dumps when "-d=dumpinlfuncprops=..." is in effect.

var dumpBuffer map[*ir.Func]fnInlHeur

exprLiterals const #

expr contains only literals

const exprLiterals

exprNoInfo const #

no info on this expr

const exprNoInfo disp = iota

exprSimple const #

expr is legal combination of literals and specified names

const exprSimple

fnDelimiter const #

const fnDelimiter = ""

fpmap var #

var fpmap = map[*ir.Func]fnInlHeur{...}

inLoopAdj const #

These constants capture the various ways in which the inliner's scoring phase can adjust a callsite score based on heuristics. They fall broadly into three categories: 1) adjustments based solely on the callsite context (ex: call appears on panic path) 2) adjustments that take into account specific interesting values passed at a call site (ex: passing a constant that could result in cprop/deadcode in the caller) 3) adjustments that take into account values returned from the call at a callsite (ex: call always returns the same inlinable function, and return value flows unmodified into an indirect call) For categories 2 and 3 above, each adjustment can have either a "must" version and a "may" version (but not both). Here the idea is that in the "must" version the value flow is unconditional: if the callsite executes, then the condition we're interested in (ex: param feeding call) is guaranteed to happen. For the "may" version, there may be control flow that could cause the benefit to be bypassed.

const inLoopAdj

initFuncAdj const #

These constants capture the various ways in which the inliner's scoring phase can adjust a callsite score based on heuristics. They fall broadly into three categories: 1) adjustments based solely on the callsite context (ex: call appears on panic path) 2) adjustments that take into account specific interesting values passed at a call site (ex: passing a constant that could result in cprop/deadcode in the caller) 3) adjustments that take into account values returned from the call at a callsite (ex: call always returns the same inlinable function, and return value flows unmodified into an indirect call) For categories 2 and 3 above, each adjustment can have either a "must" version and a "may" version (but not both). Here the idea is that in the "must" version the value flow is unconditional: if the callsite executes, then the condition we're interested in (ex: param feeding call) is guaranteed to happen. For the "may" version, there may be control flow that could cause the benefit to be bypassed.

const initFuncAdj

mayMustAdj var #

var mayMustAdj = [...]struct{...}{...}

panicPathAdj const #

Category 1 adjustments (see above)

const panicPathAdj scoreAdjustTyp = *ast.ParenExpr

paramFlagToPositiveAdj var #

var paramFlagToPositiveAdj map[ParamPropBits]scoreAdjustTyp

passConcreteToItfCallAdj const #

These constants capture the various ways in which the inliner's scoring phase can adjust a callsite score based on heuristics. They fall broadly into three categories: 1) adjustments based solely on the callsite context (ex: call appears on panic path) 2) adjustments that take into account specific interesting values passed at a call site (ex: passing a constant that could result in cprop/deadcode in the caller) 3) adjustments that take into account values returned from the call at a callsite (ex: call always returns the same inlinable function, and return value flows unmodified into an indirect call) For categories 2 and 3 above, each adjustment can have either a "must" version and a "may" version (but not both). Here the idea is that in the "must" version the value flow is unconditional: if the callsite executes, then the condition we're interested in (ex: param feeding call) is guaranteed to happen. For the "may" version, there may be control flow that could cause the benefit to be bypassed.

const passConcreteToItfCallAdj

passConcreteToNestedItfCallAdj const #

These constants capture the various ways in which the inliner's scoring phase can adjust a callsite score based on heuristics. They fall broadly into three categories: 1) adjustments based solely on the callsite context (ex: call appears on panic path) 2) adjustments that take into account specific interesting values passed at a call site (ex: passing a constant that could result in cprop/deadcode in the caller) 3) adjustments that take into account values returned from the call at a callsite (ex: call always returns the same inlinable function, and return value flows unmodified into an indirect call) For categories 2 and 3 above, each adjustment can have either a "must" version and a "may" version (but not both). Here the idea is that in the "must" version the value flow is unconditional: if the callsite executes, then the condition we're interested in (ex: param feeding call) is guaranteed to happen. For the "may" version, there may be control flow that could cause the benefit to be bypassed.

const passConcreteToNestedItfCallAdj

passConstToIfAdj const #

Category 2 adjustments (see above).

const passConstToIfAdj

passConstToNestedIfAdj const #

These constants capture the various ways in which the inliner's scoring phase can adjust a callsite score based on heuristics. They fall broadly into three categories: 1) adjustments based solely on the callsite context (ex: call appears on panic path) 2) adjustments that take into account specific interesting values passed at a call site (ex: passing a constant that could result in cprop/deadcode in the caller) 3) adjustments that take into account values returned from the call at a callsite (ex: call always returns the same inlinable function, and return value flows unmodified into an indirect call) For categories 2 and 3 above, each adjustment can have either a "must" version and a "may" version (but not both). Here the idea is that in the "must" version the value flow is unconditional: if the callsite executes, then the condition we're interested in (ex: param feeding call) is guaranteed to happen. For the "may" version, there may be control flow that could cause the benefit to be bypassed.

const passConstToNestedIfAdj

passFuncToIndCallAdj const #

These constants capture the various ways in which the inliner's scoring phase can adjust a callsite score based on heuristics. They fall broadly into three categories: 1) adjustments based solely on the callsite context (ex: call appears on panic path) 2) adjustments that take into account specific interesting values passed at a call site (ex: passing a constant that could result in cprop/deadcode in the caller) 3) adjustments that take into account values returned from the call at a callsite (ex: call always returns the same inlinable function, and return value flows unmodified into an indirect call) For categories 2 and 3 above, each adjustment can have either a "must" version and a "may" version (but not both). Here the idea is that in the "must" version the value flow is unconditional: if the callsite executes, then the condition we're interested in (ex: param feeding call) is guaranteed to happen. For the "may" version, there may be control flow that could cause the benefit to be bypassed.

const passFuncToIndCallAdj

passFuncToNestedIndCallAdj const #

These constants capture the various ways in which the inliner's scoring phase can adjust a callsite score based on heuristics. They fall broadly into three categories: 1) adjustments based solely on the callsite context (ex: call appears on panic path) 2) adjustments that take into account specific interesting values passed at a call site (ex: passing a constant that could result in cprop/deadcode in the caller) 3) adjustments that take into account values returned from the call at a callsite (ex: call always returns the same inlinable function, and return value flows unmodified into an indirect call) For categories 2 and 3 above, each adjustment can have either a "must" version and a "may" version (but not both). Here the idea is that in the "must" version the value flow is unconditional: if the callsite executes, then the condition we're interested in (ex: param feeding call) is guaranteed to happen. For the "may" version, there may be control flow that could cause the benefit to be bypassed.

const passFuncToNestedIndCallAdj

passInlinableFuncToIndCallAdj const #

These constants capture the various ways in which the inliner's scoring phase can adjust a callsite score based on heuristics. They fall broadly into three categories: 1) adjustments based solely on the callsite context (ex: call appears on panic path) 2) adjustments that take into account specific interesting values passed at a call site (ex: passing a constant that could result in cprop/deadcode in the caller) 3) adjustments that take into account values returned from the call at a callsite (ex: call always returns the same inlinable function, and return value flows unmodified into an indirect call) For categories 2 and 3 above, each adjustment can have either a "must" version and a "may" version (but not both). Here the idea is that in the "must" version the value flow is unconditional: if the callsite executes, then the condition we're interested in (ex: param feeding call) is guaranteed to happen. For the "may" version, there may be control flow that could cause the benefit to be bypassed.

const passInlinableFuncToIndCallAdj

passInlinableFuncToNestedIndCallAdj const #

These constants capture the various ways in which the inliner's scoring phase can adjust a callsite score based on heuristics. They fall broadly into three categories: 1) adjustments based solely on the callsite context (ex: call appears on panic path) 2) adjustments that take into account specific interesting values passed at a call site (ex: passing a constant that could result in cprop/deadcode in the caller) 3) adjustments that take into account values returned from the call at a callsite (ex: call always returns the same inlinable function, and return value flows unmodified into an indirect call) For categories 2 and 3 above, each adjustment can have either a "must" version and a "may" version (but not both). Here the idea is that in the "must" version the value flow is unconditional: if the callsite executes, then the condition we're interested in (ex: param feeding call) is guaranteed to happen. For the "may" version, there may be control flow that could cause the benefit to be bypassed.

const passInlinableFuncToNestedIndCallAdj

preambleDelimiter const #

delimiters written to various preambles to make parsing of dumps easier.

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 #

These constants capture the various ways in which the inliner's scoring phase can adjust a callsite score based on heuristics. They fall broadly into three categories: 1) adjustments based solely on the callsite context (ex: call appears on panic path) 2) adjustments that take into account specific interesting values passed at a call site (ex: passing a constant that could result in cprop/deadcode in the caller) 3) adjustments that take into account values returned from the call at a callsite (ex: call always returns the same inlinable function, and return value flows unmodified into an indirect call) For categories 2 and 3 above, each adjustment can have either a "must" version and a "may" version (but not both). Here the idea is that in the "must" version the value flow is unconditional: if the callsite executes, then the condition we're interested in (ex: param feeding call) is guaranteed to happen. For the "may" version, there may be control flow that could cause the benefit to be bypassed.

const returnFeedsConcreteToInterfaceCallAdj

returnFeedsConstToIfAdj const #

Category 3 adjustments.

const returnFeedsConstToIfAdj

returnFeedsFuncToIndCallAdj const #

These constants capture the various ways in which the inliner's scoring phase can adjust a callsite score based on heuristics. They fall broadly into three categories: 1) adjustments based solely on the callsite context (ex: call appears on panic path) 2) adjustments that take into account specific interesting values passed at a call site (ex: passing a constant that could result in cprop/deadcode in the caller) 3) adjustments that take into account values returned from the call at a callsite (ex: call always returns the same inlinable function, and return value flows unmodified into an indirect call) For categories 2 and 3 above, each adjustment can have either a "must" version and a "may" version (but not both). Here the idea is that in the "must" version the value flow is unconditional: if the callsite executes, then the condition we're interested in (ex: param feeding call) is guaranteed to happen. For the "may" version, there may be control flow that could cause the benefit to be bypassed.

const returnFeedsFuncToIndCallAdj

returnFeedsInlinableFuncToIndCallAdj const #

These constants capture the various ways in which the inliner's scoring phase can adjust a callsite score based on heuristics. They fall broadly into three categories: 1) adjustments based solely on the callsite context (ex: call appears on panic path) 2) adjustments that take into account specific interesting values passed at a call site (ex: passing a constant that could result in cprop/deadcode in the caller) 3) adjustments that take into account values returned from the call at a callsite (ex: call always returns the same inlinable function, and return value flows unmodified into an indirect call) For categories 2 and 3 above, each adjustment can have either a "must" version and a "may" version (but not both). Here the idea is that in the "must" version the value flow is unconditional: if the callsite executes, then the condition we're interested in (ex: param feeding call) is guaranteed to happen. For the "may" version, there may be control flow that could cause the benefit to be bypassed.

const returnFeedsInlinableFuncToIndCallAdj

scoreCallsCache var #

scoreCallsCache caches a call site table and call site list between invocations of ScoreCalls so that we can reuse previously allocated storage.

var scoreCallsCache scoreCallsCacheType

sentinelScoreAdj const #

These constants capture the various ways in which the inliner's scoring phase can adjust a callsite score based on heuristics. They fall broadly into three categories: 1) adjustments based solely on the callsite context (ex: call appears on panic path) 2) adjustments that take into account specific interesting values passed at a call site (ex: passing a constant that could result in cprop/deadcode in the caller) 3) adjustments that take into account values returned from the call at a callsite (ex: call always returns the same inlinable function, and return value flows unmodified into an indirect call) For categories 2 and 3 above, each adjustment can have either a "must" version and a "may" version (but not both). Here the idea is that in the "must" version the value flow is unconditional: if the callsite executes, then the condition we're interested in (ex: param feeding call) is guaranteed to happen. For the "may" version, there may be control flow that could cause the benefit to be bypassed.

const sentinelScoreAdj

Type Aliases

ActualExprPropBits type #

ActualExprPropBits describes a property of an actual expression (value passed to some specific func argument at a call site).

type ActualExprPropBits uint8

CSPropBits type #

type CSPropBits uint32

CallSiteTab type #

CallSiteTab is a table of call sites, keyed by call expr. Ideally it would be nice to key the table by src.XPos, but this results in collisions for calls on very long lines (the front end saturates column numbers at 255). We also wind up with many calls that share the same auto-generated pos.

type CallSiteTab map[*ir.CallExpr]*CallSite

FuncPropBits type #

type FuncPropBits uint32

ParamPropBits type #

type ParamPropBits uint32

ResultPropBits type #

type ResultPropBits uint32

csAuxBits type #

type csAuxBits uint8

disp type #

type disp int

encodedCallSiteTab type #

encodedCallSiteTab is a table keyed by "encoded" callsite (stringified src.XPos plus call site ID) mapping to a value of call property bits and score.

type encodedCallSiteTab map[string]propsAndScore

pstate type #

pstate keeps track of the disposition of a given node and its children with respect to panic/exit calls.

type pstate int

scoreAdjustTyp type #

These constants enumerate the set of possible ways/scenarios in which we'll adjust the score of a given callsite.

type scoreAdjustTyp uint

testfType type #

type testfType func(x ir.Node, param *ir.Name, idx int) (bool, bool)

Interfaces

propAnalyzer interface #

propAnalyzer interface is used for defining one or more analyzer helper objects, each tasked with computing some specific subset of the properties we're interested in. The assumption is that properties are independent, so each new analyzer that implements this interface can operate entirely on its own. For a given analyzer there will be a sequence of calls to nodeVisitPre and nodeVisitPost as the nodes within a function are visited, then a followup call to setResults so that the analyzer can transfer its results into the final properties object.

type propAnalyzer interface {
nodeVisitPre(n ir.Node)
nodeVisitPost(n ir.Node)
setResults(funcProps *FuncProps)
}

Structs

CallSite struct #

CallSite records useful information about a potentially inlinable (direct) function call. "Callee" is the target of the call, "Call" is the ir node corresponding to the call itself, "Assign" is the top-level assignment statement containing the call (if the call appears in the form of a top-level statement, e.g. "x := foo()"), "Flags" contains properties of the call that might be useful for making inlining decisions, "Score" is the final score assigned to the site, and "ID" is a numeric ID for the site within its containing function.

type CallSite struct {
Callee *ir.Func
Call *ir.CallExpr
parent *CallSite
Assign ir.Node
Flags CSPropBits
ArgProps []ActualExprPropBits
Score int
ScoreMask scoreAdjustTyp
ID uint
aux uint8
}

FuncProps struct #

FuncProps describes a set of function or method properties that may be useful for inlining heuristics. Here 'Flags' are properties that we think apply to the entire function; 'RecvrParamFlags' are properties of specific function params (or the receiver), and 'ResultFlags' are things properties we think will apply to values of specific results. Note that 'ParamFlags' includes and entry for the receiver if applicable, and does include etries for blank params; for a function such as "func foo(_ int, b byte, _ float32)" the length of ParamFlags will be 3.

type FuncProps struct {
Flags FuncPropBits
ParamFlags []ParamPropBits
ResultFlags []ResultPropBits
}

callSiteAnalyzer struct #

type callSiteAnalyzer struct {
fn *ir.Func
*nameFinder
}

callSiteTableBuilder struct #

type callSiteTableBuilder struct {
fn *ir.Func
*nameFinder
cstab CallSiteTab
ptab map[ir.Node]pstate
nstack []ir.Node
loopNest int
isInit bool
}

condLevelTracker struct #

condLevelTracker helps keeps track very roughly of "level of conditional nesting", e.g. how many "if" statements you have to go through to get to the point where a given stmt executes. Example: cond nesting level func foo() { G = 1 0 if x < 10 { 0 if y < 10 { 1 G = 0 2 } } } The intent here is to provide some sort of very abstract relative hotness metric, e.g. "G = 1" above is expected to be executed more often than "G = 0" (in the aggregate, across large numbers of functions).

type condLevelTracker struct {
condLevel int
}

exprClassifier struct #

exprClassifier holds intermediate state about nodes within an expression tree being analyzed by ShouldFoldIfNameConstant. Here "name" is the name node passed in, and "disposition" stores the result of classifying a given IR node.

type exprClassifier struct {
names map[*ir.Name]bool
disposition map[ir.Node]disp
}

fnInlHeur struct #

fnInlHeur contains inline heuristics state information about a specific Go function being analyzed/considered by the inliner. Note that in addition to constructing a fnInlHeur object by analyzing a specific *ir.Func, there is also code in the test harness (funcprops_test.go) that builds up fnInlHeur's by reading in and parsing a dump. This is the reason why we have file/fname/line fields below instead of just an *ir.Func field.

type fnInlHeur struct {
props *FuncProps
cstab CallSiteTab
fname string
file string
line uint
}

funcFlagsAnalyzer struct #

funcFlagsAnalyzer computes the "Flags" value for the FuncProps object we're computing. The main item of interest here is "nstate", which stores the disposition of a given ir Node with respect to the flags/properties we're trying to compute.

type funcFlagsAnalyzer struct {
fn *ir.Func
nstate map[ir.Node]pstate
noInfo bool
}

nameFinder struct #

nameFinder provides a set of "isXXX" query methods for clients to ask whether a given AST node corresponds to a function, a constant value, and so on. These methods use an underlying ir.ReassignOracle to return more precise results in cases where an "interesting" value is assigned to a singly-defined local temp. Example: const q = 101 fq := func() int { return q } copyOfConstant := q copyOfFunc := f interestingCall(copyOfConstant, copyOfFunc) A name finder query method invoked on the arguments being passed to "interestingCall" will be able detect that 'copyOfConstant' always evaluates to a constant (even though it is in fact a PAUTO local variable). A given nameFinder can also operate without using ir.ReassignOracle (in cases where it is not practical to look at the entire function); in such cases queries will still work for explicit constant values and functions.

type nameFinder struct {
ro *ir.ReassignOracle
}

paramsAnalyzer struct #

paramsAnalyzer holds state information for the phase that computes flags for a Go functions parameters, for use in inline heuristics. Note that the params slice below includes entries for blanks.

type paramsAnalyzer struct {
fname string
values []ParamPropBits
params []*ir.Name
top []bool
*condLevelTracker
*nameFinder
}

propsAndScore struct #

type propsAndScore struct {
props CSPropBits
score int
mask scoreAdjustTyp
}

resultPropAndCS struct #

type resultPropAndCS struct {
defcs *CallSite
props ResultPropBits
}

resultUseAnalyzer struct #

type resultUseAnalyzer struct {
resultNameTab map[*ir.Name]resultPropAndCS
fn *ir.Func
cstab CallSiteTab
*condLevelTracker
}

resultVal struct #

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
}

resultsAnalyzer struct #

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
}

scoreCallsCacheType struct #

type scoreCallsCacheType struct {
tab CallSiteTab
csl []*CallSite
}

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

dumpCallSiteComments function #

dumpCallSiteComments emits comments into the dump file for the callsites in the function of interest. If "ecst" is non-nil, we use that, otherwise generated a fresh encodedCallSiteTab from "tab".

func dumpCallSiteComments(w io.Writer, tab CallSiteTab, ecst encodedCallSiteTab)

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)

Generated with Arrow