Source file src/cmd/compile/internal/ssarewrite/rewritegeneric/generic_helpers.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 rewritegeneric
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  	"math/bits"
    11  	"strings"
    12  
    13  	"cmd/compile/internal/base"
    14  	"cmd/compile/internal/ir"
    15  	"cmd/compile/internal/reflectdata"
    16  	"cmd/compile/internal/rttype"
    17  	"cmd/compile/internal/ssa"
    18  	"cmd/compile/internal/ssa/ssaop"
    19  	"cmd/compile/internal/typecheck"
    20  	"cmd/compile/internal/types"
    21  	"cmd/internal/obj"
    22  	"cmd/internal/objabi"
    23  )
    24  
    25  func addToSub(op ssaop.Op) ssaop.Op {
    26  	switch op {
    27  	case ssaop.OpAdd64:
    28  		return ssaop.OpSub64
    29  	case ssaop.OpAdd32:
    30  		return ssaop.OpSub32
    31  	case ssaop.OpAdd16:
    32  		return ssaop.OpSub16
    33  	case ssaop.OpAdd8:
    34  		return ssaop.OpSub8
    35  	default:
    36  		panic(fmt.Sprintf("unexpected op %v", op))
    37  	}
    38  }
    39  
    40  func bitsAdd64(x, y, carry int64) (r struct{ sum, carry int64 }) {
    41  	s, c := bits.Add64(uint64(x), uint64(y), uint64(carry))
    42  	r.sum, r.carry = int64(s), int64(c)
    43  	return
    44  }
    45  
    46  func bitsMulU32(x, y int32) (r struct{ hi, lo int32 }) {
    47  	hi, lo := bits.Mul32(uint32(x), uint32(y))
    48  	r.hi, r.lo = int32(hi), int32(lo)
    49  	return
    50  }
    51  
    52  func bitsMulU64(x, y int64) (r struct{ hi, lo int64 }) {
    53  	hi, lo := bits.Mul64(uint64(x), uint64(y))
    54  	r.hi, r.lo = int64(hi), int64(lo)
    55  	return
    56  }
    57  
    58  func bitsDiv128u(hi, lo, y int64) (r struct{ quo, rem int64 }) {
    59  	q, rem := bits.Div64(uint64(hi), uint64(lo), uint64(y))
    60  	r.quo, r.rem = int64(q), int64(rem)
    61  	return
    62  }
    63  
    64  // bool2int converts bool to int: true to 1, false to 0
    65  func bool2int(x bool) int {
    66  	var b int
    67  	if x {
    68  		b = 1
    69  	}
    70  	return b
    71  }
    72  
    73  // canLoadUnaligned reports if the architecture supports unaligned load operations.
    74  func canLoadUnaligned(c *ssa.Config) bool {
    75  	return c.Ctxt.Arch.Alignment == 1
    76  }
    77  
    78  // canRotate reports whether the architecture supports
    79  // rotates of integer registers with the given number of bits.
    80  func canRotate(c *ssa.Config, bits int64) bool {
    81  	if bits > c.PtrSize*8 {
    82  		// Don't rewrite to rotates bigger than the machine word.
    83  		return false
    84  	}
    85  	switch c.Arch {
    86  	case "386", "amd64", "arm64", "loong64", "riscv64":
    87  		return true
    88  	case "arm", "s390x", "ppc64", "ppc64le", "wasm":
    89  		return bits >= 32
    90  	default:
    91  		return false
    92  	}
    93  }
    94  
    95  func copyCompatibleType(t1, t2 *types.Type) bool {
    96  	if t1.Size() != t2.Size() {
    97  		return false
    98  	}
    99  	if t1.IsInteger() {
   100  		return t2.IsInteger()
   101  	}
   102  	if ssa.IsPtr(t1) {
   103  		return ssa.IsPtr(t2)
   104  	}
   105  	return t1.Compare(t2) == types.CMPeq
   106  }
   107  
   108  func devirtLECall(v *ssa.Value, sym *obj.LSym) *ssa.Value {
   109  	v.Op = ssaop.OpStaticLECall
   110  	auxcall := v.Aux.(*ssa.AuxCall)
   111  	auxcall.Fn = sym
   112  	// Remove first arg
   113  	v.Args[0].Uses--
   114  	copy(v.Args[0:], v.Args[1:])
   115  	v.Args[len(v.Args)-1] = nil // aid GC
   116  	v.Args = v.Args[:len(v.Args)-1]
   117  	if f := v.Block.Func; f.Pass.Debug > 0 {
   118  		f.Warnl(v.Pos, "de-virtualizing call")
   119  	}
   120  	return v
   121  }
   122  
   123  // hasSmallRotate reports whether the architecture has rotate instructions
   124  // for sizes < 32-bit.  This is used to decide whether to promote some rotations.
   125  func hasSmallRotate(c *ssa.Config) bool {
   126  	switch c.Arch {
   127  	case "amd64", "386":
   128  		return true
   129  	default:
   130  		return false
   131  	}
   132  }
   133  
   134  func invertibleBool(op ssaop.Op) bool {
   135  	switch op {
   136  	case ssaop.OpLess64, ssaop.OpLess32, ssaop.OpLess16, ssaop.OpLess8,
   137  		ssaop.OpLeq64, ssaop.OpLeq32, ssaop.OpLeq16, ssaop.OpLeq8,
   138  		ssaop.OpLess64U, ssaop.OpLess32U, ssaop.OpLess16U, ssaop.OpLess8U,
   139  		ssaop.OpLeq64U, ssaop.OpLeq32U, ssaop.OpLeq16U, ssaop.OpLeq8U,
   140  		ssaop.OpEq64, ssaop.OpEq32, ssaop.OpEq16, ssaop.OpEq8,
   141  		ssaop.OpNeq64, ssaop.OpNeq32, ssaop.OpNeq16, ssaop.OpNeq8,
   142  		ssaop.OpNot:
   143  		return true
   144  	default:
   145  		return false
   146  	}
   147  }
   148  
   149  func isDictArgSym(sym ssa.Sym) bool {
   150  	return sym.(*ir.Name).Sym().Name == typecheck.LocalDictName
   151  }
   152  
   153  // isDirectAndComparableIface reports whether v represents an itab
   154  // (a *runtime._itab) for a type whose value is stored directly
   155  // in an interface (i.e., is pointer or pointer-like) and is comparable.
   156  func isDirectAndComparableIface(v *ssa.Value) bool {
   157  	return isDirectAndComparableIface1(v, 9)
   158  }
   159  
   160  // v is an itab
   161  func isDirectAndComparableIface1(v *ssa.Value, depth int) bool {
   162  	if depth == 0 {
   163  		return false
   164  	}
   165  	switch v.Op {
   166  	case ssaop.OpITab:
   167  		return isDirectAndComparableIface2(v.Args[0], depth-1)
   168  	case ssaop.OpAddr:
   169  		lsym := v.Aux.(*obj.LSym)
   170  		if ii := lsym.ItabInfo(); ii != nil {
   171  			t := ii.Type.(*types.Type)
   172  			return types.IsDirectIface(t) && types.IsComparable(t)
   173  		}
   174  	case ssaop.OpConstNil:
   175  		// We can treat this as direct, because if the itab is
   176  		// nil, the data field must be nil also.
   177  		return true
   178  	}
   179  	return false
   180  }
   181  
   182  // v is an interface
   183  func isDirectAndComparableIface2(v *ssa.Value, depth int) bool {
   184  	if depth == 0 {
   185  		return false
   186  	}
   187  	switch v.Op {
   188  	case ssaop.OpIMake:
   189  		return isDirectAndComparableIface1(v.Args[0], depth-1)
   190  	case ssaop.OpPhi:
   191  		for _, a := range v.Args {
   192  			if !isDirectAndComparableIface2(a, depth-1) {
   193  				return false
   194  			}
   195  		}
   196  		return true
   197  	}
   198  	return false
   199  }
   200  
   201  // isDirectAndComparableType reports whether v represents a type
   202  // (a *runtime._type) whose value is stored directly in an
   203  // interface (i.e., is pointer or pointer-like) and is comparable.
   204  func isDirectAndComparableType(v *ssa.Value) bool {
   205  	return isDirectAndComparableType1(v)
   206  }
   207  
   208  // v is a type
   209  func isDirectAndComparableType1(v *ssa.Value) bool {
   210  	switch v.Op {
   211  	case ssaop.OpITab:
   212  		return isDirectAndComparableType2(v.Args[0])
   213  	case ssaop.OpAddr:
   214  		lsym := v.Aux.(*obj.LSym)
   215  		if ti := lsym.TypeInfo(); ti != nil {
   216  			t := ti.Type.(*types.Type)
   217  			return types.IsDirectIface(t) && types.IsComparable(t)
   218  		}
   219  	}
   220  	return false
   221  }
   222  
   223  // v is an empty interface
   224  func isDirectAndComparableType2(v *ssa.Value) bool {
   225  	switch v.Op {
   226  	case ssaop.OpIMake:
   227  		return isDirectAndComparableType1(v.Args[0])
   228  	}
   229  	return false
   230  }
   231  
   232  // isFixedLoad returns true if the load can be resolved to fixed address or constant,
   233  // and can be rewritten by rewriteFixedLoad.
   234  func isFixedLoad(v *ssa.Value, sym ssa.Sym, off int64) bool {
   235  	lsym := sym.(*obj.LSym)
   236  	if (v.Type.IsPtrShaped() || v.Type.IsUintptr()) && lsym.Type == objabi.SRODATA {
   237  		for _, r := range lsym.R {
   238  			if (r.Type == objabi.R_ADDR || r.Type == objabi.R_WEAKADDR) && int64(r.Off) == off && r.Add == 0 {
   239  				return true
   240  			}
   241  		}
   242  		return false
   243  	}
   244  
   245  	if ti := lsym.TypeInfo(); ti != nil {
   246  		// Type symbols do not contain information about their fields, unlike the cases above.
   247  		// Hand-implement field accesses.
   248  		// TODO: can this be replaced with reflectdata.writeType and just use the code above?
   249  
   250  		t := ti.Type.(*types.Type)
   251  
   252  		for _, f := range rttype.Type.Fields() {
   253  			if f.Offset == off && copyCompatibleType(v.Type, f.Type) {
   254  				switch f.Sym.Name {
   255  				case "Size_", "PtrBytes", "Hash", "Kind_", "GCData", "TFlag":
   256  					return true
   257  				default:
   258  					// fmt.Println("unknown field", f.Sym.Name)
   259  					return false
   260  				}
   261  			}
   262  		}
   263  
   264  		if t.IsPtr() && off == rttype.PtrType.OffsetOf("Elem") {
   265  			return true
   266  		}
   267  
   268  		return false
   269  	}
   270  
   271  	return false
   272  }
   273  
   274  func isInlinableMemclr(c *ssa.Config, sz int64) bool {
   275  	if sz < 0 {
   276  		return false
   277  	}
   278  	// TODO: expand this check to allow other architectures
   279  	// see CL 454255 and issue 56997
   280  	switch c.Arch {
   281  	case "amd64", "arm64":
   282  		return true
   283  	case "ppc64le", "ppc64", "loong64":
   284  		return sz < 512
   285  	}
   286  	return false
   287  }
   288  
   289  func isMalloc(aux ssa.Aux) bool {
   290  	return ssa.IsNewObjectCall(aux) || ssa.IsSpecializedMalloc(aux)
   291  }
   292  
   293  // isNonNegative reports whether v is known to be greater or equal to zero.
   294  // Note that this is pretty simplistic. The prove pass generates more detailed
   295  // nonnegative information about values.
   296  func isNonNegative(v *ssa.Value) bool {
   297  	if !v.Type.IsInteger() {
   298  		v.Fatalf("isNonNegative bad type: %v", v.Type)
   299  	}
   300  	// TODO: return true if !v.Type.IsSigned()
   301  	// SSA isn't type-safe enough to do that now (issue 37753).
   302  	// The checks below depend only on the pattern of bits.
   303  
   304  	switch v.Op {
   305  	case ssaop.OpConst64:
   306  		return v.AuxInt >= 0
   307  
   308  	case ssaop.OpConst32:
   309  		return int32(v.AuxInt) >= 0
   310  
   311  	case ssaop.OpConst16:
   312  		return int16(v.AuxInt) >= 0
   313  
   314  	case ssaop.OpConst8:
   315  		return int8(v.AuxInt) >= 0
   316  
   317  	case ssaop.OpStringLen, ssaop.OpSliceLen, ssaop.OpSliceCap,
   318  		ssaop.OpZeroExt8to64, ssaop.OpZeroExt16to64, ssaop.OpZeroExt32to64,
   319  		ssaop.OpZeroExt8to32, ssaop.OpZeroExt16to32, ssaop.OpZeroExt8to16,
   320  		ssaop.OpCtz64, ssaop.OpCtz32, ssaop.OpCtz16, ssaop.OpCtz8,
   321  		ssaop.OpCtz64NonZero, ssaop.OpCtz32NonZero, ssaop.OpCtz16NonZero, ssaop.OpCtz8NonZero,
   322  		ssaop.OpBitLen64, ssaop.OpBitLen32, ssaop.OpBitLen16, ssaop.OpBitLen8:
   323  		return true
   324  
   325  	case ssaop.OpRsh64Ux64, ssaop.OpRsh32Ux64:
   326  		by := v.Args[1]
   327  		return by.Op == ssaop.OpConst64 && by.AuxInt > 0
   328  
   329  	case ssaop.OpRsh64x64, ssaop.OpRsh32x64, ssaop.OpRsh8x64, ssaop.OpRsh16x64, ssaop.OpRsh32x32, ssaop.OpRsh64x32,
   330  		ssaop.OpSignExt32to64, ssaop.OpSignExt16to64, ssaop.OpSignExt8to64, ssaop.OpSignExt16to32, ssaop.OpSignExt8to32:
   331  		return isNonNegative(v.Args[0])
   332  
   333  	case ssaop.OpAnd64, ssaop.OpAnd32, ssaop.OpAnd16, ssaop.OpAnd8:
   334  		return isNonNegative(v.Args[0]) || isNonNegative(v.Args[1])
   335  
   336  	case ssaop.OpMod64, ssaop.OpMod32, ssaop.OpMod16, ssaop.OpMod8,
   337  		ssaop.OpDiv64, ssaop.OpDiv32, ssaop.OpDiv16, ssaop.OpDiv8,
   338  		ssaop.OpOr64, ssaop.OpOr32, ssaop.OpOr16, ssaop.OpOr8,
   339  		ssaop.OpXor64, ssaop.OpXor32, ssaop.OpXor16, ssaop.OpXor8:
   340  		return isNonNegative(v.Args[0]) && isNonNegative(v.Args[1])
   341  
   342  		// We could handle OpPhi here, but the improvements from doing
   343  		// so are very minor, and it is neither simple nor cheap.
   344  	}
   345  	return false
   346  }
   347  
   348  func isStackPtr(v *ssa.Value) bool {
   349  	for v.Op == ssaop.OpOffPtr || v.Op == ssaop.OpAddPtr {
   350  		v = v.Args[0]
   351  	}
   352  	return v.Op == ssaop.OpSP || v.Op == ssaop.OpLocalAddr
   353  }
   354  
   355  // needRaceCleanup reports whether this call to racefuncenter/exit isn't needed.
   356  func needRaceCleanup(sym *ssa.AuxCall, v *ssa.Value) bool {
   357  	f := v.Block.Func
   358  	if !f.Config.Race {
   359  		return false
   360  	}
   361  	if !ssa.IsSameCall(sym, "runtime.racefuncenter") && !ssa.IsSameCall(sym, "runtime.racefuncexit") {
   362  		return false
   363  	}
   364  	for _, b := range f.Blocks {
   365  		for _, v := range b.Values {
   366  			switch v.Op {
   367  			case ssaop.OpStaticCall, ssaop.OpStaticLECall:
   368  				// Check for racefuncenter will encounter racefuncexit and vice versa.
   369  				// Allow calls to panic*
   370  				s := v.Aux.(*ssa.AuxCall).Fn.String()
   371  				switch s {
   372  				case "runtime.racefuncenter", "runtime.racefuncexit",
   373  					"runtime.panicdivide", "runtime.panicwrap",
   374  					"runtime.panicshift":
   375  					continue
   376  				}
   377  				// If we encountered any call, we need to keep racefunc*,
   378  				// for accurate stacktraces.
   379  				return false
   380  			case ssaop.OpPanicBounds, ssaop.OpPanicExtend:
   381  				// Note: these are panic generators that are ok (like the static calls above).
   382  			case ssaop.OpClosureCall, ssaop.OpInterCall, ssaop.OpClosureLECall, ssaop.OpInterLECall:
   383  				// We must keep the race functions if there are any other call types.
   384  				return false
   385  			}
   386  		}
   387  	}
   388  	if ssa.IsSameCall(sym, "runtime.racefuncenter") {
   389  		// TODO REGISTER ABI this needs to be cleaned up.
   390  		// If we're removing racefuncenter, remove its argument as well.
   391  		if v.Args[0].Op != ssaop.OpStore {
   392  			if v.Op == ssaop.OpStaticLECall {
   393  				// there is no store, yet.
   394  				return true
   395  			}
   396  			return false
   397  		}
   398  		mem := v.Args[0].Args[2]
   399  		v.Args[0].Reset(ssaop.OpCopy)
   400  		v.Args[0].AddArg(mem)
   401  	}
   402  	return true
   403  }
   404  
   405  func nlz16(x int16) int { return bits.LeadingZeros16(uint16(x)) }
   406  
   407  func nlz32(x int32) int { return bits.LeadingZeros32(uint32(x)) }
   408  
   409  // nlzX returns the number of leading zeros.
   410  func nlz64(x int64) int { return bits.LeadingZeros64(uint64(x)) }
   411  
   412  func nlz8(x int8) int { return bits.LeadingZeros8(uint8(x)) }
   413  
   414  func ntz16(x int16) int { return bits.TrailingZeros16(uint16(x)) }
   415  
   416  func ntz32(x int32) int { return bits.TrailingZeros32(uint32(x)) }
   417  
   418  func ntz8(x int8) int { return bits.TrailingZeros8(uint8(x)) }
   419  
   420  // reciprocalExact32 reports whether 1/c is exactly representable.
   421  func reciprocalExact32(c float32) bool {
   422  	b := math.Float32bits(c)
   423  	man := b & (1<<23 - 1)
   424  	if man != 0 {
   425  		return false // not a power of 2, denormal, or NaN
   426  	}
   427  	exp := b >> 23 & (1<<8 - 1)
   428  	// exponent bias is 0x7f.  So taking the reciprocal of a number
   429  	// changes the exponent to 0xfe-exp.
   430  	switch exp {
   431  	case 0:
   432  		return false // ±0
   433  	case 0xff:
   434  		return false // ±inf
   435  	case 0xfe:
   436  		return false // exponent is not representable
   437  	default:
   438  		return true
   439  	}
   440  }
   441  
   442  // reciprocalExact64 reports whether 1/c is exactly representable.
   443  func reciprocalExact64(c float64) bool {
   444  	b := math.Float64bits(c)
   445  	man := b & (1<<52 - 1)
   446  	if man != 0 {
   447  		return false // not a power of 2, denormal, or NaN
   448  	}
   449  	exp := b >> 52 & (1<<11 - 1)
   450  	// exponent bias is 0x3ff.  So taking the reciprocal of a number
   451  	// changes the exponent to 0x7fe-exp.
   452  	switch exp {
   453  	case 0:
   454  		return false // ±0
   455  	case 0x7ff:
   456  		return false // ±inf
   457  	case 0x7fe:
   458  		return false // exponent is not representable
   459  	default:
   460  		return true
   461  	}
   462  }
   463  
   464  // registerizable reports whether t is a primitive type that fits in
   465  // a register. It assumes float64 values will always fit into registers
   466  // even if that isn't strictly true.
   467  func registerizable(b *ssa.Block, typ *types.Type) bool {
   468  	if typ.IsPtrShaped() || typ.IsFloat() || typ.IsBoolean() {
   469  		return true
   470  	}
   471  	if typ.IsInteger() {
   472  		return typ.Size() <= b.Func.Config.RegSize
   473  	}
   474  	return false
   475  }
   476  
   477  // resetCopy resets v to be a copy of arg.
   478  // Always returns true.
   479  func resetCopy(v *ssa.Value, arg *ssa.Value) bool {
   480  	v.Reset(ssaop.OpCopy)
   481  	v.AddArg(arg)
   482  	return true
   483  }
   484  
   485  // rewriteCondSelectIntoMath reports whether x OP (y * constant) should be used instead of a CondSelect.
   486  // x arbitrary, y in [0,1]
   487  func rewriteCondSelectIntoMath(config *ssa.Config, op ssaop.Op, constant int64) bool {
   488  	// at worst this becomes a left shift by a constant which has asymmetric latency (1:3 vs 2:2)
   489  	// but performs better in accumulation chains.
   490  	// Various arches do strictly superior for specific cases, but this is a good general default.
   491  	// FIXME: optimize more constants in arches where this is possible.
   492  	switch config.Arch {
   493  	case "arm64":
   494  		switch op {
   495  		case ssaop.OpAdd64, ssaop.OpAdd32, ssaop.OpAdd16, ssaop.OpAdd8:
   496  			if constant == 1 {
   497  				return false // better done as CSINC
   498  			}
   499  			fallthrough
   500  		default:
   501  			// add sub or xor & and are implemented using inline LSL
   502  			// the rest becomes the default LSL
   503  			return ssa.IsPowerOfTwo(uint64(constant))
   504  		}
   505  	default:
   506  		return ssa.IsPowerOfTwo(uint64(constant))
   507  	}
   508  }
   509  
   510  // rewriteFixedLoad rewrites a load to a fixed address or constant, if isFixedLoad returns true.
   511  func rewriteFixedLoad(v *ssa.Value, sym ssa.Sym, sb *ssa.Value, off int64) *ssa.Value {
   512  	b := v.Block
   513  	f := b.Func
   514  
   515  	lsym := sym.(*obj.LSym)
   516  	if (v.Type.IsPtrShaped() || v.Type.IsUintptr()) && lsym.Type == objabi.SRODATA {
   517  		for _, r := range lsym.R {
   518  			if (r.Type == objabi.R_ADDR || r.Type == objabi.R_WEAKADDR) && int64(r.Off) == off && r.Add == 0 {
   519  				if strings.HasPrefix(r.Sym.Name, "type:") {
   520  					// In case we're loading a type out of a dictionary, we need to record
   521  					// that the containing function might put that type in an interface.
   522  					// That information is currently recorded in relocations in the dictionary,
   523  					// but if we perform this load at compile time then the dictionary
   524  					// might be dead.
   525  					reflectdata.MarkTypeSymUsedInInterface(r.Sym, f.Fe.Func().Linksym())
   526  				} else if strings.HasPrefix(r.Sym.Name, "go:itab") {
   527  					// Same, but if we're using an itab we need to record that the
   528  					// itab._type might be put in an interface.
   529  					reflectdata.MarkTypeSymUsedInInterface(r.Sym, f.Fe.Func().Linksym())
   530  				}
   531  				v.Reset(ssaop.OpAddr)
   532  				v.Aux = ssa.SymToAux(r.Sym)
   533  				v.AddArg(sb)
   534  				return v
   535  			}
   536  		}
   537  		base.Fatalf("fixedLoad data not known for %s:%d", sym, off)
   538  	}
   539  
   540  	if ti := lsym.TypeInfo(); ti != nil {
   541  		// Type symbols do not contain information about their fields, unlike the cases above.
   542  		// Hand-implement field accesses.
   543  		// TODO: can this be replaced with reflectdata.writeType and just use the code above?
   544  
   545  		t := ti.Type.(*types.Type)
   546  
   547  		ptrSizedOpConst := ssaop.OpConst64
   548  		if f.Config.PtrSize == 4 {
   549  			ptrSizedOpConst = ssaop.OpConst32
   550  		}
   551  
   552  		for _, f := range rttype.Type.Fields() {
   553  			if f.Offset == off && copyCompatibleType(v.Type, f.Type) {
   554  				switch f.Sym.Name {
   555  				case "Size_":
   556  					v.Reset(ptrSizedOpConst)
   557  					v.AuxInt = t.Size()
   558  					return v
   559  				case "PtrBytes":
   560  					v.Reset(ptrSizedOpConst)
   561  					v.AuxInt = types.PtrDataSize(t)
   562  					return v
   563  				case "Hash":
   564  					v.Reset(ssaop.OpConst32)
   565  					v.AuxInt = int64(int32(types.TypeHash(t)))
   566  					return v
   567  				case "TFlag":
   568  					v.Reset(ssaop.OpConst8)
   569  					v.AuxInt = int64(t.TFlag())
   570  					return v
   571  				case "Kind_":
   572  					v.Reset(ssaop.OpConst8)
   573  					v.AuxInt = int64(int8(reflectdata.ABIKindOfType(t)))
   574  					return v
   575  				case "GCData":
   576  					gcdata, _ := reflectdata.GCSym(t, true)
   577  					v.Reset(ssaop.OpAddr)
   578  					v.Aux = ssa.SymToAux(gcdata)
   579  					v.AddArg(sb)
   580  					return v
   581  				default:
   582  					base.Fatalf("unknown field %s for fixedLoad of %s at offset %d", f.Sym.Name, lsym.Name, off)
   583  				}
   584  			}
   585  		}
   586  
   587  		if t.IsPtr() && off == rttype.PtrType.OffsetOf("Elem") {
   588  			elemSym := reflectdata.TypeLinksym(t.Elem())
   589  			reflectdata.MarkTypeSymUsedInInterface(elemSym, f.Fe.Func().Linksym())
   590  			v.Reset(ssaop.OpAddr)
   591  			v.Aux = ssa.SymToAux(elemSym)
   592  			v.AddArg(sb)
   593  			return v
   594  		}
   595  
   596  		base.Fatalf("fixedLoad data not known for %s:%d", sym, off)
   597  	}
   598  
   599  	base.Fatalf("fixedLoad data not known for %s:%d", sym, off)
   600  	return nil
   601  }
   602  
   603  func rewriteStructLoad(v *ssa.Value) *ssa.Value {
   604  	b := v.Block
   605  	ptr := v.Args[0]
   606  	mem := v.Args[1]
   607  
   608  	t := v.Type
   609  	args := make([]*ssa.Value, t.NumFields())
   610  	for i := range args {
   611  		ft := t.FieldType(i)
   612  		addr := b.NewValue1I(v.Pos, ssaop.OpOffPtr, ft.PtrTo(), t.FieldOff(i), ptr)
   613  		args[i] = b.NewValue2(v.Pos, ssaop.OpLoad, ft, addr, mem)
   614  	}
   615  
   616  	v.Reset(ssaop.OpStructMake)
   617  	v.AddArgs(args...)
   618  	return v
   619  }
   620  
   621  // symIsROZero reports whether sym is a read-only global whose data contains all zeros.
   622  func symIsROZero(sym ssa.Sym) bool {
   623  	lsym := sym.(*obj.LSym)
   624  	if lsym.Type != objabi.SRODATA || len(lsym.R) != 0 {
   625  		return false
   626  	}
   627  	for _, b := range lsym.P {
   628  		if b != 0 {
   629  			return false
   630  		}
   631  	}
   632  	return true
   633  }
   634  
   635  // uaddOvf reports whether unsigned a+b would overflow.
   636  func uaddOvf(a, b int64) bool {
   637  	return uint64(a)+uint64(b) < uint64(a)
   638  }
   639  
   640  // warnRule generates compiler debug output with string s when
   641  // v is not in autogenerated code, cond is true and the rule has fired.
   642  func warnRule(cond bool, v *ssa.Value, s string) bool {
   643  	if pos := v.Pos; pos.Line() > 1 && cond {
   644  		v.Block.Func.Warnl(pos, s)
   645  	}
   646  	return true
   647  }
   648  
   649  func bitsSub64(x, y, borrow int64) (r struct{ diff, borrow int64 }) {
   650  	d, b := bits.Sub64(uint64(x), uint64(y), uint64(borrow))
   651  	r.diff, r.borrow = int64(d), int64(b)
   652  	return
   653  }
   654  
   655  func modularMultiplicativeInverse(x uint64) (y uint64) {
   656  	if x%2 != 1 {
   657  		panic("even numbers in a power-of-two modulus do not have a multiplicative inverse")
   658  	}
   659  	// we start with 3 bits of precision because each odd number is its own multiplicative inverse mod 8
   660  	y = x // 3 bits
   661  
   662  	// now use the Newton-Raphson method to double the number of correct bits in each iteration.
   663  	y *= 2 - x*y // 6 bits
   664  	y *= 2 - x*y // 12 bits
   665  	y *= 2 - x*y // 24 bits
   666  	y *= 2 - x*y // 48 bits
   667  	y *= 2 - x*y // 96 bits; good enough
   668  	return
   669  }
   670  

View as plain text