Source file src/cmd/compile/internal/ssa/rewrite/generic/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 generic
     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":
   256  					return true
   257  				case "TFlag":
   258  					return t.TFlagComputed()
   259  				default:
   260  					// fmt.Println("unknown field", f.Sym.Name)
   261  					return false
   262  				}
   263  			}
   264  		}
   265  
   266  		if t.IsPtr() && off == rttype.PtrType.OffsetOf("Elem") {
   267  			return true
   268  		}
   269  
   270  		return false
   271  	}
   272  
   273  	return false
   274  }
   275  
   276  func isInlinableMemclr(c *ssa.Config, sz int64) bool {
   277  	if sz < 0 {
   278  		return false
   279  	}
   280  	// TODO: expand this check to allow other architectures
   281  	// see CL 454255 and issue 56997
   282  	switch c.Arch {
   283  	case "amd64", "arm64":
   284  		return true
   285  	case "ppc64le", "ppc64", "loong64":
   286  		return sz < 512
   287  	}
   288  	return false
   289  }
   290  
   291  func isMalloc(aux ssa.Aux) bool {
   292  	return ssa.IsNewObjectCall(aux) || ssa.IsSpecializedMalloc(aux)
   293  }
   294  
   295  // isNonNegative reports whether v is known to be greater or equal to zero.
   296  // Note that this is pretty simplistic. The prove pass generates more detailed
   297  // nonnegative information about values.
   298  func isNonNegative(v *ssa.Value) bool {
   299  	if !v.Type.IsInteger() {
   300  		v.Fatalf("isNonNegative bad type: %v", v.Type)
   301  	}
   302  	// TODO: return true if !v.Type.IsSigned()
   303  	// SSA isn't type-safe enough to do that now (issue 37753).
   304  	// The checks below depend only on the pattern of bits.
   305  
   306  	switch v.Op {
   307  	case ssaop.OpConst64:
   308  		return v.AuxInt >= 0
   309  
   310  	case ssaop.OpConst32:
   311  		return int32(v.AuxInt) >= 0
   312  
   313  	case ssaop.OpConst16:
   314  		return int16(v.AuxInt) >= 0
   315  
   316  	case ssaop.OpConst8:
   317  		return int8(v.AuxInt) >= 0
   318  
   319  	case ssaop.OpStringLen, ssaop.OpSliceLen, ssaop.OpSliceCap,
   320  		ssaop.OpZeroExt8to64, ssaop.OpZeroExt16to64, ssaop.OpZeroExt32to64,
   321  		ssaop.OpZeroExt8to32, ssaop.OpZeroExt16to32, ssaop.OpZeroExt8to16,
   322  		ssaop.OpCtz64, ssaop.OpCtz32, ssaop.OpCtz16, ssaop.OpCtz8,
   323  		ssaop.OpCtz64NonZero, ssaop.OpCtz32NonZero, ssaop.OpCtz16NonZero, ssaop.OpCtz8NonZero,
   324  		ssaop.OpBitLen64, ssaop.OpBitLen32, ssaop.OpBitLen16, ssaop.OpBitLen8:
   325  		return true
   326  
   327  	case ssaop.OpRsh64Ux64, ssaop.OpRsh32Ux64:
   328  		by := v.Args[1]
   329  		return by.Op == ssaop.OpConst64 && by.AuxInt > 0
   330  
   331  	case ssaop.OpRsh64x64, ssaop.OpRsh32x64, ssaop.OpRsh8x64, ssaop.OpRsh16x64, ssaop.OpRsh32x32, ssaop.OpRsh64x32,
   332  		ssaop.OpSignExt32to64, ssaop.OpSignExt16to64, ssaop.OpSignExt8to64, ssaop.OpSignExt16to32, ssaop.OpSignExt8to32:
   333  		return isNonNegative(v.Args[0])
   334  
   335  	case ssaop.OpAnd64, ssaop.OpAnd32, ssaop.OpAnd16, ssaop.OpAnd8:
   336  		return isNonNegative(v.Args[0]) || isNonNegative(v.Args[1])
   337  
   338  	case ssaop.OpMod64, ssaop.OpMod32, ssaop.OpMod16, ssaop.OpMod8,
   339  		ssaop.OpDiv64, ssaop.OpDiv32, ssaop.OpDiv16, ssaop.OpDiv8,
   340  		ssaop.OpOr64, ssaop.OpOr32, ssaop.OpOr16, ssaop.OpOr8,
   341  		ssaop.OpXor64, ssaop.OpXor32, ssaop.OpXor16, ssaop.OpXor8:
   342  		return isNonNegative(v.Args[0]) && isNonNegative(v.Args[1])
   343  
   344  		// We could handle OpPhi here, but the improvements from doing
   345  		// so are very minor, and it is neither simple nor cheap.
   346  	}
   347  	return false
   348  }
   349  
   350  func isStackPtr(v *ssa.Value) bool {
   351  	for v.Op == ssaop.OpOffPtr || v.Op == ssaop.OpAddPtr {
   352  		v = v.Args[0]
   353  	}
   354  	return v.Op == ssaop.OpSP || v.Op == ssaop.OpLocalAddr
   355  }
   356  
   357  // needRaceCleanup reports whether this call to racefuncenter/exit isn't needed.
   358  func needRaceCleanup(sym *ssa.AuxCall, v *ssa.Value) bool {
   359  	f := v.Block.Func
   360  	if !f.Config.Race {
   361  		return false
   362  	}
   363  	if !ssa.IsSameCall(sym, "runtime.racefuncenter") && !ssa.IsSameCall(sym, "runtime.racefuncexit") {
   364  		return false
   365  	}
   366  	for _, b := range f.Blocks {
   367  		for _, v := range b.Values {
   368  			switch v.Op {
   369  			case ssaop.OpStaticCall, ssaop.OpStaticLECall:
   370  				// Check for racefuncenter will encounter racefuncexit and vice versa.
   371  				// Allow calls to panic*
   372  				s := v.Aux.(*ssa.AuxCall).Fn.String()
   373  				switch s {
   374  				case "runtime.racefuncenter", "runtime.racefuncexit",
   375  					"runtime.panicdivide", "runtime.panicwrap",
   376  					"runtime.panicshift":
   377  					continue
   378  				}
   379  				// If we encountered any call, we need to keep racefunc*,
   380  				// for accurate stacktraces.
   381  				return false
   382  			case ssaop.OpPanicBounds, ssaop.OpPanicExtend:
   383  				// Note: these are panic generators that are ok (like the static calls above).
   384  			case ssaop.OpClosureCall, ssaop.OpInterCall, ssaop.OpClosureLECall, ssaop.OpInterLECall:
   385  				// We must keep the race functions if there are any other call types.
   386  				return false
   387  			}
   388  		}
   389  	}
   390  	if ssa.IsSameCall(sym, "runtime.racefuncenter") {
   391  		// TODO REGISTER ABI this needs to be cleaned up.
   392  		// If we're removing racefuncenter, remove its argument as well.
   393  		if v.Args[0].Op != ssaop.OpStore {
   394  			if v.Op == ssaop.OpStaticLECall {
   395  				// there is no store, yet.
   396  				return true
   397  			}
   398  			return false
   399  		}
   400  		mem := v.Args[0].Args[2]
   401  		v.Args[0].Reset(ssaop.OpCopy)
   402  		v.Args[0].AddArg(mem)
   403  	}
   404  	return true
   405  }
   406  
   407  func nlz16(x int16) int { return bits.LeadingZeros16(uint16(x)) }
   408  
   409  func nlz32(x int32) int { return bits.LeadingZeros32(uint32(x)) }
   410  
   411  // nlzX returns the number of leading zeros.
   412  func nlz64(x int64) int { return bits.LeadingZeros64(uint64(x)) }
   413  
   414  func nlz8(x int8) int { return bits.LeadingZeros8(uint8(x)) }
   415  
   416  func ntz16(x int16) int { return bits.TrailingZeros16(uint16(x)) }
   417  
   418  func ntz32(x int32) int { return bits.TrailingZeros32(uint32(x)) }
   419  
   420  func ntz8(x int8) int { return bits.TrailingZeros8(uint8(x)) }
   421  
   422  // reciprocalExact32 reports whether 1/c is exactly representable.
   423  func reciprocalExact32(c float32) bool {
   424  	b := math.Float32bits(c)
   425  	man := b & (1<<23 - 1)
   426  	if man != 0 {
   427  		return false // not a power of 2, denormal, or NaN
   428  	}
   429  	exp := b >> 23 & (1<<8 - 1)
   430  	// exponent bias is 0x7f.  So taking the reciprocal of a number
   431  	// changes the exponent to 0xfe-exp.
   432  	switch exp {
   433  	case 0:
   434  		return false // ±0
   435  	case 0xff:
   436  		return false // ±inf
   437  	case 0xfe:
   438  		return false // exponent is not representable
   439  	default:
   440  		return true
   441  	}
   442  }
   443  
   444  // reciprocalExact64 reports whether 1/c is exactly representable.
   445  func reciprocalExact64(c float64) bool {
   446  	b := math.Float64bits(c)
   447  	man := b & (1<<52 - 1)
   448  	if man != 0 {
   449  		return false // not a power of 2, denormal, or NaN
   450  	}
   451  	exp := b >> 52 & (1<<11 - 1)
   452  	// exponent bias is 0x3ff.  So taking the reciprocal of a number
   453  	// changes the exponent to 0x7fe-exp.
   454  	switch exp {
   455  	case 0:
   456  		return false // ±0
   457  	case 0x7ff:
   458  		return false // ±inf
   459  	case 0x7fe:
   460  		return false // exponent is not representable
   461  	default:
   462  		return true
   463  	}
   464  }
   465  
   466  // registerizable reports whether t is a primitive type that fits in
   467  // a register. It assumes float64 values will always fit into registers
   468  // even if that isn't strictly true.
   469  func registerizable(b *ssa.Block, typ *types.Type) bool {
   470  	if typ.IsPtrShaped() || typ.IsFloat() || typ.IsBoolean() {
   471  		return true
   472  	}
   473  	if typ.IsInteger() {
   474  		return typ.Size() <= b.Func.Config.RegSize
   475  	}
   476  	return false
   477  }
   478  
   479  // resetCopy resets v to be a copy of arg.
   480  // Always returns true.
   481  func resetCopy(v *ssa.Value, arg *ssa.Value) bool {
   482  	v.Reset(ssaop.OpCopy)
   483  	v.AddArg(arg)
   484  	return true
   485  }
   486  
   487  // rewriteCondSelectIntoMath reports whether x OP (y * constant) should be used instead of a CondSelect.
   488  // x arbitrary, y in [0,1]
   489  func rewriteCondSelectIntoMath(config *ssa.Config, op ssaop.Op, constant int64) bool {
   490  	// at worst this becomes a left shift by a constant which has asymmetric latency (1:3 vs 2:2)
   491  	// but performs better in accumulation chains.
   492  	// Various arches do strictly superior for specific cases, but this is a good general default.
   493  	// FIXME: optimize more constants in arches where this is possible.
   494  	switch config.Arch {
   495  	case "arm64":
   496  		switch op {
   497  		case ssaop.OpAdd64, ssaop.OpAdd32, ssaop.OpAdd16, ssaop.OpAdd8:
   498  			if constant == 1 {
   499  				return false // better done as CSINC
   500  			}
   501  			fallthrough
   502  		default:
   503  			// add sub or xor & and are implemented using inline LSL
   504  			// the rest becomes the default LSL
   505  			return ssa.IsPowerOfTwo(uint64(constant))
   506  		}
   507  	default:
   508  		return ssa.IsPowerOfTwo(uint64(constant))
   509  	}
   510  }
   511  
   512  // rewriteFixedLoad rewrites a load to a fixed address or constant, if isFixedLoad returns true.
   513  func rewriteFixedLoad(v *ssa.Value, sym ssa.Sym, sb *ssa.Value, off int64) *ssa.Value {
   514  	b := v.Block
   515  	f := b.Func
   516  
   517  	lsym := sym.(*obj.LSym)
   518  	if (v.Type.IsPtrShaped() || v.Type.IsUintptr()) && lsym.Type == objabi.SRODATA {
   519  		for _, r := range lsym.R {
   520  			if (r.Type == objabi.R_ADDR || r.Type == objabi.R_WEAKADDR) && int64(r.Off) == off && r.Add == 0 {
   521  				if strings.HasPrefix(r.Sym.Name, "type:") {
   522  					// In case we're loading a type out of a dictionary, we need to record
   523  					// that the containing function might put that type in an interface.
   524  					// That information is currently recorded in relocations in the dictionary,
   525  					// but if we perform this load at compile time then the dictionary
   526  					// might be dead.
   527  					reflectdata.MarkTypeSymUsedInInterface(r.Sym, f.Fe.Func().Linksym())
   528  				} else if strings.HasPrefix(r.Sym.Name, "go:itab") {
   529  					// Same, but if we're using an itab we need to record that the
   530  					// itab._type might be put in an interface.
   531  					reflectdata.MarkTypeSymUsedInInterface(r.Sym, f.Fe.Func().Linksym())
   532  				}
   533  				v.Reset(ssaop.OpAddr)
   534  				v.Aux = ssa.SymToAux(r.Sym)
   535  				v.AddArg(sb)
   536  				return v
   537  			}
   538  		}
   539  		base.Fatalf("fixedLoad data not known for %s:%d", sym, off)
   540  	}
   541  
   542  	if ti := lsym.TypeInfo(); ti != nil {
   543  		// Type symbols do not contain information about their fields, unlike the cases above.
   544  		// Hand-implement field accesses.
   545  		// TODO: can this be replaced with reflectdata.writeType and just use the code above?
   546  
   547  		t := ti.Type.(*types.Type)
   548  
   549  		ptrSizedOpConst := ssaop.OpConst64
   550  		if f.Config.PtrSize == 4 {
   551  			ptrSizedOpConst = ssaop.OpConst32
   552  		}
   553  
   554  		for _, f := range rttype.Type.Fields() {
   555  			if f.Offset == off && copyCompatibleType(v.Type, f.Type) {
   556  				switch f.Sym.Name {
   557  				case "Size_":
   558  					v.Reset(ptrSizedOpConst)
   559  					v.AuxInt = t.Size()
   560  					return v
   561  				case "PtrBytes":
   562  					v.Reset(ptrSizedOpConst)
   563  					v.AuxInt = types.PtrDataSize(t)
   564  					return v
   565  				case "Hash":
   566  					v.Reset(ssaop.OpConst32)
   567  					v.AuxInt = int64(int32(types.TypeHash(t)))
   568  					return v
   569  				case "TFlag":
   570  					v.Reset(ssaop.OpConst8)
   571  					v.AuxInt = int64(t.TFlag())
   572  					return v
   573  				case "Kind_":
   574  					v.Reset(ssaop.OpConst8)
   575  					v.AuxInt = int64(int8(reflectdata.ABIKindOfType(t)))
   576  					return v
   577  				case "GCData":
   578  					gcdata, _ := reflectdata.GCSym(t, true)
   579  					v.Reset(ssaop.OpAddr)
   580  					v.Aux = ssa.SymToAux(gcdata)
   581  					v.AddArg(sb)
   582  					return v
   583  				default:
   584  					base.Fatalf("unknown field %s for fixedLoad of %s at offset %d", f.Sym.Name, lsym.Name, off)
   585  				}
   586  			}
   587  		}
   588  
   589  		if t.IsPtr() && off == rttype.PtrType.OffsetOf("Elem") {
   590  			elemSym := reflectdata.TypeLinksym(t.Elem())
   591  			reflectdata.MarkTypeSymUsedInInterface(elemSym, f.Fe.Func().Linksym())
   592  			v.Reset(ssaop.OpAddr)
   593  			v.Aux = ssa.SymToAux(elemSym)
   594  			v.AddArg(sb)
   595  			return v
   596  		}
   597  
   598  		base.Fatalf("fixedLoad data not known for %s:%d", sym, off)
   599  	}
   600  
   601  	base.Fatalf("fixedLoad data not known for %s:%d", sym, off)
   602  	return nil
   603  }
   604  
   605  func rewriteStructLoad(v *ssa.Value) *ssa.Value {
   606  	b := v.Block
   607  	ptr := v.Args[0]
   608  	mem := v.Args[1]
   609  
   610  	t := v.Type
   611  	args := make([]*ssa.Value, t.NumFields())
   612  	for i := range args {
   613  		ft := t.FieldType(i)
   614  		addr := b.NewValue1I(v.Pos, ssaop.OpOffPtr, ft.PtrTo(), t.FieldOff(i), ptr)
   615  		args[i] = b.NewValue2(v.Pos, ssaop.OpLoad, ft, addr, mem)
   616  	}
   617  
   618  	v.Reset(ssaop.OpStructMake)
   619  	v.AddArgs(args...)
   620  	return v
   621  }
   622  
   623  // symIsROZero reports whether sym is a read-only global whose data contains all zeros.
   624  func symIsROZero(sym ssa.Sym) bool {
   625  	lsym := sym.(*obj.LSym)
   626  	if lsym.Type != objabi.SRODATA || len(lsym.R) != 0 {
   627  		return false
   628  	}
   629  	for _, b := range lsym.P {
   630  		if b != 0 {
   631  			return false
   632  		}
   633  	}
   634  	return true
   635  }
   636  
   637  // uaddOvf reports whether unsigned a+b would overflow.
   638  func uaddOvf(a, b int64) bool {
   639  	return uint64(a)+uint64(b) < uint64(a)
   640  }
   641  
   642  // warnRule generates compiler debug output with string s when
   643  // v is not in autogenerated code, cond is true and the rule has fired.
   644  func warnRule(cond bool, v *ssa.Value, s string) bool {
   645  	if pos := v.Pos; pos.Line() > 1 && cond {
   646  		v.Block.Func.Warnl(pos, s)
   647  	}
   648  	return true
   649  }
   650  
   651  func bitsSub64(x, y, borrow int64) (r struct{ diff, borrow int64 }) {
   652  	d, b := bits.Sub64(uint64(x), uint64(y), uint64(borrow))
   653  	r.diff, r.borrow = int64(d), int64(b)
   654  	return
   655  }
   656  
   657  func modularMultiplicativeInverse(x uint64) (y uint64) {
   658  	if x%2 != 1 {
   659  		panic("even numbers in a power-of-two modulus do not have a multiplicative inverse")
   660  	}
   661  	// we start with 3 bits of precision because each odd number is its own multiplicative inverse mod 8
   662  	y = x // 3 bits
   663  
   664  	// now use the Newton-Raphson method to double the number of correct bits in each iteration.
   665  	y *= 2 - x*y // 6 bits
   666  	y *= 2 - x*y // 12 bits
   667  	y *= 2 - x*y // 24 bits
   668  	y *= 2 - x*y // 48 bits
   669  	y *= 2 - x*y // 96 bits; good enough
   670  	return
   671  }
   672  

View as plain text