github.com/cloudwego/iasm@v0.2.0/x86_64/operands.go (about)

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