Source file src/cmd/compile/internal/ssa/op.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  	"cmd/compile/internal/abi"
     9  	"cmd/compile/internal/base"
    10  	"cmd/compile/internal/ir"
    11  	"cmd/compile/internal/types"
    12  	"cmd/internal/obj"
    13  	"fmt"
    14  	rtabi "internal/abi"
    15  	"strings"
    16  )
    17  
    18  // An Op encodes the specific operation that a Value performs.
    19  // Opcodes' semantics can be modified by the type and aux fields of the Value.
    20  // For instance, OpAdd can be 32 or 64 bit, signed or unsigned, float or complex, depending on Value.Type.
    21  // Semantics of each op are described in the opcode files in _gen/*Ops.go.
    22  // There is one file for generic (architecture-independent) ops and one file
    23  // for each architecture.
    24  type Op int32
    25  
    26  type opInfo struct {
    27  	name              string
    28  	reg               regInfo
    29  	auxType           auxType
    30  	argLen            int32 // the number of arguments, -1 if variable length
    31  	asm               obj.As
    32  	generic           bool      // this is a generic (arch-independent) opcode
    33  	rematerializeable bool      // this op is rematerializeable
    34  	commutative       bool      // this operation is commutative (e.g. addition)
    35  	resultInArg0      bool      // (first, if a tuple) output of v and v.Args[0] must be allocated to the same register
    36  	resultNotInArgs   bool      // outputs must not be allocated to the same registers as inputs
    37  	clobberFlags      bool      // this op clobbers flags register
    38  	needIntTemp       bool      // need a temporary free integer register
    39  	call              bool      // is a function call
    40  	tailCall          bool      // is a tail call
    41  	nilCheck          bool      // this op is a nil check on arg0
    42  	faultOnNilArg0    bool      // this op will fault if arg0 is nil (and aux encodes a small offset)
    43  	faultOnNilArg1    bool      // this op will fault if arg1 is nil (and aux encodes a small offset)
    44  	usesScratch       bool      // this op requires scratch memory space
    45  	hasSideEffects    bool      // for "reasons", not to be eliminated.  E.g., atomic store, #19182.
    46  	zeroWidth         bool      // op never translates into any machine code. example: copy, which may sometimes translate to machine code, is not zero-width.
    47  	unsafePoint       bool      // this op is an unsafe point, i.e. not safe for async preemption
    48  	fixedReg          bool      // this op will be assigned a fixed register
    49  	symEffect         SymEffect // effect this op has on symbol in aux
    50  	scale             uint8     // amd64/386 indexed load scale
    51  }
    52  
    53  type inputInfo struct {
    54  	idx  int     // index in Args array
    55  	regs regMask // allowed input registers
    56  }
    57  
    58  type outputInfo struct {
    59  	idx  int     // index in output tuple
    60  	regs regMask // allowed output registers
    61  }
    62  
    63  type regInfo struct {
    64  	// inputs encodes the register restrictions for an instruction's inputs.
    65  	// Each entry specifies an allowed register set for a particular input.
    66  	// They are listed in the order in which regalloc should pick a register
    67  	// from the register set (most constrained first).
    68  	// Inputs which do not need registers are not listed.
    69  	inputs []inputInfo
    70  	// clobbers encodes the set of registers that are overwritten by
    71  	// the instruction (other than the output registers).
    72  	clobbers regMask
    73  	// outputs is the same as inputs, but for the outputs of the instruction.
    74  	outputs []outputInfo
    75  }
    76  
    77  func (r *regInfo) String() string {
    78  	s := ""
    79  	s += "INS:\n"
    80  	for _, i := range r.inputs {
    81  		mask := fmt.Sprintf("%64b", i.regs)
    82  		mask = strings.ReplaceAll(mask, "0", ".")
    83  		s += fmt.Sprintf("%2d |%s|\n", i.idx, mask)
    84  	}
    85  	s += "OUTS:\n"
    86  	for _, i := range r.outputs {
    87  		mask := fmt.Sprintf("%64b", i.regs)
    88  		mask = strings.ReplaceAll(mask, "0", ".")
    89  		s += fmt.Sprintf("%2d |%s|\n", i.idx, mask)
    90  	}
    91  	s += "CLOBBERS:\n"
    92  	mask := fmt.Sprintf("%64b", r.clobbers)
    93  	mask = strings.ReplaceAll(mask, "0", ".")
    94  	s += fmt.Sprintf("   |%s|\n", mask)
    95  	return s
    96  }
    97  
    98  type auxType int8
    99  
   100  type AuxNameOffset struct {
   101  	Name   *ir.Name
   102  	Offset int64
   103  }
   104  
   105  func (a *AuxNameOffset) CanBeAnSSAAux() {}
   106  func (a *AuxNameOffset) String() string {
   107  	return fmt.Sprintf("%s+%d", a.Name.Sym().Name, a.Offset)
   108  }
   109  
   110  func (a *AuxNameOffset) FrameOffset() int64 {
   111  	return a.Name.FrameOffset() + a.Offset
   112  }
   113  
   114  type AuxCall struct {
   115  	Fn      *obj.LSym
   116  	reg     *regInfo // regInfo for this call
   117  	abiInfo *abi.ABIParamResultInfo
   118  }
   119  
   120  // Reg returns the regInfo for a given call, combining the derived in/out register masks
   121  // with the machine-specific register information in the input i.  (The machine-specific
   122  // regInfo is much handier at the call site than it is when the AuxCall is being constructed,
   123  // therefore do this lazily).
   124  //
   125  // TODO: there is a Clever Hack that allows pre-generation of a small-ish number of the slices
   126  // of inputInfo and outputInfo used here, provided that we are willing to reorder the inputs
   127  // and outputs from calls, so that all integer registers come first, then all floating registers.
   128  // At this point (active development of register ABI) that is very premature,
   129  // but if this turns out to be a cost, we could do it.
   130  func (a *AuxCall) Reg(i *regInfo, c *Config) *regInfo {
   131  	if a.reg.clobbers != 0 {
   132  		// Already updated
   133  		return a.reg
   134  	}
   135  	if a.abiInfo.InRegistersUsed()+a.abiInfo.OutRegistersUsed() == 0 {
   136  		// Shortcut for zero case, also handles old ABI.
   137  		a.reg = i
   138  		return a.reg
   139  	}
   140  
   141  	k := len(i.inputs)
   142  	for _, p := range a.abiInfo.InParams() {
   143  		for _, r := range p.Registers {
   144  			m := archRegForAbiReg(r, c)
   145  			a.reg.inputs = append(a.reg.inputs, inputInfo{idx: k, regs: (1 << m)})
   146  			k++
   147  		}
   148  	}
   149  	a.reg.inputs = append(a.reg.inputs, i.inputs...) // These are less constrained, thus should come last
   150  	k = len(i.outputs)
   151  	for _, p := range a.abiInfo.OutParams() {
   152  		for _, r := range p.Registers {
   153  			m := archRegForAbiReg(r, c)
   154  			a.reg.outputs = append(a.reg.outputs, outputInfo{idx: k, regs: (1 << m)})
   155  			k++
   156  		}
   157  	}
   158  	a.reg.outputs = append(a.reg.outputs, i.outputs...)
   159  	a.reg.clobbers = i.clobbers
   160  	return a.reg
   161  }
   162  func (a *AuxCall) ABI() *abi.ABIConfig {
   163  	return a.abiInfo.Config()
   164  }
   165  func (a *AuxCall) ABIInfo() *abi.ABIParamResultInfo {
   166  	return a.abiInfo
   167  }
   168  func (a *AuxCall) ResultReg(c *Config) *regInfo {
   169  	if a.abiInfo.OutRegistersUsed() == 0 {
   170  		return a.reg
   171  	}
   172  	if len(a.reg.inputs) > 0 {
   173  		return a.reg
   174  	}
   175  	k := 0
   176  	for _, p := range a.abiInfo.OutParams() {
   177  		for _, r := range p.Registers {
   178  			m := archRegForAbiReg(r, c)
   179  			a.reg.inputs = append(a.reg.inputs, inputInfo{idx: k, regs: (1 << m)})
   180  			k++
   181  		}
   182  	}
   183  	return a.reg
   184  }
   185  
   186  // For ABI register index r, returns the (dense) register number used in
   187  // SSA backend.
   188  func archRegForAbiReg(r abi.RegIndex, c *Config) uint8 {
   189  	var m int8
   190  	if int(r) < len(c.intParamRegs) {
   191  		m = c.intParamRegs[r]
   192  	} else {
   193  		m = c.floatParamRegs[int(r)-len(c.intParamRegs)]
   194  	}
   195  	return uint8(m)
   196  }
   197  
   198  // For ABI register index r, returns the register number used in the obj
   199  // package (assembler).
   200  func ObjRegForAbiReg(r abi.RegIndex, c *Config) int16 {
   201  	m := archRegForAbiReg(r, c)
   202  	return c.registers[m].objNum
   203  }
   204  
   205  // ArgWidth returns the amount of stack needed for all the inputs
   206  // and outputs of a function or method, including ABI-defined parameter
   207  // slots and ABI-defined spill slots for register-resident parameters.
   208  //
   209  // The name is taken from the types package's ArgWidth(<function type>),
   210  // which predated changes to the ABI; this version handles those changes.
   211  func (a *AuxCall) ArgWidth() int64 {
   212  	return a.abiInfo.ArgWidth()
   213  }
   214  
   215  // ParamAssignmentForResult returns the ABI Parameter assignment for result which (indexed 0, 1, etc).
   216  func (a *AuxCall) ParamAssignmentForResult(which int64) *abi.ABIParamAssignment {
   217  	return a.abiInfo.OutParam(int(which))
   218  }
   219  
   220  // OffsetOfResult returns the SP offset of result which (indexed 0, 1, etc).
   221  func (a *AuxCall) OffsetOfResult(which int64) int64 {
   222  	n := int64(a.abiInfo.OutParam(int(which)).Offset())
   223  	return n
   224  }
   225  
   226  // OffsetOfArg returns the SP offset of argument which (indexed 0, 1, etc).
   227  // If the call is to a method, the receiver is the first argument (i.e., index 0)
   228  func (a *AuxCall) OffsetOfArg(which int64) int64 {
   229  	n := int64(a.abiInfo.InParam(int(which)).Offset())
   230  	return n
   231  }
   232  
   233  // RegsOfResult returns the register(s) used for result which (indexed 0, 1, etc).
   234  func (a *AuxCall) RegsOfResult(which int64) []abi.RegIndex {
   235  	return a.abiInfo.OutParam(int(which)).Registers
   236  }
   237  
   238  // RegsOfArg returns the register(s) used for argument which (indexed 0, 1, etc).
   239  // If the call is to a method, the receiver is the first argument (i.e., index 0)
   240  func (a *AuxCall) RegsOfArg(which int64) []abi.RegIndex {
   241  	return a.abiInfo.InParam(int(which)).Registers
   242  }
   243  
   244  // NameOfResult returns the ir.Name of result which (indexed 0, 1, etc).
   245  func (a *AuxCall) NameOfResult(which int64) *ir.Name {
   246  	return a.abiInfo.OutParam(int(which)).Name
   247  }
   248  
   249  // TypeOfResult returns the type of result which (indexed 0, 1, etc).
   250  func (a *AuxCall) TypeOfResult(which int64) *types.Type {
   251  	return a.abiInfo.OutParam(int(which)).Type
   252  }
   253  
   254  // TypeOfArg returns the type of argument which (indexed 0, 1, etc).
   255  // If the call is to a method, the receiver is the first argument (i.e., index 0)
   256  func (a *AuxCall) TypeOfArg(which int64) *types.Type {
   257  	return a.abiInfo.InParam(int(which)).Type
   258  }
   259  
   260  // SizeOfResult returns the size of result which (indexed 0, 1, etc).
   261  func (a *AuxCall) SizeOfResult(which int64) int64 {
   262  	return a.TypeOfResult(which).Size()
   263  }
   264  
   265  // SizeOfArg returns the size of argument which (indexed 0, 1, etc).
   266  // If the call is to a method, the receiver is the first argument (i.e., index 0)
   267  func (a *AuxCall) SizeOfArg(which int64) int64 {
   268  	return a.TypeOfArg(which).Size()
   269  }
   270  
   271  // NResults returns the number of results.
   272  func (a *AuxCall) NResults() int64 {
   273  	return int64(len(a.abiInfo.OutParams()))
   274  }
   275  
   276  // LateExpansionResultType returns the result type (including trailing mem)
   277  // for a call that will be expanded later in the SSA phase.
   278  func (a *AuxCall) LateExpansionResultType() *types.Type {
   279  	var tys []*types.Type
   280  	for i := int64(0); i < a.NResults(); i++ {
   281  		tys = append(tys, a.TypeOfResult(i))
   282  	}
   283  	tys = append(tys, types.TypeMem)
   284  	return types.NewResults(tys)
   285  }
   286  
   287  // NArgs returns the number of arguments (including receiver, if there is one).
   288  func (a *AuxCall) NArgs() int64 {
   289  	return int64(len(a.abiInfo.InParams()))
   290  }
   291  
   292  // String returns "AuxCall{<fn>}"
   293  func (a *AuxCall) String() string {
   294  	var fn string
   295  	if a.Fn == nil {
   296  		fn = "AuxCall{nil" // could be interface/closure etc.
   297  	} else {
   298  		fn = fmt.Sprintf("AuxCall{%v", a.Fn)
   299  	}
   300  	// TODO how much of the ABI should be printed?
   301  
   302  	return fn + "}"
   303  }
   304  
   305  // StaticAuxCall returns an AuxCall for a static call.
   306  func StaticAuxCall(sym *obj.LSym, paramResultInfo *abi.ABIParamResultInfo) *AuxCall {
   307  	if paramResultInfo == nil {
   308  		panic(fmt.Errorf("Nil paramResultInfo, sym=%v", sym))
   309  	}
   310  	var reg *regInfo
   311  	if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 {
   312  		reg = &regInfo{}
   313  	}
   314  	return &AuxCall{Fn: sym, abiInfo: paramResultInfo, reg: reg}
   315  }
   316  
   317  // InterfaceAuxCall returns an AuxCall for an interface call.
   318  func InterfaceAuxCall(paramResultInfo *abi.ABIParamResultInfo) *AuxCall {
   319  	var reg *regInfo
   320  	if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 {
   321  		reg = &regInfo{}
   322  	}
   323  	return &AuxCall{Fn: nil, abiInfo: paramResultInfo, reg: reg}
   324  }
   325  
   326  // ClosureAuxCall returns an AuxCall for a closure call.
   327  func ClosureAuxCall(paramResultInfo *abi.ABIParamResultInfo) *AuxCall {
   328  	var reg *regInfo
   329  	if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 {
   330  		reg = &regInfo{}
   331  	}
   332  	return &AuxCall{Fn: nil, abiInfo: paramResultInfo, reg: reg}
   333  }
   334  
   335  func (*AuxCall) CanBeAnSSAAux() {}
   336  
   337  // OwnAuxCall returns a function's own AuxCall.
   338  func OwnAuxCall(fn *obj.LSym, paramResultInfo *abi.ABIParamResultInfo) *AuxCall {
   339  	// TODO if this remains identical to ClosureAuxCall above after new ABI is done, should deduplicate.
   340  	var reg *regInfo
   341  	if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 {
   342  		reg = &regInfo{}
   343  	}
   344  	return &AuxCall{Fn: fn, abiInfo: paramResultInfo, reg: reg}
   345  }
   346  
   347  const (
   348  	auxNone           auxType = iota
   349  	auxBool                   // auxInt is 0/1 for false/true
   350  	auxInt8                   // auxInt is an 8-bit integer
   351  	auxInt16                  // auxInt is a 16-bit integer
   352  	auxInt32                  // auxInt is a 32-bit integer
   353  	auxInt64                  // auxInt is a 64-bit integer
   354  	auxInt128                 // auxInt represents a 128-bit integer.  Always 0.
   355  	auxUInt8                  // auxInt is an 8-bit unsigned integer
   356  	auxFloat32                // auxInt is a float32 (encoded with math.Float64bits)
   357  	auxFloat64                // auxInt is a float64 (encoded with math.Float64bits)
   358  	auxFlagConstant           // auxInt is a flagConstant
   359  	auxCCop                   // auxInt is a ssa.Op that represents a flags-to-bool conversion (e.g. LessThan)
   360  	auxNameOffsetInt8         // aux is a &struct{Name ir.Name, Offset int64}; auxInt is index in parameter registers array
   361  	auxString                 // aux is a string
   362  	auxSym                    // aux is a symbol (a *ir.Name for locals, an *obj.LSym for globals, or nil for none)
   363  	auxSymOff                 // aux is a symbol, auxInt is an offset
   364  	auxSymValAndOff           // aux is a symbol, auxInt is a ValAndOff
   365  	auxTyp                    // aux is a type
   366  	auxTypSize                // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt
   367  	auxCall                   // aux is a *ssa.AuxCall
   368  	auxCallOff                // aux is a *ssa.AuxCall, AuxInt is int64 param (in+out) size
   369  
   370  	auxPanicBoundsC  // constant for a bounds failure
   371  	auxPanicBoundsCC // two constants for a bounds failure
   372  
   373  	// architecture specific aux types
   374  	auxARM64BitField     // aux is an arm64 bitfield lsb and width packed into auxInt
   375  	auxS390XRotateParams // aux is a s390x rotate parameters object encoding start bit, end bit and rotate amount
   376  	auxS390XCCMask       // aux is a s390x 4-bit condition code mask
   377  	auxS390XCCMaskInt8   // aux is a s390x 4-bit condition code mask, auxInt is an int8 immediate
   378  	auxS390XCCMaskUint8  // aux is a s390x 4-bit condition code mask, auxInt is a uint8 immediate
   379  )
   380  
   381  // A SymEffect describes the effect that an SSA Value has on the variable
   382  // identified by the symbol in its Aux field.
   383  type SymEffect int8
   384  
   385  const (
   386  	SymRead SymEffect = 1 << iota
   387  	SymWrite
   388  	SymAddr
   389  
   390  	SymRdWr = SymRead | SymWrite
   391  
   392  	SymNone SymEffect = 0
   393  )
   394  
   395  // A Sym represents a symbolic offset from a base register.
   396  // Currently a Sym can be one of 3 things:
   397  //   - a *ir.Name, for an offset from SP (the stack pointer)
   398  //   - a *obj.LSym, for an offset from SB (the global pointer)
   399  //   - nil, for no offset
   400  type Sym interface {
   401  	Aux
   402  	CanBeAnSSASym()
   403  }
   404  
   405  // A ValAndOff is used by the several opcodes. It holds
   406  // both a value and a pointer offset.
   407  // A ValAndOff is intended to be encoded into an AuxInt field.
   408  // The zero ValAndOff encodes a value of 0 and an offset of 0.
   409  // The high 32 bits hold a value.
   410  // The low 32 bits hold a pointer offset.
   411  type ValAndOff int64
   412  
   413  func (x ValAndOff) Val() int32   { return int32(int64(x) >> 32) }
   414  func (x ValAndOff) Val64() int64 { return int64(x) >> 32 }
   415  func (x ValAndOff) Val16() int16 { return int16(int64(x) >> 32) }
   416  func (x ValAndOff) Val8() int8   { return int8(int64(x) >> 32) }
   417  
   418  func (x ValAndOff) Off64() int64 { return int64(int32(x)) }
   419  func (x ValAndOff) Off() int32   { return int32(x) }
   420  
   421  func (x ValAndOff) String() string {
   422  	return fmt.Sprintf("val=%d,off=%d", x.Val(), x.Off())
   423  }
   424  
   425  // validVal reports whether the value can be used
   426  // as an argument to makeValAndOff.
   427  func validVal(val int64) bool {
   428  	return val == int64(int32(val))
   429  }
   430  
   431  func makeValAndOff(val, off int32) ValAndOff {
   432  	return ValAndOff(int64(val)<<32 + int64(uint32(off)))
   433  }
   434  
   435  func (x ValAndOff) canAdd32(off int32) bool {
   436  	newoff := x.Off64() + int64(off)
   437  	return newoff == int64(int32(newoff))
   438  }
   439  func (x ValAndOff) canAdd64(off int64) bool {
   440  	newoff := x.Off64() + off
   441  	return newoff == int64(int32(newoff))
   442  }
   443  
   444  func (x ValAndOff) addOffset32(off int32) ValAndOff {
   445  	if !x.canAdd32(off) {
   446  		panic("invalid ValAndOff.addOffset32")
   447  	}
   448  	return makeValAndOff(x.Val(), x.Off()+off)
   449  }
   450  func (x ValAndOff) addOffset64(off int64) ValAndOff {
   451  	if !x.canAdd64(off) {
   452  		panic("invalid ValAndOff.addOffset64")
   453  	}
   454  	return makeValAndOff(x.Val(), x.Off()+int32(off))
   455  }
   456  
   457  // int128 is a type that stores a 128-bit constant.
   458  // The only allowed constant right now is 0, so we can cheat quite a bit.
   459  type int128 int64
   460  
   461  type BoundsKind uint8
   462  
   463  const (
   464  	BoundsIndex       BoundsKind = iota // indexing operation, 0 <= idx < len failed
   465  	BoundsIndexU                        // ... with unsigned idx
   466  	BoundsSliceAlen                     // 2-arg slicing operation, 0 <= high <= len failed
   467  	BoundsSliceAlenU                    // ... with unsigned high
   468  	BoundsSliceAcap                     // 2-arg slicing operation, 0 <= high <= cap failed
   469  	BoundsSliceAcapU                    // ... with unsigned high
   470  	BoundsSliceB                        // 2-arg slicing operation, 0 <= low <= high failed
   471  	BoundsSliceBU                       // ... with unsigned low
   472  	BoundsSlice3Alen                    // 3-arg slicing operation, 0 <= max <= len failed
   473  	BoundsSlice3AlenU                   // ... with unsigned max
   474  	BoundsSlice3Acap                    // 3-arg slicing operation, 0 <= max <= cap failed
   475  	BoundsSlice3AcapU                   // ... with unsigned max
   476  	BoundsSlice3B                       // 3-arg slicing operation, 0 <= high <= max failed
   477  	BoundsSlice3BU                      // ... with unsigned high
   478  	BoundsSlice3C                       // 3-arg slicing operation, 0 <= low <= high failed
   479  	BoundsSlice3CU                      // ... with unsigned low
   480  	BoundsConvert                       // conversion to array pointer failed
   481  	BoundsKindCount
   482  )
   483  
   484  // boundsABI determines which register arguments a bounds check call should use. For an [a:b:c] slice, we do:
   485  //
   486  //	CMPQ c, cap
   487  //	JA   fail1
   488  //	CMPQ b, c
   489  //	JA   fail2
   490  //	CMPQ a, b
   491  //	JA   fail3
   492  //
   493  // fail1: CALL panicSlice3Acap (c, cap)
   494  // fail2: CALL panicSlice3B (b, c)
   495  // fail3: CALL panicSlice3C (a, b)
   496  //
   497  // When we register allocate that code, we want the same register to be used for
   498  // the first arg of panicSlice3Acap and the second arg to panicSlice3B. That way,
   499  // initializing that register once will satisfy both calls.
   500  // That desire ends up dividing the set of bounds check calls into 3 sets. This function
   501  // determines which set to use for a given panic call.
   502  // The first arg for set 0 should be the second arg for set 1.
   503  // The first arg for set 1 should be the second arg for set 2.
   504  func boundsABI(b int64) int {
   505  	switch BoundsKind(b) {
   506  	case BoundsSlice3Alen,
   507  		BoundsSlice3AlenU,
   508  		BoundsSlice3Acap,
   509  		BoundsSlice3AcapU,
   510  		BoundsConvert:
   511  		return 0
   512  	case BoundsSliceAlen,
   513  		BoundsSliceAlenU,
   514  		BoundsSliceAcap,
   515  		BoundsSliceAcapU,
   516  		BoundsSlice3B,
   517  		BoundsSlice3BU:
   518  		return 1
   519  	case BoundsIndex,
   520  		BoundsIndexU,
   521  		BoundsSliceB,
   522  		BoundsSliceBU,
   523  		BoundsSlice3C,
   524  		BoundsSlice3CU:
   525  		return 2
   526  	default:
   527  		panic("bad BoundsKind")
   528  	}
   529  }
   530  
   531  // Returns the bounds error code needed by the runtime, and
   532  // whether the x field is signed.
   533  func (b BoundsKind) Code() (rtabi.BoundsErrorCode, bool) {
   534  	switch b {
   535  	case BoundsIndex:
   536  		return rtabi.BoundsIndex, true
   537  	case BoundsIndexU:
   538  		return rtabi.BoundsIndex, false
   539  	case BoundsSliceAlen:
   540  		return rtabi.BoundsSliceAlen, true
   541  	case BoundsSliceAlenU:
   542  		return rtabi.BoundsSliceAlen, false
   543  	case BoundsSliceAcap:
   544  		return rtabi.BoundsSliceAcap, true
   545  	case BoundsSliceAcapU:
   546  		return rtabi.BoundsSliceAcap, false
   547  	case BoundsSliceB:
   548  		return rtabi.BoundsSliceB, true
   549  	case BoundsSliceBU:
   550  		return rtabi.BoundsSliceB, false
   551  	case BoundsSlice3Alen:
   552  		return rtabi.BoundsSlice3Alen, true
   553  	case BoundsSlice3AlenU:
   554  		return rtabi.BoundsSlice3Alen, false
   555  	case BoundsSlice3Acap:
   556  		return rtabi.BoundsSlice3Acap, true
   557  	case BoundsSlice3AcapU:
   558  		return rtabi.BoundsSlice3Acap, false
   559  	case BoundsSlice3B:
   560  		return rtabi.BoundsSlice3B, true
   561  	case BoundsSlice3BU:
   562  		return rtabi.BoundsSlice3B, false
   563  	case BoundsSlice3C:
   564  		return rtabi.BoundsSlice3C, true
   565  	case BoundsSlice3CU:
   566  		return rtabi.BoundsSlice3C, false
   567  	case BoundsConvert:
   568  		return rtabi.BoundsConvert, false
   569  	default:
   570  		base.Fatalf("bad bounds kind %d", b)
   571  		return 0, false
   572  	}
   573  }
   574  
   575  // arm64BitField is the GO type of ARM64BitField auxInt.
   576  // if x is an ARM64BitField, then width=x&0xff, lsb=(x>>8)&0xff, and
   577  // width+lsb<64 for 64-bit variant, width+lsb<32 for 32-bit variant.
   578  // the meaning of width and lsb are instruction-dependent.
   579  type arm64BitField int16
   580  

View as plain text