mirror of
https://github.com/golang/go.git
synced 2025-05-28 02:41:30 +00:00
This is part of a general effort to shrink walk. In an ideal world, we'd have an SSA op for allocation, but we don't yet have a good mechanism for introducing function calling during SSA compilation. In the meantime, SSA conversion is a better place for it. This also makes it easier to introduce new optimizations; instead of doing the typecheck walk dance, we can simply write what we want the backend to do. I introduced a new opcode in this change because: (a) It avoids a class of bugs involving correctly detecting whether this ONEW is a "before walk" ONEW or an "after walk" ONEW. It also means that using ONEW or ONEWOBJ in the wrong context will generally result in a faster failure. (b) Opcodes are cheap. (c) It provides a better place to put documentation. This change also is also marginally more performant: name old alloc/op new alloc/op delta Template 39.1MB ± 0% 39.0MB ± 0% -0.14% (p=0.008 n=5+5) Unicode 28.4MB ± 0% 28.4MB ± 0% ~ (p=0.421 n=5+5) GoTypes 132MB ± 0% 132MB ± 0% -0.23% (p=0.008 n=5+5) Compiler 608MB ± 0% 607MB ± 0% -0.25% (p=0.008 n=5+5) SSA 2.04GB ± 0% 2.04GB ± 0% -0.01% (p=0.008 n=5+5) Flate 24.4MB ± 0% 24.3MB ± 0% -0.13% (p=0.008 n=5+5) GoParser 29.3MB ± 0% 29.1MB ± 0% -0.54% (p=0.008 n=5+5) Reflect 84.8MB ± 0% 84.7MB ± 0% -0.21% (p=0.008 n=5+5) Tar 36.7MB ± 0% 36.6MB ± 0% -0.10% (p=0.008 n=5+5) XML 48.7MB ± 0% 48.6MB ± 0% -0.24% (p=0.008 n=5+5) [Geo mean] 85.0MB 84.8MB -0.19% name old allocs/op new allocs/op delta Template 383k ± 0% 382k ± 0% -0.26% (p=0.008 n=5+5) Unicode 341k ± 0% 341k ± 0% ~ (p=0.579 n=5+5) GoTypes 1.37M ± 0% 1.36M ± 0% -0.39% (p=0.008 n=5+5) Compiler 5.59M ± 0% 5.56M ± 0% -0.49% (p=0.008 n=5+5) SSA 16.9M ± 0% 16.9M ± 0% -0.03% (p=0.008 n=5+5) Flate 238k ± 0% 238k ± 0% -0.23% (p=0.008 n=5+5) GoParser 306k ± 0% 303k ± 0% -0.93% (p=0.008 n=5+5) Reflect 990k ± 0% 987k ± 0% -0.33% (p=0.008 n=5+5) Tar 356k ± 0% 355k ± 0% -0.20% (p=0.008 n=5+5) XML 444k ± 0% 442k ± 0% -0.45% (p=0.008 n=5+5) [Geo mean] 848k 845k -0.33% Change-Id: I2c36003a7cbf71b53857b7de734852b698f49310 Reviewed-on: https://go-review.googlesource.com/c/go/+/167957 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
334 lines
7.2 KiB
Go
334 lines
7.2 KiB
Go
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package gc
|
|
|
|
import (
|
|
"cmd/compile/internal/ssa"
|
|
"cmd/compile/internal/types"
|
|
"cmd/internal/obj"
|
|
"cmd/internal/src"
|
|
"sync"
|
|
)
|
|
|
|
const (
|
|
BADWIDTH = types.BADWIDTH
|
|
|
|
// maximum size variable which we will allocate on the stack.
|
|
// This limit is for explicit variable declarations like "var x T" or "x := ...".
|
|
maxStackVarSize = 10 * 1024 * 1024
|
|
|
|
// maximum size of implicit variables that we will allocate on the stack.
|
|
// p := new(T) allocating T on the stack
|
|
// p := &T{} allocating T on the stack
|
|
// s := make([]T, n) allocating [n]T on the stack
|
|
// s := []byte("...") allocating [n]byte on the stack
|
|
maxImplicitStackVarSize = 64 * 1024
|
|
)
|
|
|
|
// isRuntimePkg reports whether p is package runtime.
|
|
func isRuntimePkg(p *types.Pkg) bool {
|
|
if compiling_runtime && p == localpkg {
|
|
return true
|
|
}
|
|
return p.Path == "runtime"
|
|
}
|
|
|
|
// The Class of a variable/function describes the "storage class"
|
|
// of a variable or function. During parsing, storage classes are
|
|
// called declaration contexts.
|
|
type Class uint8
|
|
|
|
//go:generate stringer -type=Class
|
|
const (
|
|
Pxxx Class = iota // no class; used during ssa conversion to indicate pseudo-variables
|
|
PEXTERN // global variable
|
|
PAUTO // local variables
|
|
PAUTOHEAP // local variable or parameter moved to heap
|
|
PPARAM // input arguments
|
|
PPARAMOUT // output results
|
|
PFUNC // global function
|
|
|
|
PDISCARD // discard during parse of duplicate import
|
|
// Careful: Class is stored in three bits in Node.flags.
|
|
// Adding a new Class will overflow that.
|
|
)
|
|
|
|
func init() {
|
|
if PDISCARD != 7 {
|
|
panic("PDISCARD changed; does all Class values still fit in three bits?")
|
|
}
|
|
}
|
|
|
|
// note this is the runtime representation
|
|
// of the compilers arrays.
|
|
//
|
|
// typedef struct
|
|
// { // must not move anything
|
|
// uchar array[8]; // pointer to data
|
|
// uchar nel[4]; // number of elements
|
|
// uchar cap[4]; // allocated number of elements
|
|
// } Array;
|
|
var array_array int // runtime offsetof(Array,array) - same for String
|
|
|
|
var array_nel int // runtime offsetof(Array,nel) - same for String
|
|
|
|
var array_cap int // runtime offsetof(Array,cap)
|
|
|
|
var sizeof_Array int // runtime sizeof(Array)
|
|
|
|
// note this is the runtime representation
|
|
// of the compilers strings.
|
|
//
|
|
// typedef struct
|
|
// { // must not move anything
|
|
// uchar array[8]; // pointer to data
|
|
// uchar nel[4]; // number of elements
|
|
// } String;
|
|
var sizeof_String int // runtime sizeof(String)
|
|
|
|
var pragcgobuf [][]string
|
|
|
|
var outfile string
|
|
var linkobj string
|
|
|
|
// nerrors is the number of compiler errors reported
|
|
// since the last call to saveerrors.
|
|
var nerrors int
|
|
|
|
// nsavederrors is the total number of compiler errors
|
|
// reported before the last call to saveerrors.
|
|
var nsavederrors int
|
|
|
|
var nsyntaxerrors int
|
|
|
|
var decldepth int32
|
|
|
|
var nolocalimports bool
|
|
|
|
var Debug [256]int
|
|
|
|
var debugstr string
|
|
|
|
var Debug_checknil int
|
|
var Debug_typeassert int
|
|
|
|
var localpkg *types.Pkg // package being compiled
|
|
|
|
var inimport bool // set during import
|
|
|
|
var itabpkg *types.Pkg // fake pkg for itab entries
|
|
|
|
var itablinkpkg *types.Pkg // fake package for runtime itab entries
|
|
|
|
var Runtimepkg *types.Pkg // fake package runtime
|
|
|
|
var racepkg *types.Pkg // package runtime/race
|
|
|
|
var msanpkg *types.Pkg // package runtime/msan
|
|
|
|
var unsafepkg *types.Pkg // package unsafe
|
|
|
|
var trackpkg *types.Pkg // fake package for field tracking
|
|
|
|
var mappkg *types.Pkg // fake package for map zero value
|
|
|
|
var gopkg *types.Pkg // pseudo-package for method symbols on anonymous receiver types
|
|
|
|
var zerosize int64
|
|
|
|
var myimportpath string
|
|
|
|
var localimport string
|
|
|
|
var asmhdr string
|
|
|
|
var simtype [NTYPE]types.EType
|
|
|
|
var (
|
|
isInt [NTYPE]bool
|
|
isFloat [NTYPE]bool
|
|
isComplex [NTYPE]bool
|
|
issimple [NTYPE]bool
|
|
)
|
|
|
|
var (
|
|
okforeq [NTYPE]bool
|
|
okforadd [NTYPE]bool
|
|
okforand [NTYPE]bool
|
|
okfornone [NTYPE]bool
|
|
okforcmp [NTYPE]bool
|
|
okforbool [NTYPE]bool
|
|
okforcap [NTYPE]bool
|
|
okforlen [NTYPE]bool
|
|
okforarith [NTYPE]bool
|
|
okforconst [NTYPE]bool
|
|
)
|
|
|
|
var (
|
|
okfor [OEND][]bool
|
|
iscmp [OEND]bool
|
|
)
|
|
|
|
var minintval [NTYPE]*Mpint
|
|
|
|
var maxintval [NTYPE]*Mpint
|
|
|
|
var minfltval [NTYPE]*Mpflt
|
|
|
|
var maxfltval [NTYPE]*Mpflt
|
|
|
|
var xtop []*Node
|
|
|
|
var exportlist []*Node
|
|
|
|
var importlist []*Node // imported functions and methods with inlinable bodies
|
|
|
|
var (
|
|
funcsymsmu sync.Mutex // protects funcsyms and associated package lookups (see func funcsym)
|
|
funcsyms []*types.Sym
|
|
)
|
|
|
|
var dclcontext Class // PEXTERN/PAUTO
|
|
|
|
var Curfn *Node
|
|
|
|
var Widthptr int
|
|
|
|
var Widthreg int
|
|
|
|
var nblank *Node
|
|
|
|
var typecheckok bool
|
|
|
|
var compiling_runtime bool
|
|
|
|
// Compiling the standard library
|
|
var compiling_std bool
|
|
|
|
var use_writebarrier bool
|
|
|
|
var pure_go bool
|
|
|
|
var flag_installsuffix string
|
|
|
|
var flag_race bool
|
|
|
|
var flag_msan bool
|
|
|
|
var flagDWARF bool
|
|
|
|
// Whether we are adding any sort of code instrumentation, such as
|
|
// when the race detector is enabled.
|
|
var instrumenting bool
|
|
|
|
// Whether we are tracking lexical scopes for DWARF.
|
|
var trackScopes bool
|
|
|
|
// Controls generation of DWARF inlined instance records. Zero
|
|
// disables, 1 emits inlined routines but suppresses var info,
|
|
// and 2 emits inlined routines with tracking of formals/locals.
|
|
var genDwarfInline int
|
|
|
|
var debuglive int
|
|
|
|
var Ctxt *obj.Link
|
|
|
|
var writearchive bool
|
|
|
|
var Nacl bool
|
|
|
|
var nodfp *Node
|
|
|
|
var disable_checknil int
|
|
|
|
var autogeneratedPos src.XPos
|
|
|
|
// interface to back end
|
|
|
|
type Arch struct {
|
|
LinkArch *obj.LinkArch
|
|
|
|
REGSP int
|
|
MAXWIDTH int64
|
|
Use387 bool // should 386 backend use 387 FP instructions instead of sse2.
|
|
SoftFloat bool
|
|
|
|
PadFrame func(int64) int64
|
|
ZeroRange func(*Progs, *obj.Prog, int64, int64, *uint32) *obj.Prog
|
|
Ginsnop func(*Progs) *obj.Prog
|
|
Ginsnopdefer func(*Progs) *obj.Prog // special ginsnop for deferreturn
|
|
|
|
// SSAMarkMoves marks any MOVXconst ops that need to avoid clobbering flags.
|
|
SSAMarkMoves func(*SSAGenState, *ssa.Block)
|
|
|
|
// SSAGenValue emits Prog(s) for the Value.
|
|
SSAGenValue func(*SSAGenState, *ssa.Value)
|
|
|
|
// SSAGenBlock emits end-of-block Progs. SSAGenValue should be called
|
|
// for all values in the block before SSAGenBlock.
|
|
SSAGenBlock func(s *SSAGenState, b, next *ssa.Block)
|
|
|
|
// ZeroAuto emits code to zero the given auto stack variable.
|
|
// ZeroAuto must not use any non-temporary registers.
|
|
// ZeroAuto will only be called for variables which contain a pointer.
|
|
ZeroAuto func(*Progs, *Node)
|
|
}
|
|
|
|
var thearch Arch
|
|
|
|
var (
|
|
staticbytes,
|
|
zerobase *Node
|
|
|
|
assertE2I,
|
|
assertE2I2,
|
|
assertI2I,
|
|
assertI2I2,
|
|
deferproc,
|
|
Deferreturn,
|
|
Duffcopy,
|
|
Duffzero,
|
|
gcWriteBarrier,
|
|
goschedguarded,
|
|
growslice,
|
|
msanread,
|
|
msanwrite,
|
|
newobject,
|
|
newproc,
|
|
panicdivide,
|
|
panicshift,
|
|
panicdottypeE,
|
|
panicdottypeI,
|
|
panicnildottype,
|
|
panicoverflow,
|
|
raceread,
|
|
racereadrange,
|
|
racewrite,
|
|
racewriterange,
|
|
x86HasPOPCNT,
|
|
x86HasSSE41,
|
|
arm64HasATOMICS,
|
|
typedmemclr,
|
|
typedmemmove,
|
|
Udiv,
|
|
writeBarrier,
|
|
zerobaseSym *obj.LSym
|
|
|
|
BoundsCheckFunc [ssa.BoundsKindCount]*obj.LSym
|
|
ExtendCheckFunc [ssa.BoundsKindCount]*obj.LSym
|
|
|
|
// GO386=387
|
|
ControlWord64trunc,
|
|
ControlWord32 *obj.LSym
|
|
|
|
// Wasm
|
|
WasmMove,
|
|
WasmZero,
|
|
WasmDiv,
|
|
WasmTruncS,
|
|
WasmTruncU,
|
|
SigPanic *obj.LSym
|
|
)
|