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  	// Instruction clobbers the register containing input 0.
    74  	clobbersArg0 bool
    75  	// Instruction clobbers the register containing input 1.
    76  	clobbersArg1 bool
    77  	// outputs is the same as inputs, but for the outputs of the instruction.
    78  	outputs []outputInfo
    79  }
    80  
    81  func (r *regInfo) String() string {
    82  	s := ""
    83  	s += "INS:\n"
    84  	for _, i := range r.inputs {
    85  		mask := fmt.Sprintf("%64b", i.regs)
    86  		mask = strings.ReplaceAll(mask, "0", ".")
    87  		s += fmt.Sprintf("%2d |%s|\n", i.idx, mask)
    88  	}
    89  	s += "OUTS:\n"
    90  	for _, i := range r.outputs {
    91  		mask := fmt.Sprintf("%64b", i.regs)
    92  		mask = strings.ReplaceAll(mask, "0", ".")
    93  		s += fmt.Sprintf("%2d |%s|\n", i.idx, mask)
    94  	}
    95  	s += "CLOBBERS:\n"
    96  	mask := fmt.Sprintf("%64b", r.clobbers)
    97  	mask = strings.ReplaceAll(mask, "0", ".")
    98  	s += fmt.Sprintf("   |%s|\n", mask)
    99  	return s
   100  }
   101  
   102  type auxType int8
   103  
   104  type AuxNameOffset struct {
   105  	Name   *ir.Name
   106  	Offset int64
   107  }
   108  
   109  func (a *AuxNameOffset) CanBeAnSSAAux() {}
   110  func (a *AuxNameOffset) String() string {
   111  	return fmt.Sprintf("%s+%d", a.Name.Sym().Name, a.Offset)
   112  }
   113  
   114  func (a *AuxNameOffset) FrameOffset() int64 {
   115  	return a.Name.FrameOffset() + a.Offset
   116  }
   117  
   118  type AuxCall struct {
   119  	Fn      *obj.LSym
   120  	reg     *regInfo // regInfo for this call
   121  	abiInfo *abi.ABIParamResultInfo
   122  }
   123  
   124  // Reg returns the regInfo for a given call, combining the derived in/out register masks
   125  // with the machine-specific register information in the input i.  (The machine-specific
   126  // regInfo is much handier at the call site than it is when the AuxCall is being constructed,
   127  // therefore do this lazily).
   128  //
   129  // TODO: there is a Clever Hack that allows pre-generation of a small-ish number of the slices
   130  // of inputInfo and outputInfo used here, provided that we are willing to reorder the inputs
   131  // and outputs from calls, so that all integer registers come first, then all floating registers.
   132  // At this point (active development of register ABI) that is very premature,
   133  // but if this turns out to be a cost, we could do it.
   134  func (a *AuxCall) Reg(i *regInfo, c *Config) *regInfo {
   135  	if a.reg.clobbers != 0 {
   136  		// Already updated
   137  		return a.reg
   138  	}
   139  	if a.abiInfo.InRegistersUsed()+a.abiInfo.OutRegistersUsed() == 0 {
   140  		// Shortcut for zero case, also handles old ABI.
   141  		a.reg = i
   142  		return a.reg
   143  	}
   144  
   145  	k := len(i.inputs)
   146  	for _, p := range a.abiInfo.InParams() {
   147  		for _, r := range p.Registers {
   148  			m := archRegForAbiReg(r, c)
   149  			a.reg.inputs = append(a.reg.inputs, inputInfo{idx: k, regs: (1 << m)})
   150  			k++
   151  		}
   152  	}
   153  	a.reg.inputs = append(a.reg.inputs, i.inputs...) // These are less constrained, thus should come last
   154  	k = len(i.outputs)
   155  	for _, p := range a.abiInfo.OutParams() {
   156  		for _, r := range p.Registers {
   157  			m := archRegForAbiReg(r, c)
   158  			a.reg.outputs = append(a.reg.outputs, outputInfo{idx: k, regs: (1 << m)})
   159  			k++
   160  		}
   161  	}
   162  	a.reg.outputs = append(a.reg.outputs, i.outputs...)
   163  	a.reg.clobbers = i.clobbers
   164  	return a.reg
   165  }
   166  func (a *AuxCall) ABI() *abi.ABIConfig {
   167  	return a.abiInfo.Config()
   168  }
   169  func (a *AuxCall) ABIInfo() *abi.ABIParamResultInfo {
   170  	return a.abiInfo
   171  }
   172  func (a *AuxCall) ResultReg(c *Config) *regInfo {
   173  	if a.abiInfo.OutRegistersUsed() == 0 {
   174  		return a.reg
   175  	}
   176  	if len(a.reg.inputs) > 0 {
   177  		return a.reg
   178  	}
   179  	k := 0
   180  	for _, p := range a.abiInfo.OutParams() {
   181  		for _, r := range p.Registers {
   182  			m := archRegForAbiReg(r, c)
   183  			a.reg.inputs = append(a.reg.inputs, inputInfo{idx: k, regs: (1 << m)})
   184  			k++
   185  		}
   186  	}
   187  	return a.reg
   188  }
   189  
   190  // For ABI register index r, returns the (dense) register number used in
   191  // SSA backend.
   192  func archRegForAbiReg(r abi.RegIndex, c *Config) uint8 {
   193  	var m int8
   194  	if int(r) < len(c.intParamRegs) {
   195  		m = c.intParamRegs[r]
   196  	} else {
   197  		m = c.floatParamRegs[int(r)-len(c.intParamRegs)]
   198  	}
   199  	return uint8(m)
   200  }
   201  
   202  // For ABI register index r, returns the register number used in the obj
   203  // package (assembler).
   204  func ObjRegForAbiReg(r abi.RegIndex, c *Config) int16 {
   205  	m := archRegForAbiReg(r, c)
   206  	return c.registers[m].objNum
   207  }
   208  
   209  // ArgWidth returns the amount of stack needed for all the inputs
   210  // and outputs of a function or method, including ABI-defined parameter
   211  // slots and ABI-defined spill slots for register-resident parameters.
   212  //
   213  // The name is taken from the types package's ArgWidth(<function type>),
   214  // which predated changes to the ABI; this version handles those changes.
   215  func (a *AuxCall) ArgWidth() int64 {
   216  	return a.abiInfo.ArgWidth()
   217  }
   218  
   219  // ParamAssignmentForResult returns the ABI Parameter assignment for result which (indexed 0, 1, etc).
   220  func (a *AuxCall) ParamAssignmentForResult(which int64) *abi.ABIParamAssignment {
   221  	return a.abiInfo.OutParam(int(which))
   222  }
   223  
   224  // OffsetOfResult returns the SP offset of result which (indexed 0, 1, etc).
   225  func (a *AuxCall) OffsetOfResult(which int64) int64 {
   226  	n := int64(a.abiInfo.OutParam(int(which)).Offset())
   227  	return n
   228  }
   229  
   230  // OffsetOfArg returns the SP offset of argument which (indexed 0, 1, etc).
   231  // If the call is to a method, the receiver is the first argument (i.e., index 0)
   232  func (a *AuxCall) OffsetOfArg(which int64) int64 {
   233  	n := int64(a.abiInfo.InParam(int(which)).Offset())
   234  	return n
   235  }
   236  
   237  // RegsOfResult returns the register(s) used for result which (indexed 0, 1, etc).
   238  func (a *AuxCall) RegsOfResult(which int64) []abi.RegIndex {
   239  	return a.abiInfo.OutParam(int(which)).Registers
   240  }
   241  
   242  // RegsOfArg returns the register(s) used for argument which (indexed 0, 1, etc).
   243  // If the call is to a method, the receiver is the first argument (i.e., index 0)
   244  func (a *AuxCall) RegsOfArg(which int64) []abi.RegIndex {
   245  	return a.abiInfo.InParam(int(which)).Registers
   246  }
   247  
   248  // NameOfResult returns the ir.Name of result which (indexed 0, 1, etc).
   249  func (a *AuxCall) NameOfResult(which int64) *ir.Name {
   250  	return a.abiInfo.OutParam(int(which)).Name
   251  }
   252  
   253  // TypeOfResult returns the type of result which (indexed 0, 1, etc).
   254  func (a *AuxCall) TypeOfResult(which int64) *types.Type {
   255  	return a.abiInfo.OutParam(int(which)).Type
   256  }
   257  
   258  // TypeOfArg returns the type of argument which (indexed 0, 1, etc).
   259  // If the call is to a method, the receiver is the first argument (i.e., index 0)
   260  func (a *AuxCall) TypeOfArg(which int64) *types.Type {
   261  	return a.abiInfo.InParam(int(which)).Type
   262  }
   263  
   264  // SizeOfResult returns the size of result which (indexed 0, 1, etc).
   265  func (a *AuxCall) SizeOfResult(which int64) int64 {
   266  	return a.TypeOfResult(which).Size()
   267  }
   268  
   269  // SizeOfArg returns the size of argument which (indexed 0, 1, etc).
   270  // If the call is to a method, the receiver is the first argument (i.e., index 0)
   271  func (a *AuxCall) SizeOfArg(which int64) int64 {
   272  	return a.TypeOfArg(which).Size()
   273  }
   274  
   275  // NResults returns the number of results.
   276  func (a *AuxCall) NResults() int64 {
   277  	return int64(len(a.abiInfo.OutParams()))
   278  }
   279  
   280  // LateExpansionResultType returns the result type (including trailing mem)
   281  // for a call that will be expanded later in the SSA phase.
   282  func (a *AuxCall) LateExpansionResultType() *types.Type {
   283  	var tys []*types.Type
   284  	for i := int64(0); i < a.NResults(); i++ {
   285  		tys = append(tys, a.TypeOfResult(i))
   286  	}
   287  	tys = append(tys, types.TypeMem)
   288  	return types.NewResults(tys)
   289  }
   290  
   291  // NArgs returns the number of arguments (including receiver, if there is one).
   292  func (a *AuxCall) NArgs() int64 {
   293  	return int64(len(a.abiInfo.InParams()))
   294  }
   295  
   296  // String returns "AuxCall{<fn>}"
   297  func (a *AuxCall) String() string {
   298  	var fn string
   299  	if a.Fn == nil {
   300  		fn = "AuxCall{nil" // could be interface/closure etc.
   301  	} else {
   302  		fn = fmt.Sprintf("AuxCall{%v", a.Fn)
   303  	}
   304  	// TODO how much of the ABI should be printed?
   305  
   306  	return fn + "}"
   307  }
   308  
   309  // StaticAuxCall returns an AuxCall for a static call.
   310  func StaticAuxCall(sym *obj.LSym, paramResultInfo *abi.ABIParamResultInfo) *AuxCall {
   311  	if paramResultInfo == nil {
   312  		panic(fmt.Errorf("Nil paramResultInfo, sym=%v", sym))
   313  	}
   314  	var reg *regInfo
   315  	if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 {
   316  		reg = &regInfo{}
   317  	}
   318  	return &AuxCall{Fn: sym, abiInfo: paramResultInfo, reg: reg}
   319  }
   320  
   321  // InterfaceAuxCall returns an AuxCall for an interface call.
   322  func InterfaceAuxCall(paramResultInfo *abi.ABIParamResultInfo) *AuxCall {
   323  	var reg *regInfo
   324  	if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 {
   325  		reg = &regInfo{}
   326  	}
   327  	return &AuxCall{Fn: nil, abiInfo: paramResultInfo, reg: reg}
   328  }
   329  
   330  // ClosureAuxCall returns an AuxCall for a closure call.
   331  func ClosureAuxCall(paramResultInfo *abi.ABIParamResultInfo) *AuxCall {
   332  	var reg *regInfo
   333  	if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 {
   334  		reg = &regInfo{}
   335  	}
   336  	return &AuxCall{Fn: nil, abiInfo: paramResultInfo, reg: reg}
   337  }
   338  
   339  func (*AuxCall) CanBeAnSSAAux() {}
   340  
   341  // OwnAuxCall returns a function's own AuxCall.
   342  func OwnAuxCall(fn *obj.LSym, paramResultInfo *abi.ABIParamResultInfo) *AuxCall {
   343  	// TODO if this remains identical to ClosureAuxCall above after new ABI is done, should deduplicate.
   344  	var reg *regInfo
   345  	if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 {
   346  		reg = &regInfo{}
   347  	}
   348  	return &AuxCall{Fn: fn, abiInfo: paramResultInfo, reg: reg}
   349  }
   350  
   351  const (
   352  	auxNone           auxType = iota
   353  	auxBool                   // auxInt is 0/1 for false/true
   354  	auxInt8                   // auxInt is an 8-bit integer
   355  	auxInt16                  // auxInt is a 16-bit integer
   356  	auxInt32                  // auxInt is a 32-bit integer
   357  	auxInt64                  // auxInt is a 64-bit integer
   358  	auxInt128                 // auxInt represents a 128-bit integer.  Always 0.
   359  	auxUInt8                  // auxInt is an 8-bit unsigned integer
   360  	auxFloat32                // auxInt is a float32 (encoded with math.Float64bits)
   361  	auxFloat64                // auxInt is a float64 (encoded with math.Float64bits)
   362  	auxFlagConstant           // auxInt is a flagConstant
   363  	auxCCop                   // auxInt is a ssa.Op that represents a flags-to-bool conversion (e.g. LessThan)
   364  	auxNameOffsetInt8         // aux is a &struct{Name ir.Name, Offset int64}; auxInt is index in parameter registers array
   365  	auxString                 // aux is a string
   366  	auxSym                    // aux is a symbol (a *ir.Name for locals, an *obj.LSym for globals, or nil for none)
   367  	auxSymOff                 // aux is a symbol, auxInt is an offset
   368  	auxSymValAndOff           // aux is a symbol, auxInt is a ValAndOff
   369  	auxTyp                    // aux is a type
   370  	auxTypSize                // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt
   371  	auxCall                   // aux is a *ssa.AuxCall
   372  	auxCallOff                // aux is a *ssa.AuxCall, AuxInt is int64 param (in+out) size
   373  
   374  	auxPanicBoundsC  // constant for a bounds failure
   375  	auxPanicBoundsCC // two constants for a bounds failure
   376  
   377  	// architecture specific aux types
   378  	auxARM64BitField     // aux is an arm64 bitfield lsb and width packed into auxInt
   379  	auxS390XRotateParams // aux is a s390x rotate parameters object encoding start bit, end bit and rotate amount
   380  	auxS390XCCMask       // aux is a s390x 4-bit condition code mask
   381  	auxS390XCCMaskInt8   // aux is a s390x 4-bit condition code mask, auxInt is an int8 immediate
   382  	auxS390XCCMaskUint8  // aux is a s390x 4-bit condition code mask, auxInt is a uint8 immediate
   383  )
   384  
   385  // A SymEffect describes the effect that an SSA Value has on the variable
   386  // identified by the symbol in its Aux field.
   387  type SymEffect int8
   388  
   389  const (
   390  	SymRead SymEffect = 1 << iota
   391  	SymWrite
   392  	SymAddr
   393  
   394  	SymRdWr = SymRead | SymWrite
   395  
   396  	SymNone SymEffect = 0
   397  )
   398  
   399  // A Sym represents a symbolic offset from a base register.
   400  // Currently a Sym can be one of 3 things:
   401  //   - a *ir.Name, for an offset from SP (the stack pointer)
   402  //   - a *obj.LSym, for an offset from SB (the global pointer)
   403  //   - nil, for no offset
   404  type Sym interface {
   405  	Aux
   406  	CanBeAnSSASym()
   407  }
   408  
   409  // A ValAndOff is used by the several opcodes. It holds
   410  // both a value and a pointer offset.
   411  // A ValAndOff is intended to be encoded into an AuxInt field.
   412  // The zero ValAndOff encodes a value of 0 and an offset of 0.
   413  // The high 32 bits hold a value.
   414  // The low 32 bits hold a pointer offset.
   415  type ValAndOff int64
   416  
   417  func (x ValAndOff) Val() int32   { return int32(int64(x) >> 32) }
   418  func (x ValAndOff) Val64() int64 { return int64(x) >> 32 }
   419  func (x ValAndOff) Val16() int16 { return int16(int64(x) >> 32) }
   420  func (x ValAndOff) Val8() int8   { return int8(int64(x) >> 32) }
   421  
   422  func (x ValAndOff) Off64() int64 { return int64(int32(x)) }
   423  func (x ValAndOff) Off() int32   { return int32(x) }
   424  
   425  func (x ValAndOff) String() string {
   426  	return fmt.Sprintf("val=%d,off=%d", x.Val(), x.Off())
   427  }
   428  
   429  // validVal reports whether the value can be used
   430  // as an argument to makeValAndOff.
   431  func validVal(val int64) bool {
   432  	return val == int64(int32(val))
   433  }
   434  
   435  func makeValAndOff(val, off int32) ValAndOff {
   436  	return ValAndOff(int64(val)<<32 + int64(uint32(off)))
   437  }
   438  
   439  func (x ValAndOff) canAdd32(off int32) bool {
   440  	newoff := x.Off64() + int64(off)
   441  	return newoff == int64(int32(newoff))
   442  }
   443  func (x ValAndOff) canAdd64(off int64) bool {
   444  	newoff := x.Off64() + off
   445  	return newoff == int64(int32(newoff))
   446  }
   447  
   448  func (x ValAndOff) addOffset32(off int32) ValAndOff {
   449  	if !x.canAdd32(off) {
   450  		panic("invalid ValAndOff.addOffset32")
   451  	}
   452  	return makeValAndOff(x.Val(), x.Off()+off)
   453  }
   454  func (x ValAndOff) addOffset64(off int64) ValAndOff {
   455  	if !x.canAdd64(off) {
   456  		panic("invalid ValAndOff.addOffset64")
   457  	}
   458  	return makeValAndOff(x.Val(), x.Off()+int32(off))
   459  }
   460  
   461  // int128 is a type that stores a 128-bit constant.
   462  // The only allowed constant right now is 0, so we can cheat quite a bit.
   463  type int128 int64
   464  
   465  type BoundsKind uint8
   466  
   467  const (
   468  	BoundsIndex       BoundsKind = iota // indexing operation, 0 <= idx < len failed
   469  	BoundsIndexU                        // ... with unsigned idx
   470  	BoundsSliceAlen                     // 2-arg slicing operation, 0 <= high <= len failed
   471  	BoundsSliceAlenU                    // ... with unsigned high
   472  	BoundsSliceAcap                     // 2-arg slicing operation, 0 <= high <= cap failed
   473  	BoundsSliceAcapU                    // ... with unsigned high
   474  	BoundsSliceB                        // 2-arg slicing operation, 0 <= low <= high failed
   475  	BoundsSliceBU                       // ... with unsigned low
   476  	BoundsSlice3Alen                    // 3-arg slicing operation, 0 <= max <= len failed
   477  	BoundsSlice3AlenU                   // ... with unsigned max
   478  	BoundsSlice3Acap                    // 3-arg slicing operation, 0 <= max <= cap failed
   479  	BoundsSlice3AcapU                   // ... with unsigned max
   480  	BoundsSlice3B                       // 3-arg slicing operation, 0 <= high <= max failed
   481  	BoundsSlice3BU                      // ... with unsigned high
   482  	BoundsSlice3C                       // 3-arg slicing operation, 0 <= low <= high failed
   483  	BoundsSlice3CU                      // ... with unsigned low
   484  	BoundsConvert                       // conversion to array pointer failed
   485  	BoundsKindCount
   486  )
   487  
   488  // Returns the bounds error code needed by the runtime, and
   489  // whether the x field is signed.
   490  func (b BoundsKind) Code() (rtabi.BoundsErrorCode, bool) {
   491  	switch b {
   492  	case BoundsIndex:
   493  		return rtabi.BoundsIndex, true
   494  	case BoundsIndexU:
   495  		return rtabi.BoundsIndex, false
   496  	case BoundsSliceAlen:
   497  		return rtabi.BoundsSliceAlen, true
   498  	case BoundsSliceAlenU:
   499  		return rtabi.BoundsSliceAlen, false
   500  	case BoundsSliceAcap:
   501  		return rtabi.BoundsSliceAcap, true
   502  	case BoundsSliceAcapU:
   503  		return rtabi.BoundsSliceAcap, false
   504  	case BoundsSliceB:
   505  		return rtabi.BoundsSliceB, true
   506  	case BoundsSliceBU:
   507  		return rtabi.BoundsSliceB, false
   508  	case BoundsSlice3Alen:
   509  		return rtabi.BoundsSlice3Alen, true
   510  	case BoundsSlice3AlenU:
   511  		return rtabi.BoundsSlice3Alen, false
   512  	case BoundsSlice3Acap:
   513  		return rtabi.BoundsSlice3Acap, true
   514  	case BoundsSlice3AcapU:
   515  		return rtabi.BoundsSlice3Acap, false
   516  	case BoundsSlice3B:
   517  		return rtabi.BoundsSlice3B, true
   518  	case BoundsSlice3BU:
   519  		return rtabi.BoundsSlice3B, false
   520  	case BoundsSlice3C:
   521  		return rtabi.BoundsSlice3C, true
   522  	case BoundsSlice3CU:
   523  		return rtabi.BoundsSlice3C, false
   524  	case BoundsConvert:
   525  		return rtabi.BoundsConvert, false
   526  	default:
   527  		base.Fatalf("bad bounds kind %d", b)
   528  		return 0, false
   529  	}
   530  }
   531  
   532  // arm64BitField is the GO type of ARM64BitField auxInt.
   533  // if x is an ARM64BitField, then width=x&0xff, lsb=(x>>8)&0xff, and
   534  // width+lsb<64 for 64-bit variant, width+lsb<32 for 32-bit variant.
   535  // the meaning of width and lsb are instruction-dependent.
   536  type arm64BitField int16
   537  

View as plain text