Help us shape the future of Go! Take the 2026 Go Developer Survey

Source file src/cmd/compile/internal/ssa/func.go

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ssa
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  	"strings"
    11  
    12  	"cmd/compile/internal/abi"
    13  	"cmd/compile/internal/base"
    14  	"cmd/compile/internal/ir"
    15  	"cmd/compile/internal/ssa/block"
    16  	"cmd/compile/internal/ssa/ssabase"
    17  	"cmd/compile/internal/ssa/ssaop"
    18  	"cmd/compile/internal/stats"
    19  	"cmd/compile/internal/typecheck"
    20  	"cmd/compile/internal/types"
    21  	"cmd/internal/obj"
    22  	"cmd/internal/src"
    23  )
    24  
    25  // A Func represents a Go func declaration (or function literal) and its body.
    26  // This package compiles each Func independently.
    27  // Funcs are single-use; a new Func must be created for every compiled function.
    28  type Func struct {
    29  	Config *Config     // architecture information
    30  	Cache  *Cache      // re-usable cache
    31  	Fe     Frontend    // frontend state associated with this Func, callbacks into compiler frontend
    32  	Pass   *Pass       // current pass information (name, options, etc.)
    33  	Name   string      // e.g. NewFunc or (*Func).NumBlocks (no package prefix)
    34  	Type   *types.Type // type signature of the function.
    35  	Blocks []*Block    // unordered set of all basic blocks (note: not indexable by ID)
    36  	Entry  *Block      // the entry basic block
    37  
    38  	bid IDAlloc // block ID allocator
    39  	vid IDAlloc // value ID allocator
    40  
    41  	HTMLWriter     HTMLWriter
    42  	FatalCleanup   func()         // cleanup function to run before reporting a fatal error
    43  	PrintOrHtmlSSA bool           // true if GOSSAFUNC matches, true even if fe.Log() (spew phase results to stdout) is false.  There's an odd dependence on this in debug.go for method logf.
    44  	RuleMatches    map[string]int // number of times countRule was called during compilation for any given string
    45  	ABI0           *abi.ABIConfig // ABI configuration for ABI0
    46  	ABI1           *abi.ABIConfig // ABI configuration for ABIInternal
    47  	ABISelf        *abi.ABIConfig // ABI for function being compiled
    48  	ABIDefault     *abi.ABIConfig // ABI for rtcall and other no-parsed-signature/pragma functions.
    49  
    50  	MaxCPUFeatures CPUfeatures // union of all the CPU features in all the blocks.
    51  
    52  	Scheduled   bool  // Values in Blocks are in final order
    53  	Laidout     bool  // Blocks are ordered
    54  	NoSplit     bool  // true if function is marked as nosplit.  Used by schedule check pass.
    55  	dumpFileSeq uint8 // the sequence numbers of dump file. (%s_%02d__%s.dump", funcname, dumpFileSeq, phaseName)
    56  	IsPgoHot    bool
    57  	DeferReturn *Block // avoid creating more than one deferreturn if there's multiple calls to deferproc-etc.
    58  
    59  	// when register allocation is done, maps value ids to locations
    60  	RegAlloc []Location
    61  
    62  	// temporary registers allocated to rare instructions
    63  	TempRegs map[ID]*ssabase.Register
    64  
    65  	// map from LocalSlot to set of Values that we want to store in that slot.
    66  	NamedValues map[LocalSlot][]*Value
    67  	// Names is a copy of NamedValues.Keys. We keep a separate list
    68  	// of keys to make iteration order deterministic.
    69  	Names []LocalSlot
    70  	// Canonicalize root/top-level local slots, and canonicalize their pieces.
    71  	// Because LocalSlot pieces refer to their parents with a pointer, this ensures that equivalent slots really are equal.
    72  	CanonicalLocalSlots  map[LocalSlot]*LocalSlot
    73  	CanonicalLocalSplits map[LocalSlotSplitKey]*LocalSlot
    74  
    75  	// RegArgs is a slice of register-memory pairs that must be spilled and unspilled in the uncommon path of function entry.
    76  	RegArgs []Spill
    77  	// OwnAux describes parameters and results for this function.
    78  	OwnAux *AuxCall
    79  	// CloSlot holds the compiler-synthesized name (".closureptr")
    80  	// where we spill the closure pointer for range func bodies.
    81  	CloSlot *ir.Name
    82  
    83  	FreeValues *Value // free Values linked by argstorage[0].  All other fields except ID are 0/nil.
    84  	FreeBlocks *Block // free Blocks linked by succstorage[0].b.  All other fields except ID are 0/nil.
    85  
    86  	cachedPostorder  []*Block   // cached postorder traversal
    87  	cachedIdom       []*Block   // cached immediate dominators
    88  	cachedSdom       SparseTree // cached dominator tree
    89  	cachedLoopnest   *LoopNest  // cached loop nest information
    90  	CachedLineStarts *XPosMap   // cached map/set of xpos to integers
    91  
    92  	Auxmap    AuxMap             // map from aux values to opaque ids used by CSE
    93  	constants map[int64][]*Value // constants cache, keyed by constant value; users must check value's Op and Type
    94  }
    95  
    96  // FuncNameABI returns n followed by a comma and the value of a.
    97  // This is a separate function to allow a single point encoding
    98  // of the format, which is used in places where there's not a Func yet.
    99  func FuncNameABI(n string, a obj.ABI) string {
   100  	return fmt.Sprintf("%s,%d", n, a)
   101  }
   102  
   103  type LocalSlotSplitKey struct {
   104  	parent *LocalSlot
   105  	Off    int64       // offset of slot in N
   106  	Type   *types.Type // type of slot
   107  }
   108  
   109  // These magic auxint values let us easily cache non-numeric constants
   110  // using the same constants map while making collisions unlikely.
   111  // These values are unlikely to occur in regular code and
   112  // are easy to grep for in case of bugs.
   113  const (
   114  	constSliceMagic       = 1122334455
   115  	constInterfaceMagic   = 2233445566
   116  	constNilMagic         = 3344556677
   117  	constEmptyStringMagic = 4455667788
   118  	constSIMDMagic        = 5566778899
   119  )
   120  
   121  // IsMergeCandidate returns true if variable n could participate in
   122  // stack slot merging. For now we're restricting the set to things to
   123  // items larger than what CanSSA would allow (approximateky, we disallow things
   124  // marked as open defer slots so as to avoid complicating liveness
   125  // analysis.
   126  func IsMergeCandidate(n *ir.Name) bool {
   127  	if base.Debug.MergeLocals == 0 ||
   128  		base.Flag.N != 0 ||
   129  		n.Class != ir.PAUTO ||
   130  		n.Type().Size() <= int64(3*types.PtrSize) ||
   131  		n.Addrtaken() ||
   132  		n.NonMergeable() ||
   133  		n.OpenDeferSlot() {
   134  		return false
   135  	}
   136  	return true
   137  }
   138  
   139  // NewFunc returns a new, empty function object.
   140  // Caller must reset cache before calling NewFunc.
   141  func (c *Config) NewFunc(fe Frontend, cache *Cache) *Func {
   142  	return &Func{
   143  		Fe:     fe,
   144  		Config: c,
   145  		Cache:  cache,
   146  
   147  		NamedValues:          make(map[LocalSlot][]*Value),
   148  		CanonicalLocalSlots:  make(map[LocalSlot]*LocalSlot),
   149  		CanonicalLocalSplits: make(map[LocalSlotSplitKey]*LocalSlot),
   150  		OwnAux:               &AuxCall{},
   151  	}
   152  }
   153  
   154  func (f *Func) NewStats(prefix string) *stats.PrefixStats {
   155  	fef := f.Fe.Func()
   156  	if fef == nil {
   157  		return nil
   158  	}
   159  	s := fef.Stats
   160  	return s.NewPrefixStat(prefix)
   161  }
   162  
   163  // NumBlocks returns an integer larger than the id of any Block in the Func.
   164  func (f *Func) NumBlocks() int {
   165  	return f.bid.Num()
   166  }
   167  
   168  // NumValues returns an integer larger than the id of any Value in the Func.
   169  func (f *Func) NumValues() int {
   170  	return f.vid.Num()
   171  }
   172  
   173  // NameABI returns the function name followed by comma and the ABI number.
   174  // This is intended for use with GOSSAFUNC and HTML dumps, and differs from
   175  // the linker's "<1>" convention because "<" and ">" require shell quoting
   176  // and are not legal file names (for use with GOSSADIR) on Windows.
   177  func (f *Func) NameABI() string {
   178  	return FuncNameABI(f.Name, f.ABISelf.Which())
   179  }
   180  
   181  // NewSparseSet returns a sparse set that can store at least up to n integers.
   182  func (f *Func) NewSparseSet(n int) *SparseSet {
   183  	return f.Cache.AllocSparseSet(n)
   184  }
   185  
   186  // RetSparseSet returns a sparse set to the config's cache of sparse
   187  // sets to be reused by f.newSparseSet.
   188  func (f *Func) RetSparseSet(ss *SparseSet) {
   189  	f.Cache.FreeSparseSet(ss)
   190  }
   191  
   192  // NewSparseMap returns a sparse map that can store at least up to n integers.
   193  func (f *Func) NewSparseMap(n int) *SparseMap {
   194  	return f.Cache.AllocSparseMap(n)
   195  }
   196  
   197  // RetSparseMap returns a sparse map to the config's cache of sparse
   198  // sets to be reused by f.newSparseMap.
   199  func (f *Func) RetSparseMap(ss *SparseMap) {
   200  	f.Cache.FreeSparseMap(ss)
   201  }
   202  
   203  // NewSparseMapPos returns a sparse map that can store at least up to n integers.
   204  func (f *Func) NewSparseMapPos(n int) *SparseMapPos {
   205  	return f.Cache.AllocSparseMapPos(n)
   206  }
   207  
   208  // RetSparseMapPos returns a sparse map to the config's cache of sparse
   209  // sets to be reused by f.newSparseMapPos.
   210  func (f *Func) RetSparseMapPos(ss *SparseMapPos) {
   211  	f.Cache.FreeSparseMapPos(ss)
   212  }
   213  
   214  // NewPoset returns a new poset from the internal cache
   215  func (f *Func) NewPoset() *Poset {
   216  	if len(f.Cache.scrPoset) > 0 {
   217  		po := f.Cache.scrPoset[len(f.Cache.scrPoset)-1]
   218  		f.Cache.scrPoset = f.Cache.scrPoset[:len(f.Cache.scrPoset)-1]
   219  		return po
   220  	}
   221  	return newPoset()
   222  }
   223  
   224  // RetPoset returns a poset to the internal cache
   225  func (f *Func) RetPoset(po *Poset) {
   226  	f.Cache.scrPoset = append(f.Cache.scrPoset, po)
   227  }
   228  
   229  // LocalSlotAddr returns a stable canonical *LocalSlot for slot, created on
   230  // first use. SplitOf parents need it: f.Names holds values, not pointers.
   231  func (f *Func) LocalSlotAddr(slot LocalSlot) *LocalSlot {
   232  	a, ok := f.CanonicalLocalSlots[slot]
   233  	if !ok {
   234  		a = new(LocalSlot)
   235  		*a = slot // don't escape slot
   236  		f.CanonicalLocalSlots[slot] = a
   237  	}
   238  	return a
   239  }
   240  
   241  func (f *Func) SplitString(name *LocalSlot) (*LocalSlot, *LocalSlot) {
   242  	ptrType := types.NewPtr(types.Types[types.TUINT8])
   243  	lenType := types.Types[types.TINT]
   244  	// Split this string up into two separate variables.
   245  	p := f.SplitSlot(name, ".ptr", 0, ptrType)
   246  	l := f.SplitSlot(name, ".len", ptrType.Size(), lenType)
   247  	return p, l
   248  }
   249  
   250  func (f *Func) SplitInterface(name *LocalSlot) (*LocalSlot, *LocalSlot) {
   251  	n := name.N
   252  	u := types.Types[types.TUINTPTR]
   253  	t := types.NewPtr(types.Types[types.TUINT8])
   254  	// Split this interface up into two separate variables.
   255  	sfx := ".itab"
   256  	if n.Type().IsEmptyInterface() {
   257  		sfx = ".type"
   258  	}
   259  	c := f.SplitSlot(name, sfx, 0, u) // see comment in typebits.Set
   260  	d := f.SplitSlot(name, ".data", u.Size(), t)
   261  	return c, d
   262  }
   263  
   264  func (f *Func) SplitSlice(name *LocalSlot) (*LocalSlot, *LocalSlot, *LocalSlot) {
   265  	ptrType := types.NewPtr(name.Type.Elem())
   266  	lenType := types.Types[types.TINT]
   267  	p := f.SplitSlot(name, ".ptr", 0, ptrType)
   268  	l := f.SplitSlot(name, ".len", ptrType.Size(), lenType)
   269  	c := f.SplitSlot(name, ".cap", ptrType.Size()+lenType.Size(), lenType)
   270  	return p, l, c
   271  }
   272  
   273  func (f *Func) SplitComplex(name *LocalSlot) (*LocalSlot, *LocalSlot) {
   274  	s := name.Type.Size() / 2
   275  	var t *types.Type
   276  	if s == 8 {
   277  		t = types.Types[types.TFLOAT64]
   278  	} else {
   279  		t = types.Types[types.TFLOAT32]
   280  	}
   281  	r := f.SplitSlot(name, ".real", 0, t)
   282  	i := f.SplitSlot(name, ".imag", t.Size(), t)
   283  	return r, i
   284  }
   285  
   286  func (f *Func) SplitInt64(name *LocalSlot) (*LocalSlot, *LocalSlot) {
   287  	var t *types.Type
   288  	if name.Type.IsSigned() {
   289  		t = types.Types[types.TINT32]
   290  	} else {
   291  		t = types.Types[types.TUINT32]
   292  	}
   293  	if f.Config.BigEndian {
   294  		return f.SplitSlot(name, ".hi", 0, t), f.SplitSlot(name, ".lo", t.Size(), types.Types[types.TUINT32])
   295  	}
   296  	return f.SplitSlot(name, ".hi", t.Size(), t), f.SplitSlot(name, ".lo", 0, types.Types[types.TUINT32])
   297  }
   298  
   299  func (f *Func) SplitStruct(name *LocalSlot, i int) *LocalSlot {
   300  	st := name.Type
   301  	return f.SplitSlot(name, st.FieldName(i), st.FieldOff(i), st.FieldType(i))
   302  }
   303  
   304  func (f *Func) SplitArray(name *LocalSlot) *LocalSlot {
   305  	n := name.N
   306  	at := name.Type
   307  	if at.NumElem() != 1 {
   308  		base.FatalfAt(n.Pos(), "bad array size")
   309  	}
   310  	et := at.Elem()
   311  	return f.SplitSlot(name, "[0]", 0, et)
   312  }
   313  
   314  func (f *Func) SplitSlot(name *LocalSlot, sfx string, offset int64, t *types.Type) *LocalSlot {
   315  	lssk := LocalSlotSplitKey{name, offset, t}
   316  	if als, ok := f.CanonicalLocalSplits[lssk]; ok {
   317  		return als
   318  	}
   319  	// Note: the _ field may appear several times.  But
   320  	// have no fear, identically-named but distinct Autos are
   321  	// ok, albeit maybe confusing for a debugger.
   322  	ls := f.Fe.SplitSlot(name, sfx, offset, t)
   323  	f.CanonicalLocalSplits[lssk] = &ls
   324  	return &ls
   325  }
   326  
   327  // NewValue allocates a new Value with the given fields and places it at the end of b.Values.
   328  func (f *Func) NewValue(op ssaop.Op, t *types.Type, b *Block, pos src.XPos) *Value {
   329  	var v *Value
   330  	if f.FreeValues != nil {
   331  		v = f.FreeValues
   332  		f.FreeValues = v.Argstorage[0]
   333  		v.Argstorage[0] = nil
   334  	} else {
   335  		ID := f.vid.Get()
   336  		if int(ID) < len(f.Cache.values) {
   337  			v = &f.Cache.values[ID]
   338  			v.ID = ID
   339  		} else {
   340  			v = &Value{ID: ID}
   341  		}
   342  	}
   343  	v.Op = op
   344  	v.Type = t
   345  	v.Block = b
   346  	if NotStmtBoundary(op) {
   347  		pos = pos.WithNotStmt()
   348  	}
   349  	v.Pos = pos
   350  	b.Values = append(b.Values, v)
   351  	return v
   352  }
   353  
   354  // NewValueNoBlock allocates a new Value with the given fields.
   355  // The returned value is not placed in any block.  Once the caller
   356  // decides on a block b, it must set b.Block and append
   357  // the returned value to b.Values.
   358  func (f *Func) NewValueNoBlock(op ssaop.Op, t *types.Type, pos src.XPos) *Value {
   359  	var v *Value
   360  	if f.FreeValues != nil {
   361  		v = f.FreeValues
   362  		f.FreeValues = v.Argstorage[0]
   363  		v.Argstorage[0] = nil
   364  	} else {
   365  		ID := f.vid.Get()
   366  		if int(ID) < len(f.Cache.values) {
   367  			v = &f.Cache.values[ID]
   368  			v.ID = ID
   369  		} else {
   370  			v = &Value{ID: ID}
   371  		}
   372  	}
   373  	v.Op = op
   374  	v.Type = t
   375  	v.Block = nil // caller must fix this.
   376  	if NotStmtBoundary(op) {
   377  		pos = pos.WithNotStmt()
   378  	}
   379  	v.Pos = pos
   380  	return v
   381  }
   382  
   383  // LogStat writes a string key and int value as a warning in a
   384  // tab-separated format easily handled by spreadsheets or awk.
   385  // file names, lines, and function names are included to provide enough (?)
   386  // context to allow item-by-item comparisons across runs.
   387  // For example:
   388  // awk 'BEGIN {FS="\t"} $3~/TIME/{sum+=$4} END{print "t(ns)=",sum}' t.log
   389  func (f *Func) LogStat(key string, args ...any) {
   390  	value := ""
   391  	for _, a := range args {
   392  		value += fmt.Sprintf("\t%v", a)
   393  	}
   394  	n := "missing_pass"
   395  	if f.Pass != nil {
   396  		n = strings.ReplaceAll(f.Pass.Name, " ", "_")
   397  	}
   398  	f.Warnl(f.Entry.Pos, "\t%s\t%s%s\t%s", n, key, value, f.Name)
   399  }
   400  
   401  // unCacheLine removes v from f's constant cache "line" for aux,
   402  // resets v.InCache when it is found (and removed),
   403  // and returns whether v was found in that line.
   404  func (f *Func) unCacheLine(v *Value, aux int64) bool {
   405  	vv := f.constants[aux]
   406  	for i, cv := range vv {
   407  		if v == cv {
   408  			vv[i] = vv[len(vv)-1]
   409  			vv[len(vv)-1] = nil
   410  			f.constants[aux] = vv[0 : len(vv)-1]
   411  			v.InCache = false
   412  			return true
   413  		}
   414  	}
   415  	return false
   416  }
   417  
   418  // UnCache removes v from f's constant cache.
   419  func (f *Func) UnCache(v *Value) {
   420  	if v.InCache {
   421  		aux := v.AuxInt
   422  		if f.unCacheLine(v, aux) {
   423  			return
   424  		}
   425  		if aux == 0 {
   426  			switch v.Op {
   427  			case ssaop.OpConstNil:
   428  				aux = constNilMagic
   429  			case ssaop.OpConstSlice:
   430  				aux = constSliceMagic
   431  			case ssaop.OpConstString:
   432  				aux = constEmptyStringMagic
   433  			case ssaop.OpConstInterface:
   434  				aux = constInterfaceMagic
   435  			case ssaop.OpZeroSIMD:
   436  				aux = constSIMDMagic
   437  			}
   438  			if aux != 0 && f.unCacheLine(v, aux) {
   439  				return
   440  			}
   441  		}
   442  		f.Fatalf("unCached value %s not found in cache, auxInt=0x%x, adjusted aux=0x%x", v.LongString(), v.AuxInt, aux)
   443  	}
   444  }
   445  
   446  // FreeValue frees a value. It must no longer be referenced or have any args.
   447  func (f *Func) FreeValue(v *Value) {
   448  	if v.Block == nil {
   449  		f.Fatalf("trying to free an already freed value")
   450  	}
   451  	if v.Uses != 0 {
   452  		f.Fatalf("value %s still has %d uses", v, v.Uses)
   453  	}
   454  	if len(v.Args) != 0 {
   455  		f.Fatalf("value %s still has %d args", v, len(v.Args))
   456  	}
   457  	// Clear everything but ID (which we reuse).
   458  	id := v.ID
   459  	if v.InCache {
   460  		f.UnCache(v)
   461  	}
   462  	*v = Value{}
   463  	v.ID = id
   464  	v.Argstorage[0] = f.FreeValues
   465  	f.FreeValues = v
   466  }
   467  
   468  // NewBlock allocates a new Block of the given kind and places it at the end of f.Blocks.
   469  func (f *Func) NewBlock(kind block.BlockKind) *Block {
   470  	var b *Block
   471  	if f.FreeBlocks != nil {
   472  		b = f.FreeBlocks
   473  		f.FreeBlocks = b.Succstorage[0].B
   474  		b.Succstorage[0].B = nil
   475  	} else {
   476  		ID := f.bid.Get()
   477  		if int(ID) < len(f.Cache.blocks) {
   478  			b = &f.Cache.blocks[ID]
   479  			b.ID = ID
   480  		} else {
   481  			b = &Block{ID: ID}
   482  		}
   483  	}
   484  	b.Kind = kind
   485  	b.Func = f
   486  	b.Preds = b.Predstorage[:0]
   487  	b.Succs = b.Succstorage[:0]
   488  	b.Values = b.Valstorage[:0]
   489  	f.Blocks = append(f.Blocks, b)
   490  	f.InvalidateCFG()
   491  	return b
   492  }
   493  
   494  func (f *Func) FreeBlock(b *Block) {
   495  	if b.Func == nil {
   496  		f.Fatalf("trying to free an already freed block")
   497  	}
   498  	// Clear everything but ID (which we reuse).
   499  	id := b.ID
   500  	*b = Block{}
   501  	b.ID = id
   502  	b.Succstorage[0].B = f.FreeBlocks
   503  	f.FreeBlocks = b
   504  }
   505  
   506  // NewValue0 returns a new value in the block with no arguments and zero aux values.
   507  func (b *Block) NewValue0(pos src.XPos, op ssaop.Op, t *types.Type) *Value {
   508  	v := b.Func.NewValue(op, t, b, pos)
   509  	v.AuxInt = 0
   510  	v.Args = v.Argstorage[:0]
   511  	return v
   512  }
   513  
   514  // NewValue0I returns a new value in the block with no arguments and an auxint value.
   515  func (b *Block) NewValue0I(pos src.XPos, op ssaop.Op, t *types.Type, auxint int64) *Value {
   516  	v := b.Func.NewValue(op, t, b, pos)
   517  	v.AuxInt = auxint
   518  	v.Args = v.Argstorage[:0]
   519  	return v
   520  }
   521  
   522  // NewValue0A returns a new value in the block with no arguments and an aux value.
   523  func (b *Block) NewValue0A(pos src.XPos, op ssaop.Op, t *types.Type, aux Aux) *Value {
   524  	v := b.Func.NewValue(op, t, b, pos)
   525  	v.AuxInt = 0
   526  	v.Aux = aux
   527  	v.Args = v.Argstorage[:0]
   528  	return v
   529  }
   530  
   531  // NewValue0IA returns a new value in the block with no arguments and both an auxint and aux values.
   532  func (b *Block) NewValue0IA(pos src.XPos, op ssaop.Op, t *types.Type, auxint int64, aux Aux) *Value {
   533  	v := b.Func.NewValue(op, t, b, pos)
   534  	v.AuxInt = auxint
   535  	v.Aux = aux
   536  	v.Args = v.Argstorage[:0]
   537  	return v
   538  }
   539  
   540  // NewValue1 returns a new value in the block with one argument and zero aux values.
   541  func (b *Block) NewValue1(pos src.XPos, op ssaop.Op, t *types.Type, arg *Value) *Value {
   542  	v := b.Func.NewValue(op, t, b, pos)
   543  	v.AuxInt = 0
   544  	v.Args = v.Argstorage[:1]
   545  	v.Argstorage[0] = arg
   546  	arg.Uses++
   547  	return v
   548  }
   549  
   550  // NewValue1I returns a new value in the block with one argument and an auxint value.
   551  func (b *Block) NewValue1I(pos src.XPos, op ssaop.Op, t *types.Type, auxint int64, arg *Value) *Value {
   552  	v := b.Func.NewValue(op, t, b, pos)
   553  	v.AuxInt = auxint
   554  	v.Args = v.Argstorage[:1]
   555  	v.Argstorage[0] = arg
   556  	arg.Uses++
   557  	return v
   558  }
   559  
   560  // NewValue1A returns a new value in the block with one argument and an aux value.
   561  func (b *Block) NewValue1A(pos src.XPos, op ssaop.Op, t *types.Type, aux Aux, arg *Value) *Value {
   562  	v := b.Func.NewValue(op, t, b, pos)
   563  	v.AuxInt = 0
   564  	v.Aux = aux
   565  	v.Args = v.Argstorage[:1]
   566  	v.Argstorage[0] = arg
   567  	arg.Uses++
   568  	return v
   569  }
   570  
   571  // NewValue1IA returns a new value in the block with one argument and both an auxint and aux values.
   572  func (b *Block) NewValue1IA(pos src.XPos, op ssaop.Op, t *types.Type, auxint int64, aux Aux, arg *Value) *Value {
   573  	v := b.Func.NewValue(op, t, b, pos)
   574  	v.AuxInt = auxint
   575  	v.Aux = aux
   576  	v.Args = v.Argstorage[:1]
   577  	v.Argstorage[0] = arg
   578  	arg.Uses++
   579  	return v
   580  }
   581  
   582  // NewValue2 returns a new value in the block with two arguments and zero aux values.
   583  func (b *Block) NewValue2(pos src.XPos, op ssaop.Op, t *types.Type, arg0, arg1 *Value) *Value {
   584  	v := b.Func.NewValue(op, t, b, pos)
   585  	v.AuxInt = 0
   586  	v.Args = v.Argstorage[:2]
   587  	v.Argstorage[0] = arg0
   588  	v.Argstorage[1] = arg1
   589  	arg0.Uses++
   590  	arg1.Uses++
   591  	return v
   592  }
   593  
   594  // NewValue2A returns a new value in the block with two arguments and one aux values.
   595  func (b *Block) NewValue2A(pos src.XPos, op ssaop.Op, t *types.Type, aux Aux, arg0, arg1 *Value) *Value {
   596  	v := b.Func.NewValue(op, t, b, pos)
   597  	v.AuxInt = 0
   598  	v.Aux = aux
   599  	v.Args = v.Argstorage[:2]
   600  	v.Argstorage[0] = arg0
   601  	v.Argstorage[1] = arg1
   602  	arg0.Uses++
   603  	arg1.Uses++
   604  	return v
   605  }
   606  
   607  // NewValue2I returns a new value in the block with two arguments and an auxint value.
   608  func (b *Block) NewValue2I(pos src.XPos, op ssaop.Op, t *types.Type, auxint int64, arg0, arg1 *Value) *Value {
   609  	v := b.Func.NewValue(op, t, b, pos)
   610  	v.AuxInt = auxint
   611  	v.Args = v.Argstorage[:2]
   612  	v.Argstorage[0] = arg0
   613  	v.Argstorage[1] = arg1
   614  	arg0.Uses++
   615  	arg1.Uses++
   616  	return v
   617  }
   618  
   619  // NewValue2IA returns a new value in the block with two arguments and both an auxint and aux values.
   620  func (b *Block) NewValue2IA(pos src.XPos, op ssaop.Op, t *types.Type, auxint int64, aux Aux, arg0, arg1 *Value) *Value {
   621  	v := b.Func.NewValue(op, t, b, pos)
   622  	v.AuxInt = auxint
   623  	v.Aux = aux
   624  	v.Args = v.Argstorage[:2]
   625  	v.Argstorage[0] = arg0
   626  	v.Argstorage[1] = arg1
   627  	arg0.Uses++
   628  	arg1.Uses++
   629  	return v
   630  }
   631  
   632  // NewValue3 returns a new value in the block with three arguments and zero aux values.
   633  func (b *Block) NewValue3(pos src.XPos, op ssaop.Op, t *types.Type, arg0, arg1, arg2 *Value) *Value {
   634  	v := b.Func.NewValue(op, t, b, pos)
   635  	v.AuxInt = 0
   636  	v.Args = v.Argstorage[:3]
   637  	v.Argstorage[0] = arg0
   638  	v.Argstorage[1] = arg1
   639  	v.Argstorage[2] = arg2
   640  	arg0.Uses++
   641  	arg1.Uses++
   642  	arg2.Uses++
   643  	return v
   644  }
   645  
   646  // NewValue3I returns a new value in the block with three arguments and an auxint value.
   647  func (b *Block) NewValue3I(pos src.XPos, op ssaop.Op, t *types.Type, auxint int64, arg0, arg1, arg2 *Value) *Value {
   648  	v := b.Func.NewValue(op, t, b, pos)
   649  	v.AuxInt = auxint
   650  	v.Args = v.Argstorage[:3]
   651  	v.Argstorage[0] = arg0
   652  	v.Argstorage[1] = arg1
   653  	v.Argstorage[2] = arg2
   654  	arg0.Uses++
   655  	arg1.Uses++
   656  	arg2.Uses++
   657  	return v
   658  }
   659  
   660  // NewValue3A returns a new value in the block with three argument and an aux value.
   661  func (b *Block) NewValue3A(pos src.XPos, op ssaop.Op, t *types.Type, aux Aux, arg0, arg1, arg2 *Value) *Value {
   662  	v := b.Func.NewValue(op, t, b, pos)
   663  	v.AuxInt = 0
   664  	v.Aux = aux
   665  	v.Args = v.Argstorage[:3]
   666  	v.Argstorage[0] = arg0
   667  	v.Argstorage[1] = arg1
   668  	v.Argstorage[2] = arg2
   669  	arg0.Uses++
   670  	arg1.Uses++
   671  	arg2.Uses++
   672  	return v
   673  }
   674  
   675  // NewValue4 returns a new value in the block with four arguments and zero aux values.
   676  func (b *Block) NewValue4(pos src.XPos, op ssaop.Op, t *types.Type, arg0, arg1, arg2, arg3 *Value) *Value {
   677  	v := b.Func.NewValue(op, t, b, pos)
   678  	v.AuxInt = 0
   679  	v.Args = []*Value{arg0, arg1, arg2, arg3}
   680  	arg0.Uses++
   681  	arg1.Uses++
   682  	arg2.Uses++
   683  	arg3.Uses++
   684  	return v
   685  }
   686  
   687  // NewValue4A returns a new value in the block with four arguments and zero aux values.
   688  func (b *Block) NewValue4A(pos src.XPos, op ssaop.Op, t *types.Type, aux Aux, arg0, arg1, arg2, arg3 *Value) *Value {
   689  	v := b.Func.NewValue(op, t, b, pos)
   690  	v.AuxInt = 0
   691  	v.Aux = aux
   692  	v.Args = []*Value{arg0, arg1, arg2, arg3}
   693  	arg0.Uses++
   694  	arg1.Uses++
   695  	arg2.Uses++
   696  	arg3.Uses++
   697  	return v
   698  }
   699  
   700  // NewValue4I returns a new value in the block with four arguments and auxint value.
   701  func (b *Block) NewValue4I(pos src.XPos, op ssaop.Op, t *types.Type, auxint int64, arg0, arg1, arg2, arg3 *Value) *Value {
   702  	v := b.Func.NewValue(op, t, b, pos)
   703  	v.AuxInt = auxint
   704  	v.Args = []*Value{arg0, arg1, arg2, arg3}
   705  	arg0.Uses++
   706  	arg1.Uses++
   707  	arg2.Uses++
   708  	arg3.Uses++
   709  	return v
   710  }
   711  
   712  // ConstVal returns a constant value for c.
   713  func (f *Func) ConstVal(op ssaop.Op, t *types.Type, c int64, setAuxInt bool) *Value {
   714  	if f.constants == nil {
   715  		f.constants = make(map[int64][]*Value)
   716  	}
   717  	vv := f.constants[c]
   718  	for _, v := range vv {
   719  		if v.Op == op && v.Type.Compare(t) == types.CMPeq {
   720  			if setAuxInt && v.AuxInt != c {
   721  				panic(fmt.Sprintf("cached const %s should have AuxInt of %d", v.LongString(), c))
   722  			}
   723  			return v
   724  		}
   725  	}
   726  	var v *Value
   727  	if setAuxInt {
   728  		v = f.Entry.NewValue0I(src.NoXPos, op, t, c)
   729  	} else {
   730  		v = f.Entry.NewValue0(src.NoXPos, op, t)
   731  	}
   732  	f.constants[c] = append(vv, v)
   733  	v.InCache = true
   734  	return v
   735  }
   736  
   737  // ConstBool returns an int constant representing its argument.
   738  func (f *Func) ConstBool(t *types.Type, c bool) *Value {
   739  	i := int64(0)
   740  	if c {
   741  		i = 1
   742  	}
   743  	return f.ConstVal(ssaop.OpConstBool, t, i, true)
   744  }
   745  
   746  func (f *Func) ConstInt8(t *types.Type, c int8) *Value {
   747  	return f.ConstVal(ssaop.OpConst8, t, int64(c), true)
   748  }
   749  
   750  func (f *Func) ConstInt16(t *types.Type, c int16) *Value {
   751  	return f.ConstVal(ssaop.OpConst16, t, int64(c), true)
   752  }
   753  
   754  func (f *Func) ConstInt32(t *types.Type, c int32) *Value {
   755  	return f.ConstVal(ssaop.OpConst32, t, int64(c), true)
   756  }
   757  
   758  func (f *Func) ConstInt64(t *types.Type, c int64) *Value {
   759  	return f.ConstVal(ssaop.OpConst64, t, c, true)
   760  }
   761  
   762  func (f *Func) ConstFloat32(t *types.Type, c float64) *Value {
   763  	return f.ConstVal(ssaop.OpConst32F, t, int64(math.Float64bits(float64(float32(c)))), true)
   764  }
   765  
   766  func (f *Func) ConstFloat64(t *types.Type, c float64) *Value {
   767  	return f.ConstVal(ssaop.OpConst64F, t, int64(math.Float64bits(c)), true)
   768  }
   769  
   770  func (f *Func) ConstSlice(t *types.Type) *Value {
   771  	return f.ConstVal(ssaop.OpConstSlice, t, constSliceMagic, false)
   772  }
   773  
   774  func (f *Func) ConstInterface(t *types.Type) *Value {
   775  	return f.ConstVal(ssaop.OpConstInterface, t, constInterfaceMagic, false)
   776  }
   777  
   778  func (f *Func) ConstNil(t *types.Type) *Value {
   779  	return f.ConstVal(ssaop.OpConstNil, t, constNilMagic, false)
   780  }
   781  
   782  func (f *Func) ConstEmptyString(t *types.Type) *Value {
   783  	v := f.ConstVal(ssaop.OpConstString, t, constEmptyStringMagic, false)
   784  	v.Aux = StringToAux("")
   785  	return v
   786  }
   787  
   788  func (f *Func) ConstSIMD(t *types.Type) *Value {
   789  	return f.ConstVal(ssaop.OpZeroSIMD, t, constSIMDMagic, false)
   790  }
   791  
   792  func (f *Func) ConstOffPtrSP(t *types.Type, c int64, sp *Value) *Value {
   793  	v := f.ConstVal(ssaop.OpOffPtr, t, c, true)
   794  	if len(v.Args) == 0 {
   795  		v.AddArg(sp)
   796  	}
   797  	return v
   798  }
   799  
   800  func (f *Func) Frontend() Frontend { return f.Fe }
   801  
   802  func (f *Func) Warnl(pos src.XPos, msg string, args ...any) { f.Fe.Warnl(pos, msg, args...) }
   803  
   804  func (f *Func) Logf(msg string, args ...any) { f.Fe.Logf(msg, args...) }
   805  
   806  func (f *Func) Log() bool { return f.Fe.Log() }
   807  
   808  func (f *Func) Fatalf(msg string, args ...any) { f.FatalfWithPos(f.Entry.Pos, msg, args...) }
   809  
   810  func (f *Func) FatalfWithPos(pos src.XPos, msg string, args ...any) {
   811  	if f.Log() {
   812  		f.Logf("  pass %s end crashed\n", f.Pass.Name)
   813  		PrintFunc(f)
   814  	}
   815  	if f.FatalCleanup != nil {
   816  		f.FatalCleanup()
   817  	}
   818  	f.Fe.Fatalf(pos, msg, args...)
   819  }
   820  
   821  // postorder returns the reachable blocks in f in a postorder traversal.
   822  func (f *Func) postorder() []*Block {
   823  	if f.cachedPostorder == nil {
   824  		f.cachedPostorder = postorder(f)
   825  	}
   826  	return f.cachedPostorder
   827  }
   828  
   829  func (f *Func) Postorder() []*Block {
   830  	return f.postorder()
   831  }
   832  
   833  // Idom returns a map from block ID to the immediate dominator of that block.
   834  // f.Entry.ID maps to nil. Unreachable blocks map to nil as well.
   835  func (f *Func) Idom() []*Block {
   836  	if f.cachedIdom == nil {
   837  		f.cachedIdom = Dominators(f)
   838  	}
   839  	return f.cachedIdom
   840  }
   841  
   842  // Sdom returns a sparse tree representing the dominator relationships
   843  // among the blocks of f.
   844  func (f *Func) Sdom() SparseTree {
   845  	if f.cachedSdom == nil {
   846  		f.cachedSdom = NewSparseTree(f, f.Idom())
   847  	}
   848  	return f.cachedSdom
   849  }
   850  
   851  // Loopnest returns the loop nest information for f.
   852  func (f *Func) Loopnest() *LoopNest {
   853  	if f.cachedLoopnest == nil {
   854  		f.cachedLoopnest = Loopnestfor(f)
   855  	}
   856  	return f.cachedLoopnest
   857  }
   858  
   859  // InvalidateCFG tells f that its CFG has changed.
   860  func (f *Func) InvalidateCFG() {
   861  	f.cachedPostorder = nil
   862  	f.cachedIdom = nil
   863  	f.cachedSdom = nil
   864  	f.cachedLoopnest = nil
   865  }
   866  
   867  // DebugHashMatch returns
   868  //
   869  //	base.DebugHashMatch(this function's package.name)
   870  //
   871  // for use in bug isolation.  The return value is true unless
   872  // environment variable GOCOMPILEDEBUG=gossahash=X is set, in which case "it depends on X".
   873  // See [base.DebugHashMatch] for more information.
   874  func (f *Func) DebugHashMatch() bool {
   875  	if !base.HasDebugHash() {
   876  		return true
   877  	}
   878  	sym := f.Fe.Func().Sym()
   879  	return base.DebugHashMatchPkgFunc(sym.Pkg.Path, sym.Name)
   880  }
   881  
   882  func (f *Func) SpSb() (sp, sb *Value) {
   883  	initpos := src.NoXPos // These are originally created with no position in ssa.go; if they are optimized out then recreated, should be the same.
   884  	for _, v := range f.Entry.Values {
   885  		if v.Op == ssaop.OpSB {
   886  			sb = v
   887  		}
   888  		if v.Op == ssaop.OpSP {
   889  			sp = v
   890  		}
   891  		if sb != nil && sp != nil {
   892  			return
   893  		}
   894  	}
   895  	if sb == nil {
   896  		sb = f.Entry.NewValue0(initpos.WithNotStmt(), ssaop.OpSB, f.Config.Types.Uintptr)
   897  	}
   898  	if sp == nil {
   899  		sp = f.Entry.NewValue0(initpos.WithNotStmt(), ssaop.OpSP, f.Config.Types.Uintptr)
   900  	}
   901  	return
   902  }
   903  
   904  // UseFMA allows targeted debugging w/ GOFMAHASH
   905  // If you have an architecture-dependent FP glitch, this will help you find it.
   906  func (f *Func) UseFMA(v *Value) bool {
   907  	if base.FmaHash == nil {
   908  		return true
   909  	}
   910  	return base.FmaHash.MatchPos(v.Pos, nil)
   911  }
   912  
   913  // NewLocal returns a new anonymous local variable of the given type.
   914  func (f *Func) NewLocal(pos src.XPos, typ *types.Type) *ir.Name {
   915  	nn := typecheck.TempAt(pos, f.Fe.Func(), typ) // Note: adds new auto to fn.Dcl list
   916  	nn.SetNonMergeable(true)
   917  	return nn
   918  }
   919  

View as plain text