Source file src/cmd/compile/internal/ssa/rewrite.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  	"encoding/binary"
     9  	"fmt"
    10  	"internal/buildcfg"
    11  	"io"
    12  	"math"
    13  	"math/bits"
    14  	"os"
    15  	"path/filepath"
    16  	"strings"
    17  
    18  	"cmd/compile/internal/base"
    19  	"cmd/compile/internal/logopt"
    20  	"cmd/compile/internal/ssa/ssaop"
    21  	"cmd/compile/internal/types"
    22  	"cmd/internal/obj"
    23  	"cmd/internal/obj/s390x"
    24  	"cmd/internal/objabi"
    25  	"cmd/internal/src"
    26  )
    27  
    28  // Aux is an interface to hold miscellaneous data in Blocks and Values.
    29  type Aux interface {
    30  	CanBeAnSSAAux()
    31  }
    32  
    33  func BoolToAuxInt(b bool) int64 {
    34  	if b {
    35  		return 1
    36  	}
    37  	return 0
    38  }
    39  
    40  // FlagConstant represents the result of a compile-time comparison.
    41  // The sense of these flags does not necessarily represent the hardware's notion
    42  // of a flags register - these are just a compile-time construct.
    43  // We happen to match the semantics to those of arm/arm64.
    44  // Note that these semantics differ from x86: the carry flag has the opposite
    45  // sense on a subtraction!
    46  //
    47  //	On amd64, C=1 represents a borrow, e.g. SBB on amd64 does x - y - C.
    48  //	On arm64, C=0 represents a borrow, e.g. SBC on arm64 does x - y - ^C.
    49  //	 (because it does x + ^y + C).
    50  //
    51  // See https://en.wikipedia.org/wiki/Carry_flag#Vs._borrow_flag
    52  type FlagConstant uint8
    53  
    54  func IsNewObjectCall(aux Aux) bool {
    55  	fn := aux.(*AuxCall).Fn
    56  	return fn != nil && fn.String() == "runtime.newobject"
    57  }
    58  
    59  func IsSpecializedMalloc(aux Aux) bool {
    60  	fn := aux.(*AuxCall).Fn
    61  	if fn == nil {
    62  		return false
    63  	}
    64  	name := fn.String()
    65  	return strings.HasPrefix(name, "runtime.mallocgcSmallNoScanSC") ||
    66  		strings.HasPrefix(name, "runtime.mallocgcSmallScanNoHeaderSC") ||
    67  		strings.HasPrefix(name, "runtime.mallocgcTinySC")
    68  }
    69  
    70  // StringAux wraps string values for use in Aux.
    71  type StringAux string
    72  
    73  func StringToAux(s string) Aux {
    74  	return StringAux(s)
    75  }
    76  
    77  func AuxIntToArm64ConditionalParams(i int64) Arm64ConditionalParams {
    78  	var params Arm64ConditionalParams
    79  	params.Cond = ssaop.Op(i & 0xffff)
    80  	i >>= 16
    81  	params.NzcvVal = uint8(i & 0x0f)
    82  	i >>= 4
    83  	params.ConstVal = uint8(i & 0x1f)
    84  	i >>= 5
    85  	params.Ind = i == 1
    86  	return params
    87  }
    88  
    89  func LogLargeCopy(funcName string, pos src.XPos, s int64) {
    90  	if s < 128 {
    91  		return
    92  	}
    93  	if logopt.Enabled() {
    94  		logopt.LogOpt(pos, "copy", "lower", funcName, fmt.Sprintf("%d bytes", s))
    95  	}
    96  }
    97  
    98  // for now only used to mark moves that need to avoid clobbering flags
    99  type auxMark bool
   100  
   101  var AuxMark auxMark
   102  
   103  // PanicBoundsC contains a constant for a bounds failure.
   104  type PanicBoundsC struct {
   105  	C int64
   106  }
   107  
   108  // PanicBoundsCC contains 2 constants for a bounds failure.
   109  type PanicBoundsCC struct {
   110  	Cx int64
   111  	Cy int64
   112  }
   113  
   114  func GetPPC64Shiftsh(auxint int64) int64 {
   115  	return int64(int8(auxint >> 16))
   116  }
   117  
   118  func GetPPC64Shiftmb(auxint int64) int64 {
   119  	return int64(int8(auxint >> 8))
   120  }
   121  
   122  // DecodePPC64RotateMask is the inverse operation of encodePPC64RotateMask.  The values returned as
   123  // mb and me satisfy the POWER ISA definition of MASK(x,y) where MASK(mb,me) = mask.
   124  func DecodePPC64RotateMask(sauxint int64) (rotate, mb, me int64, mask uint64) {
   125  	auxint := uint64(sauxint)
   126  	rotate = int64((auxint >> 16) & 0xFF)
   127  	mb = int64((auxint >> 8) & 0xFF)
   128  	me = int64((auxint >> 0) & 0xFF)
   129  	nbits := int64((auxint >> 24) & 0xFF)
   130  	mask = ((1 << uint(nbits-mb)) - 1) ^ ((1 << uint(nbits-me)) - 1)
   131  	if mb > me {
   132  		mask = ^mask
   133  	}
   134  	if nbits == 32 {
   135  		mask = uint64(uint32(mask))
   136  	}
   137  
   138  	// Fixup ME to match ISA definition.  The second argument to MASK(..,me)
   139  	// is inclusive.
   140  	me = (me - 1) & (nbits - 1)
   141  	return
   142  }
   143  
   144  // DivisionNeedsFixUp reports whether the division needs fix-up code.
   145  func DivisionNeedsFixUp(v *Value) bool {
   146  	return v.AuxInt == 0
   147  }
   148  
   149  // ZeroUpper32Bits checks if value zeroes out upper 32-bit of 64-bit register.
   150  // depth limits recursion depth. In AMD64.rules 3 is used as limit,
   151  // because it catches same amount of cases as 4.
   152  func ZeroUpper32Bits(x *Value) bool { return zeroUpperBits(x, 32, 3) }
   153  
   154  // zeroUpperBits reports whether the 64-bit register holding x provably has
   155  // its upper `bits` bits zero, i.e. the value is below 2^(64-bits).
   156  //
   157  // Which ops guarantee this is declared per op in the _gen op definitions
   158  // (the zeroUpperBits attribute); only the value-dependent cases live here.
   159  func zeroUpperBits(x *Value, bits int64, depth int) bool {
   160  	if x.Type.IsSigned() && 8*x.Type.Size() <= 64-bits {
   161  		// A spill/restore sign-extends from the type's width (issue 68227).
   162  		// A signed type no wider than the claimed value width may have its
   163  		// sign bit set, so a restore can write ones into the upper bits.
   164  		// Wider signed types are safe: their value is below the type's
   165  		// sign bit, so a restore zero-extends.
   166  		return false
   167  	}
   168  	if int64(ssaop.OpcodeTable[x.Op].ZeroUpperBits) >= bits {
   169  		return true
   170  	}
   171  	switch x.Op {
   172  	case ssaop.OpAMD64MOVQconst, ssaop.OpAMD64MOVLconst:
   173  		// A constant qualifies whenever its value fits the claimed width.
   174  		// (MOVLconst always zeroes the upper 32 bits, so for bits==32 it
   175  		// is already handled by its zeroUpperBits attribute.)
   176  		return uint64(x.AuxInt)>>(64-bits) == 0
   177  	case ssaop.OpArg: // note: but not ArgIntReg
   178  		// amd64 always loads args from the stack unsigned.
   179  		// most other architectures load them sign/zero extended based on the type.
   180  		return 8*x.Type.Size() == 64-bits && x.Block.Func.Config.Arch == "amd64"
   181  	case ssaop.OpSelect0, ssaop.OpSelect1:
   182  		// A Select names one register result of a tuple-producing op, so
   183  		// the question is what that op's write does. The op's attribute
   184  		// covers every integer result; a Select of a non-covered result
   185  		// (flags, memory) never appears as an operand of the rules that
   186  		// ask about upper bits.
   187  		return int64(ssaop.OpcodeTable[x.Args[0].Op].ZeroUpperBits) >= bits
   188  	case ssaop.OpPhi:
   189  		// Phis can use each-other as an arguments, instead of tracking visited values,
   190  		// just limit recursion depth.
   191  		if depth <= 0 {
   192  			return false
   193  		}
   194  		for i := range x.Args {
   195  			if !zeroUpperBits(x.Args[i], bits, depth-1) {
   196  				return false
   197  			}
   198  		}
   199  		return true
   200  	}
   201  	return false
   202  }
   203  
   204  // ZeroUpper48Bits is similar to ZeroUpper32Bits, but for upper 48 bits.
   205  func ZeroUpper48Bits(x *Value) bool { return zeroUpperBits(x, 48, 3) }
   206  
   207  // ZeroUpper56Bits is similar to ZeroUpper32Bits, but for upper 56 bits.
   208  func ZeroUpper56Bits(x *Value) bool { return zeroUpperBits(x, 56, 3) }
   209  
   210  // IsSamePtr reports whether p1 and p2 point to the same address.
   211  func IsSamePtr(p1, p2 *Value) bool {
   212  	if p1 == p2 {
   213  		return true
   214  	}
   215  	if p1.Op != p2.Op {
   216  		for p1.Op == ssaop.OpOffPtr && p1.AuxInt == 0 {
   217  			p1 = p1.Args[0]
   218  		}
   219  		for p2.Op == ssaop.OpOffPtr && p2.AuxInt == 0 {
   220  			p2 = p2.Args[0]
   221  		}
   222  		if p1 == p2 {
   223  			return true
   224  		}
   225  		if p1.Op != p2.Op {
   226  			return false
   227  		}
   228  	}
   229  	switch p1.Op {
   230  	case ssaop.OpOffPtr:
   231  		return p1.AuxInt == p2.AuxInt && IsSamePtr(p1.Args[0], p2.Args[0])
   232  	case ssaop.OpAddr, ssaop.OpLocalAddr:
   233  		return p1.Aux == p2.Aux
   234  	case ssaop.OpAddPtr:
   235  		return p1.Args[1] == p2.Args[1] && IsSamePtr(p1.Args[0], p2.Args[0])
   236  	}
   237  	return false
   238  }
   239  
   240  // Disjoint reports whether the memory region specified by [p1:p1+t1.Size())
   241  // does not overlap with [p2:p2+t2.Size()).
   242  // A return value of false does not imply the regions overlap.
   243  func Disjoint(p1 *Value, t1 *types.Type, p2 *Value, t2 *types.Type) bool {
   244  	return Disjoint1(p1, t1.Size(), p2, t2.Size())
   245  }
   246  
   247  // Disjoint1 reports whether the memory region specified by [p1:p1+n1)
   248  // does not overlap with [p2:p2+n2).
   249  // A return value of false does not imply the regions overlap.
   250  func Disjoint1(p1 *Value, n1 int64, p2 *Value, n2 int64) bool {
   251  	if n1 == 0 || n2 == 0 {
   252  		return true
   253  	}
   254  	if p1 == p2 {
   255  		return false
   256  	}
   257  	baseAndOffset := func(ptr *Value) (base *Value, offset int64) {
   258  		base, offset = ptr, 0
   259  		for base.Op == ssaop.OpOffPtr {
   260  			offset += base.AuxInt
   261  			base = base.Args[0]
   262  		}
   263  		if ssaop.OpcodeTable[base.Op].NilCheck {
   264  			base = base.Args[0]
   265  		}
   266  		return base, offset
   267  	}
   268  
   269  	// Run types-based analysis
   270  	if DisjointTypes(p1.Type, p2.Type) {
   271  		return true
   272  	}
   273  
   274  	p1, off1 := baseAndOffset(p1)
   275  	p2, off2 := baseAndOffset(p2)
   276  	if IsSamePtr(p1, p2) {
   277  		return !Overlap(off1, n1, off2, n2)
   278  	}
   279  	// p1 and p2 are not the same, so if they are both OpAddrs then
   280  	// they point to different variables.
   281  	// If one pointer is on the stack and the other is an argument
   282  	// then they can't overlap.
   283  	switch p1.Op {
   284  	case ssaop.OpAddr, ssaop.OpLocalAddr:
   285  		if p2.Op == ssaop.OpAddr || p2.Op == ssaop.OpLocalAddr || p2.Op == ssaop.OpSP {
   286  			return true
   287  		}
   288  		return (p2.Op == ssaop.OpArg || p2.Op == ssaop.OpArgIntReg) && p1.Args[0].Op == ssaop.OpSP
   289  	case ssaop.OpArg, ssaop.OpArgIntReg:
   290  		if p2.Op == ssaop.OpSP || p2.Op == ssaop.OpLocalAddr {
   291  			return true
   292  		}
   293  	case ssaop.OpSP:
   294  		return p2.Op == ssaop.OpAddr || p2.Op == ssaop.OpLocalAddr || p2.Op == ssaop.OpArg || p2.Op == ssaop.OpArgIntReg || p2.Op == ssaop.OpSP
   295  	}
   296  	return false
   297  }
   298  
   299  // DisjointTypes reports whether a memory region pointed to by a pointer of type
   300  // t1 does not overlap with a memory region pointed to by a pointer of type t2 --
   301  // based on type aliasing rules.
   302  func DisjointTypes(t1 *types.Type, t2 *types.Type) bool {
   303  	// Unsafe pointer can alias with anything.
   304  	if t1.IsUnsafePtr() || t2.IsUnsafePtr() {
   305  		return false
   306  	}
   307  
   308  	if !t1.IsPtr() || !t2.IsPtr() {
   309  		// Treat non-pointer types (such as TFUNC, TMAP, uintptr) conservatively.
   310  		return false
   311  	}
   312  
   313  	t1 = t1.Elem()
   314  	t2 = t2.Elem()
   315  
   316  	// Not-in-heap types are not supported -- they are rare and non-important; also,
   317  	// type.HasPointers check doesn't work for them correctly.
   318  	if t1.NotInHeap() || t2.NotInHeap() {
   319  		return false
   320  	}
   321  
   322  	isPtrShaped := func(t *types.Type) bool { return int(t.Size()) == types.PtrSize && t.HasPointers() }
   323  
   324  	// Pointers and non-pointers are disjoint (https://pkg.go.dev/unsafe#Pointer).
   325  	if (isPtrShaped(t1) && !t2.HasPointers()) ||
   326  		(isPtrShaped(t2) && !t1.HasPointers()) {
   327  		return true
   328  	}
   329  
   330  	return false
   331  }
   332  
   333  // Overlap reports whether the ranges given by the given offset and
   334  // size pairs Overlap.
   335  func Overlap(offset1, size1, offset2, size2 int64) bool {
   336  	if offset1 >= offset2 && offset2+size2 > offset1 {
   337  		return true
   338  	}
   339  	if offset2 >= offset1 && offset1+size1 > offset2 {
   340  		return true
   341  	}
   342  	return false
   343  }
   344  
   345  // isInlinableMemmove reports whether the given arch performs a Move of the given size
   346  // faster than memmove. It will only return true if replacing the memmove with a Move is
   347  // safe, either because Move will do all of its loads before any of its stores, or
   348  // because the arguments are known to be disjoint.
   349  // This is used as a check for replacing memmove with Move ops.
   350  func isInlinableMemmove(dst, src *Value, sz int64, c *Config) bool {
   351  	// It is always safe to convert memmove into Move when its arguments are disjoint.
   352  	// Move ops may or may not be faster for large sizes depending on how the platform
   353  	// lowers them, so we only perform this optimization on platforms that we know to
   354  	// have fast Move ops.
   355  	switch c.Arch {
   356  	case "amd64":
   357  		return sz <= 16 || (sz < 1024 && Disjoint1(dst, sz, src, sz))
   358  	case "arm64":
   359  		return sz <= 64 || (sz <= 1024 && Disjoint1(dst, sz, src, sz))
   360  	case "loong64":
   361  		return sz <= 16 || (sz <= 64 && Disjoint1(dst, sz, src, sz))
   362  	case "386":
   363  		return sz <= 8
   364  	case "s390x", "ppc64", "ppc64le":
   365  		return sz <= 8 || Disjoint1(dst, sz, src, sz)
   366  	case "arm", "mips", "mips64", "mipsle", "mips64le":
   367  		return sz <= 4
   368  	}
   369  	return false
   370  }
   371  
   372  func IsInlinableMemmove(dst, src *Value, sz int64, c *Config) bool {
   373  	return isInlinableMemmove(dst, src, sz, c)
   374  }
   375  
   376  func (auxMark) CanBeAnSSAAux() {}
   377  
   378  func (StringAux) CanBeAnSSAAux() {}
   379  
   380  // returns the Lsb part of the auxInt field of arm64 bitfield ops.
   381  func (bfc Arm64BitField) Lsb() int64 {
   382  	return int64(uint64(bfc) >> 8)
   383  }
   384  
   385  // returns the Width part of the auxInt field of arm64 bitfield ops.
   386  func (bfc Arm64BitField) Width() int64 {
   387  	return int64(bfc) & 0xff
   388  }
   389  
   390  // extracts NZCV flags from auxint.
   391  func (condParams Arm64ConditionalParams) Nzcv() int64 {
   392  	return int64(condParams.NzcvVal)
   393  }
   394  
   395  // extracts constant value from auxint if present.
   396  func (condParams Arm64ConditionalParams) ConstValue() (int64, bool) {
   397  	return int64(condParams.ConstVal), condParams.Ind
   398  }
   399  
   400  // N reports whether the result of an operation is negative (high bit set).
   401  func (fc FlagConstant) N() bool {
   402  	return fc&1 != 0
   403  }
   404  
   405  // Z reports whether the result of an operation is 0.
   406  func (fc FlagConstant) Z() bool {
   407  	return fc&2 != 0
   408  }
   409  
   410  // C reports whether an unsigned add overflowed (carry), or an
   411  // unsigned subtract did not underflow (borrow).
   412  func (fc FlagConstant) C() bool {
   413  	return fc&4 != 0
   414  }
   415  
   416  // V reports whether a signed operation overflowed or underflowed.
   417  func (fc FlagConstant) V() bool {
   418  	return fc&8 != 0
   419  }
   420  
   421  func (fc FlagConstant) Eq() bool {
   422  	return fc.Z()
   423  }
   424  
   425  func (fc FlagConstant) Ne() bool {
   426  	return !fc.Z()
   427  }
   428  
   429  func (fc FlagConstant) Lt() bool {
   430  	return fc.N() != fc.V()
   431  }
   432  
   433  func (fc FlagConstant) Le() bool {
   434  	return fc.Z() || fc.Lt()
   435  }
   436  
   437  func (fc FlagConstant) Gt() bool {
   438  	return !fc.Z() && fc.Ge()
   439  }
   440  
   441  func (fc FlagConstant) Ge() bool {
   442  	return fc.N() == fc.V()
   443  }
   444  
   445  func (fc FlagConstant) Ult() bool {
   446  	return !fc.C()
   447  }
   448  
   449  func (fc FlagConstant) Ule() bool {
   450  	return fc.Z() || fc.Ult()
   451  }
   452  
   453  func (fc FlagConstant) Ugt() bool {
   454  	return !fc.Z() && fc.Uge()
   455  }
   456  
   457  func (fc FlagConstant) Uge() bool {
   458  	return fc.C()
   459  }
   460  
   461  func (fc FlagConstant) LtNoov() bool {
   462  	return fc.Lt() && !fc.V()
   463  }
   464  
   465  func (fc FlagConstant) LeNoov() bool {
   466  	return fc.Le() && !fc.V()
   467  }
   468  
   469  func (fc FlagConstant) GtNoov() bool {
   470  	return fc.Gt() && !fc.V()
   471  }
   472  
   473  func (fc FlagConstant) GeNoov() bool {
   474  	return fc.Ge() && !fc.V()
   475  }
   476  
   477  func (fc FlagConstant) String() string {
   478  	return fmt.Sprintf("N=%v,Z=%v,C=%v,V=%v", fc.N(), fc.Z(), fc.C(), fc.V())
   479  }
   480  
   481  func (p PanicBoundsC) CanBeAnSSAAux() {
   482  }
   483  
   484  func (p PanicBoundsCC) CanBeAnSSAAux() {
   485  }
   486  
   487  // AddFlags32 returns the flags that would be set from computing x+y.
   488  func AddFlags32(x, y int32) FlagConstant {
   489  	var fcb FlagConstantBuilder
   490  	fcb.Z = x+y == 0
   491  	fcb.N = x+y < 0
   492  	fcb.C = uint32(x+y) < uint32(x)
   493  	fcb.V = x >= 0 && y >= 0 && x+y < 0 || x < 0 && y < 0 && x+y >= 0
   494  	return fcb.Encode()
   495  }
   496  
   497  // Note: addFlags(x,y) != subFlags(x,-y) in some situations:
   498  //  - the results of the C flag are different
   499  //  - the results of the V flag when y==minint are different
   500  
   501  // AddFlags64 returns the flags that would be set from computing x+y.
   502  func AddFlags64(x, y int64) FlagConstant {
   503  	var fcb FlagConstantBuilder
   504  	fcb.Z = x+y == 0
   505  	fcb.N = x+y < 0
   506  	fcb.C = uint64(x+y) < uint64(x)
   507  	fcb.V = x >= 0 && y >= 0 && x+y < 0 || x < 0 && y < 0 && x+y >= 0
   508  	return fcb.Encode()
   509  }
   510  
   511  func Arm64BitFieldToAuxInt(v Arm64BitField) int64 {
   512  	return int64(v)
   513  }
   514  
   515  func Arm64ConditionalParamsToAuxInt(v Arm64ConditionalParams) int64 {
   516  	if v.Cond&^0xffff != 0 {
   517  		panic("condition value exceeds 16 bits")
   518  	}
   519  
   520  	var i int64
   521  	if v.Ind {
   522  		i = 1 << 25
   523  	}
   524  	i |= int64(v.ConstVal) << 20
   525  	i |= int64(v.NzcvVal) << 16
   526  	i |= int64(v.Cond)
   527  	return i
   528  }
   529  
   530  type Int64Aux int64
   531  
   532  func (Int64Aux) CanBeAnSSAAux() {}
   533  
   534  func Int64ToAux(v int64) Aux {
   535  	return Int64Aux(v)
   536  }
   537  
   538  // encodes the lsb and width for arm(64) bitfield ops into the expected auxInt format.
   539  func ArmBFAuxInt(lsb, width int64) Arm64BitField {
   540  	if lsb < 0 || lsb > 63 {
   541  		panic("ARM(64) bit field lsb constant out of range")
   542  	}
   543  	if width < 1 || lsb+width > 64 {
   544  		panic("ARM(64) bit field width constant out of range")
   545  	}
   546  	return Arm64BitField(width | lsb<<8)
   547  }
   548  
   549  func AuxIntToArm64BitField(i int64) Arm64BitField {
   550  	return Arm64BitField(i)
   551  }
   552  
   553  func AuxIntToBool(i int64) bool {
   554  	if i == 0 {
   555  		return false
   556  	}
   557  	return true
   558  }
   559  
   560  func AuxIntToFlagConstant(x int64) FlagConstant {
   561  	return FlagConstant(x)
   562  }
   563  
   564  func AuxIntToFloat32(i int64) float32 {
   565  	return float32(math.Float64frombits(uint64(i)))
   566  }
   567  
   568  func AuxIntToFloat64(i int64) float64 {
   569  	return math.Float64frombits(uint64(i))
   570  }
   571  
   572  func AuxIntToInt16(i int64) int16 {
   573  	return int16(i)
   574  }
   575  
   576  func AuxIntToInt32(i int64) int32 {
   577  	return int32(i)
   578  }
   579  
   580  func AuxIntToInt64(i int64) int64 {
   581  	return i
   582  }
   583  
   584  func AuxIntToInt8(i int64) int8 {
   585  	return int8(i)
   586  }
   587  
   588  func AuxIntToOp(cc int64) ssaop.Op {
   589  	return ssaop.Op(cc)
   590  }
   591  
   592  func AuxIntToUint64(i int64) uint64 {
   593  	return uint64(i)
   594  }
   595  
   596  func AuxIntToUint8(i int64) uint8 {
   597  	return uint8(i)
   598  }
   599  
   600  func AuxIntToValAndOff(i int64) ValAndOff {
   601  	return ValAndOff(i)
   602  }
   603  
   604  func AuxToCall(i Aux) *AuxCall {
   605  	return i.(*AuxCall)
   606  }
   607  
   608  func AuxToPanicBoundsC(i Aux) PanicBoundsC {
   609  	return i.(PanicBoundsC)
   610  }
   611  
   612  func AuxToPanicBoundsCC(i Aux) PanicBoundsCC {
   613  	return i.(PanicBoundsCC)
   614  }
   615  
   616  func AuxToS390xCCMask(i Aux) s390x.CCMask {
   617  	return i.(s390x.CCMask)
   618  }
   619  
   620  func AuxToS390xRotateParams(i Aux) s390x.RotateParams {
   621  	return i.(s390x.RotateParams)
   622  }
   623  
   624  func AuxToString(i Aux) string {
   625  	return string(i.(StringAux))
   626  }
   627  
   628  func AuxToSym(i Aux) Sym {
   629  	// TODO: kind of a hack - allows nil interface through
   630  	s, _ := i.(Sym)
   631  	return s
   632  }
   633  
   634  func AuxToType(i Aux) *types.Type {
   635  	return i.(*types.Type)
   636  }
   637  
   638  // B2i translates a boolean value to 0 or 1 for assigning to auxInt.
   639  func B2i(b bool) int64 {
   640  	if b {
   641  		return 1
   642  	}
   643  	return 0
   644  }
   645  
   646  // B2i32 translates a boolean value to 0 or 1.
   647  func B2i32(b bool) int32 {
   648  	if b {
   649  		return 1
   650  	}
   651  	return 0
   652  }
   653  
   654  func CallToAux(s *AuxCall) Aux {
   655  	return s
   656  }
   657  
   658  // CanMergeLoad reports whether the load can be merged into target without
   659  // invalidating the schedule.
   660  func CanMergeLoad(target, load *Value) bool {
   661  	if target.Block.ID != load.Block.ID {
   662  		// If the load is in a different block do not merge it.
   663  		return false
   664  	}
   665  
   666  	// We can't merge the load into the target if the load
   667  	// has more than one use.
   668  	if load.Uses != 1 {
   669  		return false
   670  	}
   671  
   672  	mem := load.MemoryArg()
   673  
   674  	// We need the load's memory arg to still be alive at target. That
   675  	// can't be the case if one of target's args depends on a memory
   676  	// state that is a successor of load's memory arg.
   677  	//
   678  	// For example, it would be invalid to merge load into target in
   679  	// the following situation because newmem has killed oldmem
   680  	// before target is reached:
   681  	//     load = read ... oldmem
   682  	//   newmem = write ... oldmem
   683  	//     arg0 = read ... newmem
   684  	//   target = add arg0 load
   685  	//
   686  	// If the argument comes from a different block then we can exclude
   687  	// it immediately because it must dominate load (which is in the
   688  	// same block as target).
   689  	var args []*Value
   690  	for _, a := range target.Args {
   691  		if a != load && a.Block.ID == target.Block.ID {
   692  			args = append(args, a)
   693  		}
   694  	}
   695  
   696  	f := target.Block.Func
   697  	visited := f.NewSparseSet(f.NumValues())
   698  	defer f.RetSparseSet(visited)
   699  
   700  	// memPreds contains memory states known to be predecessors of load's
   701  	// memory state. It is lazily initialized.
   702  	var memPreds map[*Value]bool
   703  	for len(args) > 0 {
   704  		const limit = 2048 // enough to comfortably cover unrolled crypto blocks
   705  		if visited.Size() >= limit {
   706  			// Give up if we have visited a lot of values.
   707  			return false
   708  		}
   709  		v := args[len(args)-1]
   710  		args = args[:len(args)-1]
   711  		if visited.Contains(v.ID) {
   712  			continue
   713  		}
   714  		visited.Add(v.ID)
   715  		if target.Block.ID != v.Block.ID {
   716  			// Since target and load are in the same block
   717  			// we can stop searching when we leave the block.
   718  			continue
   719  		}
   720  		if v.Op == ssaop.OpPhi {
   721  			// A Phi implies we have reached the top of the block.
   722  			// The memory phi, if it exists, is always
   723  			// the first logical store in the block.
   724  			continue
   725  		}
   726  		if v.Type.IsTuple() && v.Type.FieldType(1).IsMemory() {
   727  			// We could handle this situation however it is likely
   728  			// to be very rare.
   729  			return false
   730  		}
   731  		if v.Op.SymEffect()&ssaop.SymAddr != 0 {
   732  			// This case prevents an operation that calculates the
   733  			// address of a local variable from being forced to schedule
   734  			// before its corresponding VarDef.
   735  			// See issue 28445.
   736  			//   v1 = LOAD ...
   737  			//   v2 = VARDEF
   738  			//   v3 = LEAQ
   739  			//   v4 = CMPQ v1 v3
   740  			// We don't want to combine the CMPQ with the load, because
   741  			// that would force the CMPQ to schedule before the VARDEF, which
   742  			// in turn requires the LEAQ to schedule before the VARDEF.
   743  			return false
   744  		}
   745  		if v.Type.IsMemory() {
   746  			if memPreds == nil {
   747  				// Initialise a map containing memory states
   748  				// known to be predecessors of load's memory
   749  				// state.
   750  				memPreds = make(map[*Value]bool)
   751  				m := mem
   752  				const limit = 50
   753  				for i := 0; i < limit; i++ {
   754  					if m.Op == ssaop.OpPhi {
   755  						// The memory phi, if it exists, is always
   756  						// the first logical store in the block.
   757  						break
   758  					}
   759  					if m.Block.ID != target.Block.ID {
   760  						break
   761  					}
   762  					if !m.Type.IsMemory() {
   763  						break
   764  					}
   765  					memPreds[m] = true
   766  					if len(m.Args) == 0 {
   767  						break
   768  					}
   769  					m = m.MemoryArg()
   770  				}
   771  			}
   772  
   773  			// We can merge if v is a predecessor of mem.
   774  			//
   775  			// For example, we can merge load into target in the
   776  			// following scenario:
   777  			//      x = read ... v
   778  			//    mem = write ... v
   779  			//   load = read ... mem
   780  			// target = add x load
   781  			if memPreds[v] {
   782  				continue
   783  			}
   784  			return false
   785  		}
   786  		if len(v.Args) > 0 && v.Args[len(v.Args)-1] == mem {
   787  			// If v takes mem as an input then we know mem
   788  			// is valid at this point.
   789  			continue
   790  		}
   791  		for _, a := range v.Args {
   792  			if target.Block.ID == a.Block.ID {
   793  				args = append(args, a)
   794  			}
   795  		}
   796  	}
   797  
   798  	return true
   799  }
   800  
   801  // CanMergeLoadClobber reports whether the load can be merged into target without
   802  // invalidating the schedule.
   803  // It also checks that the other non-load argument x is something we
   804  // are ok with clobbering.
   805  func CanMergeLoadClobber(target, load, x *Value) bool {
   806  	// The register containing x is going to get clobbered.
   807  	// Don't merge if we still need the value of x.
   808  	// We don't have liveness information here, but we can
   809  	// approximate x dying with:
   810  	//  1) target is x's only use.
   811  	//  2) target is not in a deeper loop than x.
   812  	switch {
   813  	case x.Uses == 2 && x.Op == ssaop.OpPhi && len(x.Args) == 2 && (x.Args[0] == target || x.Args[1] == target) && target.Uses == 1:
   814  		// This is a simple detector to determine that x is probably
   815  		// not live after target. (It does not need to be perfect,
   816  		// regalloc will issue a reg-reg move to save it if we are wrong.)
   817  		// We have:
   818  		//   x = Phi(?, target)
   819  		//   target = Op(load, x)
   820  		// Because target has only one use as a Phi argument, we can schedule it
   821  		// very late. Hopefully, later than the other use of x. (The other use died
   822  		// between x and target, or exists on another branch entirely).
   823  	case x.Uses > 1:
   824  		return false
   825  	}
   826  	loopnest := x.Block.Func.Loopnest()
   827  	if loopnest.Depth(target.Block.ID) > loopnest.Depth(x.Block.ID) {
   828  		return false
   829  	}
   830  	return CanMergeLoad(target, load)
   831  }
   832  
   833  func CanMergeSym(x, y Sym) bool {
   834  	return x == nil || y == nil
   835  }
   836  
   837  func CanMulStrengthReduce(config *Config, x int64) bool {
   838  	_, ok := config.MulRecipes[x]
   839  	return ok
   840  }
   841  
   842  func CanMulStrengthReduce32(config *Config, x int32) bool {
   843  	_, ok := config.MulRecipes[int64(x)]
   844  	return ok
   845  }
   846  
   847  // CanonLessThan returns whether x is "ordered" less than y, for purposes of normalizing
   848  // generated code as much as possible.
   849  func CanonLessThan(x, y *Value) bool {
   850  	if x.Op != y.Op {
   851  		return x.Op < y.Op
   852  	}
   853  	if !x.Pos.SameFileAndLine(y.Pos) {
   854  		return x.Pos.Before(y.Pos)
   855  	}
   856  	return x.ID < y.ID
   857  }
   858  
   859  // Clobber invalidates values. Returns true.
   860  // Clobber is used by rewrite rules to:
   861  //
   862  //	A) make sure the values are really dead and never used again.
   863  //	B) decrement use counts of the values' args.
   864  func Clobber(vv ...*Value) bool {
   865  	for _, v := range vv {
   866  		v.Reset(ssaop.OpInvalid)
   867  		// Note: leave v.Block intact.  The Block field is used after clobber.
   868  	}
   869  	return true
   870  }
   871  
   872  // ClobberIfDead resets v when use count is 1. Returns true.
   873  // ClobberIfDead is used by rewrite rules to decrement
   874  // use counts of v's args when v is dead and never used.
   875  func ClobberIfDead(v *Value) bool {
   876  	if v.Uses == 1 {
   877  		v.Reset(ssaop.OpInvalid)
   878  	}
   879  	// Note: leave v.Block intact.  The Block field is used after clobberIfDead.
   880  	return true
   881  }
   882  
   883  // CountRule increments Func.ruleMatches[key].
   884  // If Func.ruleMatches is non-nil at the end
   885  // of compilation, it will be printed to stdout.
   886  // This is intended to make it easier to find which functions
   887  // which contain lots of rules matches when developing new rules.
   888  func CountRule(v *Value, key string) bool {
   889  	f := v.Block.Func
   890  	if f.RuleMatches == nil {
   891  		f.RuleMatches = make(map[string]int)
   892  	}
   893  	f.RuleMatches[key]++
   894  	return true
   895  }
   896  
   897  type DeadValueChoice bool
   898  
   899  // Compress mask and shift into single value of the form
   900  // me | mb<<8 | rotate<<16 | nbits<<24 where me and mb can
   901  // be used to regenerate the input mask.
   902  func EncodePPC64RotateMask(rotate, mask, nbits int64) int64 {
   903  	var mb, me, mbn, men int
   904  
   905  	// Determine boundaries and then decode them
   906  	if mask == 0 || ^mask == 0 || rotate >= nbits {
   907  		panic(fmt.Sprintf("invalid PPC64 rotate mask: %x %d %d", uint64(mask), rotate, nbits))
   908  	} else if nbits == 32 {
   909  		mb = bits.LeadingZeros32(uint32(mask))
   910  		me = 32 - bits.TrailingZeros32(uint32(mask))
   911  		mbn = bits.LeadingZeros32(^uint32(mask))
   912  		men = 32 - bits.TrailingZeros32(^uint32(mask))
   913  	} else {
   914  		mb = bits.LeadingZeros64(uint64(mask))
   915  		me = 64 - bits.TrailingZeros64(uint64(mask))
   916  		mbn = bits.LeadingZeros64(^uint64(mask))
   917  		men = 64 - bits.TrailingZeros64(^uint64(mask))
   918  	}
   919  	// Check for a wrapping mask (e.g bits at 0 and 63)
   920  	if mb == 0 && me == int(nbits) {
   921  		// swap the inverted values
   922  		mb, me = men, mbn
   923  	}
   924  
   925  	return int64(me) | int64(mb<<8) | rotate<<16 | nbits<<24
   926  }
   927  
   928  // for a pseudo-op like (LessThan x), extract x.
   929  func FlagArg(v *Value) *Value {
   930  	if len(v.Args) != 1 || !v.Args[0].Type.IsFlags() {
   931  		return nil
   932  	}
   933  	return v.Args[0]
   934  }
   935  
   936  type FlagConstantBuilder struct {
   937  	N bool
   938  	Z bool
   939  	C bool
   940  	V bool
   941  }
   942  
   943  func FlagConstantToAuxInt(x FlagConstant) int64 {
   944  	return int64(x)
   945  }
   946  
   947  func Float32ToAuxInt(f float32) int64 {
   948  	return int64(math.Float64bits(float64(f)))
   949  }
   950  
   951  func Float64ToAuxInt(f float64) int64 {
   952  	return int64(math.Float64bits(f))
   953  }
   954  
   955  // When v is (IMake typ (StructMake ...)), convert to
   956  // (IMake typ arg) where arg is the pointer-y argument to
   957  // the StructMake (there must be exactly one).
   958  func ImakeOfStructMake(v *Value) *Value {
   959  	var arg *Value
   960  	for _, a := range v.Args[1].Args {
   961  		if a.Type.Size() > 0 {
   962  			arg = a
   963  			break
   964  		}
   965  	}
   966  	return v.Block.NewValue2(v.Pos, ssaop.OpIMake, v.Type, v.Args[0], arg)
   967  }
   968  
   969  func Int16ToAuxInt(i int16) int64 {
   970  	return int64(i)
   971  }
   972  
   973  func Int32ToAuxInt(i int32) int64 {
   974  	return int64(i)
   975  }
   976  
   977  func Int64ToAuxInt(i int64) int64 {
   978  	return i
   979  }
   980  
   981  func Int8ToAuxInt(i int8) int64 {
   982  	return int64(i)
   983  }
   984  
   985  // Is12Bit reports whether n can be represented as a signed 12 bit integer.
   986  func Is12Bit(n int64) bool {
   987  	return -(1<<11) <= n && n < (1<<11)
   988  }
   989  
   990  // Is16Bit reports whether n can be represented as a signed 16 bit integer.
   991  func Is16Bit(n int64) bool {
   992  	return n == int64(int16(n))
   993  }
   994  
   995  func Is16BitInt(t *types.Type) bool {
   996  	return t.Size() == 2 && t.IsInteger()
   997  }
   998  
   999  // Is20Bit reports whether n can be represented as a signed 20 bit integer.
  1000  func Is20Bit(n int64) bool {
  1001  	return -(1<<19) <= n && n < (1<<19)
  1002  }
  1003  
  1004  // Is32Bit reports whether n can be represented as a signed 32 bit integer.
  1005  func Is32Bit(n int64) bool {
  1006  	return n == int64(int32(n))
  1007  }
  1008  
  1009  func Is32BitFloat(t *types.Type) bool {
  1010  	return t.Size() == 4 && t.IsFloat()
  1011  }
  1012  
  1013  func Is32BitInt(t *types.Type) bool {
  1014  	return t.Size() == 4 && t.IsInteger()
  1015  }
  1016  
  1017  // Common functions called from rewriting rules
  1018  
  1019  func Is64BitFloat(t *types.Type) bool {
  1020  	return t.Size() == 8 && t.IsFloat()
  1021  }
  1022  
  1023  func Is64BitInt(t *types.Type) bool {
  1024  	return t.Size() == 8 && t.IsInteger()
  1025  }
  1026  
  1027  func Is8BitInt(t *types.Type) bool {
  1028  	return t.Size() == 1 && t.IsInteger()
  1029  }
  1030  
  1031  // isPowerOfTwoX functions report whether n is a power of 2.
  1032  func IsPowerOfTwo[T int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64](n T) bool {
  1033  	return n > 0 && n&(n-1) == 0
  1034  }
  1035  
  1036  // This verifies that the mask is a set of
  1037  // consecutive bits including the least
  1038  // significant bit.
  1039  func IsPPC64ValidShiftMask(v int64) bool {
  1040  	if (v != 0) && ((v+1)&v) == 0 {
  1041  		return true
  1042  	}
  1043  	return false
  1044  }
  1045  
  1046  // Test if this value can encoded as a mask for a rlwinm like
  1047  // operation.  Masks can also extend from the msb and wrap to
  1048  // the lsb too.  That is, the valid masks are 32 bit strings
  1049  // of the form: 0..01..10..0 or 1..10..01..1 or 1...1
  1050  //
  1051  // Note: This ignores the upper 32 bits of the input. When a
  1052  // zero extended result is desired (e.g a 64 bit result), the
  1053  // user must verify the upper 32 bits are 0 and the mask is
  1054  // contiguous (that is, non-wrapping).
  1055  func IsPPC64WordRotateMask(v64 int64) bool {
  1056  	// Isolate rightmost 1 (if none 0) and add.
  1057  	v := uint32(v64)
  1058  	vp := (v & -v) + v
  1059  	// Likewise, for the wrapping case.
  1060  	vn := ^v
  1061  	vpn := (vn & -vn) + vn
  1062  	return (v&vp == 0 || vn&vpn == 0) && v != 0
  1063  }
  1064  
  1065  func IsPtr(t *types.Type) bool {
  1066  	return t.IsPtrShaped()
  1067  }
  1068  
  1069  // IsSameCall reports whether aux is the same as the given named symbol.
  1070  func IsSameCall(aux Aux, name string) bool {
  1071  	fn := aux.(*AuxCall).Fn
  1072  	return fn != nil && fn.String() == name
  1073  }
  1074  
  1075  // IsU32Bit reports whether n can be represented as an unsigned 32 bit integer.
  1076  func IsU32Bit(n int64) bool {
  1077  	return n == int64(uint32(n))
  1078  }
  1079  
  1080  // IsVolatile reports whether v is a pointer to argument region on stack which
  1081  // will be clobbered by a function call.
  1082  func IsVolatile(v *Value) bool {
  1083  	for v.Op == ssaop.OpOffPtr || v.Op == ssaop.OpAddPtr || v.Op == ssaop.OpPtrIndex || v.Op == ssaop.OpCopy || v.Op == ssaop.OpSelectNAddr {
  1084  		v = v.Args[0]
  1085  	}
  1086  	return v.Op == ssaop.OpSP
  1087  }
  1088  
  1089  const (
  1090  	LeaveDeadValues  DeadValueChoice = false
  1091  	RemoveDeadValues                 = true
  1092  
  1093  	RepZeroThreshold = 1408 // size beyond which we use REP STOS for zeroing
  1094  	RepMoveThreshold = 1408 // size beyond which we use REP MOVS for copying
  1095  )
  1096  
  1097  func Log16(n int16) int64 { return Log16u(uint16(n)) }
  1098  
  1099  func Log16u(n uint16) int64 { return int64(bits.Len16(n)) - 1 }
  1100  
  1101  func Log32(n int32) int64 { return Log32u(uint32(n)) }
  1102  
  1103  func Log32u(n uint32) int64 { return int64(bits.Len32(n)) - 1 }
  1104  
  1105  func Log64(n int64) int64 { return Log64u(uint64(n)) }
  1106  
  1107  func Log64u(n uint64) int64 { return int64(bits.Len64(n)) - 1 }
  1108  
  1109  // logXu returns the logarithm of n base 2.
  1110  // n must be a power of 2 (isPowerOfTwo returns true)
  1111  func Log8u(n uint8) int64 { return int64(bits.Len8(n)) - 1 }
  1112  
  1113  // LogicFlags32 returns flags set to the sign/zeroness of x.
  1114  // C and V are set to false.
  1115  func LogicFlags32(x int32) FlagConstant {
  1116  	var fcb FlagConstantBuilder
  1117  	fcb.Z = x == 0
  1118  	fcb.N = x < 0
  1119  	return fcb.Encode()
  1120  }
  1121  
  1122  // LogicFlags64 returns flags set to the sign/zeroness of x.
  1123  // C and V are set to false.
  1124  func LogicFlags64(x int64) FlagConstant {
  1125  	var fcb FlagConstantBuilder
  1126  	fcb.Z = x == 0
  1127  	fcb.N = x < 0
  1128  	return fcb.Encode()
  1129  }
  1130  
  1131  // LogLargeCopyValue logs the occurrence of a large copy.
  1132  // The best place to do this is in the rewrite rules where the size of the move is easy to find.
  1133  // "Large" is arbitrarily chosen to be 128 bytes; this may change.
  1134  func LogLargeCopyValue(v *Value, s int64) bool {
  1135  	if s < 128 {
  1136  		return true
  1137  	}
  1138  	if logopt.Enabled() {
  1139  		logopt.LogOpt(v.Pos, "copy", "lower", v.Block.Func.Name, fmt.Sprintf("%d bytes", s))
  1140  	}
  1141  	return true
  1142  }
  1143  
  1144  // LogRule logs the use of the rule s. This will only be enabled if
  1145  // rewrite rules were generated with the -log option, see _gen/rulegen.go.
  1146  func LogRule(s string) {
  1147  	if ruleFile == nil {
  1148  		// Open a log file to write log to. We open in append
  1149  		// mode because all.bash runs the compiler lots of times,
  1150  		// and we want the concatenation of all of those logs.
  1151  		// This means, of course, that users need to rm the old log
  1152  		// to get fresh data.
  1153  		// TODO: all.bash runs compilers in parallel. Need to synchronize logging somehow?
  1154  		w, err := os.OpenFile(filepath.Join(os.Getenv("GOROOT"), "src", "rulelog"),
  1155  			os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  1156  		if err != nil {
  1157  			panic(err)
  1158  		}
  1159  		ruleFile = w
  1160  	}
  1161  	// Ignore errors in case of multiple processes fighting over the file.
  1162  	fmt.Fprintln(ruleFile, s)
  1163  }
  1164  
  1165  func MakeJumpTableSym(b *Block) *obj.LSym {
  1166  	s := base.Ctxt.Lookup(fmt.Sprintf("%s.jump%d", b.Func.Fe.Func().LSym.Name, b.ID))
  1167  	// The jump table symbol is accessed only from the function symbol.
  1168  	s.Set(obj.AttrStatic, true)
  1169  	return s
  1170  }
  1171  
  1172  // Combine (ANDconst [m] (SRWconst [s])) into (RLWINM [y]) or return 0
  1173  func MergePPC64AndSrwi(m, s int64) int64 {
  1174  	mask := MergePPC64RShiftMask(m, s, 32)
  1175  	if !IsPPC64WordRotateMask(mask) {
  1176  		return 0
  1177  	}
  1178  	return EncodePPC64RotateMask((32-s)&31, mask, 32)
  1179  }
  1180  
  1181  // Test if a RLWINM feeding into a CLRLSLDI can be merged into RLWINM.  Return
  1182  // the encoded RLWINM constant, or 0 if they cannot be merged.
  1183  func MergePPC64ClrlsldiRlwinm(sld int32, rlw int64) int64 {
  1184  	r_1, _, _, mask_1 := DecodePPC64RotateMask(rlw)
  1185  	// for CLRLSLDI, it's more convenient to think of it as a mask left bits then rotate left.
  1186  	mask_2 := uint64(0xFFFFFFFFFFFFFFFF) >> uint(GetPPC64Shiftmb(int64(sld)))
  1187  
  1188  	// combine the masks, and adjust for the final left shift.
  1189  	mask_3 := (mask_1 & mask_2) << uint(GetPPC64Shiftsh(int64(sld)))
  1190  	r_2 := GetPPC64Shiftsh(int64(sld))
  1191  	r_3 := (r_1 + r_2) & 31 // This can wrap.
  1192  
  1193  	// Verify the result is still a valid bitmask of <= 32 bits.
  1194  	if !IsPPC64WordRotateMask(int64(mask_3)) || uint64(uint32(mask_3)) != mask_3 {
  1195  		return 0
  1196  	}
  1197  	return EncodePPC64RotateMask(r_3, int64(mask_3), 32)
  1198  }
  1199  
  1200  // Test if a word shift right feeding into a CLRLSLDI can be merged into RLWINM.
  1201  // Return the encoded RLWINM constant, or 0 if they cannot be merged.
  1202  func MergePPC64ClrlsldiSrw(sld, srw int64) int64 {
  1203  	mask_1 := uint64(0xFFFFFFFF >> uint(srw))
  1204  	// for CLRLSLDI, it's more convenient to think of it as a mask left bits then rotate left.
  1205  	mask_2 := uint64(0xFFFFFFFFFFFFFFFF) >> uint(GetPPC64Shiftmb(sld))
  1206  
  1207  	// Rewrite mask to apply after the final left shift.
  1208  	mask_3 := (mask_1 & mask_2) << uint(GetPPC64Shiftsh(sld))
  1209  
  1210  	r_1 := 32 - srw
  1211  	r_2 := GetPPC64Shiftsh(sld)
  1212  	r_3 := (r_1 + r_2) & 31 // This can wrap.
  1213  
  1214  	if uint64(uint32(mask_3)) != mask_3 || mask_3 == 0 {
  1215  		return 0
  1216  	}
  1217  	return EncodePPC64RotateMask(r_3, int64(mask_3), 32)
  1218  }
  1219  
  1220  // Decompose a shift right into an equivalent rotate/mask,
  1221  // and return mask & m.
  1222  func MergePPC64RShiftMask(m, s, nbits int64) int64 {
  1223  	smask := uint64((1<<uint(nbits))-1) >> uint(s)
  1224  	return m & int64(smask)
  1225  }
  1226  
  1227  // Compute the encoded RLWINM constant from combining (SLDconst [sld] (SRWconst [srw] x)),
  1228  // or return 0 if they cannot be combined.
  1229  func MergePPC64SldiSrw(sld, srw int64) int64 {
  1230  	if sld > srw || srw >= 32 {
  1231  		return 0
  1232  	}
  1233  	mask_r := uint32(0xFFFFFFFF) >> uint(srw)
  1234  	mask_l := uint32(0xFFFFFFFF) >> uint(sld)
  1235  	mask := (mask_r & mask_l) << uint(sld)
  1236  	return EncodePPC64RotateMask((32-srw+sld)&31, int64(mask), 32)
  1237  }
  1238  
  1239  // MergeSym merges two symbolic offsets. There is no real merging of
  1240  // offsets, we just pick the non-nil one.
  1241  func MergeSym(x, y Sym) Sym {
  1242  	if x == nil {
  1243  		return y
  1244  	}
  1245  	if y == nil {
  1246  		return x
  1247  	}
  1248  	panic(fmt.Sprintf("mergeSym with two non-nil syms %v %v", x, y))
  1249  }
  1250  
  1251  // MoveSize returns the number of bytes an aligned MOV instruction moves.
  1252  func MoveSize(align int64, c *Config) int64 {
  1253  	switch {
  1254  	case align%8 == 0 && c.PtrSize == 8:
  1255  		return 8
  1256  	case align%4 == 0:
  1257  		return 4
  1258  	case align%2 == 0:
  1259  		return 2
  1260  	}
  1261  	return 1
  1262  }
  1263  
  1264  // MulStrengthReduce returns v*x evaluated at the location
  1265  // (block and source position) of m.
  1266  // canMulStrengthReduce must have returned true.
  1267  func MulStrengthReduce(m *Value, v *Value, x int64) *Value {
  1268  	return v.Block.Func.Config.MulRecipes[x].Build(m, v)
  1269  }
  1270  
  1271  // MulStrengthReduce32 returns v*x evaluated at the location
  1272  // (block and source position) of m.
  1273  // canMulStrengthReduce32 must have returned true.
  1274  // The upper 32 bits of m might be set to junk.
  1275  func MulStrengthReduce32(m *Value, v *Value, x int32) *Value {
  1276  	return v.Block.Func.Config.MulRecipes[int64(x)].Build(m, v)
  1277  }
  1278  
  1279  func NewPPC64ShiftAuxInt(sh, mb, me, sz int64) int32 {
  1280  	if sh < 0 || sh >= sz {
  1281  		panic("PPC64 shift arg sh out of range")
  1282  	}
  1283  	if mb < 0 || mb >= sz {
  1284  		panic("PPC64 shift arg mb out of range")
  1285  	}
  1286  	if me < 0 || me >= sz {
  1287  		panic("PPC64 shift arg me out of range")
  1288  	}
  1289  	return int32(sh<<16 | mb<<8 | me)
  1290  }
  1291  
  1292  // NoteRule is an easy way to track if a rule is matched when writing
  1293  // new ones.  Make the rule of interest also conditional on
  1294  //
  1295  //	NoteRule("note to self: rule of interest matched")
  1296  //
  1297  // and that message will print when the rule matches.
  1298  func NoteRule(s string) bool {
  1299  	fmt.Println(s)
  1300  	return true
  1301  }
  1302  
  1303  // ntzX returns the number of trailing zeros.
  1304  func Ntz64(x int64) int { return bits.TrailingZeros64(uint64(x)) }
  1305  
  1306  // OneBit reports whether x contains exactly one set bit.
  1307  func OneBit[T int8 | int16 | int32 | int64](x T) bool {
  1308  	return x&(x-1) == 0 && x != 0
  1309  }
  1310  
  1311  func OpToAuxInt(o ssaop.Op) int64 {
  1312  	return int64(o)
  1313  }
  1314  
  1315  func PanicBoundsCCToAux(p PanicBoundsCC) Aux {
  1316  	return p
  1317  }
  1318  
  1319  func PanicBoundsCToAux(p PanicBoundsC) Aux {
  1320  	return p
  1321  }
  1322  
  1323  // Read16 reads two bytes from the read-only global sym at offset off.
  1324  func Read16(sym Sym, off int64, byteorder binary.ByteOrder) uint16 {
  1325  	lsym := sym.(*obj.LSym)
  1326  	// lsym.P is written lazily.
  1327  	// Bytes requested after the end of lsym.P are 0.
  1328  	var src []byte
  1329  	if 0 <= off && off < int64(len(lsym.P)) {
  1330  		src = lsym.P[off:]
  1331  	}
  1332  	buf := make([]byte, 2)
  1333  	copy(buf, src)
  1334  	return byteorder.Uint16(buf)
  1335  }
  1336  
  1337  // Read32 reads four bytes from the read-only global sym at offset off.
  1338  func Read32(sym Sym, off int64, byteorder binary.ByteOrder) uint32 {
  1339  	lsym := sym.(*obj.LSym)
  1340  	var src []byte
  1341  	if 0 <= off && off < int64(len(lsym.P)) {
  1342  		src = lsym.P[off:]
  1343  	}
  1344  	buf := make([]byte, 4)
  1345  	copy(buf, src)
  1346  	return byteorder.Uint32(buf)
  1347  }
  1348  
  1349  // Read64 reads eight bytes from the read-only global sym at offset off.
  1350  func Read64(sym Sym, off int64, byteorder binary.ByteOrder) uint64 {
  1351  	lsym := sym.(*obj.LSym)
  1352  	var src []byte
  1353  	if 0 <= off && off < int64(len(lsym.P)) {
  1354  		src = lsym.P[off:]
  1355  	}
  1356  	buf := make([]byte, 8)
  1357  	copy(buf, src)
  1358  	return byteorder.Uint64(buf)
  1359  }
  1360  
  1361  // Read8 reads one byte from the read-only global sym at offset off.
  1362  func Read8(sym Sym, off int64) uint8 {
  1363  	lsym := sym.(*obj.LSym)
  1364  	if off >= int64(len(lsym.P)) || off < 0 {
  1365  		// Invalid index into the global sym.
  1366  		// This can happen in dead code, so we don't want to panic.
  1367  		// Just return any value, it will eventually get ignored.
  1368  		// See issue 29215.
  1369  		return 0
  1370  	}
  1371  	return lsym.P[off]
  1372  }
  1373  
  1374  func RewriteStructStore(v *Value) *Value {
  1375  	b := v.Block
  1376  	dst := v.Args[0]
  1377  	x := v.Args[1]
  1378  	if x.Op != ssaop.OpStructMake {
  1379  		base.Fatalf("invalid struct store: %v", x)
  1380  	}
  1381  	mem := v.Args[2]
  1382  
  1383  	t := x.Type
  1384  	for i, arg := range x.Args {
  1385  		ft := t.FieldType(i)
  1386  
  1387  		addr := b.NewValue1I(v.Pos, ssaop.OpOffPtr, ft.PtrTo(), t.FieldOff(i), dst)
  1388  		mem = b.NewValue3A(v.Pos, ssaop.OpStore, types.TypeMem, TypeToAux(ft), addr, arg, mem)
  1389  	}
  1390  
  1391  	return mem
  1392  }
  1393  
  1394  func S390xCCMaskToAux(c s390x.CCMask) Aux {
  1395  	return c
  1396  }
  1397  
  1398  func S390xRotateParamsToAux(r s390x.RotateParams) Aux {
  1399  	return r
  1400  }
  1401  
  1402  // SetPos sets the position of v to pos, then returns true.
  1403  // Useful for setting the result of a rewrite's position to
  1404  // something other than the default.
  1405  func SetPos(v *Value, pos src.XPos) bool {
  1406  	v.Pos = pos
  1407  	return true
  1408  }
  1409  
  1410  // ShiftIsBounded reports whether (left/right) shift Value v is known to be bounded.
  1411  // A shift is bounded if it is shifting by less than the width of the shifted value.
  1412  func ShiftIsBounded(v *Value) bool {
  1413  	return v.AuxInt != 0
  1414  }
  1415  
  1416  // SubFlags32 returns the flags that would be set from computing x-y.
  1417  func SubFlags32(x, y int32) FlagConstant {
  1418  	var fcb FlagConstantBuilder
  1419  	fcb.Z = x-y == 0
  1420  	fcb.N = x-y < 0
  1421  	fcb.C = uint32(y) <= uint32(x) // This code follows the arm carry flag model.
  1422  	fcb.V = x >= 0 && y < 0 && x-y < 0 || x < 0 && y >= 0 && x-y >= 0
  1423  	return fcb.Encode()
  1424  }
  1425  
  1426  // SubFlags64 returns the flags that would be set from computing x-y.
  1427  func SubFlags64(x, y int64) FlagConstant {
  1428  	var fcb FlagConstantBuilder
  1429  	fcb.Z = x-y == 0
  1430  	fcb.N = x-y < 0
  1431  	fcb.C = uint64(y) <= uint64(x) // This code follows the arm carry flag model.
  1432  	fcb.V = x >= 0 && y < 0 && x-y < 0 || x < 0 && y >= 0 && x-y >= 0
  1433  	return fcb.Encode()
  1434  }
  1435  
  1436  func SupportsPPC64PCRel() bool {
  1437  	// PCRel is currently supported for >= power10, linux only
  1438  	// Internal and external linking supports this on ppc64le; internal linking on ppc64.
  1439  	return buildcfg.GOPPC64 >= 10 && buildcfg.GOOS == "linux"
  1440  }
  1441  
  1442  // SymIsRO reports whether sym is a read-only global.
  1443  func SymIsRO(sym Sym) bool {
  1444  	lsym := sym.(*obj.LSym)
  1445  	return lsym.Type == objabi.SRODATA && len(lsym.R) == 0
  1446  }
  1447  
  1448  func SymToAux(s Sym) Aux {
  1449  	return s
  1450  }
  1451  
  1452  func TypeToAux(t *types.Type) Aux {
  1453  	return t
  1454  }
  1455  
  1456  func Uint64ToAuxInt(i uint64) int64 {
  1457  	return int64(i)
  1458  }
  1459  
  1460  func Uint8ToAuxInt(i uint8) int64 {
  1461  	return int64(int8(i))
  1462  }
  1463  
  1464  func ValAndOffToAuxInt(v ValAndOff) int64 {
  1465  	return int64(v)
  1466  }
  1467  
  1468  var ruleFile io.Writer
  1469  
  1470  func (fcs FlagConstantBuilder) Encode() FlagConstant {
  1471  	var fc FlagConstant
  1472  	if fcs.N {
  1473  		fc |= 1
  1474  	}
  1475  	if fcs.Z {
  1476  		fc |= 2
  1477  	}
  1478  	if fcs.C {
  1479  		fc |= 4
  1480  	}
  1481  	if fcs.V {
  1482  		fc |= 8
  1483  	}
  1484  	return fc
  1485  }
  1486  
  1487  func IsConstZero(v *Value) bool {
  1488  	switch v.Op {
  1489  	case ssaop.OpConstNil:
  1490  		return true
  1491  	case ssaop.OpConst64, ssaop.OpConst32, ssaop.OpConst16, ssaop.OpConst8, ssaop.OpConstBool, ssaop.OpConst32F, ssaop.OpConst64F:
  1492  		return v.AuxInt == 0
  1493  	case ssaop.OpStringMake, ssaop.OpIMake, ssaop.OpComplexMake:
  1494  		return IsConstZero(v.Args[0]) && IsConstZero(v.Args[1])
  1495  	case ssaop.OpSliceMake:
  1496  		return IsConstZero(v.Args[0]) && IsConstZero(v.Args[1]) && IsConstZero(v.Args[2])
  1497  	case ssaop.OpStringPtr, ssaop.OpStringLen, ssaop.OpSlicePtr, ssaop.OpSliceLen, ssaop.OpSliceCap, ssaop.OpITab, ssaop.OpIData, ssaop.OpComplexReal, ssaop.OpComplexImag:
  1498  		return IsConstZero(v.Args[0])
  1499  	}
  1500  	return false
  1501  }
  1502  

View as plain text