var ssaConfig … var ssaCaches … var ssaDump … var ssaDir … var ssaDumpStdout … var ssaDumpCFG … const ssaDumpFile … var ssaDumpInlined … func DumpInline(fn *ir.Func) { … } func InitEnv() { … } func InitConfig() { … } func InitTables() { … } // AbiForBodylessFuncStackMap returns the ABI for a bodyless function's stack map. // This is not necessarily the ABI used to call it. // Currently (1.17 dev) such a stack map is always ABI0; // any ABI wrapper that is present is nosplit, hence a precise // stack map is not needed there (the parameters survive only long // enough to call the wrapped assembly function). // This always returns a freshly copied ABI. func AbiForBodylessFuncStackMap(fn *ir.Func) *abi.ABIConfig { … } // abiForFunc implements ABI policy for a function, but does not return a copy of the ABI. // Passing a nil function returns the default ABI based on experiment configuration. func abiForFunc(fn *ir.Func, abi0, abi1 *abi.ABIConfig) *abi.ABIConfig { … } // emitOpenDeferInfo emits FUNCDATA information about the defers in a function // that is using open-coded defers. This funcdata is used to determine the active // defers in a function and execute those defers during panic processing. // // The funcdata is all encoded in varints (since values will almost always be less than // 128, but stack offsets could potentially be up to 2Gbyte). All "locations" (offsets) // for stack variables are specified as the number of bytes below varp (pointer to the // top of the local variables) for their starting address. The format is: // // - Offset of the deferBits variable // - Offset of the first closure slot (the rest are laid out consecutively). func (s *state) emitOpenDeferInfo() { … } // buildssa builds an SSA function for fn. // worker indicates which of the backend workers is doing the processing. func buildssa(fn *ir.Func, worker int, isPgoHot bool) *ssa.Func { … } func (s *state) storeParameterRegsToStack(abi *abi.ABIConfig, paramAssignment *abi.ABIParamAssignment, n *ir.Name, addr *ssa.Value, pointersOnly bool) { … } // zeroResults zeros the return values at the start of the function. // We need to do this very early in the function. Defer might stop a // panic and show the return values as they exist at the time of // panic. For precise stacks, the garbage collector assumes results // are always live, so we need to zero them before any allocations, // even allocations to move params/results to the heap. func (s *state) zeroResults() { … } // paramsToHeap produces code to allocate memory for heap-escaped parameters // and to copy non-result parameters' values from the stack. func (s *state) paramsToHeap() { … } // newHeapaddr allocates heap memory for n and sets its heap address. func (s *state) newHeapaddr(n *ir.Name) { … } // setHeapaddr allocates a new PAUTO variable to store ptr (which must be non-nil) // and then sets it as n's heap address. func (s *state) setHeapaddr(pos src.XPos, n *ir.Name, ptr *ssa.Value) { … } // newObject returns an SSA value denoting new(typ). func (s *state) newObject(typ *types.Type, rtype *ssa.Value) *ssa.Value { … } func (s *state) checkPtrAlignment(n *ir.ConvExpr, v *ssa.Value, count *ssa.Value) { … } // reflectType returns an SSA value representing a pointer to typ's // reflection type descriptor. func (s *state) reflectType(typ *types.Type) *ssa.Value { … } func dumpSourcesColumn(writer *ssa.HTMLWriter, fn *ir.Func) { … } func readFuncLines(file string, start, end uint) (*ssa.FuncLines, error) { … } // updateUnsetPredPos propagates the earliest-value position information for b // towards all of b's predecessors that need a position, and recurs on that // predecessor if its position is updated. B should have a non-empty position. func (s *state) updateUnsetPredPos(b *ssa.Block) { … } type openDeferInfo … type state … type funcLine … type ssaLabel … // label returns the label associated with sym, creating it if necessary. func (s *state) label(sym *types.Sym) *ssaLabel { … } func (s *state) Logf(msg string, args ...interface{ … } func (s *state) Log() bool { … } func (s *state) Fatalf(msg string, args ...interface{ … } func (s *state) Warnl(pos src.XPos, msg string, args ...interface{ … } func (s *state) Debug_checknil() bool { … } func ssaMarker(name string) *ir.Name { … } var memVar … var ptrVar … var lenVar … var capVar … var typVar … var okVar … var deferBitsVar … var hashVar … // startBlock sets the current block we're generating code in to b. func (s *state) startBlock(b *ssa.Block) { … } // endBlock marks the end of generating code for the current block. // Returns the (former) current block. Returns nil if there is no current // block, i.e. if no code flows to the current execution point. func (s *state) endBlock() *ssa.Block { … } // pushLine pushes a line number on the line number stack. func (s *state) pushLine(line src.XPos) { … } // popLine pops the top of the line number stack. func (s *state) popLine() { … } // peekPos peeks the top of the line number stack. func (s *state) peekPos() src.XPos { … } // newValue0 adds a new value with no arguments to the current block. func (s *state) newValue0(op ssa.Op, t *types.Type) *ssa.Value { … } // newValue0A adds a new value with no arguments and an aux value to the current block. func (s *state) newValue0A(op ssa.Op, t *types.Type, aux ssa.Aux) *ssa.Value { … } // newValue0I adds a new value with no arguments and an auxint value to the current block. func (s *state) newValue0I(op ssa.Op, t *types.Type, auxint int64) *ssa.Value { … } // newValue1 adds a new value with one argument to the current block. func (s *state) newValue1(op ssa.Op, t *types.Type, arg *ssa.Value) *ssa.Value { … } // newValue1A adds a new value with one argument and an aux value to the current block. func (s *state) newValue1A(op ssa.Op, t *types.Type, aux ssa.Aux, arg *ssa.Value) *ssa.Value { … } // newValue1Apos adds a new value with one argument and an aux value to the current block. // isStmt determines whether the created values may be a statement or not // (i.e., false means never, yes means maybe). func (s *state) newValue1Apos(op ssa.Op, t *types.Type, aux ssa.Aux, arg *ssa.Value, isStmt bool) *ssa.Value { … } // newValue1I adds a new value with one argument and an auxint value to the current block. func (s *state) newValue1I(op ssa.Op, t *types.Type, aux int64, arg *ssa.Value) *ssa.Value { … } // newValue2 adds a new value with two arguments to the current block. func (s *state) newValue2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) *ssa.Value { … } // newValue2A adds a new value with two arguments and an aux value to the current block. func (s *state) newValue2A(op ssa.Op, t *types.Type, aux ssa.Aux, arg0, arg1 *ssa.Value) *ssa.Value { … } // newValue2Apos adds a new value with two arguments and an aux value to the current block. // isStmt determines whether the created values may be a statement or not // (i.e., false means never, yes means maybe). func (s *state) newValue2Apos(op ssa.Op, t *types.Type, aux ssa.Aux, arg0, arg1 *ssa.Value, isStmt bool) *ssa.Value { … } // newValue2I adds a new value with two arguments and an auxint value to the current block. func (s *state) newValue2I(op ssa.Op, t *types.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value { … } // newValue3 adds a new value with three arguments to the current block. func (s *state) newValue3(op ssa.Op, t *types.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value { … } // newValue3I adds a new value with three arguments and an auxint value to the current block. func (s *state) newValue3I(op ssa.Op, t *types.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value { … } // newValue3A adds a new value with three arguments and an aux value to the current block. func (s *state) newValue3A(op ssa.Op, t *types.Type, aux ssa.Aux, arg0, arg1, arg2 *ssa.Value) *ssa.Value { … } // newValue3Apos adds a new value with three arguments and an aux value to the current block. // isStmt determines whether the created values may be a statement or not // (i.e., false means never, yes means maybe). func (s *state) newValue3Apos(op ssa.Op, t *types.Type, aux ssa.Aux, arg0, arg1, arg2 *ssa.Value, isStmt bool) *ssa.Value { … } // newValue4 adds a new value with four arguments to the current block. func (s *state) newValue4(op ssa.Op, t *types.Type, arg0, arg1, arg2, arg3 *ssa.Value) *ssa.Value { … } // newValue4I adds a new value with four arguments and an auxint value to the current block. func (s *state) newValue4I(op ssa.Op, t *types.Type, aux int64, arg0, arg1, arg2, arg3 *ssa.Value) *ssa.Value { … } func (s *state) entryBlock() *ssa.Block { … } // entryNewValue0 adds a new value with no arguments to the entry block. func (s *state) entryNewValue0(op ssa.Op, t *types.Type) *ssa.Value { … } // entryNewValue0A adds a new value with no arguments and an aux value to the entry block. func (s *state) entryNewValue0A(op ssa.Op, t *types.Type, aux ssa.Aux) *ssa.Value { … } // entryNewValue1 adds a new value with one argument to the entry block. func (s *state) entryNewValue1(op ssa.Op, t *types.Type, arg *ssa.Value) *ssa.Value { … } // entryNewValue1I adds a new value with one argument and an auxint value to the entry block. func (s *state) entryNewValue1I(op ssa.Op, t *types.Type, auxint int64, arg *ssa.Value) *ssa.Value { … } // entryNewValue1A adds a new value with one argument and an aux value to the entry block. func (s *state) entryNewValue1A(op ssa.Op, t *types.Type, aux ssa.Aux, arg *ssa.Value) *ssa.Value { … } // entryNewValue2 adds a new value with two arguments to the entry block. func (s *state) entryNewValue2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) *ssa.Value { … } // entryNewValue2A adds a new value with two arguments and an aux value to the entry block. func (s *state) entryNewValue2A(op ssa.Op, t *types.Type, aux ssa.Aux, arg0, arg1 *ssa.Value) *ssa.Value { … } // const* routines add a new const value to the entry block. func (s *state) constSlice(t *types.Type) *ssa.Value { … } func (s *state) constInterface(t *types.Type) *ssa.Value { … } func (s *state) constNil(t *types.Type) *ssa.Value { … } func (s *state) constEmptyString(t *types.Type) *ssa.Value { … } func (s *state) constBool(c bool) *ssa.Value { … } func (s *state) constInt8(t *types.Type, c int8) *ssa.Value { … } func (s *state) constInt16(t *types.Type, c int16) *ssa.Value { … } func (s *state) constInt32(t *types.Type, c int32) *ssa.Value { … } func (s *state) constInt64(t *types.Type, c int64) *ssa.Value { … } func (s *state) constFloat32(t *types.Type, c float64) *ssa.Value { … } func (s *state) constFloat64(t *types.Type, c float64) *ssa.Value { … } func (s *state) constInt(t *types.Type, c int64) *ssa.Value { … } func (s *state) constOffPtrSP(t *types.Type, c int64) *ssa.Value { … } // newValueOrSfCall* are wrappers around newValue*, which may create a call to a // soft-float runtime function instead (when emitting soft-float code). func (s *state) newValueOrSfCall1(op ssa.Op, t *types.Type, arg *ssa.Value) *ssa.Value { … } func (s *state) newValueOrSfCall2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) *ssa.Value { … } type instrumentKind … const instrumentRead … const instrumentWrite … const instrumentMove … func (s *state) instrument(t *types.Type, addr *ssa.Value, kind instrumentKind) { … } // instrumentFields instruments a read/write operation on addr. // If it is instrumenting for MSAN or ASAN and t is a struct type, it instruments // operation for each field, instead of for the whole struct. func (s *state) instrumentFields(t *types.Type, addr *ssa.Value, kind instrumentKind) { … } func (s *state) instrumentMove(t *types.Type, dst, src *ssa.Value) { … } func (s *state) instrument2(t *types.Type, addr, addr2 *ssa.Value, kind instrumentKind) { … } func (s *state) load(t *types.Type, src *ssa.Value) *ssa.Value { … } func (s *state) rawLoad(t *types.Type, src *ssa.Value) *ssa.Value { … } func (s *state) store(t *types.Type, dst, val *ssa.Value) { … } func (s *state) zero(t *types.Type, dst *ssa.Value) { … } func (s *state) move(t *types.Type, dst, src *ssa.Value) { … } func (s *state) moveWhichMayOverlap(t *types.Type, dst, src *ssa.Value, mayOverlap bool) { … } // stmtList converts the statement list n to SSA and adds it to s. func (s *state) stmtList(l ir.Nodes) { … } // stmt converts the statement n to SSA and adds it to s. func (s *state) stmt(n ir.Node) { … } const shareDeferExits … // exit processes any code that needs to be generated just before returning. // It returns a BlockRet block that ends the control flow. Its control value // will be set to the final memory state. func (s *state) exit() *ssa.Block { … } type opAndType … var opToSSA … func (s *state) concreteEtype(t *types.Type) types.Kind { … } func (s *state) ssaOp(op ir.Op, t *types.Type) ssa.Op { … } type opAndTwoTypes … type twoTypes … type twoOpsAndType … var fpConvOpToSSA … var fpConvOpToSSA32 … var uint64fpConvOpToSSA … var shiftOpToSSA … func (s *state) ssaShiftOp(op ir.Op, t *types.Type, u *types.Type) ssa.Op { … } func (s *state) uintptrConstant(v uint64) *ssa.Value { … } func (s *state) conv(n ir.Node, v *ssa.Value, ft, tt *types.Type) *ssa.Value { … } // expr converts the expression n to ssa, adds it to s and returns the ssa result. func (s *state) expr(n ir.Node) *ssa.Value { … } func (s *state) exprCheckPtr(n ir.Node, checkPtrOK bool) *ssa.Value { … } func (s *state) resultOfCall(c *ssa.Value, which int64, t *types.Type) *ssa.Value { … } func (s *state) resultAddrOfCall(c *ssa.Value, which int64, t *types.Type) *ssa.Value { … } // append converts an OAPPEND node to SSA. // If inplace is false, it converts the OAPPEND expression n to an ssa.Value, // adds it to s, and returns the Value. // If inplace is true, it writes the result of the OAPPEND expression n // back to the slice being appended to, and returns nil. // inplace MUST be set to false if the slice can be SSA'd. // Note: this code only handles fixed-count appends. Dotdotdot appends // have already been rewritten at this point (by walk). func (s *state) append(n *ir.CallExpr, inplace bool) *ssa.Value { … } // minMax converts an OMIN/OMAX builtin call into SSA. func (s *state) minMax(n *ir.CallExpr) *ssa.Value { … } // ternary emits code to evaluate cond ? x : y. func (s *state) ternary(cond, x, y *ssa.Value) *ssa.Value { … } // condBranch evaluates the boolean expression cond and branches to yes // if cond is true and no if cond is false. // This function is intended to handle && and || better than just calling // s.expr(cond) and branching on the result. func (s *state) condBranch(cond ir.Node, yes, no *ssa.Block, likely int8) { … } type skipMask … const skipPtr … const skipLen … const skipCap … // assign does left = right. // Right has already been evaluated to ssa, left has not. // If deref is true, then we do left = *right instead (and right has already been nil-checked). // If deref is true and right == nil, just do left = 0. // skip indicates assignments (at the top level) that can be avoided. // mayOverlap indicates whether left&right might partially overlap in memory. Default is false. func (s *state) assign(left ir.Node, right *ssa.Value, deref bool, skip skipMask) { … } func (s *state) assignWhichMayOverlap(left ir.Node, right *ssa.Value, deref bool, skip skipMask, mayOverlap bool) { … } // zeroVal returns the zero value for type t. func (s *state) zeroVal(t *types.Type) *ssa.Value { … } type callKind … const callNormal … const callDefer … const callDeferStack … const callGo … const callTail … type sfRtCallDef … var softFloatOps … func softfloatInit() { … } // TODO: do not emit sfcall if operation can be optimized to constant in later // opt phase func (s *state) sfcall(op ssa.Op, args ...*ssa.Value) (*ssa.Value, bool) { … } // split breaks up a tuple-typed value into its 2 parts. func (s *state) split(v *ssa.Value) (*ssa.Value, *ssa.Value) { … } // intrinsicCall converts a call to a recognized intrinsic function into the intrinsic SSA operation. func (s *state) intrinsicCall(n *ir.CallExpr) *ssa.Value { … } // intrinsicArgs extracts args from n, evaluates them to SSA values, and returns them. func (s *state) intrinsicArgs(n *ir.CallExpr) []*ssa.Value { … } // openDeferRecord adds code to evaluate and store the function for an open-code defer // call, and records info about the defer, so we can generate proper code on the // exit paths. n is the sub-node of the defer node that is the actual function // call. We will also record funcdata information on where the function is stored // (as well as the deferBits variable), and this will enable us to run the proper // defer calls during panics. func (s *state) openDeferRecord(n *ir.CallExpr) { … } // openDeferSave generates SSA nodes to store a value (with type t) for an // open-coded defer at an explicit autotmp location on the stack, so it can be // reloaded and used for the appropriate call on exit. Type t must be a function type // (therefore SSAable). val is the value to be stored. The function returns an SSA // value representing a pointer to the autotmp location. func (s *state) openDeferSave(t *types.Type, val *ssa.Value) *ssa.Value { … } // openDeferExit generates SSA for processing all the open coded defers at exit. // The code involves loading deferBits, and checking each of the bits to see if // the corresponding defer statement was executed. For each bit that is turned // on, the associated defer call is made. func (s *state) openDeferExit() { … } func (s *state) callResult(n *ir.CallExpr, k callKind) *ssa.Value { … } func (s *state) callAddr(n *ir.CallExpr, k callKind) *ssa.Value { … } // Calls the function n using the specified call type. // Returns the address of the return value (or nil if none). func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool, deferExtra ir.Expr) *ssa.Value { … } // maybeNilCheckClosure checks if a nil check of a closure is needed in some // architecture-dependent situations and, if so, emits the nil check. func (s *state) maybeNilCheckClosure(closure *ssa.Value, k callKind) { … } // getClosureAndRcvr returns values for the appropriate closure and receiver of an // interface call func (s *state) getClosureAndRcvr(fn *ir.SelectorExpr) (*ssa.Value, *ssa.Value) { … } // etypesign returns the signed-ness of e, for integer/pointer etypes. // -1 means signed, +1 means unsigned, 0 means non-integer/non-pointer. func etypesign(e types.Kind) int8 { … } // addr converts the address of the expression n to SSA, adds it to s and returns the SSA result. // The value that the returned Value represents is guaranteed to be non-nil. func (s *state) addr(n ir.Node) *ssa.Value { … } // canSSA reports whether n is SSA-able. // n must be an ONAME (or an ODOT sequence with an ONAME base). func (s *state) canSSA(n ir.Node) bool { … } func (s *state) canSSAName(name *ir.Name) bool { … } // exprPtr evaluates n to a pointer and nil-checks it. func (s *state) exprPtr(n ir.Node, bounded bool, lineno src.XPos) *ssa.Value { … } // nilCheck generates nil pointer checking code. // Used only for automatically inserted nil checks, // not for user code like 'x != nil'. // Returns a "definitely not nil" copy of x to ensure proper ordering // of the uses of the post-nilcheck pointer. func (s *state) nilCheck(ptr *ssa.Value) *ssa.Value { … } // boundsCheck generates bounds checking code. Checks if 0 <= idx <[=] len, branches to exit if not. // Starts a new block on return. // On input, len must be converted to full int width and be nonnegative. // Returns idx converted to full int width. // If bounded is true then caller guarantees the index is not out of bounds // (but boundsCheck will still extend the index to full int width). func (s *state) boundsCheck(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value { … } // If cmp (a bool) is false, panic using the given function. func (s *state) check(cmp *ssa.Value, fn *obj.LSym) { … } func (s *state) intDivide(n ir.Node, a, b *ssa.Value) *ssa.Value { … } // rtcall issues a call to the given runtime function fn with the listed args. // Returns a slice of results of the given result types. // The call is added to the end of the current block. // If returns is false, the block is marked as an exit block. func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args ...*ssa.Value) []*ssa.Value { … } // do *left = right for type t. func (s *state) storeType(t *types.Type, left, right *ssa.Value, skip skipMask, leftIsStmt bool) { … } // do *left = right for all scalar (non-pointer) parts of t. func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip skipMask) { … } // do *left = right for all pointer parts of t. func (s *state) storeTypePtrs(t *types.Type, left, right *ssa.Value) { … } // putArg evaluates n for the purpose of passing it as an argument to a function and returns the value for the call. func (s *state) putArg(n ir.Node, t *types.Type) *ssa.Value { … } func (s *state) storeArgWithBase(n ir.Node, t *types.Type, base *ssa.Value, off int64) { … } // slice computes the slice v[i:j:k] and returns ptr, len, and cap of result. // i,j,k may be nil, in which case they are set to their default value. // v may be a slice, string or pointer to an array. func (s *state) slice(v, i, j, k *ssa.Value, bounded bool) (p, l, c *ssa.Value) { … } type u642fcvtTab … var u64_f64 … var u64_f32 … func (s *state) uint64Tofloat64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { … } func (s *state) uint64Tofloat32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { … } func (s *state) uint64Tofloat(cvttab *u642fcvtTab, n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { … } type u322fcvtTab … var u32_f64 … var u32_f32 … func (s *state) uint32Tofloat64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { … } func (s *state) uint32Tofloat32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { … } func (s *state) uint32Tofloat(cvttab *u322fcvtTab, n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { … } // referenceTypeBuiltin generates code for the len/cap builtins for maps and channels. func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value { … } type f2uCvtTab … var f32_u64 … var f64_u64 … var f32_u32 … var f64_u32 … func (s *state) float32ToUint64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { … } func (s *state) float64ToUint64(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { … } func (s *state) float32ToUint32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { … } func (s *state) float64ToUint32(n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { … } func (s *state) floatToUint(cvttab *f2uCvtTab, n ir.Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { … } // dottype generates SSA for a type assertion node. // commaok indicates whether to panic or return a bool. // If commaok is false, resok will be nil. func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Value) { … } func (s *state) dynamicDottype(n *ir.DynamicTypeAssertExpr, commaok bool) (res, resok *ssa.Value) { … } // dottype1 implements a x.(T) operation. iface is the argument (x), dst is the type we're asserting to (T) // and src is the type we're asserting from. // source is the *runtime._type of src // target is the *runtime._type of dst. // If src is a nonempty interface and dst is not an interface, targetItab is an itab representing (dst, src). Otherwise it is nil. // commaok is true if the caller wants a boolean success value. Otherwise, the generated code panics if the conversion fails. // descriptor is a compiler-allocated internal/abi.TypeAssert whose address is passed to runtime.typeAssert when // the target type is a compile-time-known non-empty interface. It may be nil. func (s *state) dottype1(pos src.XPos, src, dst *types.Type, iface, source, target, targetItab *ssa.Value, commaok bool, descriptor *obj.LSym) (res, resok *ssa.Value) { … } // temp allocates a temp of type t at position pos func (s *state) temp(pos src.XPos, t *types.Type) (*ir.Name, *ssa.Value) { … } // variable returns the value of a variable at the current location. func (s *state) variable(n ir.Node, t *types.Type) *ssa.Value { … } func (s *state) mem() *ssa.Value { … } func (s *state) addNamedValue(n *ir.Name, v *ssa.Value) { … } type Branch … type State … func (s *State) FuncInfo() *obj.FuncInfo { … } // Prog appends a new Prog. func (s *State) Prog(as obj.As) *obj.Prog { … } // Pc returns the current Prog. func (s *State) Pc() *obj.Prog { … } // SetPos sets the current source position. func (s *State) SetPos(pos src.XPos) { … } // Br emits a single branch instruction and returns the instruction. // Not all architectures need the returned instruction, but otherwise // the boilerplate is common to all. func (s *State) Br(op obj.As, target *ssa.Block) *obj.Prog { … } // DebugFriendlySetPosFrom adjusts Pos.IsStmt subject to heuristics // that reduce "jumpy" line number churn when debugging. // Spill/fill/copy instructions from the register allocator, // phi functions, and instructions with a no-pos position // are examples of instructions that can cause churn. func (s *State) DebugFriendlySetPosFrom(v *ssa.Value) { … } // emit argument info (locations on stack) for traceback. func emitArgInfo(e *ssafn, f *ssa.Func, pp *objw.Progs) { … } // emit argument info (locations on stack) of f for traceback. func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym { … } // for wrapper, emit info of wrapped function. func emitWrappedFuncInfo(e *ssafn, pp *objw.Progs) { … } // genssa appends entries to pp for each instruction in f. func genssa(f *ssa.Func, pp *objw.Progs) { … } func defframe(s *State, e *ssafn, f *ssa.Func) { … } type IndexJump … func (s *State) oneJump(b *ssa.Block, jump *IndexJump) { … } // CombJump generates combinational instructions (2 at present) for a block jump, // thereby the behaviour of non-standard condition codes could be simulated func (s *State) CombJump(b, next *ssa.Block, jumps *[2][2]IndexJump) { … } // AddAux adds the offset in the aux fields (AuxInt and Aux) of v to a. func AddAux(a *obj.Addr, v *ssa.Value) { … } func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) { … } // extendIndex extends v to a full int width. // panic with the given kind if v does not fit in an int (only on 32-bit archs). func (s *state) extendIndex(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value { … } // CheckLoweredPhi checks that regalloc and stackalloc correctly handled phi values. // Called during ssaGenValue. func CheckLoweredPhi(v *ssa.Value) { … } // CheckLoweredGetClosurePtr checks that v is the first instruction in the function's entry block, // except for incoming in-register arguments. // The output of LoweredGetClosurePtr is generally hardwired to the correct register. // That register contains the closure pointer on closure entry. func CheckLoweredGetClosurePtr(v *ssa.Value) { … } // CheckArgReg ensures that v is in the function's entry block. func CheckArgReg(v *ssa.Value) { … } func AddrAuto(a *obj.Addr, v *ssa.Value) { … } // Call returns a new CALL instruction for the SSA value v. // It uses PrepareCall to prepare the call. func (s *State) Call(v *ssa.Value) *obj.Prog { … } // TailCall returns a new tail call instruction for the SSA value v. // It is like Call, but for a tail call. func (s *State) TailCall(v *ssa.Value) *obj.Prog { … } // PrepareCall prepares to emit a CALL instruction for v and does call-related bookkeeping. // It must be called immediately before emitting the actual CALL instruction, // since it emits PCDATA for the stack map at the call (calls are safe points). func (s *State) PrepareCall(v *ssa.Value) { … } // UseArgs records the fact that an instruction needs a certain amount of // callee args space for its use. func (s *State) UseArgs(n int64) { … } // fieldIdx finds the index of the field referred to by the ODOT node n. func fieldIdx(n *ir.SelectorExpr) int { … } type ssafn … // StringData returns a symbol which // is the data component of a global string constant containing s. func (e *ssafn) StringData(s string) *obj.LSym { … } // SplitSlot returns a slot representing the data of parent starting at offset. func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot { … } // Logf logs a message from the compiler. func (e *ssafn) Logf(msg string, args ...interface{ … } func (e *ssafn) Log() bool { … } // Fatalf reports a compiler error and exits. func (e *ssafn) Fatalf(pos src.XPos, msg string, args ...interface{ … } // Warnl reports a "warning", which is usually flag-triggered // logging output for the benefit of tests. func (e *ssafn) Warnl(pos src.XPos, fmt_ string, args ...interface{ … } func (e *ssafn) Debug_checknil() bool { … } func (e *ssafn) UseWriteBarrier() bool { … } func (e *ssafn) Syslook(name string) *obj.LSym { … } func (e *ssafn) Func() *ir.Func { … } func clobberBase(n ir.Node) ir.Node { … } // callTargetLSym returns the correct LSym to call 'callee' using its ABI. func callTargetLSym(callee *ir.Name) *obj.LSym { … } const deferStructFnField … var deferType … // deferstruct returns a type interchangeable with runtime._defer. // Make sure this stays in sync with runtime/runtime2.go:_defer. func deferstruct() *types.Type { … } // SpillSlotAddr uses LocalSlot information to initialize an obj.Addr // The resulting addr is used in a non-standard context -- in the prologue // of a function, before the frame has been constructed, so the standard // addressing for the parameters will be wrong. func SpillSlotAddr(spill ssa.Spill, baseReg int16, extraOffset int64) obj.Addr { … } var BoundsCheckFunc … var ExtendCheckFunc …