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  	call              bool      // is a function call
    37  	tailCall          bool      // is a tail call
    38  	nilCheck          bool      // this op is a nil check on arg0
    39  	faultOnNilArg0    bool      // this op will fault if arg0 is nil (and aux encodes a small offset)
    40  	faultOnNilArg1    bool      // this op will fault if arg1 is nil (and aux encodes a small offset)
    41  	usesScratch       bool      // this op requires scratch memory space
    42  	hasSideEffects    bool      // for "reasons", not to be eliminated.  E.g., atomic store, #19182.
    43  	zeroWidth         bool      // op never translates into any machine code. example: copy, which may sometimes translate to machine code, is not zero-width.
    44  	unsafePoint       bool      // this op is an unsafe point, i.e. not safe for async preemption
    45  	symEffect         SymEffect // effect this op has on symbol in aux
    46  	scale             uint8     // amd64/386 indexed load scale
    47  }
    48  
    49  type inputInfo struct {
    50  	idx  int     // index in Args array
    51  	regs regMask // allowed input registers
    52  }
    53  
    54  type outputInfo struct {
    55  	idx  int     // index in output tuple
    56  	regs regMask // allowed output registers
    57  }
    58  
    59  type regInfo struct {
    60  	// inputs encodes the register restrictions for an instruction's inputs.
    61  	// Each entry specifies an allowed register set for a particular input.
    62  	// They are listed in the order in which regalloc should pick a register
    63  	// from the register set (most constrained first).
    64  	// Inputs which do not need registers are not listed.
    65  	inputs []inputInfo
    66  	// clobbers encodes the set of registers that are overwritten by
    67  	// the instruction (other than the output registers).
    68  	clobbers regMask
    69  	// outputs is the same as inputs, but for the outputs of the instruction.
    70  	outputs []outputInfo
    71  }
    72  
    73  func (r *regInfo) String() string {
    74  	s := ""
    75  	s += "INS:\n"
    76  	for _, i := range r.inputs {
    77  		mask := fmt.Sprintf("%64b", i.regs)
    78  		mask = strings.Replace(mask, "0", ".", -1)
    79  		s += fmt.Sprintf("%2d |%s|\n", i.idx, mask)
    80  	}
    81  	s += "OUTS:\n"
    82  	for _, i := range r.outputs {
    83  		mask := fmt.Sprintf("%64b", i.regs)
    84  		mask = strings.Replace(mask, "0", ".", -1)
    85  		s += fmt.Sprintf("%2d |%s|\n", i.idx, mask)
    86  	}
    87  	s += "CLOBBERS:\n"
    88  	mask := fmt.Sprintf("%64b", r.clobbers)
    89  	mask = strings.Replace(mask, "0", ".", -1)
    90  	s += fmt.Sprintf("   |%s|\n", mask)
    91  	return s
    92  }
    93  
    94  type auxType int8
    95  
    96  type AuxNameOffset struct {
    97  	Name   *ir.Name
    98  	Offset int64
    99  }
   100  
   101  func (a *AuxNameOffset) CanBeAnSSAAux() {}
   102  func (a *AuxNameOffset) String() string {
   103  	return fmt.Sprintf("%s+%d", a.Name.Sym().Name, a.Offset)
   104  }
   105  
   106  func (a *AuxNameOffset) FrameOffset() int64 {
   107  	return a.Name.FrameOffset() + a.Offset
   108  }
   109  
   110  type AuxCall struct {
   111  	Fn      *obj.LSym
   112  	reg     *regInfo // regInfo for this call
   113  	abiInfo *abi.ABIParamResultInfo
   114  }
   115  
   116  // Reg returns the regInfo for a given call, combining the derived in/out register masks
   117  // with the machine-specific register information in the input i.  (The machine-specific
   118  // regInfo is much handier at the call site than it is when the AuxCall is being constructed,
   119  // therefore do this lazily).
   120  //
   121  // TODO: there is a Clever Hack that allows pre-generation of a small-ish number of the slices
   122  // of inputInfo and outputInfo used here, provided that we are willing to reorder the inputs
   123  // and outputs from calls, so that all integer registers come first, then all floating registers.
   124  // At this point (active development of register ABI) that is very premature,
   125  // but if this turns out to be a cost, we could do it.
   126  func (a *AuxCall) Reg(i *regInfo, c *Config) *regInfo {
   127  	if a.reg.clobbers != 0 {
   128  		// Already updated
   129  		return a.reg
   130  	}
   131  	if a.abiInfo.InRegistersUsed()+a.abiInfo.OutRegistersUsed() == 0 {
   132  		// Shortcut for zero case, also handles old ABI.
   133  		a.reg = i
   134  		return a.reg
   135  	}
   136  
   137  	k := len(i.inputs)
   138  	for _, p := range a.abiInfo.InParams() {
   139  		for _, r := range p.Registers {
   140  			m := archRegForAbiReg(r, c)
   141  			a.reg.inputs = append(a.reg.inputs, inputInfo{idx: k, regs: (1 << m)})
   142  			k++
   143  		}
   144  	}
   145  	a.reg.inputs = append(a.reg.inputs, i.inputs...) // These are less constrained, thus should come last
   146  	k = len(i.outputs)
   147  	for _, p := range a.abiInfo.OutParams() {
   148  		for _, r := range p.Registers {
   149  			m := archRegForAbiReg(r, c)
   150  			a.reg.outputs = append(a.reg.outputs, outputInfo{idx: k, regs: (1 << m)})
   151  			k++
   152  		}
   153  	}
   154  	a.reg.outputs = append(a.reg.outputs, i.outputs...)
   155  	a.reg.clobbers = i.clobbers
   156  	return a.reg
   157  }
   158  func (a *AuxCall) ABI() *abi.ABIConfig {
   159  	return a.abiInfo.Config()
   160  }
   161  func (a *AuxCall) ABIInfo() *abi.ABIParamResultInfo {
   162  	return a.abiInfo
   163  }
   164  func (a *AuxCall) ResultReg(c *Config) *regInfo {
   165  	if a.abiInfo.OutRegistersUsed() == 0 {
   166  		return a.reg
   167  	}
   168  	if len(a.reg.inputs) > 0 {
   169  		return a.reg
   170  	}
   171  	k := 0
   172  	for _, p := range a.abiInfo.OutParams() {
   173  		for _, r := range p.Registers {
   174  			m := archRegForAbiReg(r, c)
   175  			a.reg.inputs = append(a.reg.inputs, inputInfo{idx: k, regs: (1 << m)})
   176  			k++
   177  		}
   178  	}
   179  	return a.reg
   180  }
   181  
   182  // For ABI register index r, returns the (dense) register number used in
   183  // SSA backend.
   184  func archRegForAbiReg(r abi.RegIndex, c *Config) uint8 {
   185  	var m int8
   186  	if int(r) < len(c.intParamRegs) {
   187  		m = c.intParamRegs[r]
   188  	} else {
   189  		m = c.floatParamRegs[int(r)-len(c.intParamRegs)]
   190  	}
   191  	return uint8(m)
   192  }
   193  
   194  // For ABI register index r, returns the register number used in the obj
   195  // package (assembler).
   196  func ObjRegForAbiReg(r abi.RegIndex, c *Config) int16 {
   197  	m := archRegForAbiReg(r, c)
   198  	return c.registers[m].objNum
   199  }
   200  
   201  // ArgWidth returns the amount of stack needed for all the inputs
   202  // and outputs of a function or method, including ABI-defined parameter
   203  // slots and ABI-defined spill slots for register-resident parameters.
   204  //
   205  // The name is taken from the types package's ArgWidth(<function type>),
   206  // which predated changes to the ABI; this version handles those changes.
   207  func (a *AuxCall) ArgWidth() int64 {
   208  	return a.abiInfo.ArgWidth()
   209  }
   210  
   211  // ParamAssignmentForResult returns the ABI Parameter assignment for result which (indexed 0, 1, etc).
   212  func (a *AuxCall) ParamAssignmentForResult(which int64) *abi.ABIParamAssignment {
   213  	return a.abiInfo.OutParam(int(which))
   214  }
   215  
   216  // OffsetOfResult returns the SP offset of result which (indexed 0, 1, etc).
   217  func (a *AuxCall) OffsetOfResult(which int64) int64 {
   218  	n := int64(a.abiInfo.OutParam(int(which)).Offset())
   219  	return n
   220  }
   221  
   222  // OffsetOfArg returns the SP offset of argument which (indexed 0, 1, etc).
   223  // If the call is to a method, the receiver is the first argument (i.e., index 0)
   224  func (a *AuxCall) OffsetOfArg(which int64) int64 {
   225  	n := int64(a.abiInfo.InParam(int(which)).Offset())
   226  	return n
   227  }
   228  
   229  // RegsOfResult returns the register(s) used for result which (indexed 0, 1, etc).
   230  func (a *AuxCall) RegsOfResult(which int64) []abi.RegIndex {
   231  	return a.abiInfo.OutParam(int(which)).Registers
   232  }
   233  
   234  // RegsOfArg returns the register(s) used for argument which (indexed 0, 1, etc).
   235  // If the call is to a method, the receiver is the first argument (i.e., index 0)
   236  func (a *AuxCall) RegsOfArg(which int64) []abi.RegIndex {
   237  	return a.abiInfo.InParam(int(which)).Registers
   238  }
   239  
   240  // NameOfResult returns the type of result which (indexed 0, 1, etc).
   241  func (a *AuxCall) NameOfResult(which int64) *ir.Name {
   242  	name := a.abiInfo.OutParam(int(which)).Name
   243  	if name == nil {
   244  		return nil
   245  	}
   246  	return name.(*ir.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  	auxNameOffsetInt8         // aux is a &struct{Name ir.Name, Offset int64}; auxInt is index in parameter registers array
   360  	auxString                 // aux is a string
   361  	auxSym                    // aux is a symbol (a *gc.Node for locals, an *obj.LSym for globals, or nil for none)
   362  	auxSymOff                 // aux is a symbol, auxInt is an offset
   363  	auxSymValAndOff           // aux is a symbol, auxInt is a ValAndOff
   364  	auxTyp                    // aux is a type
   365  	auxTypSize                // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt
   366  	auxCCop                   // aux is a ssa.Op that represents a flags-to-bool conversion (e.g. LessThan)
   367  	auxCall                   // aux is a *ssa.AuxCall
   368  	auxCallOff                // aux is a *ssa.AuxCall, AuxInt is int64 param (in+out) size
   369  
   370  	// architecture specific aux types
   371  	auxARM64BitField     // aux is an arm64 bitfield lsb and width packed into auxInt
   372  	auxS390XRotateParams // aux is a s390x rotate parameters object encoding start bit, end bit and rotate amount
   373  	auxS390XCCMask       // aux is a s390x 4-bit condition code mask
   374  	auxS390XCCMaskInt8   // aux is a s390x 4-bit condition code mask, auxInt is a int8 immediate
   375  	auxS390XCCMaskUint8  // aux is a s390x 4-bit condition code mask, auxInt is a uint8 immediate
   376  )
   377  
   378  // A SymEffect describes the effect that an SSA Value has on the variable
   379  // identified by the symbol in its Aux field.
   380  type SymEffect int8
   381  
   382  const (
   383  	SymRead SymEffect = 1 << iota
   384  	SymWrite
   385  	SymAddr
   386  
   387  	SymRdWr = SymRead | SymWrite
   388  
   389  	SymNone SymEffect = 0
   390  )
   391  
   392  // A Sym represents a symbolic offset from a base register.
   393  // Currently a Sym can be one of 3 things:
   394  //  - a *gc.Node, for an offset from SP (the stack pointer)
   395  //  - a *obj.LSym, for an offset from SB (the global pointer)
   396  //  - nil, for no offset
   397  type Sym interface {
   398  	CanBeAnSSASym()
   399  	CanBeAnSSAAux()
   400  }
   401  
   402  // A ValAndOff is used by the several opcodes. It holds
   403  // both a value and a pointer offset.
   404  // A ValAndOff is intended to be encoded into an AuxInt field.
   405  // The zero ValAndOff encodes a value of 0 and an offset of 0.
   406  // The high 32 bits hold a value.
   407  // The low 32 bits hold a pointer offset.
   408  type ValAndOff int64
   409  
   410  func (x ValAndOff) Val() int32   { return int32(int64(x) >> 32) }
   411  func (x ValAndOff) Val64() int64 { return int64(x) >> 32 }
   412  func (x ValAndOff) Val16() int16 { return int16(int64(x) >> 32) }
   413  func (x ValAndOff) Val8() int8   { return int8(int64(x) >> 32) }
   414  
   415  func (x ValAndOff) Off64() int64 { return int64(int32(x)) }
   416  func (x ValAndOff) Off() int32   { return int32(x) }
   417  
   418  func (x ValAndOff) String() string {
   419  	return fmt.Sprintf("val=%d,off=%d", x.Val(), x.Off())
   420  }
   421  
   422  // validVal reports whether the value can be used
   423  // as an argument to makeValAndOff.
   424  func validVal(val int64) bool {
   425  	return val == int64(int32(val))
   426  }
   427  
   428  func makeValAndOff(val, off int32) ValAndOff {
   429  	return ValAndOff(int64(val)<<32 + int64(uint32(off)))
   430  }
   431  
   432  func (x ValAndOff) canAdd32(off int32) bool {
   433  	newoff := x.Off64() + int64(off)
   434  	return newoff == int64(int32(newoff))
   435  }
   436  func (x ValAndOff) canAdd64(off int64) bool {
   437  	newoff := x.Off64() + off
   438  	return newoff == int64(int32(newoff))
   439  }
   440  
   441  func (x ValAndOff) addOffset32(off int32) ValAndOff {
   442  	if !x.canAdd32(off) {
   443  		panic("invalid ValAndOff.addOffset32")
   444  	}
   445  	return makeValAndOff(x.Val(), x.Off()+off)
   446  }
   447  func (x ValAndOff) addOffset64(off int64) ValAndOff {
   448  	if !x.canAdd64(off) {
   449  		panic("invalid ValAndOff.addOffset64")
   450  	}
   451  	return makeValAndOff(x.Val(), x.Off()+int32(off))
   452  }
   453  
   454  // int128 is a type that stores a 128-bit constant.
   455  // The only allowed constant right now is 0, so we can cheat quite a bit.
   456  type int128 int64
   457  
   458  type BoundsKind uint8
   459  
   460  const (
   461  	BoundsIndex       BoundsKind = iota // indexing operation, 0 <= idx < len failed
   462  	BoundsIndexU                        // ... with unsigned idx
   463  	BoundsSliceAlen                     // 2-arg slicing operation, 0 <= high <= len failed
   464  	BoundsSliceAlenU                    // ... with unsigned high
   465  	BoundsSliceAcap                     // 2-arg slicing operation, 0 <= high <= cap failed
   466  	BoundsSliceAcapU                    // ... with unsigned high
   467  	BoundsSliceB                        // 2-arg slicing operation, 0 <= low <= high failed
   468  	BoundsSliceBU                       // ... with unsigned low
   469  	BoundsSlice3Alen                    // 3-arg slicing operation, 0 <= max <= len failed
   470  	BoundsSlice3AlenU                   // ... with unsigned max
   471  	BoundsSlice3Acap                    // 3-arg slicing operation, 0 <= max <= cap failed
   472  	BoundsSlice3AcapU                   // ... with unsigned max
   473  	BoundsSlice3B                       // 3-arg slicing operation, 0 <= high <= max failed
   474  	BoundsSlice3BU                      // ... with unsigned high
   475  	BoundsSlice3C                       // 3-arg slicing operation, 0 <= low <= high failed
   476  	BoundsSlice3CU                      // ... with unsigned low
   477  	BoundsConvert                       // conversion to array pointer failed
   478  	BoundsKindCount
   479  )
   480  
   481  // boundsAPI determines which register arguments a bounds check call should use. For an [a:b:c] slice, we do:
   482  //   CMPQ c, cap
   483  //   JA   fail1
   484  //   CMPQ b, c
   485  //   JA   fail2
   486  //   CMPQ a, b
   487  //   JA   fail3
   488  //
   489  // fail1: CALL panicSlice3Acap (c, cap)
   490  // fail2: CALL panicSlice3B (b, c)
   491  // fail3: CALL panicSlice3C (a, b)
   492  //
   493  // When we register allocate that code, we want the same register to be used for
   494  // the first arg of panicSlice3Acap and the second arg to panicSlice3B. That way,
   495  // initializing that register once will satisfy both calls.
   496  // That desire ends up dividing the set of bounds check calls into 3 sets. This function
   497  // determines which set to use for a given panic call.
   498  // The first arg for set 0 should be the second arg for set 1.
   499  // The first arg for set 1 should be the second arg for set 2.
   500  func boundsABI(b int64) int {
   501  	switch BoundsKind(b) {
   502  	case BoundsSlice3Alen,
   503  		BoundsSlice3AlenU,
   504  		BoundsSlice3Acap,
   505  		BoundsSlice3AcapU,
   506  		BoundsConvert:
   507  		return 0
   508  	case BoundsSliceAlen,
   509  		BoundsSliceAlenU,
   510  		BoundsSliceAcap,
   511  		BoundsSliceAcapU,
   512  		BoundsSlice3B,
   513  		BoundsSlice3BU:
   514  		return 1
   515  	case BoundsIndex,
   516  		BoundsIndexU,
   517  		BoundsSliceB,
   518  		BoundsSliceBU,
   519  		BoundsSlice3C,
   520  		BoundsSlice3CU:
   521  		return 2
   522  	default:
   523  		panic("bad BoundsKind")
   524  	}
   525  }
   526  
   527  // arm64BitFileld is the GO type of ARM64BitField auxInt.
   528  // if x is an ARM64BitField, then width=x&0xff, lsb=(x>>8)&0xff, and
   529  // width+lsb<64 for 64-bit variant, width+lsb<32 for 32-bit variant.
   530  // the meaning of width and lsb are instruction-dependent.
   531  type arm64BitField int16
   532  

View as plain text