github.com/chenzhuoyu/iasm@v0.9.1/x86_64/operands.go (about)

     1  package x86_64
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math"
     7  	"reflect"
     8  	"strconv"
     9  	"strings"
    10  	"sync/atomic"
    11  )
    12  
    13  // RelativeOffset represents an RIP-relative offset.
    14  type RelativeOffset int32
    15  
    16  // String implements the fmt.Stringer interface.
    17  func (self RelativeOffset) String() string {
    18  	if self == 0 {
    19  		return "(%rip)"
    20  	} else {
    21  		return fmt.Sprintf("%d(%%rip)", self)
    22  	}
    23  }
    24  
    25  // RoundingControl represents a floating-point rounding option.
    26  type RoundingControl uint8
    27  
    28  const (
    29  	// RN_SAE represents "Round Nearest", which is the default rounding option.
    30  	RN_SAE RoundingControl = iota
    31  
    32  	// RD_SAE represents "Round Down".
    33  	RD_SAE
    34  
    35  	// RU_SAE represents "Round Up".
    36  	RU_SAE
    37  
    38  	// RZ_SAE represents "Round towards Zero".
    39  	RZ_SAE
    40  )
    41  
    42  var _RC_NAMES = map[RoundingControl]string{
    43  	RN_SAE: "rn-sae",
    44  	RD_SAE: "rd-sae",
    45  	RU_SAE: "ru-sae",
    46  	RZ_SAE: "rz-sae",
    47  }
    48  
    49  func (self RoundingControl) String() string {
    50  	if v, ok := _RC_NAMES[self]; ok {
    51  		return v
    52  	} else {
    53  		panic("invalid RoundingControl value")
    54  	}
    55  }
    56  
    57  // ExceptionControl represents the "Suppress All Exceptions" flag.
    58  type ExceptionControl uint8
    59  
    60  const (
    61  	// SAE represents the flag "Suppress All Exceptions" for floating point operations.
    62  	SAE ExceptionControl = iota
    63  )
    64  
    65  func (ExceptionControl) String() string {
    66  	return "sae"
    67  }
    68  
    69  // AddressType indicates which kind of value that an Addressable object contains.
    70  type AddressType uint
    71  
    72  const (
    73  	// None indicates the Addressable does not contain any addressable value.
    74  	None AddressType = iota
    75  
    76  	// Memory indicates the Addressable contains a memory address.
    77  	Memory
    78  
    79  	// Offset indicates the Addressable contains an RIP-relative offset.
    80  	Offset
    81  
    82  	// Reference indicates the Addressable contains a label reference.
    83  	Reference
    84  )
    85  
    86  // Disposable is a type of object that can be Free'd manually.
    87  type Disposable interface {
    88  	Free()
    89  }
    90  
    91  // Label represents a location within the program.
    92  type Label struct {
    93  	refs int64
    94  	Name string
    95  	Dest *Instruction
    96  }
    97  
    98  func (self *Label) offset(p uintptr, n int) RelativeOffset {
    99  	if self.Dest == nil {
   100  		panic("unresolved label: " + self.Name)
   101  	} else {
   102  		return RelativeOffset(self.Dest.pc - p - uintptr(n))
   103  	}
   104  }
   105  
   106  // Free decreases the reference count of a Label, if the
   107  // refcount drops to 0, the Label will be recycled.
   108  func (self *Label) Free() {
   109  	if atomic.AddInt64(&self.refs, -1) == 0 {
   110  		//freeLabel(self)
   111  	}
   112  }
   113  
   114  // String implements the fmt.Stringer interface.
   115  func (self *Label) String() string {
   116  	if self.Dest == nil {
   117  		return fmt.Sprintf("%s(%%rip)", self.Name)
   118  	} else {
   119  		return fmt.Sprintf("%s(%%rip)@%#x", self.Name, self.Dest.pc)
   120  	}
   121  }
   122  
   123  // Retain increases the reference count of a Label.
   124  func (self *Label) Retain() *Label {
   125  	atomic.AddInt64(&self.refs, 1)
   126  	return self
   127  }
   128  
   129  // Evaluate implements the interface expr.Term.
   130  func (self *Label) Evaluate() (int64, error) {
   131  	if self.Dest != nil {
   132  		return int64(self.Dest.pc), nil
   133  	} else {
   134  		return 0, errors.New("unresolved label: " + self.Name)
   135  	}
   136  }
   137  
   138  // Addressable is a union to represent an addressable operand.
   139  type Addressable struct {
   140  	Type      AddressType
   141  	Memory    MemoryAddress
   142  	Offset    RelativeOffset
   143  	Reference *Label
   144  }
   145  
   146  // String implements the fmt.Stringer interface.
   147  func (self *Addressable) String() string {
   148  	switch self.Type {
   149  	case None:
   150  		return "(not addressable)"
   151  	case Memory:
   152  		return self.Memory.String()
   153  	case Offset:
   154  		return self.Offset.String()
   155  	case Reference:
   156  		return self.Reference.String()
   157  	default:
   158  		return "(invalid addressable)"
   159  	}
   160  }
   161  
   162  // MemoryOperand represents a memory operand for an instruction.
   163  type MemoryOperand struct {
   164  	refs      int64
   165  	Size      int
   166  	Addr      Addressable
   167  	Mask      RegisterMask
   168  	Masked    bool
   169  	Broadcast uint8
   170  }
   171  
   172  const (
   173  	_Sizes = 0b10000000100010111 // bit-mask for valid sizes (0, 1, 2, 4, 8, 16)
   174  )
   175  
   176  func (self *MemoryOperand) isVMX(evex bool) bool {
   177  	return self.Addr.Type == Memory && self.Addr.Memory.isVMX(evex)
   178  }
   179  
   180  func (self *MemoryOperand) isVMY(evex bool) bool {
   181  	return self.Addr.Type == Memory && self.Addr.Memory.isVMY(evex)
   182  }
   183  
   184  func (self *MemoryOperand) isVMZ() bool {
   185  	return self.Addr.Type == Memory && self.Addr.Memory.isVMZ()
   186  }
   187  
   188  func (self *MemoryOperand) isMem() bool {
   189  	if (_Sizes & (1 << self.Broadcast)) == 0 {
   190  		return false
   191  	} else if self.Addr.Type == Memory {
   192  		return self.Addr.Memory.isMem()
   193  	} else if self.Addr.Type == Offset {
   194  		return true
   195  	} else if self.Addr.Type == Reference {
   196  		return true
   197  	} else {
   198  		return false
   199  	}
   200  }
   201  
   202  func (self *MemoryOperand) isSize(n int) bool {
   203  	return self.Size == 0 || self.Size == n
   204  }
   205  
   206  func (self *MemoryOperand) isBroadcast(n int, b uint8) bool {
   207  	return self.Size == n && self.Broadcast == b
   208  }
   209  
   210  func (self *MemoryOperand) formatMask() string {
   211  	if !self.Masked {
   212  		return ""
   213  	} else {
   214  		return self.Mask.String()
   215  	}
   216  }
   217  
   218  func (self *MemoryOperand) formatBroadcast() string {
   219  	if self.Broadcast == 0 {
   220  		return ""
   221  	} else {
   222  		return fmt.Sprintf("{1to%d}", self.Broadcast)
   223  	}
   224  }
   225  
   226  func (self *MemoryOperand) ensureAddrValid() {
   227  	switch self.Addr.Type {
   228  	case None:
   229  		break
   230  	case Memory:
   231  		self.Addr.Memory.EnsureValid()
   232  	case Offset:
   233  		break
   234  	case Reference:
   235  		break
   236  	default:
   237  		panic("invalid address type")
   238  	}
   239  }
   240  
   241  func (self *MemoryOperand) ensureSizeValid() {
   242  	if (_Sizes & (1 << self.Size)) == 0 {
   243  		panic("invalid memory operand size")
   244  	}
   245  }
   246  
   247  func (self *MemoryOperand) ensureBroadcastValid() {
   248  	if (_Sizes & (1 << self.Broadcast)) == 0 {
   249  		panic("invalid memory operand broadcast")
   250  	}
   251  }
   252  
   253  // Free decreases the reference count of a MemoryOperand, if the
   254  // refcount drops to 0, the Label will be recycled.
   255  func (self *MemoryOperand) Free() {
   256  	if atomic.AddInt64(&self.refs, -1) == 0 {
   257  		//freeMemoryOperand(self)
   258  	}
   259  }
   260  
   261  // String implements the fmt.Stringer interface.
   262  func (self *MemoryOperand) String() string {
   263  	return self.Addr.String() + self.formatMask() + self.formatBroadcast()
   264  }
   265  
   266  // Retain increases the reference count of a MemoryOperand.
   267  func (self *MemoryOperand) Retain() *MemoryOperand {
   268  	atomic.AddInt64(&self.refs, 1)
   269  	return self
   270  }
   271  
   272  // EnsureValid checks if the memory operand is valid, if not, it panics.
   273  func (self *MemoryOperand) EnsureValid() {
   274  	self.ensureAddrValid()
   275  	self.ensureSizeValid()
   276  	self.ensureBroadcastValid()
   277  }
   278  
   279  // MemoryAddress represents a memory address.
   280  type MemoryAddress struct {
   281  	Base         Register
   282  	Index        Register
   283  	Scale        uint8
   284  	Displacement int32
   285  }
   286  
   287  const (
   288  	_Scales = 0b100010111 // bit-mask for valid scales (0, 1, 2, 4, 8)
   289  )
   290  
   291  func (self *MemoryAddress) isVMX(evex bool) bool {
   292  	return self.isMemBase() && (self.Index == nil || isXMM(self.Index) || (evex && isEVEXXMM(self.Index)))
   293  }
   294  
   295  func (self *MemoryAddress) isVMY(evex bool) bool {
   296  	return self.isMemBase() && (self.Index == nil || isYMM(self.Index) || (evex && isEVEXYMM(self.Index)))
   297  }
   298  
   299  func (self *MemoryAddress) isVMZ() bool {
   300  	return self.isMemBase() && (self.Index == nil || isZMM(self.Index))
   301  }
   302  
   303  func (self *MemoryAddress) isMem() bool {
   304  	return self.isMemBase() && (self.Index == nil || isReg64(self.Index))
   305  }
   306  
   307  func (self *MemoryAddress) isMemBase() bool {
   308  	return (self.Base == nil || isReg64(self.Base)) && // `Base` must be 64-bit if present
   309  		(self.Scale == 0) == (self.Index == nil) && // `Scale` and `Index` depends on each other
   310  		(_Scales&(1<<self.Scale)) != 0 // `Scale` can only be 0, 1, 2, 4 or 8
   311  }
   312  
   313  // String implements the fmt.Stringer interface.
   314  func (self *MemoryAddress) String() string {
   315  	var dp int
   316  	var sb strings.Builder
   317  
   318  	/* the displacement part */
   319  	if dp = int(self.Displacement); dp != 0 {
   320  		sb.WriteString(strconv.Itoa(dp))
   321  	}
   322  
   323  	/* the base register */
   324  	if sb.WriteByte('('); self.Base != nil {
   325  		sb.WriteByte('%')
   326  		sb.WriteString(self.Base.String())
   327  	}
   328  
   329  	/* index is optional */
   330  	if self.Index != nil {
   331  		sb.WriteString(",%")
   332  		sb.WriteString(self.Index.String())
   333  
   334  		/* scale is also optional */
   335  		if self.Scale >= 2 {
   336  			sb.WriteByte(',')
   337  			sb.WriteString(strconv.Itoa(int(self.Scale)))
   338  		}
   339  	}
   340  
   341  	/* close the bracket */
   342  	sb.WriteByte(')')
   343  	return sb.String()
   344  }
   345  
   346  // EnsureValid checks if the memory address is valid, if not, it panics.
   347  func (self *MemoryAddress) EnsureValid() {
   348  	if !self.isMemBase() || (self.Index != nil && !isIndexable(self.Index)) {
   349  		panic("not a valid memory address")
   350  	}
   351  }
   352  
   353  // Ref constructs a memory reference to a label.
   354  func Ref(ref *Label) (v *MemoryOperand) {
   355  	v = CreateMemoryOperand()
   356  	v.Addr.Type = Reference
   357  	v.Addr.Reference = ref
   358  	return
   359  }
   360  
   361  // Abs construct a simple memory address that represents absolute addressing.
   362  func Abs(disp int32) *MemoryOperand {
   363  	return Sib(nil, nil, 0, disp)
   364  }
   365  
   366  // Ptr constructs a simple memory operand with base and displacement.
   367  func Ptr(base Register, disp int32) *MemoryOperand {
   368  	return Sib(base, nil, 0, disp)
   369  }
   370  
   371  // Sib constructs a simple memory operand that represents a complete memory address.
   372  func Sib(base Register, index Register, scale uint8, disp int32) (v *MemoryOperand) {
   373  	v = CreateMemoryOperand()
   374  	v.Addr.Type = Memory
   375  	v.Addr.Memory.Base = base
   376  	v.Addr.Memory.Index = index
   377  	v.Addr.Memory.Scale = scale
   378  	v.Addr.Memory.Displacement = disp
   379  	v.EnsureValid()
   380  	return
   381  }
   382  
   383  /** Operand Matching Helpers **/
   384  
   385  const _IntMask = (1 << reflect.Int) |
   386  	(1 << reflect.Int8) |
   387  	(1 << reflect.Int16) |
   388  	(1 << reflect.Int32) |
   389  	(1 << reflect.Int64) |
   390  	(1 << reflect.Uint) |
   391  	(1 << reflect.Uint8) |
   392  	(1 << reflect.Uint16) |
   393  	(1 << reflect.Uint32) |
   394  	(1 << reflect.Uint64) |
   395  	(1 << reflect.Uintptr)
   396  
   397  func isInt(k reflect.Kind) bool {
   398  	return (_IntMask & (1 << k)) != 0
   399  }
   400  
   401  func asInt64(v interface{}) (int64, bool) {
   402  	if isSpecial(v) {
   403  		return 0, false
   404  	} else if x := efaceOf(v); isInt(x.kind()) {
   405  		return x.toInt64(), true
   406  	} else {
   407  		return 0, false
   408  	}
   409  }
   410  
   411  func inRange(v interface{}, low int64, high int64) bool {
   412  	x, ok := asInt64(v)
   413  	return ok && x >= low && x <= high
   414  }
   415  
   416  func isSpecial(v interface{}) bool {
   417  	switch v.(type) {
   418  	case Register8:
   419  		return true
   420  	case Register16:
   421  		return true
   422  	case Register32:
   423  		return true
   424  	case Register64:
   425  		return true
   426  	case KRegister:
   427  		return true
   428  	case MMRegister:
   429  		return true
   430  	case XMMRegister:
   431  		return true
   432  	case YMMRegister:
   433  		return true
   434  	case ZMMRegister:
   435  		return true
   436  	case RelativeOffset:
   437  		return true
   438  	case RoundingControl:
   439  		return true
   440  	case ExceptionControl:
   441  		return true
   442  	default:
   443  		return false
   444  	}
   445  }
   446  
   447  func isIndexable(v interface{}) bool {
   448  	return isZMM(v) || isReg64(v) || isEVEXXMM(v) || isEVEXYMM(v)
   449  }
   450  
   451  func isImm4(v interface{}) bool   { return inRange(v, 0, 15) }
   452  func isImm8(v interface{}) bool   { return inRange(v, math.MinInt8, math.MaxUint8) }
   453  func isImm16(v interface{}) bool  { return inRange(v, math.MinInt16, math.MaxUint16) }
   454  func isImm32(v interface{}) bool  { return inRange(v, math.MinInt32, math.MaxUint32) }
   455  func isImm64(v interface{}) bool  { _, r := asInt64(v); return r }
   456  func isConst1(v interface{}) bool { x, r := asInt64(v); return r && x == 1 }
   457  func isConst3(v interface{}) bool { x, r := asInt64(v); return r && x == 3 }
   458  func isRel8(v interface{}) bool {
   459  	x, r := v.(RelativeOffset)
   460  	return r && x >= math.MinInt8 && x <= math.MaxInt8
   461  }
   462  func isRel32(v interface{}) bool { _, r := v.(RelativeOffset); return r }
   463  func isLabel(v interface{}) bool { _, r := v.(*Label); return r }
   464  func isReg8(v interface{}) bool  { _, r := v.(Register8); return r }
   465  func isReg8REX(v interface{}) bool {
   466  	x, r := v.(Register8)
   467  	return r && (x&0x80) == 0 && x >= SPL
   468  }
   469  func isReg16(v interface{}) bool   { _, r := v.(Register16); return r }
   470  func isReg32(v interface{}) bool   { _, r := v.(Register32); return r }
   471  func isReg64(v interface{}) bool   { _, r := v.(Register64); return r }
   472  func isMM(v interface{}) bool      { _, r := v.(MMRegister); return r }
   473  func isXMM(v interface{}) bool     { x, r := v.(XMMRegister); return r && x <= XMM15 }
   474  func isEVEXXMM(v interface{}) bool { _, r := v.(XMMRegister); return r }
   475  func isXMMk(v interface{}) bool {
   476  	x, r := v.(MaskedRegister)
   477  	return isXMM(v) || (r && isXMM(x.Reg) && !x.Mask.Z)
   478  }
   479  func isXMMkz(v interface{}) bool {
   480  	x, r := v.(MaskedRegister)
   481  	return isXMM(v) || (r && isXMM(x.Reg))
   482  }
   483  func isYMM(v interface{}) bool     { x, r := v.(YMMRegister); return r && x <= YMM15 }
   484  func isEVEXYMM(v interface{}) bool { _, r := v.(YMMRegister); return r }
   485  func isYMMk(v interface{}) bool {
   486  	x, r := v.(MaskedRegister)
   487  	return isYMM(v) || (r && isYMM(x.Reg) && !x.Mask.Z)
   488  }
   489  func isYMMkz(v interface{}) bool {
   490  	x, r := v.(MaskedRegister)
   491  	return isYMM(v) || (r && isYMM(x.Reg))
   492  }
   493  func isZMM(v interface{}) bool { _, r := v.(ZMMRegister); return r }
   494  func isZMMk(v interface{}) bool {
   495  	x, r := v.(MaskedRegister)
   496  	return isZMM(v) || (r && isZMM(x.Reg) && !x.Mask.Z)
   497  }
   498  func isZMMkz(v interface{}) bool {
   499  	x, r := v.(MaskedRegister)
   500  	return isZMM(v) || (r && isZMM(x.Reg))
   501  }
   502  func isK(v interface{}) bool { _, r := v.(KRegister); return r }
   503  func isKk(v interface{}) bool {
   504  	x, r := v.(MaskedRegister)
   505  	return isK(v) || (r && isK(x.Reg) && !x.Mask.Z)
   506  }
   507  func isM(v interface{}) bool {
   508  	x, r := v.(*MemoryOperand)
   509  	return r && x.isMem() && x.Broadcast == 0 && !x.Masked
   510  }
   511  func isMk(v interface{}) bool {
   512  	x, r := v.(*MemoryOperand)
   513  	return r && x.isMem() && x.Broadcast == 0 && !(x.Masked && x.Mask.Z)
   514  }
   515  func isMkz(v interface{}) bool {
   516  	x, r := v.(*MemoryOperand)
   517  	return r && x.isMem() && x.Broadcast == 0
   518  }
   519  func isM8(v interface{}) bool {
   520  	x, r := v.(*MemoryOperand)
   521  	return r && isM(v) && x.isSize(1)
   522  }
   523  func isM16(v interface{}) bool {
   524  	x, r := v.(*MemoryOperand)
   525  	return r && isM(v) && x.isSize(2)
   526  }
   527  func isM16kz(v interface{}) bool {
   528  	x, r := v.(*MemoryOperand)
   529  	return r && isMkz(v) && x.isSize(2)
   530  }
   531  func isM32(v interface{}) bool {
   532  	x, r := v.(*MemoryOperand)
   533  	return r && isM(v) && x.isSize(4)
   534  }
   535  func isM32k(v interface{}) bool {
   536  	x, r := v.(*MemoryOperand)
   537  	return r && isMk(v) && x.isSize(4)
   538  }
   539  func isM32kz(v interface{}) bool {
   540  	x, r := v.(*MemoryOperand)
   541  	return r && isMkz(v) && x.isSize(4)
   542  }
   543  func isM64(v interface{}) bool {
   544  	x, r := v.(*MemoryOperand)
   545  	return r && isM(v) && x.isSize(8)
   546  }
   547  func isM64k(v interface{}) bool {
   548  	x, r := v.(*MemoryOperand)
   549  	return r && isMk(v) && x.isSize(8)
   550  }
   551  func isM64kz(v interface{}) bool {
   552  	x, r := v.(*MemoryOperand)
   553  	return r && isMkz(v) && x.isSize(8)
   554  }
   555  func isM128(v interface{}) bool {
   556  	x, r := v.(*MemoryOperand)
   557  	return r && isM(v) && x.isSize(16)
   558  }
   559  func isM128kz(v interface{}) bool {
   560  	x, r := v.(*MemoryOperand)
   561  	return r && isMkz(v) && x.isSize(16)
   562  }
   563  func isM256(v interface{}) bool {
   564  	x, r := v.(*MemoryOperand)
   565  	return r && isM(v) && x.isSize(32)
   566  }
   567  func isM256kz(v interface{}) bool {
   568  	x, r := v.(*MemoryOperand)
   569  	return r && isMkz(v) && x.isSize(32)
   570  }
   571  func isM512(v interface{}) bool {
   572  	x, r := v.(*MemoryOperand)
   573  	return r && isM(v) && x.isSize(64)
   574  }
   575  func isM512kz(v interface{}) bool {
   576  	x, r := v.(*MemoryOperand)
   577  	return r && isMkz(v) && x.isSize(64)
   578  }
   579  func isM64M32bcst(v interface{}) bool {
   580  	x, r := v.(*MemoryOperand)
   581  	return isM64(v) || (r && x.isBroadcast(4, 2))
   582  }
   583  func isM128M32bcst(v interface{}) bool {
   584  	x, r := v.(*MemoryOperand)
   585  	return isM128(v) || (r && x.isBroadcast(4, 4))
   586  }
   587  func isM256M32bcst(v interface{}) bool {
   588  	x, r := v.(*MemoryOperand)
   589  	return isM256(v) || (r && x.isBroadcast(4, 8))
   590  }
   591  func isM512M32bcst(v interface{}) bool {
   592  	x, r := v.(*MemoryOperand)
   593  	return isM512(v) || (r && x.isBroadcast(4, 16))
   594  }
   595  func isM128M64bcst(v interface{}) bool {
   596  	x, r := v.(*MemoryOperand)
   597  	return isM128(v) || (r && x.isBroadcast(8, 2))
   598  }
   599  func isM256M64bcst(v interface{}) bool {
   600  	x, r := v.(*MemoryOperand)
   601  	return isM256(v) || (r && x.isBroadcast(8, 4))
   602  }
   603  func isM512M64bcst(v interface{}) bool {
   604  	x, r := v.(*MemoryOperand)
   605  	return isM512(v) || (r && x.isBroadcast(8, 8))
   606  }
   607  func isVMX(v interface{}) bool {
   608  	x, r := v.(*MemoryOperand)
   609  	return r && x.isVMX(false) && !x.Masked
   610  }
   611  func isEVEXVMX(v interface{}) bool {
   612  	x, r := v.(*MemoryOperand)
   613  	return r && x.isVMX(true) && !x.Masked
   614  }
   615  func isVMXk(v interface{}) bool { x, r := v.(*MemoryOperand); return r && x.isVMX(true) }
   616  func isVMY(v interface{}) bool {
   617  	x, r := v.(*MemoryOperand)
   618  	return r && x.isVMY(false) && !x.Masked
   619  }
   620  func isEVEXVMY(v interface{}) bool {
   621  	x, r := v.(*MemoryOperand)
   622  	return r && x.isVMY(true) && !x.Masked
   623  }
   624  func isVMYk(v interface{}) bool { x, r := v.(*MemoryOperand); return r && x.isVMY(true) }
   625  func isVMZ(v interface{}) bool {
   626  	x, r := v.(*MemoryOperand)
   627  	return r && x.isVMZ() && !x.Masked
   628  }
   629  func isVMZk(v interface{}) bool { x, r := v.(*MemoryOperand); return r && x.isVMZ() }
   630  func isSAE(v interface{}) bool  { _, r := v.(ExceptionControl); return r }
   631  func isER(v interface{}) bool   { _, r := v.(RoundingControl); return r }
   632  
   633  func isImmExt(v interface{}, ext int, min int64, max int64) bool {
   634  	if x, ok := asInt64(v); !ok {
   635  		return false
   636  	} else if m := int64(1) << (8 * ext); x < m && x >= m+min {
   637  		return true
   638  	} else {
   639  		return x <= max && x >= min
   640  	}
   641  }
   642  
   643  func isImm8Ext(v interface{}, ext int) bool {
   644  	return isImmExt(v, ext, math.MinInt8, math.MaxInt8)
   645  }
   646  
   647  func isImm32Ext(v interface{}, ext int) bool {
   648  	return isImmExt(v, ext, math.MinInt32, math.MaxInt32)
   649  }