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

View as plain text