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

View as plain text