github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/wazevo/ssa/instructions.go (about)

     1  package ssa
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"strings"
     7  
     8  	"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
     9  )
    10  
    11  // Opcode represents a SSA instruction.
    12  type Opcode uint32
    13  
    14  // Instruction represents an instruction whose opcode is specified by
    15  // Opcode. Since Go doesn't have union type, we use this flattened type
    16  // for all instructions, and therefore each field has different meaning
    17  // depending on Opcode.
    18  type Instruction struct {
    19  	// id is the unique ID of this instruction which ascends from 0 following the order of program.
    20  	id         int
    21  	opcode     Opcode
    22  	u1, u2     uint64
    23  	v          Value
    24  	v2         Value
    25  	v3         Value
    26  	vs         Values
    27  	typ        Type
    28  	blk        BasicBlock
    29  	targets    []BasicBlock
    30  	prev, next *Instruction
    31  
    32  	rValue         Value
    33  	rValues        Values
    34  	gid            InstructionGroupID
    35  	sourceOffset   SourceOffset
    36  	live           bool
    37  	alreadyLowered bool
    38  }
    39  
    40  // SourceOffset represents the offset of the source of an instruction.
    41  type SourceOffset int64
    42  
    43  const sourceOffsetUnknown = -1
    44  
    45  // Valid returns true if this source offset is valid.
    46  func (l SourceOffset) Valid() bool {
    47  	return l != sourceOffsetUnknown
    48  }
    49  
    50  func (i *Instruction) annotateSourceOffset(line SourceOffset) {
    51  	i.sourceOffset = line
    52  }
    53  
    54  // SourceOffset returns the source offset of this instruction.
    55  func (i *Instruction) SourceOffset() SourceOffset {
    56  	return i.sourceOffset
    57  }
    58  
    59  // Opcode returns the opcode of this instruction.
    60  func (i *Instruction) Opcode() Opcode {
    61  	return i.opcode
    62  }
    63  
    64  // GroupID returns the InstructionGroupID of this instruction.
    65  func (i *Instruction) GroupID() InstructionGroupID {
    66  	return i.gid
    67  }
    68  
    69  // MarkLowered marks this instruction as already lowered.
    70  func (i *Instruction) MarkLowered() {
    71  	i.alreadyLowered = true
    72  }
    73  
    74  // Lowered returns true if this instruction is already lowered.
    75  func (i *Instruction) Lowered() bool {
    76  	return i.alreadyLowered
    77  }
    78  
    79  // resetInstruction resets this instruction to the initial state.
    80  func resetInstruction(i *Instruction) {
    81  	*i = Instruction{}
    82  	i.v = ValueInvalid
    83  	i.v2 = ValueInvalid
    84  	i.v3 = ValueInvalid
    85  	i.rValue = ValueInvalid
    86  	i.typ = typeInvalid
    87  	i.vs = ValuesNil
    88  	i.sourceOffset = sourceOffsetUnknown
    89  }
    90  
    91  // InstructionGroupID is assigned to each instruction and represents a group of instructions
    92  // where each instruction is interchangeable with others except for the last instruction
    93  // in the group which has side effects. In short, InstructionGroupID is determined by the side effects of instructions.
    94  // That means, if there's an instruction with side effect between two instructions, then these two instructions
    95  // will have different instructionGroupID. Note that each block always ends with branching, which is with side effects,
    96  // therefore, instructions in different blocks always have different InstructionGroupID(s).
    97  //
    98  // The notable application of this is used in lowering SSA-level instruction to a ISA specific instruction,
    99  // where we eagerly try to merge multiple instructions into single operation etc. Such merging cannot be done
   100  // if these instruction have different InstructionGroupID since it will change the semantics of a program.
   101  //
   102  // See passDeadCodeElimination.
   103  type InstructionGroupID uint32
   104  
   105  // Returns Value(s) produced by this instruction if any.
   106  // The `first` is the first return value, and `rest` is the rest of the values.
   107  func (i *Instruction) Returns() (first Value, rest []Value) {
   108  	return i.rValue, i.rValues.View()
   109  }
   110  
   111  // Return returns a Value(s) produced by this instruction if any.
   112  // If there's multiple return values, only the first one is returned.
   113  func (i *Instruction) Return() (first Value) {
   114  	return i.rValue
   115  }
   116  
   117  // Args returns the arguments to this instruction.
   118  func (i *Instruction) Args() (v1, v2, v3 Value, vs []Value) {
   119  	return i.v, i.v2, i.v3, i.vs.View()
   120  }
   121  
   122  // Arg returns the first argument to this instruction.
   123  func (i *Instruction) Arg() Value {
   124  	return i.v
   125  }
   126  
   127  // Arg2 returns the first two arguments to this instruction.
   128  func (i *Instruction) Arg2() (Value, Value) {
   129  	return i.v, i.v2
   130  }
   131  
   132  // ArgWithLane returns the first argument to this instruction, and the lane type.
   133  func (i *Instruction) ArgWithLane() (Value, VecLane) {
   134  	return i.v, VecLane(i.u1)
   135  }
   136  
   137  // Arg2WithLane returns the first two arguments to this instruction, and the lane type.
   138  func (i *Instruction) Arg2WithLane() (Value, Value, VecLane) {
   139  	return i.v, i.v2, VecLane(i.u1)
   140  }
   141  
   142  // ShuffleData returns the first two arguments to this instruction and 2 uint64s `lo`, `hi`.
   143  //
   144  // Note: Each uint64 encodes a sequence of 8 bytes where each byte encodes a VecLane,
   145  // so that the 128bit integer `hi<<64|lo` packs a slice `[16]VecLane`,
   146  // where `lane[0]` is the least significant byte, and `lane[n]` is shifted to offset `n*8`.
   147  func (i *Instruction) ShuffleData() (v Value, v2 Value, lo uint64, hi uint64) {
   148  	return i.v, i.v2, i.u1, i.u2
   149  }
   150  
   151  // Arg3 returns the first three arguments to this instruction.
   152  func (i *Instruction) Arg3() (Value, Value, Value) {
   153  	return i.v, i.v2, i.v3
   154  }
   155  
   156  // Next returns the next instruction laid out next to itself.
   157  func (i *Instruction) Next() *Instruction {
   158  	return i.next
   159  }
   160  
   161  // Prev returns the previous instruction laid out prior to itself.
   162  func (i *Instruction) Prev() *Instruction {
   163  	return i.prev
   164  }
   165  
   166  // IsBranching returns true if this instruction is a branching instruction.
   167  func (i *Instruction) IsBranching() bool {
   168  	switch i.opcode {
   169  	case OpcodeJump, OpcodeBrz, OpcodeBrnz, OpcodeBrTable:
   170  		return true
   171  	default:
   172  		return false
   173  	}
   174  }
   175  
   176  // TODO: complete opcode comments.
   177  const (
   178  	OpcodeInvalid Opcode = iota
   179  
   180  	// OpcodeUndefined is a placeholder for undefined opcode. This can be used for debugging to intentionally
   181  	// cause a crash at certain point.
   182  	OpcodeUndefined
   183  
   184  	// OpcodeJump takes the list of args to the `block` and unconditionally jumps to it.
   185  	OpcodeJump
   186  
   187  	// OpcodeBrz branches into `blk` with `args`  if the value `c` equals zero: `Brz c, blk, args`.
   188  	OpcodeBrz
   189  
   190  	// OpcodeBrnz branches into `blk` with `args`  if the value `c` is not zero: `Brnz c, blk, args`.
   191  	OpcodeBrnz
   192  
   193  	// OpcodeBrTable takes the index value `index`, and branches into `labelX`. If the `index` is out of range,
   194  	// it branches into the last labelN: `BrTable index, [label1, label2, ... labelN]`.
   195  	OpcodeBrTable
   196  
   197  	// OpcodeExitWithCode exit the execution immediately.
   198  	OpcodeExitWithCode
   199  
   200  	// OpcodeExitIfTrueWithCode exits the execution immediately if the value `c` is not zero.
   201  	OpcodeExitIfTrueWithCode
   202  
   203  	// OpcodeReturn returns from the function: `return rvalues`.
   204  	OpcodeReturn
   205  
   206  	// OpcodeCall calls a function specified by the symbol FN with arguments `args`: `returnvals = Call FN, args...`
   207  	// This is a "near" call, which means the call target is known at compile time, and the target is relatively close
   208  	// to this function. If the target cannot be reached by near call, the backend fails to compile.
   209  	OpcodeCall
   210  
   211  	// OpcodeCallIndirect calls a function specified by `callee` which is a function address: `returnvals = call_indirect SIG, callee, args`.
   212  	// Note that this is different from call_indirect in Wasm, which also does type checking, etc.
   213  	OpcodeCallIndirect
   214  
   215  	// OpcodeSplat performs a vector splat operation: `v = Splat.lane x`.
   216  	OpcodeSplat
   217  
   218  	// OpcodeSwizzle performs a vector swizzle operation: `v = Swizzle.lane x, y`.
   219  	OpcodeSwizzle
   220  
   221  	// OpcodeInsertlane inserts a lane value into a vector: `v = InsertLane x, y, Idx`.
   222  	OpcodeInsertlane
   223  
   224  	// OpcodeExtractlane extracts a lane value from a vector: `v = ExtractLane x, Idx`.
   225  	OpcodeExtractlane
   226  
   227  	// OpcodeLoad loads a Type value from the [base + offset] address: `v = Load base, offset`.
   228  	OpcodeLoad
   229  
   230  	// OpcodeStore stores a Type value to the [base + offset] address: `Store v, base, offset`.
   231  	OpcodeStore
   232  
   233  	// OpcodeUload8 loads the 8-bit value from the [base + offset] address, zero-extended to 64 bits: `v = Uload8 base, offset`.
   234  	OpcodeUload8
   235  
   236  	// OpcodeSload8 loads the 8-bit value from the [base + offset] address, sign-extended to 64 bits: `v = Sload8 base, offset`.
   237  	OpcodeSload8
   238  
   239  	// OpcodeIstore8 stores the 8-bit value to the [base + offset] address, sign-extended to 64 bits: `Istore8 v, base, offset`.
   240  	OpcodeIstore8
   241  
   242  	// OpcodeUload16 loads the 16-bit value from the [base + offset] address, zero-extended to 64 bits: `v = Uload16 base, offset`.
   243  	OpcodeUload16
   244  
   245  	// OpcodeSload16 loads the 16-bit value from the [base + offset] address, sign-extended to 64 bits: `v = Sload16 base, offset`.
   246  	OpcodeSload16
   247  
   248  	// OpcodeIstore16 stores the 16-bit value to the [base + offset] address, zero-extended to 64 bits: `Istore16 v, base, offset`.
   249  	OpcodeIstore16
   250  
   251  	// OpcodeUload32 loads the 32-bit value from the [base + offset] address, zero-extended to 64 bits: `v = Uload32 base, offset`.
   252  	OpcodeUload32
   253  
   254  	// OpcodeSload32 loads the 32-bit value from the [base + offset] address, sign-extended to 64 bits: `v = Sload32 base, offset`.
   255  	OpcodeSload32
   256  
   257  	// OpcodeIstore32 stores the 32-bit value to the [base + offset] address, zero-extended to 64 bits: `Istore16 v, base, offset`.
   258  	OpcodeIstore32
   259  
   260  	// OpcodeLoadSplat represents a load that replicates the loaded value to all lanes `v = LoadSplat.lane p, Offset`.
   261  	OpcodeLoadSplat
   262  
   263  	// OpcodeVZeroExtLoad loads a scalar single/double precision floating point value from the [p + Offset] address,
   264  	// and zero-extend it to the V128 value: `v = VExtLoad  p, Offset`.
   265  	OpcodeVZeroExtLoad
   266  
   267  	// OpcodeIconst represents the integer const.
   268  	OpcodeIconst
   269  
   270  	// OpcodeF32const represents the single-precision const.
   271  	OpcodeF32const
   272  
   273  	// OpcodeF64const represents the double-precision const.
   274  	OpcodeF64const
   275  
   276  	// OpcodeVconst represents the 128bit vector const.
   277  	OpcodeVconst
   278  
   279  	// OpcodeVbor computes binary or between two 128bit vectors: `v = bor x, y`.
   280  	OpcodeVbor
   281  
   282  	// OpcodeVbxor computes binary xor between two 128bit vectors: `v = bxor x, y`.
   283  	OpcodeVbxor
   284  
   285  	// OpcodeVband computes binary and between two 128bit vectors: `v = band x, y`.
   286  	OpcodeVband
   287  
   288  	// OpcodeVbandnot computes binary and-not between two 128bit vectors: `v = bandnot x, y`.
   289  	OpcodeVbandnot
   290  
   291  	// OpcodeVbnot negates a 128bit vector: `v = bnot x`.
   292  	OpcodeVbnot
   293  
   294  	// OpcodeVbitselect uses the bits in the control mask c to select the corresponding bit from x when 1
   295  	// and y when 0: `v = bitselect c, x, y`.
   296  	OpcodeVbitselect
   297  
   298  	// OpcodeShuffle shuffles two vectors using the given 128-bit immediate: `v = shuffle imm, x, y`.
   299  	// For each byte in the immediate, a value i in [0, 15] selects the i-th byte in vector x;
   300  	// i in [16, 31] selects the (i-16)-th byte in vector y.
   301  	OpcodeShuffle
   302  
   303  	// OpcodeSelect chooses between two values based on a condition `c`: `v = Select c, x, y`.
   304  	OpcodeSelect
   305  
   306  	// OpcodeVanyTrue performs a any true operation: `s = VanyTrue a`.
   307  	OpcodeVanyTrue
   308  
   309  	// OpcodeVallTrue performs a lane-wise all true operation: `s = VallTrue.lane a`.
   310  	OpcodeVallTrue
   311  
   312  	// OpcodeVhighBits performs a lane-wise extract of the high bits: `v = VhighBits.lane a`.
   313  	OpcodeVhighBits
   314  
   315  	// OpcodeIcmp compares two integer values with the given condition: `v = icmp Cond, x, y`.
   316  	OpcodeIcmp
   317  
   318  	// OpcodeVIcmp compares two integer values with the given condition: `v = vicmp Cond, x, y` on vector.
   319  	OpcodeVIcmp
   320  
   321  	// OpcodeIcmpImm compares an integer value with the immediate value on the given condition: `v = icmp_imm Cond, x, Y`.
   322  	OpcodeIcmpImm
   323  
   324  	// OpcodeIadd performs an integer addition: `v = Iadd x, y`.
   325  	OpcodeIadd
   326  
   327  	// OpcodeVIadd performs an integer addition: `v = VIadd.lane x, y` on vector.
   328  	OpcodeVIadd
   329  
   330  	// OpcodeVSaddSat performs a signed saturating vector addition: `v = VSaddSat.lane x, y` on vector.
   331  	OpcodeVSaddSat
   332  
   333  	// OpcodeVUaddSat performs an unsigned saturating vector addition: `v = VUaddSat.lane x, y` on vector.
   334  	OpcodeVUaddSat
   335  
   336  	// OpcodeIsub performs an integer subtraction: `v = Isub x, y`.
   337  	OpcodeIsub
   338  
   339  	// OpcodeVIsub performs an integer subtraction: `v = VIsub.lane x, y` on vector.
   340  	OpcodeVIsub
   341  
   342  	// OpcodeVSsubSat performs a signed saturating vector subtraction: `v = VSsubSat.lane x, y` on vector.
   343  	OpcodeVSsubSat
   344  
   345  	// OpcodeVUsubSat performs an unsigned saturating vector subtraction: `v = VUsubSat.lane x, y` on vector.
   346  	OpcodeVUsubSat
   347  
   348  	// OpcodeVImin performs a signed integer min: `v = VImin.lane x, y` on vector.
   349  	OpcodeVImin
   350  
   351  	// OpcodeVUmin performs an unsigned integer min: `v = VUmin.lane x, y` on vector.
   352  	OpcodeVUmin
   353  
   354  	// OpcodeVImax performs a signed integer max: `v = VImax.lane x, y` on vector.
   355  	OpcodeVImax
   356  
   357  	// OpcodeVUmax performs an unsigned integer max: `v = VUmax.lane x, y` on vector.
   358  	OpcodeVUmax
   359  
   360  	// OpcodeVAvgRound performs an unsigned integer avg, truncating to zero: `v = VAvgRound.lane x, y` on vector.
   361  	OpcodeVAvgRound
   362  
   363  	// OpcodeVImul performs an integer multiplication: `v = VImul.lane x, y` on vector.
   364  	OpcodeVImul
   365  
   366  	// OpcodeVIneg negates the given integer vector value: `v = VIneg x`.
   367  	OpcodeVIneg
   368  
   369  	// OpcodeVIpopcnt counts the number of 1-bits in the given vector: `v = VIpopcnt x`.
   370  	OpcodeVIpopcnt
   371  
   372  	// OpcodeVIabs returns the absolute value for the given vector value: `v = VIabs.lane x`.
   373  	OpcodeVIabs
   374  
   375  	// OpcodeVIshl shifts x left by (y mod lane-width): `v = VIshl.lane x, y` on vector.
   376  	OpcodeVIshl
   377  
   378  	// OpcodeVUshr shifts x right by (y mod lane-width), unsigned: `v = VUshr.lane x, y` on vector.
   379  	OpcodeVUshr
   380  
   381  	// OpcodeVSshr shifts x right by (y mod lane-width), signed: `v = VSshr.lane x, y` on vector.
   382  	OpcodeVSshr
   383  
   384  	// OpcodeVFabs takes the absolute value of a floating point value: `v = VFabs.lane x on vector.
   385  	OpcodeVFabs
   386  
   387  	// OpcodeVFmax takes the maximum of two floating point values: `v = VFmax.lane x, y on vector.
   388  	OpcodeVFmax
   389  
   390  	// OpcodeVFmin takes the minimum of two floating point values: `v = VFmin.lane x, y on vector.
   391  	OpcodeVFmin
   392  
   393  	// OpcodeVFneg negates the given floating point vector value: `v = VFneg x`.
   394  	OpcodeVFneg
   395  
   396  	// OpcodeVFadd performs a floating point addition: `v = VFadd.lane x, y` on vector.
   397  	OpcodeVFadd
   398  
   399  	// OpcodeVFsub performs a floating point subtraction: `v = VFsub.lane x, y` on vector.
   400  	OpcodeVFsub
   401  
   402  	// OpcodeVFmul performs a floating point multiplication: `v = VFmul.lane x, y` on vector.
   403  	OpcodeVFmul
   404  
   405  	// OpcodeVFdiv performs a floating point division: `v = VFdiv.lane x, y` on vector.
   406  	OpcodeVFdiv
   407  
   408  	// OpcodeVFcmp compares two float values with the given condition: `v = VFcmp.lane Cond, x, y` on float.
   409  	OpcodeVFcmp
   410  
   411  	// OpcodeVCeil takes the ceiling of the given floating point value: `v = ceil.lane x` on vector.
   412  	OpcodeVCeil
   413  
   414  	// OpcodeVFloor takes the floor of the given floating point value: `v = floor.lane x` on vector.
   415  	OpcodeVFloor
   416  
   417  	// OpcodeVTrunc takes the truncation of the given floating point value: `v = trunc.lane x` on vector.
   418  	OpcodeVTrunc
   419  
   420  	// OpcodeVNearest takes the nearest integer of the given floating point value: `v = nearest.lane x` on vector.
   421  	OpcodeVNearest
   422  
   423  	// OpcodeVMaxPseudo computes the lane-wise maximum value `v = VMaxPseudo.lane x, y` on vector defined as `x < y ? x : y`.
   424  	OpcodeVMaxPseudo
   425  
   426  	// OpcodeVMinPseudo computes the lane-wise minimum value `v = VMinPseudo.lane x, y` on vector defined as `y < x ? x : y`.
   427  	OpcodeVMinPseudo
   428  
   429  	// OpcodeVSqrt takes the minimum of two floating point values: `v = VFmin.lane x, y` on vector.
   430  	OpcodeVSqrt
   431  
   432  	// OpcodeVFcvtToUintSat converts a floating point value to an unsigned integer: `v = FcvtToUintSat.lane x` on vector.
   433  	OpcodeVFcvtToUintSat
   434  
   435  	// OpcodeVFcvtToSintSat converts a floating point value to a signed integer: `v = VFcvtToSintSat.lane x` on vector.
   436  	OpcodeVFcvtToSintSat
   437  
   438  	// OpcodeVFcvtFromUint converts a floating point value from an unsigned integer: `v = FcvtFromUint.lane x` on vector.
   439  	// x is always a 32-bit integer lane, and the result is either a 32-bit or 64-bit floating point-sized vector.
   440  	OpcodeVFcvtFromUint
   441  
   442  	// OpcodeVFcvtFromSint converts a floating point value from a signed integer: `v = VFcvtFromSint.lane x` on vector.
   443  	// x is always a 32-bit integer lane, and the result is either a 32-bit or 64-bit floating point-sized vector.
   444  	OpcodeVFcvtFromSint
   445  
   446  	// OpcodeImul performs an integer multiplication: `v = Imul x, y`.
   447  	OpcodeImul
   448  
   449  	// OpcodeUdiv performs the unsigned integer division `v = Udiv x, y`.
   450  	OpcodeUdiv
   451  
   452  	// OpcodeSdiv performs the signed integer division `v = Sdiv x, y`.
   453  	OpcodeSdiv
   454  
   455  	// OpcodeUrem computes the remainder of the unsigned integer division `v = Urem x, y`.
   456  	OpcodeUrem
   457  
   458  	// OpcodeSrem computes the remainder of the signed integer division `v = Srem x, y`.
   459  	OpcodeSrem
   460  
   461  	// OpcodeBand performs a binary and: `v = Band x, y`.
   462  	OpcodeBand
   463  
   464  	// OpcodeBor performs a binary or: `v = Bor x, y`.
   465  	OpcodeBor
   466  
   467  	// OpcodeBxor performs a binary xor: `v = Bxor x, y`.
   468  	OpcodeBxor
   469  
   470  	// OpcodeBnot performs a binary not: `v = Bnot x`.
   471  	OpcodeBnot
   472  
   473  	// OpcodeRotl rotates the given integer value to the left: `v = Rotl x, y`.
   474  	OpcodeRotl
   475  
   476  	// OpcodeRotr rotates the given integer value to the right: `v = Rotr x, y`.
   477  	OpcodeRotr
   478  
   479  	// OpcodeIshl does logical shift left: `v = Ishl x, y`.
   480  	OpcodeIshl
   481  
   482  	// OpcodeUshr does logical shift right: `v = Ushr x, y`.
   483  	OpcodeUshr
   484  
   485  	// OpcodeSshr does arithmetic shift right: `v = Sshr x, y`.
   486  	OpcodeSshr
   487  
   488  	// OpcodeClz counts the number of leading zeros: `v = clz x`.
   489  	OpcodeClz
   490  
   491  	// OpcodeCtz counts the number of trailing zeros: `v = ctz x`.
   492  	OpcodeCtz
   493  
   494  	// OpcodePopcnt counts the number of 1-bits: `v = popcnt x`.
   495  	OpcodePopcnt
   496  
   497  	// OpcodeFcmp compares two floating point values: `v = fcmp Cond, x, y`.
   498  	OpcodeFcmp
   499  
   500  	// OpcodeFadd performs a floating point addition: / `v = Fadd x, y`.
   501  	OpcodeFadd
   502  
   503  	// OpcodeFsub performs a floating point subtraction: `v = Fsub x, y`.
   504  	OpcodeFsub
   505  
   506  	// OpcodeFmul performs a floating point multiplication: `v = Fmul x, y`.
   507  	OpcodeFmul
   508  
   509  	// OpcodeSqmulRoundSat performs a lane-wise saturating rounding multiplication
   510  	// in Q15 format: `v = SqmulRoundSat.lane x,y` on vector.
   511  	OpcodeSqmulRoundSat
   512  
   513  	// OpcodeFdiv performs a floating point division: `v = Fdiv x, y`.
   514  	OpcodeFdiv
   515  
   516  	// OpcodeSqrt takes the square root of the given floating point value: `v = sqrt x`.
   517  	OpcodeSqrt
   518  
   519  	// OpcodeFneg negates the given floating point value: `v = Fneg x`.
   520  	OpcodeFneg
   521  
   522  	// OpcodeFabs takes the absolute value of the given floating point value: `v = fabs x`.
   523  	OpcodeFabs
   524  
   525  	// OpcodeFcopysign copies the sign of the second floating point value to the first floating point value:
   526  	// `v = Fcopysign x, y`.
   527  	OpcodeFcopysign
   528  
   529  	// OpcodeFmin takes the minimum of two floating point values: `v = fmin x, y`.
   530  	OpcodeFmin
   531  
   532  	// OpcodeFmax takes the maximum of two floating point values: `v = fmax x, y`.
   533  	OpcodeFmax
   534  
   535  	// OpcodeCeil takes the ceiling of the given floating point value: `v = ceil x`.
   536  	OpcodeCeil
   537  
   538  	// OpcodeFloor takes the floor of the given floating point value: `v = floor x`.
   539  	OpcodeFloor
   540  
   541  	// OpcodeTrunc takes the truncation of the given floating point value: `v = trunc x`.
   542  	OpcodeTrunc
   543  
   544  	// OpcodeNearest takes the nearest integer of the given floating point value: `v = nearest x`.
   545  	OpcodeNearest
   546  
   547  	// OpcodeBitcast is a bitcast operation: `v = bitcast x`.
   548  	OpcodeBitcast
   549  
   550  	// OpcodeIreduce narrow the given integer: `v = Ireduce x`.
   551  	OpcodeIreduce
   552  
   553  	// OpcodeSnarrow converts two input vectors x, y into a smaller lane vector by narrowing each lane, signed `v = Snarrow.lane x, y`.
   554  	OpcodeSnarrow
   555  
   556  	// OpcodeUnarrow converts two input vectors x, y into a smaller lane vector by narrowing each lane, unsigned `v = Unarrow.lane x, y`.
   557  	OpcodeUnarrow
   558  
   559  	// OpcodeSwidenLow converts low half of the smaller lane vector to a larger lane vector, sign extended: `v = SwidenLow.lane x`.
   560  	OpcodeSwidenLow
   561  
   562  	// OpcodeSwidenHigh converts high half of the smaller lane vector to a larger lane vector, sign extended: `v = SwidenHigh.lane x`.
   563  	OpcodeSwidenHigh
   564  
   565  	// OpcodeUwidenLow converts low half of the smaller lane vector to a larger lane vector, zero (unsigned) extended: `v = UwidenLow.lane x`.
   566  	OpcodeUwidenLow
   567  
   568  	// OpcodeUwidenHigh converts high half of the smaller lane vector to a larger lane vector, zero (unsigned) extended: `v = UwidenHigh.lane x`.
   569  	OpcodeUwidenHigh
   570  
   571  	// OpcodeExtIaddPairwise is a lane-wise integer extended pairwise addition producing extended results (twice wider results than the inputs): `v = extiadd_pairwise x, y` on vector.
   572  	OpcodeExtIaddPairwise
   573  
   574  	// OpcodeWideningPairwiseDotProductS is a lane-wise widening pairwise dot product with signed saturation: `v = WideningPairwiseDotProductS x, y` on vector.
   575  	// Currently, the only lane is i16, and the result is i32.
   576  	OpcodeWideningPairwiseDotProductS
   577  
   578  	// OpcodeUExtend zero-extends the given integer: `v = UExtend x, from->to`.
   579  	OpcodeUExtend
   580  
   581  	// OpcodeSExtend sign-extends the given integer: `v = SExtend x, from->to`.
   582  	OpcodeSExtend
   583  
   584  	// OpcodeFpromote promotes the given floating point value: `v = Fpromote x`.
   585  	OpcodeFpromote
   586  
   587  	// OpcodeFvpromoteLow converts the two lower single-precision floating point lanes
   588  	// to the two double-precision lanes of the result: `v = FvpromoteLow.lane x` on vector.
   589  	OpcodeFvpromoteLow
   590  
   591  	// OpcodeFdemote demotes the given float point value: `v = Fdemote x`.
   592  	OpcodeFdemote
   593  
   594  	// OpcodeFvdemote converts the two double-precision floating point lanes
   595  	// to two lower single-precision lanes of the result `v = Fvdemote.lane x`.
   596  	OpcodeFvdemote
   597  
   598  	// OpcodeFcvtToUint converts a floating point value to an unsigned integer: `v = FcvtToUint x`.
   599  	OpcodeFcvtToUint
   600  
   601  	// OpcodeFcvtToSint converts a floating point value to a signed integer: `v = FcvtToSint x`.
   602  	OpcodeFcvtToSint
   603  
   604  	// OpcodeFcvtToUintSat converts a floating point value to an unsigned integer: `v = FcvtToUintSat x` which saturates on overflow.
   605  	OpcodeFcvtToUintSat
   606  
   607  	// OpcodeFcvtToSintSat converts a floating point value to a signed integer: `v = FcvtToSintSat x` which saturates on overflow.
   608  	OpcodeFcvtToSintSat
   609  
   610  	// OpcodeFcvtFromUint converts an unsigned integer to a floating point value: `v = FcvtFromUint x`.
   611  	OpcodeFcvtFromUint
   612  
   613  	// OpcodeFcvtFromSint converts a signed integer to a floating point value: `v = FcvtFromSint x`.
   614  	OpcodeFcvtFromSint
   615  
   616  	// OpcodeAtomicRmw is atomic read-modify-write operation: `v = atomic_rmw op, p, offset, value`.
   617  	OpcodeAtomicRmw
   618  
   619  	// OpcodeAtomicCas is atomic compare-and-swap operation.
   620  	OpcodeAtomicCas
   621  
   622  	// OpcodeAtomicLoad is atomic load operation.
   623  	OpcodeAtomicLoad
   624  
   625  	// OpcodeAtomicStore is atomic store operation.
   626  	OpcodeAtomicStore
   627  
   628  	// OpcodeFence is a memory fence operation.
   629  	OpcodeFence
   630  
   631  	// opcodeEnd marks the end of the opcode list.
   632  	opcodeEnd
   633  )
   634  
   635  // AtomicRmwOp represents the atomic read-modify-write operation.
   636  type AtomicRmwOp byte
   637  
   638  const (
   639  	// AtomicRmwOpAdd is an atomic add operation.
   640  	AtomicRmwOpAdd AtomicRmwOp = iota
   641  	// AtomicRmwOpSub is an atomic sub operation.
   642  	AtomicRmwOpSub
   643  	// AtomicRmwOpAnd is an atomic and operation.
   644  	AtomicRmwOpAnd
   645  	// AtomicRmwOpOr is an atomic or operation.
   646  	AtomicRmwOpOr
   647  	// AtomicRmwOpXor is an atomic xor operation.
   648  	AtomicRmwOpXor
   649  	// AtomicRmwOpXchg is an atomic swap operation.
   650  	AtomicRmwOpXchg
   651  )
   652  
   653  // String implements the fmt.Stringer.
   654  func (op AtomicRmwOp) String() string {
   655  	switch op {
   656  	case AtomicRmwOpAdd:
   657  		return "add"
   658  	case AtomicRmwOpSub:
   659  		return "sub"
   660  	case AtomicRmwOpAnd:
   661  		return "and"
   662  	case AtomicRmwOpOr:
   663  		return "or"
   664  	case AtomicRmwOpXor:
   665  		return "xor"
   666  	case AtomicRmwOpXchg:
   667  		return "xchg"
   668  	}
   669  	panic(fmt.Sprintf("unknown AtomicRmwOp: %d", op))
   670  }
   671  
   672  // returnTypesFn provides the info to determine the type of instruction.
   673  // t1 is the type of the first result, ts are the types of the remaining results.
   674  type returnTypesFn func(b *builder, instr *Instruction) (t1 Type, ts []Type)
   675  
   676  var (
   677  	returnTypesFnNoReturns returnTypesFn = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return typeInvalid, nil }
   678  	returnTypesFnSingle                  = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return instr.typ, nil }
   679  	returnTypesFnI32                     = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return TypeI32, nil }
   680  	returnTypesFnF32                     = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return TypeF32, nil }
   681  	returnTypesFnF64                     = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return TypeF64, nil }
   682  	returnTypesFnV128                    = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return TypeV128, nil }
   683  )
   684  
   685  // sideEffect provides the info to determine if an instruction has side effects which
   686  // is used to determine if it can be optimized out, interchanged with others, etc.
   687  type sideEffect byte
   688  
   689  const (
   690  	sideEffectUnknown sideEffect = iota
   691  	// sideEffectStrict represents an instruction with side effects, and should be always alive plus cannot be reordered.
   692  	sideEffectStrict
   693  	// sideEffectTraps represents an instruction that can trap, and should be always alive but can be reordered within the group.
   694  	sideEffectTraps
   695  	// sideEffectNone represents an instruction without side effects, and can be eliminated if the result is not used, plus can be reordered within the group.
   696  	sideEffectNone
   697  )
   698  
   699  // instructionSideEffects provides the info to determine if an instruction has side effects.
   700  // Instructions with side effects must not be eliminated regardless whether the result is used or not.
   701  var instructionSideEffects = [opcodeEnd]sideEffect{
   702  	OpcodeUndefined:                   sideEffectStrict,
   703  	OpcodeJump:                        sideEffectStrict,
   704  	OpcodeIconst:                      sideEffectNone,
   705  	OpcodeCall:                        sideEffectStrict,
   706  	OpcodeCallIndirect:                sideEffectStrict,
   707  	OpcodeIadd:                        sideEffectNone,
   708  	OpcodeImul:                        sideEffectNone,
   709  	OpcodeIsub:                        sideEffectNone,
   710  	OpcodeIcmp:                        sideEffectNone,
   711  	OpcodeExtractlane:                 sideEffectNone,
   712  	OpcodeInsertlane:                  sideEffectNone,
   713  	OpcodeBand:                        sideEffectNone,
   714  	OpcodeBor:                         sideEffectNone,
   715  	OpcodeBxor:                        sideEffectNone,
   716  	OpcodeRotl:                        sideEffectNone,
   717  	OpcodeRotr:                        sideEffectNone,
   718  	OpcodeFcmp:                        sideEffectNone,
   719  	OpcodeFadd:                        sideEffectNone,
   720  	OpcodeClz:                         sideEffectNone,
   721  	OpcodeCtz:                         sideEffectNone,
   722  	OpcodePopcnt:                      sideEffectNone,
   723  	OpcodeLoad:                        sideEffectNone,
   724  	OpcodeLoadSplat:                   sideEffectNone,
   725  	OpcodeUload8:                      sideEffectNone,
   726  	OpcodeUload16:                     sideEffectNone,
   727  	OpcodeUload32:                     sideEffectNone,
   728  	OpcodeSload8:                      sideEffectNone,
   729  	OpcodeSload16:                     sideEffectNone,
   730  	OpcodeSload32:                     sideEffectNone,
   731  	OpcodeSExtend:                     sideEffectNone,
   732  	OpcodeUExtend:                     sideEffectNone,
   733  	OpcodeSwidenLow:                   sideEffectNone,
   734  	OpcodeUwidenLow:                   sideEffectNone,
   735  	OpcodeSwidenHigh:                  sideEffectNone,
   736  	OpcodeUwidenHigh:                  sideEffectNone,
   737  	OpcodeSnarrow:                     sideEffectNone,
   738  	OpcodeUnarrow:                     sideEffectNone,
   739  	OpcodeSwizzle:                     sideEffectNone,
   740  	OpcodeShuffle:                     sideEffectNone,
   741  	OpcodeSplat:                       sideEffectNone,
   742  	OpcodeFsub:                        sideEffectNone,
   743  	OpcodeF32const:                    sideEffectNone,
   744  	OpcodeF64const:                    sideEffectNone,
   745  	OpcodeIshl:                        sideEffectNone,
   746  	OpcodeSshr:                        sideEffectNone,
   747  	OpcodeUshr:                        sideEffectNone,
   748  	OpcodeStore:                       sideEffectStrict,
   749  	OpcodeIstore8:                     sideEffectStrict,
   750  	OpcodeIstore16:                    sideEffectStrict,
   751  	OpcodeIstore32:                    sideEffectStrict,
   752  	OpcodeExitWithCode:                sideEffectStrict,
   753  	OpcodeExitIfTrueWithCode:          sideEffectStrict,
   754  	OpcodeReturn:                      sideEffectStrict,
   755  	OpcodeBrz:                         sideEffectStrict,
   756  	OpcodeBrnz:                        sideEffectStrict,
   757  	OpcodeBrTable:                     sideEffectStrict,
   758  	OpcodeFdiv:                        sideEffectNone,
   759  	OpcodeFmul:                        sideEffectNone,
   760  	OpcodeFmax:                        sideEffectNone,
   761  	OpcodeSqmulRoundSat:               sideEffectNone,
   762  	OpcodeSelect:                      sideEffectNone,
   763  	OpcodeFmin:                        sideEffectNone,
   764  	OpcodeFneg:                        sideEffectNone,
   765  	OpcodeFcvtToSint:                  sideEffectTraps,
   766  	OpcodeFcvtToUint:                  sideEffectTraps,
   767  	OpcodeFcvtFromSint:                sideEffectNone,
   768  	OpcodeFcvtFromUint:                sideEffectNone,
   769  	OpcodeFcvtToSintSat:               sideEffectNone,
   770  	OpcodeFcvtToUintSat:               sideEffectNone,
   771  	OpcodeVFcvtFromUint:               sideEffectNone,
   772  	OpcodeVFcvtFromSint:               sideEffectNone,
   773  	OpcodeFdemote:                     sideEffectNone,
   774  	OpcodeFvpromoteLow:                sideEffectNone,
   775  	OpcodeFvdemote:                    sideEffectNone,
   776  	OpcodeFpromote:                    sideEffectNone,
   777  	OpcodeBitcast:                     sideEffectNone,
   778  	OpcodeIreduce:                     sideEffectNone,
   779  	OpcodeSqrt:                        sideEffectNone,
   780  	OpcodeCeil:                        sideEffectNone,
   781  	OpcodeFloor:                       sideEffectNone,
   782  	OpcodeTrunc:                       sideEffectNone,
   783  	OpcodeNearest:                     sideEffectNone,
   784  	OpcodeSdiv:                        sideEffectTraps,
   785  	OpcodeSrem:                        sideEffectTraps,
   786  	OpcodeUdiv:                        sideEffectTraps,
   787  	OpcodeUrem:                        sideEffectTraps,
   788  	OpcodeFabs:                        sideEffectNone,
   789  	OpcodeFcopysign:                   sideEffectNone,
   790  	OpcodeExtIaddPairwise:             sideEffectNone,
   791  	OpcodeVconst:                      sideEffectNone,
   792  	OpcodeVbor:                        sideEffectNone,
   793  	OpcodeVbxor:                       sideEffectNone,
   794  	OpcodeVband:                       sideEffectNone,
   795  	OpcodeVbandnot:                    sideEffectNone,
   796  	OpcodeVbnot:                       sideEffectNone,
   797  	OpcodeVbitselect:                  sideEffectNone,
   798  	OpcodeVanyTrue:                    sideEffectNone,
   799  	OpcodeVallTrue:                    sideEffectNone,
   800  	OpcodeVhighBits:                   sideEffectNone,
   801  	OpcodeVIadd:                       sideEffectNone,
   802  	OpcodeVSaddSat:                    sideEffectNone,
   803  	OpcodeVUaddSat:                    sideEffectNone,
   804  	OpcodeVIsub:                       sideEffectNone,
   805  	OpcodeVSsubSat:                    sideEffectNone,
   806  	OpcodeVUsubSat:                    sideEffectNone,
   807  	OpcodeVIcmp:                       sideEffectNone,
   808  	OpcodeVImin:                       sideEffectNone,
   809  	OpcodeVUmin:                       sideEffectNone,
   810  	OpcodeVImax:                       sideEffectNone,
   811  	OpcodeVUmax:                       sideEffectNone,
   812  	OpcodeVAvgRound:                   sideEffectNone,
   813  	OpcodeVImul:                       sideEffectNone,
   814  	OpcodeVIabs:                       sideEffectNone,
   815  	OpcodeVIneg:                       sideEffectNone,
   816  	OpcodeVIpopcnt:                    sideEffectNone,
   817  	OpcodeVIshl:                       sideEffectNone,
   818  	OpcodeVSshr:                       sideEffectNone,
   819  	OpcodeVUshr:                       sideEffectNone,
   820  	OpcodeVSqrt:                       sideEffectNone,
   821  	OpcodeVFabs:                       sideEffectNone,
   822  	OpcodeVFmin:                       sideEffectNone,
   823  	OpcodeVFmax:                       sideEffectNone,
   824  	OpcodeVFneg:                       sideEffectNone,
   825  	OpcodeVFadd:                       sideEffectNone,
   826  	OpcodeVFsub:                       sideEffectNone,
   827  	OpcodeVFmul:                       sideEffectNone,
   828  	OpcodeVFdiv:                       sideEffectNone,
   829  	OpcodeVFcmp:                       sideEffectNone,
   830  	OpcodeVCeil:                       sideEffectNone,
   831  	OpcodeVFloor:                      sideEffectNone,
   832  	OpcodeVTrunc:                      sideEffectNone,
   833  	OpcodeVNearest:                    sideEffectNone,
   834  	OpcodeVMaxPseudo:                  sideEffectNone,
   835  	OpcodeVMinPseudo:                  sideEffectNone,
   836  	OpcodeVFcvtToUintSat:              sideEffectNone,
   837  	OpcodeVFcvtToSintSat:              sideEffectNone,
   838  	OpcodeVZeroExtLoad:                sideEffectNone,
   839  	OpcodeAtomicRmw:                   sideEffectStrict,
   840  	OpcodeAtomicLoad:                  sideEffectStrict,
   841  	OpcodeAtomicStore:                 sideEffectStrict,
   842  	OpcodeAtomicCas:                   sideEffectStrict,
   843  	OpcodeFence:                       sideEffectStrict,
   844  	OpcodeWideningPairwiseDotProductS: sideEffectNone,
   845  }
   846  
   847  // sideEffect returns true if this instruction has side effects.
   848  func (i *Instruction) sideEffect() sideEffect {
   849  	if e := instructionSideEffects[i.opcode]; e == sideEffectUnknown {
   850  		panic("BUG: side effect info not registered for " + i.opcode.String())
   851  	} else {
   852  		return e
   853  	}
   854  }
   855  
   856  // instructionReturnTypes provides the function to determine the return types of an instruction.
   857  var instructionReturnTypes = [opcodeEnd]returnTypesFn{
   858  	OpcodeExtIaddPairwise: returnTypesFnV128,
   859  	OpcodeVbor:            returnTypesFnV128,
   860  	OpcodeVbxor:           returnTypesFnV128,
   861  	OpcodeVband:           returnTypesFnV128,
   862  	OpcodeVbnot:           returnTypesFnV128,
   863  	OpcodeVbandnot:        returnTypesFnV128,
   864  	OpcodeVbitselect:      returnTypesFnV128,
   865  	OpcodeVanyTrue:        returnTypesFnI32,
   866  	OpcodeVallTrue:        returnTypesFnI32,
   867  	OpcodeVhighBits:       returnTypesFnI32,
   868  	OpcodeVIadd:           returnTypesFnV128,
   869  	OpcodeVSaddSat:        returnTypesFnV128,
   870  	OpcodeVUaddSat:        returnTypesFnV128,
   871  	OpcodeVIsub:           returnTypesFnV128,
   872  	OpcodeVSsubSat:        returnTypesFnV128,
   873  	OpcodeVUsubSat:        returnTypesFnV128,
   874  	OpcodeVIcmp:           returnTypesFnV128,
   875  	OpcodeVImin:           returnTypesFnV128,
   876  	OpcodeVUmin:           returnTypesFnV128,
   877  	OpcodeVImax:           returnTypesFnV128,
   878  	OpcodeVUmax:           returnTypesFnV128,
   879  	OpcodeVImul:           returnTypesFnV128,
   880  	OpcodeVAvgRound:       returnTypesFnV128,
   881  	OpcodeVIabs:           returnTypesFnV128,
   882  	OpcodeVIneg:           returnTypesFnV128,
   883  	OpcodeVIpopcnt:        returnTypesFnV128,
   884  	OpcodeVIshl:           returnTypesFnV128,
   885  	OpcodeVSshr:           returnTypesFnV128,
   886  	OpcodeVUshr:           returnTypesFnV128,
   887  	OpcodeExtractlane:     returnTypesFnSingle,
   888  	OpcodeInsertlane:      returnTypesFnV128,
   889  	OpcodeBand:            returnTypesFnSingle,
   890  	OpcodeFcopysign:       returnTypesFnSingle,
   891  	OpcodeBitcast:         returnTypesFnSingle,
   892  	OpcodeBor:             returnTypesFnSingle,
   893  	OpcodeBxor:            returnTypesFnSingle,
   894  	OpcodeRotl:            returnTypesFnSingle,
   895  	OpcodeRotr:            returnTypesFnSingle,
   896  	OpcodeIshl:            returnTypesFnSingle,
   897  	OpcodeSshr:            returnTypesFnSingle,
   898  	OpcodeSdiv:            returnTypesFnSingle,
   899  	OpcodeSrem:            returnTypesFnSingle,
   900  	OpcodeUdiv:            returnTypesFnSingle,
   901  	OpcodeUrem:            returnTypesFnSingle,
   902  	OpcodeUshr:            returnTypesFnSingle,
   903  	OpcodeJump:            returnTypesFnNoReturns,
   904  	OpcodeUndefined:       returnTypesFnNoReturns,
   905  	OpcodeIconst:          returnTypesFnSingle,
   906  	OpcodeSelect:          returnTypesFnSingle,
   907  	OpcodeSExtend:         returnTypesFnSingle,
   908  	OpcodeUExtend:         returnTypesFnSingle,
   909  	OpcodeSwidenLow:       returnTypesFnV128,
   910  	OpcodeUwidenLow:       returnTypesFnV128,
   911  	OpcodeSwidenHigh:      returnTypesFnV128,
   912  	OpcodeUwidenHigh:      returnTypesFnV128,
   913  	OpcodeSnarrow:         returnTypesFnV128,
   914  	OpcodeUnarrow:         returnTypesFnV128,
   915  	OpcodeSwizzle:         returnTypesFnSingle,
   916  	OpcodeShuffle:         returnTypesFnV128,
   917  	OpcodeSplat:           returnTypesFnV128,
   918  	OpcodeIreduce:         returnTypesFnSingle,
   919  	OpcodeFabs:            returnTypesFnSingle,
   920  	OpcodeSqrt:            returnTypesFnSingle,
   921  	OpcodeCeil:            returnTypesFnSingle,
   922  	OpcodeFloor:           returnTypesFnSingle,
   923  	OpcodeTrunc:           returnTypesFnSingle,
   924  	OpcodeNearest:         returnTypesFnSingle,
   925  	OpcodeCallIndirect: func(b *builder, instr *Instruction) (t1 Type, ts []Type) {
   926  		sigID := SignatureID(instr.u1)
   927  		sig, ok := b.signatures[sigID]
   928  		if !ok {
   929  			panic("BUG")
   930  		}
   931  		switch len(sig.Results) {
   932  		case 0:
   933  			t1 = typeInvalid
   934  		case 1:
   935  			t1 = sig.Results[0]
   936  		default:
   937  			t1, ts = sig.Results[0], sig.Results[1:]
   938  		}
   939  		return
   940  	},
   941  	OpcodeCall: func(b *builder, instr *Instruction) (t1 Type, ts []Type) {
   942  		sigID := SignatureID(instr.u2)
   943  		sig, ok := b.signatures[sigID]
   944  		if !ok {
   945  			panic("BUG")
   946  		}
   947  		switch len(sig.Results) {
   948  		case 0:
   949  			t1 = typeInvalid
   950  		case 1:
   951  			t1 = sig.Results[0]
   952  		default:
   953  			t1, ts = sig.Results[0], sig.Results[1:]
   954  		}
   955  		return
   956  	},
   957  	OpcodeLoad:                        returnTypesFnSingle,
   958  	OpcodeVZeroExtLoad:                returnTypesFnV128,
   959  	OpcodeLoadSplat:                   returnTypesFnV128,
   960  	OpcodeIadd:                        returnTypesFnSingle,
   961  	OpcodeIsub:                        returnTypesFnSingle,
   962  	OpcodeImul:                        returnTypesFnSingle,
   963  	OpcodeIcmp:                        returnTypesFnI32,
   964  	OpcodeFcmp:                        returnTypesFnI32,
   965  	OpcodeFadd:                        returnTypesFnSingle,
   966  	OpcodeFsub:                        returnTypesFnSingle,
   967  	OpcodeFdiv:                        returnTypesFnSingle,
   968  	OpcodeFmul:                        returnTypesFnSingle,
   969  	OpcodeFmax:                        returnTypesFnSingle,
   970  	OpcodeFmin:                        returnTypesFnSingle,
   971  	OpcodeSqmulRoundSat:               returnTypesFnV128,
   972  	OpcodeF32const:                    returnTypesFnF32,
   973  	OpcodeF64const:                    returnTypesFnF64,
   974  	OpcodeClz:                         returnTypesFnSingle,
   975  	OpcodeCtz:                         returnTypesFnSingle,
   976  	OpcodePopcnt:                      returnTypesFnSingle,
   977  	OpcodeStore:                       returnTypesFnNoReturns,
   978  	OpcodeIstore8:                     returnTypesFnNoReturns,
   979  	OpcodeIstore16:                    returnTypesFnNoReturns,
   980  	OpcodeIstore32:                    returnTypesFnNoReturns,
   981  	OpcodeExitWithCode:                returnTypesFnNoReturns,
   982  	OpcodeExitIfTrueWithCode:          returnTypesFnNoReturns,
   983  	OpcodeReturn:                      returnTypesFnNoReturns,
   984  	OpcodeBrz:                         returnTypesFnNoReturns,
   985  	OpcodeBrnz:                        returnTypesFnNoReturns,
   986  	OpcodeBrTable:                     returnTypesFnNoReturns,
   987  	OpcodeUload8:                      returnTypesFnSingle,
   988  	OpcodeUload16:                     returnTypesFnSingle,
   989  	OpcodeUload32:                     returnTypesFnSingle,
   990  	OpcodeSload8:                      returnTypesFnSingle,
   991  	OpcodeSload16:                     returnTypesFnSingle,
   992  	OpcodeSload32:                     returnTypesFnSingle,
   993  	OpcodeFcvtToSint:                  returnTypesFnSingle,
   994  	OpcodeFcvtToUint:                  returnTypesFnSingle,
   995  	OpcodeFcvtFromSint:                returnTypesFnSingle,
   996  	OpcodeFcvtFromUint:                returnTypesFnSingle,
   997  	OpcodeFcvtToSintSat:               returnTypesFnSingle,
   998  	OpcodeFcvtToUintSat:               returnTypesFnSingle,
   999  	OpcodeVFcvtFromUint:               returnTypesFnV128,
  1000  	OpcodeVFcvtFromSint:               returnTypesFnV128,
  1001  	OpcodeFneg:                        returnTypesFnSingle,
  1002  	OpcodeFdemote:                     returnTypesFnF32,
  1003  	OpcodeFvdemote:                    returnTypesFnV128,
  1004  	OpcodeFvpromoteLow:                returnTypesFnV128,
  1005  	OpcodeFpromote:                    returnTypesFnF64,
  1006  	OpcodeVconst:                      returnTypesFnV128,
  1007  	OpcodeVFabs:                       returnTypesFnV128,
  1008  	OpcodeVSqrt:                       returnTypesFnV128,
  1009  	OpcodeVFmax:                       returnTypesFnV128,
  1010  	OpcodeVFmin:                       returnTypesFnV128,
  1011  	OpcodeVFneg:                       returnTypesFnV128,
  1012  	OpcodeVFadd:                       returnTypesFnV128,
  1013  	OpcodeVFsub:                       returnTypesFnV128,
  1014  	OpcodeVFmul:                       returnTypesFnV128,
  1015  	OpcodeVFdiv:                       returnTypesFnV128,
  1016  	OpcodeVFcmp:                       returnTypesFnV128,
  1017  	OpcodeVCeil:                       returnTypesFnV128,
  1018  	OpcodeVFloor:                      returnTypesFnV128,
  1019  	OpcodeVTrunc:                      returnTypesFnV128,
  1020  	OpcodeVNearest:                    returnTypesFnV128,
  1021  	OpcodeVMaxPseudo:                  returnTypesFnV128,
  1022  	OpcodeVMinPseudo:                  returnTypesFnV128,
  1023  	OpcodeVFcvtToUintSat:              returnTypesFnV128,
  1024  	OpcodeVFcvtToSintSat:              returnTypesFnV128,
  1025  	OpcodeAtomicRmw:                   returnTypesFnSingle,
  1026  	OpcodeAtomicLoad:                  returnTypesFnSingle,
  1027  	OpcodeAtomicStore:                 returnTypesFnNoReturns,
  1028  	OpcodeAtomicCas:                   returnTypesFnSingle,
  1029  	OpcodeFence:                       returnTypesFnNoReturns,
  1030  	OpcodeWideningPairwiseDotProductS: returnTypesFnV128,
  1031  }
  1032  
  1033  // AsLoad initializes this instruction as a store instruction with OpcodeLoad.
  1034  func (i *Instruction) AsLoad(ptr Value, offset uint32, typ Type) *Instruction {
  1035  	i.opcode = OpcodeLoad
  1036  	i.v = ptr
  1037  	i.u1 = uint64(offset)
  1038  	i.typ = typ
  1039  	return i
  1040  }
  1041  
  1042  // AsExtLoad initializes this instruction as a store instruction with OpcodeLoad.
  1043  func (i *Instruction) AsExtLoad(op Opcode, ptr Value, offset uint32, dst64bit bool) *Instruction {
  1044  	i.opcode = op
  1045  	i.v = ptr
  1046  	i.u1 = uint64(offset)
  1047  	if dst64bit {
  1048  		i.typ = TypeI64
  1049  	} else {
  1050  		i.typ = TypeI32
  1051  	}
  1052  	return i
  1053  }
  1054  
  1055  // AsVZeroExtLoad initializes this instruction as a store instruction with OpcodeVExtLoad.
  1056  func (i *Instruction) AsVZeroExtLoad(ptr Value, offset uint32, scalarType Type) *Instruction {
  1057  	i.opcode = OpcodeVZeroExtLoad
  1058  	i.v = ptr
  1059  	i.u1 = uint64(offset)
  1060  	i.u2 = uint64(scalarType)
  1061  	i.typ = TypeV128
  1062  	return i
  1063  }
  1064  
  1065  // VZeroExtLoadData returns the operands for a load instruction. The returned `typ` is the scalar type of the load target.
  1066  func (i *Instruction) VZeroExtLoadData() (ptr Value, offset uint32, typ Type) {
  1067  	return i.v, uint32(i.u1), Type(i.u2)
  1068  }
  1069  
  1070  // AsLoadSplat initializes this instruction as a store instruction with OpcodeLoadSplat.
  1071  func (i *Instruction) AsLoadSplat(ptr Value, offset uint32, lane VecLane) *Instruction {
  1072  	i.opcode = OpcodeLoadSplat
  1073  	i.v = ptr
  1074  	i.u1 = uint64(offset)
  1075  	i.u2 = uint64(lane)
  1076  	i.typ = TypeV128
  1077  	return i
  1078  }
  1079  
  1080  // LoadData returns the operands for a load instruction.
  1081  func (i *Instruction) LoadData() (ptr Value, offset uint32, typ Type) {
  1082  	return i.v, uint32(i.u1), i.typ
  1083  }
  1084  
  1085  // LoadSplatData returns the operands for a load splat instruction.
  1086  func (i *Instruction) LoadSplatData() (ptr Value, offset uint32, lane VecLane) {
  1087  	return i.v, uint32(i.u1), VecLane(i.u2)
  1088  }
  1089  
  1090  // AsStore initializes this instruction as a store instruction with OpcodeStore.
  1091  func (i *Instruction) AsStore(storeOp Opcode, value, ptr Value, offset uint32) *Instruction {
  1092  	i.opcode = storeOp
  1093  	i.v = value
  1094  	i.v2 = ptr
  1095  
  1096  	var dstSize uint64
  1097  	switch storeOp {
  1098  	case OpcodeStore:
  1099  		dstSize = uint64(value.Type().Bits())
  1100  	case OpcodeIstore8:
  1101  		dstSize = 8
  1102  	case OpcodeIstore16:
  1103  		dstSize = 16
  1104  	case OpcodeIstore32:
  1105  		dstSize = 32
  1106  	default:
  1107  		panic("invalid store opcode" + storeOp.String())
  1108  	}
  1109  	i.u1 = uint64(offset) | dstSize<<32
  1110  	return i
  1111  }
  1112  
  1113  // StoreData returns the operands for a store instruction.
  1114  func (i *Instruction) StoreData() (value, ptr Value, offset uint32, storeSizeInBits byte) {
  1115  	return i.v, i.v2, uint32(i.u1), byte(i.u1 >> 32)
  1116  }
  1117  
  1118  // AsIconst64 initializes this instruction as a 64-bit integer constant instruction with OpcodeIconst.
  1119  func (i *Instruction) AsIconst64(v uint64) *Instruction {
  1120  	i.opcode = OpcodeIconst
  1121  	i.typ = TypeI64
  1122  	i.u1 = v
  1123  	return i
  1124  }
  1125  
  1126  // AsIconst32 initializes this instruction as a 32-bit integer constant instruction with OpcodeIconst.
  1127  func (i *Instruction) AsIconst32(v uint32) *Instruction {
  1128  	i.opcode = OpcodeIconst
  1129  	i.typ = TypeI32
  1130  	i.u1 = uint64(v)
  1131  	return i
  1132  }
  1133  
  1134  // AsIadd initializes this instruction as an integer addition instruction with OpcodeIadd.
  1135  func (i *Instruction) AsIadd(x, y Value) *Instruction {
  1136  	i.opcode = OpcodeIadd
  1137  	i.v = x
  1138  	i.v2 = y
  1139  	i.typ = x.Type()
  1140  	return i
  1141  }
  1142  
  1143  // AsVIadd initializes this instruction as an integer addition instruction with OpcodeVIadd on a vector.
  1144  func (i *Instruction) AsVIadd(x, y Value, lane VecLane) *Instruction {
  1145  	i.opcode = OpcodeVIadd
  1146  	i.v = x
  1147  	i.v2 = y
  1148  	i.u1 = uint64(lane)
  1149  	i.typ = TypeV128
  1150  	return i
  1151  }
  1152  
  1153  // AsWideningPairwiseDotProductS initializes this instruction as a lane-wise integer extended pairwise addition instruction
  1154  // with OpcodeIaddPairwise on a vector.
  1155  func (i *Instruction) AsWideningPairwiseDotProductS(x, y Value) *Instruction {
  1156  	i.opcode = OpcodeWideningPairwiseDotProductS
  1157  	i.v = x
  1158  	i.v2 = y
  1159  	i.typ = TypeV128
  1160  	return i
  1161  }
  1162  
  1163  // AsExtIaddPairwise initializes this instruction as a lane-wise integer extended pairwise addition instruction
  1164  // with OpcodeIaddPairwise on a vector.
  1165  func (i *Instruction) AsExtIaddPairwise(x Value, srcLane VecLane, signed bool) *Instruction {
  1166  	i.opcode = OpcodeExtIaddPairwise
  1167  	i.v = x
  1168  	i.u1 = uint64(srcLane)
  1169  	if signed {
  1170  		i.u2 = 1
  1171  	}
  1172  	i.typ = TypeV128
  1173  	return i
  1174  }
  1175  
  1176  // ExtIaddPairwiseData returns the operands for a lane-wise integer extended pairwise addition instruction.
  1177  func (i *Instruction) ExtIaddPairwiseData() (x Value, srcLane VecLane, signed bool) {
  1178  	return i.v, VecLane(i.u1), i.u2 != 0
  1179  }
  1180  
  1181  // AsVSaddSat initializes this instruction as a vector addition with saturation instruction with OpcodeVSaddSat on a vector.
  1182  func (i *Instruction) AsVSaddSat(x, y Value, lane VecLane) *Instruction {
  1183  	i.opcode = OpcodeVSaddSat
  1184  	i.v = x
  1185  	i.v2 = y
  1186  	i.u1 = uint64(lane)
  1187  	i.typ = TypeV128
  1188  	return i
  1189  }
  1190  
  1191  // AsVUaddSat initializes this instruction as a vector addition with saturation instruction with OpcodeVUaddSat on a vector.
  1192  func (i *Instruction) AsVUaddSat(x, y Value, lane VecLane) *Instruction {
  1193  	i.opcode = OpcodeVUaddSat
  1194  	i.v = x
  1195  	i.v2 = y
  1196  	i.u1 = uint64(lane)
  1197  	i.typ = TypeV128
  1198  	return i
  1199  }
  1200  
  1201  // AsVIsub initializes this instruction as an integer subtraction instruction with OpcodeVIsub on a vector.
  1202  func (i *Instruction) AsVIsub(x, y Value, lane VecLane) *Instruction {
  1203  	i.opcode = OpcodeVIsub
  1204  	i.v = x
  1205  	i.v2 = y
  1206  	i.u1 = uint64(lane)
  1207  	i.typ = TypeV128
  1208  	return i
  1209  }
  1210  
  1211  // AsVSsubSat initializes this instruction as a vector addition with saturation instruction with OpcodeVSsubSat on a vector.
  1212  func (i *Instruction) AsVSsubSat(x, y Value, lane VecLane) *Instruction {
  1213  	i.opcode = OpcodeVSsubSat
  1214  	i.v = x
  1215  	i.v2 = y
  1216  	i.u1 = uint64(lane)
  1217  	i.typ = TypeV128
  1218  	return i
  1219  }
  1220  
  1221  // AsVUsubSat initializes this instruction as a vector addition with saturation instruction with OpcodeVUsubSat on a vector.
  1222  func (i *Instruction) AsVUsubSat(x, y Value, lane VecLane) *Instruction {
  1223  	i.opcode = OpcodeVUsubSat
  1224  	i.v = x
  1225  	i.v2 = y
  1226  	i.u1 = uint64(lane)
  1227  	i.typ = TypeV128
  1228  	return i
  1229  }
  1230  
  1231  // AsVImin initializes this instruction as a signed integer min instruction with OpcodeVImin on a vector.
  1232  func (i *Instruction) AsVImin(x, y Value, lane VecLane) *Instruction {
  1233  	i.opcode = OpcodeVImin
  1234  	i.v = x
  1235  	i.v2 = y
  1236  	i.u1 = uint64(lane)
  1237  	i.typ = TypeV128
  1238  	return i
  1239  }
  1240  
  1241  // AsVUmin initializes this instruction as an unsigned integer min instruction with OpcodeVUmin on a vector.
  1242  func (i *Instruction) AsVUmin(x, y Value, lane VecLane) *Instruction {
  1243  	i.opcode = OpcodeVUmin
  1244  	i.v = x
  1245  	i.v2 = y
  1246  	i.u1 = uint64(lane)
  1247  	i.typ = TypeV128
  1248  	return i
  1249  }
  1250  
  1251  // AsVImax initializes this instruction as a signed integer max instruction with OpcodeVImax on a vector.
  1252  func (i *Instruction) AsVImax(x, y Value, lane VecLane) *Instruction {
  1253  	i.opcode = OpcodeVImax
  1254  	i.v = x
  1255  	i.v2 = y
  1256  	i.u1 = uint64(lane)
  1257  	i.typ = TypeV128
  1258  	return i
  1259  }
  1260  
  1261  // AsVUmax initializes this instruction as an unsigned integer max instruction with OpcodeVUmax on a vector.
  1262  func (i *Instruction) AsVUmax(x, y Value, lane VecLane) *Instruction {
  1263  	i.opcode = OpcodeVUmax
  1264  	i.v = x
  1265  	i.v2 = y
  1266  	i.u1 = uint64(lane)
  1267  	i.typ = TypeV128
  1268  	return i
  1269  }
  1270  
  1271  // AsVAvgRound initializes this instruction as an unsigned integer avg instruction, truncating to zero with OpcodeVAvgRound on a vector.
  1272  func (i *Instruction) AsVAvgRound(x, y Value, lane VecLane) *Instruction {
  1273  	i.opcode = OpcodeVAvgRound
  1274  	i.v = x
  1275  	i.v2 = y
  1276  	i.u1 = uint64(lane)
  1277  	i.typ = TypeV128
  1278  	return i
  1279  }
  1280  
  1281  // AsVImul initializes this instruction as an integer multiplication with OpcodeVImul on a vector.
  1282  func (i *Instruction) AsVImul(x, y Value, lane VecLane) *Instruction {
  1283  	i.opcode = OpcodeVImul
  1284  	i.v = x
  1285  	i.v2 = y
  1286  	i.u1 = uint64(lane)
  1287  	i.typ = TypeV128
  1288  	return i
  1289  }
  1290  
  1291  // AsSqmulRoundSat initializes this instruction as a lane-wise saturating rounding multiplication
  1292  // in Q15 format with OpcodeSqmulRoundSat on a vector.
  1293  func (i *Instruction) AsSqmulRoundSat(x, y Value, lane VecLane) *Instruction {
  1294  	i.opcode = OpcodeSqmulRoundSat
  1295  	i.v = x
  1296  	i.v2 = y
  1297  	i.u1 = uint64(lane)
  1298  	i.typ = TypeV128
  1299  	return i
  1300  }
  1301  
  1302  // AsVIabs initializes this instruction as a vector absolute value with OpcodeVIabs.
  1303  func (i *Instruction) AsVIabs(x Value, lane VecLane) *Instruction {
  1304  	i.opcode = OpcodeVIabs
  1305  	i.v = x
  1306  	i.u1 = uint64(lane)
  1307  	i.typ = TypeV128
  1308  	return i
  1309  }
  1310  
  1311  // AsVIneg initializes this instruction as a vector negation with OpcodeVIneg.
  1312  func (i *Instruction) AsVIneg(x Value, lane VecLane) *Instruction {
  1313  	i.opcode = OpcodeVIneg
  1314  	i.v = x
  1315  	i.u1 = uint64(lane)
  1316  	i.typ = TypeV128
  1317  	return i
  1318  }
  1319  
  1320  // AsVIpopcnt initializes this instruction as a Population Count instruction with OpcodeVIpopcnt on a vector.
  1321  func (i *Instruction) AsVIpopcnt(x Value, lane VecLane) *Instruction {
  1322  	if lane != VecLaneI8x16 {
  1323  		panic("Unsupported lane type " + lane.String())
  1324  	}
  1325  	i.opcode = OpcodeVIpopcnt
  1326  	i.v = x
  1327  	i.u1 = uint64(lane)
  1328  	i.typ = TypeV128
  1329  	return i
  1330  }
  1331  
  1332  // AsVSqrt initializes this instruction as a sqrt instruction with OpcodeVSqrt on a vector.
  1333  func (i *Instruction) AsVSqrt(x Value, lane VecLane) *Instruction {
  1334  	i.opcode = OpcodeVSqrt
  1335  	i.v = x
  1336  	i.u1 = uint64(lane)
  1337  	i.typ = TypeV128
  1338  	return i
  1339  }
  1340  
  1341  // AsVFabs initializes this instruction as a float abs instruction with OpcodeVFabs on a vector.
  1342  func (i *Instruction) AsVFabs(x Value, lane VecLane) *Instruction {
  1343  	i.opcode = OpcodeVFabs
  1344  	i.v = x
  1345  	i.u1 = uint64(lane)
  1346  	i.typ = TypeV128
  1347  	return i
  1348  }
  1349  
  1350  // AsVFneg initializes this instruction as a float neg instruction with OpcodeVFneg on a vector.
  1351  func (i *Instruction) AsVFneg(x Value, lane VecLane) *Instruction {
  1352  	i.opcode = OpcodeVFneg
  1353  	i.v = x
  1354  	i.u1 = uint64(lane)
  1355  	i.typ = TypeV128
  1356  	return i
  1357  }
  1358  
  1359  // AsVFmax initializes this instruction as a float max instruction with OpcodeVFmax on a vector.
  1360  func (i *Instruction) AsVFmax(x, y Value, lane VecLane) *Instruction {
  1361  	i.opcode = OpcodeVFmax
  1362  	i.v = x
  1363  	i.v2 = y
  1364  	i.u1 = uint64(lane)
  1365  	i.typ = TypeV128
  1366  	return i
  1367  }
  1368  
  1369  // AsVFmin initializes this instruction as a float min instruction with OpcodeVFmin on a vector.
  1370  func (i *Instruction) AsVFmin(x, y Value, lane VecLane) *Instruction {
  1371  	i.opcode = OpcodeVFmin
  1372  	i.v = x
  1373  	i.v2 = y
  1374  	i.u1 = uint64(lane)
  1375  	i.typ = TypeV128
  1376  	return i
  1377  }
  1378  
  1379  // AsVFadd initializes this instruction as a floating point add instruction with OpcodeVFadd on a vector.
  1380  func (i *Instruction) AsVFadd(x, y Value, lane VecLane) *Instruction {
  1381  	i.opcode = OpcodeVFadd
  1382  	i.v = x
  1383  	i.v2 = y
  1384  	i.u1 = uint64(lane)
  1385  	i.typ = TypeV128
  1386  	return i
  1387  }
  1388  
  1389  // AsVFsub initializes this instruction as a floating point subtraction instruction with OpcodeVFsub on a vector.
  1390  func (i *Instruction) AsVFsub(x, y Value, lane VecLane) *Instruction {
  1391  	i.opcode = OpcodeVFsub
  1392  	i.v = x
  1393  	i.v2 = y
  1394  	i.u1 = uint64(lane)
  1395  	i.typ = TypeV128
  1396  	return i
  1397  }
  1398  
  1399  // AsVFmul initializes this instruction as a floating point multiplication instruction with OpcodeVFmul on a vector.
  1400  func (i *Instruction) AsVFmul(x, y Value, lane VecLane) *Instruction {
  1401  	i.opcode = OpcodeVFmul
  1402  	i.v = x
  1403  	i.v2 = y
  1404  	i.u1 = uint64(lane)
  1405  	i.typ = TypeV128
  1406  	return i
  1407  }
  1408  
  1409  // AsVFdiv initializes this instruction as a floating point division instruction with OpcodeVFdiv on a vector.
  1410  func (i *Instruction) AsVFdiv(x, y Value, lane VecLane) *Instruction {
  1411  	i.opcode = OpcodeVFdiv
  1412  	i.v = x
  1413  	i.v2 = y
  1414  	i.u1 = uint64(lane)
  1415  	i.typ = TypeV128
  1416  	return i
  1417  }
  1418  
  1419  // AsImul initializes this instruction as an integer addition instruction with OpcodeImul.
  1420  func (i *Instruction) AsImul(x, y Value) *Instruction {
  1421  	i.opcode = OpcodeImul
  1422  	i.v = x
  1423  	i.v2 = y
  1424  	i.typ = x.Type()
  1425  	return i
  1426  }
  1427  
  1428  func (i *Instruction) Insert(b Builder) *Instruction {
  1429  	b.InsertInstruction(i)
  1430  	return i
  1431  }
  1432  
  1433  // AsIsub initializes this instruction as an integer subtraction instruction with OpcodeIsub.
  1434  func (i *Instruction) AsIsub(x, y Value) *Instruction {
  1435  	i.opcode = OpcodeIsub
  1436  	i.v = x
  1437  	i.v2 = y
  1438  	i.typ = x.Type()
  1439  	return i
  1440  }
  1441  
  1442  // AsIcmp initializes this instruction as an integer comparison instruction with OpcodeIcmp.
  1443  func (i *Instruction) AsIcmp(x, y Value, c IntegerCmpCond) *Instruction {
  1444  	i.opcode = OpcodeIcmp
  1445  	i.v = x
  1446  	i.v2 = y
  1447  	i.u1 = uint64(c)
  1448  	i.typ = TypeI32
  1449  	return i
  1450  }
  1451  
  1452  // AsFcmp initializes this instruction as an integer comparison instruction with OpcodeFcmp.
  1453  func (i *Instruction) AsFcmp(x, y Value, c FloatCmpCond) {
  1454  	i.opcode = OpcodeFcmp
  1455  	i.v = x
  1456  	i.v2 = y
  1457  	i.u1 = uint64(c)
  1458  	i.typ = TypeI32
  1459  }
  1460  
  1461  // AsVIcmp initializes this instruction as an integer vector comparison instruction with OpcodeVIcmp.
  1462  func (i *Instruction) AsVIcmp(x, y Value, c IntegerCmpCond, lane VecLane) *Instruction {
  1463  	i.opcode = OpcodeVIcmp
  1464  	i.v = x
  1465  	i.v2 = y
  1466  	i.u1 = uint64(c)
  1467  	i.u2 = uint64(lane)
  1468  	i.typ = TypeV128
  1469  	return i
  1470  }
  1471  
  1472  // AsVFcmp initializes this instruction as a float comparison instruction with OpcodeVFcmp on Vector.
  1473  func (i *Instruction) AsVFcmp(x, y Value, c FloatCmpCond, lane VecLane) *Instruction {
  1474  	i.opcode = OpcodeVFcmp
  1475  	i.v = x
  1476  	i.v2 = y
  1477  	i.u1 = uint64(c)
  1478  	i.typ = TypeV128
  1479  	i.u2 = uint64(lane)
  1480  	return i
  1481  }
  1482  
  1483  // AsVCeil initializes this instruction as an instruction with OpcodeCeil.
  1484  func (i *Instruction) AsVCeil(x Value, lane VecLane) *Instruction {
  1485  	i.opcode = OpcodeVCeil
  1486  	i.v = x
  1487  	i.typ = x.Type()
  1488  	i.u1 = uint64(lane)
  1489  	return i
  1490  }
  1491  
  1492  // AsVFloor initializes this instruction as an instruction with OpcodeFloor.
  1493  func (i *Instruction) AsVFloor(x Value, lane VecLane) *Instruction {
  1494  	i.opcode = OpcodeVFloor
  1495  	i.v = x
  1496  	i.typ = x.Type()
  1497  	i.u1 = uint64(lane)
  1498  	return i
  1499  }
  1500  
  1501  // AsVTrunc initializes this instruction as an instruction with OpcodeTrunc.
  1502  func (i *Instruction) AsVTrunc(x Value, lane VecLane) *Instruction {
  1503  	i.opcode = OpcodeVTrunc
  1504  	i.v = x
  1505  	i.typ = x.Type()
  1506  	i.u1 = uint64(lane)
  1507  	return i
  1508  }
  1509  
  1510  // AsVNearest initializes this instruction as an instruction with OpcodeNearest.
  1511  func (i *Instruction) AsVNearest(x Value, lane VecLane) *Instruction {
  1512  	i.opcode = OpcodeVNearest
  1513  	i.v = x
  1514  	i.typ = x.Type()
  1515  	i.u1 = uint64(lane)
  1516  	return i
  1517  }
  1518  
  1519  // AsVMaxPseudo initializes this instruction as an instruction with OpcodeVMaxPseudo.
  1520  func (i *Instruction) AsVMaxPseudo(x, y Value, lane VecLane) *Instruction {
  1521  	i.opcode = OpcodeVMaxPseudo
  1522  	i.typ = x.Type()
  1523  	i.v = x
  1524  	i.v2 = y
  1525  	i.u1 = uint64(lane)
  1526  	return i
  1527  }
  1528  
  1529  // AsVMinPseudo initializes this instruction as an instruction with OpcodeVMinPseudo.
  1530  func (i *Instruction) AsVMinPseudo(x, y Value, lane VecLane) *Instruction {
  1531  	i.opcode = OpcodeVMinPseudo
  1532  	i.typ = x.Type()
  1533  	i.v = x
  1534  	i.v2 = y
  1535  	i.u1 = uint64(lane)
  1536  	return i
  1537  }
  1538  
  1539  // AsSDiv initializes this instruction as an integer bitwise and instruction with OpcodeSdiv.
  1540  func (i *Instruction) AsSDiv(x, y, ctx Value) *Instruction {
  1541  	i.opcode = OpcodeSdiv
  1542  	i.v = x
  1543  	i.v2 = y
  1544  	i.v3 = ctx
  1545  	i.typ = x.Type()
  1546  	return i
  1547  }
  1548  
  1549  // AsUDiv initializes this instruction as an integer bitwise and instruction with OpcodeUdiv.
  1550  func (i *Instruction) AsUDiv(x, y, ctx Value) *Instruction {
  1551  	i.opcode = OpcodeUdiv
  1552  	i.v = x
  1553  	i.v2 = y
  1554  	i.v3 = ctx
  1555  	i.typ = x.Type()
  1556  	return i
  1557  }
  1558  
  1559  // AsSRem initializes this instruction as an integer bitwise and instruction with OpcodeSrem.
  1560  func (i *Instruction) AsSRem(x, y, ctx Value) *Instruction {
  1561  	i.opcode = OpcodeSrem
  1562  	i.v = x
  1563  	i.v2 = y
  1564  	i.v3 = ctx
  1565  	i.typ = x.Type()
  1566  	return i
  1567  }
  1568  
  1569  // AsURem initializes this instruction as an integer bitwise and instruction with OpcodeUrem.
  1570  func (i *Instruction) AsURem(x, y, ctx Value) *Instruction {
  1571  	i.opcode = OpcodeUrem
  1572  	i.v = x
  1573  	i.v2 = y
  1574  	i.v3 = ctx
  1575  	i.typ = x.Type()
  1576  	return i
  1577  }
  1578  
  1579  // AsBand initializes this instruction as an integer bitwise and instruction with OpcodeBand.
  1580  func (i *Instruction) AsBand(x, amount Value) *Instruction {
  1581  	i.opcode = OpcodeBand
  1582  	i.v = x
  1583  	i.v2 = amount
  1584  	i.typ = x.Type()
  1585  	return i
  1586  }
  1587  
  1588  // AsBor initializes this instruction as an integer bitwise or instruction with OpcodeBor.
  1589  func (i *Instruction) AsBor(x, amount Value) {
  1590  	i.opcode = OpcodeBor
  1591  	i.v = x
  1592  	i.v2 = amount
  1593  	i.typ = x.Type()
  1594  }
  1595  
  1596  // AsBxor initializes this instruction as an integer bitwise xor instruction with OpcodeBxor.
  1597  func (i *Instruction) AsBxor(x, amount Value) {
  1598  	i.opcode = OpcodeBxor
  1599  	i.v = x
  1600  	i.v2 = amount
  1601  	i.typ = x.Type()
  1602  }
  1603  
  1604  // AsIshl initializes this instruction as an integer shift left instruction with OpcodeIshl.
  1605  func (i *Instruction) AsIshl(x, amount Value) *Instruction {
  1606  	i.opcode = OpcodeIshl
  1607  	i.v = x
  1608  	i.v2 = amount
  1609  	i.typ = x.Type()
  1610  	return i
  1611  }
  1612  
  1613  // AsVIshl initializes this instruction as an integer shift left instruction with OpcodeVIshl on vector.
  1614  func (i *Instruction) AsVIshl(x, amount Value, lane VecLane) *Instruction {
  1615  	i.opcode = OpcodeVIshl
  1616  	i.v = x
  1617  	i.v2 = amount
  1618  	i.u1 = uint64(lane)
  1619  	i.typ = x.Type()
  1620  	return i
  1621  }
  1622  
  1623  // AsUshr initializes this instruction as an integer unsigned shift right (logical shift right) instruction with OpcodeUshr.
  1624  func (i *Instruction) AsUshr(x, amount Value) *Instruction {
  1625  	i.opcode = OpcodeUshr
  1626  	i.v = x
  1627  	i.v2 = amount
  1628  	i.typ = x.Type()
  1629  	return i
  1630  }
  1631  
  1632  // AsVUshr initializes this instruction as an integer unsigned shift right (logical shift right) instruction with OpcodeVUshr on vector.
  1633  func (i *Instruction) AsVUshr(x, amount Value, lane VecLane) *Instruction {
  1634  	i.opcode = OpcodeVUshr
  1635  	i.v = x
  1636  	i.v2 = amount
  1637  	i.u1 = uint64(lane)
  1638  	i.typ = x.Type()
  1639  	return i
  1640  }
  1641  
  1642  // AsSshr initializes this instruction as an integer signed shift right (arithmetic shift right) instruction with OpcodeSshr.
  1643  func (i *Instruction) AsSshr(x, amount Value) *Instruction {
  1644  	i.opcode = OpcodeSshr
  1645  	i.v = x
  1646  	i.v2 = amount
  1647  	i.typ = x.Type()
  1648  	return i
  1649  }
  1650  
  1651  // AsVSshr initializes this instruction as an integer signed shift right (arithmetic shift right) instruction with OpcodeVSshr on vector.
  1652  func (i *Instruction) AsVSshr(x, amount Value, lane VecLane) *Instruction {
  1653  	i.opcode = OpcodeVSshr
  1654  	i.v = x
  1655  	i.v2 = amount
  1656  	i.u1 = uint64(lane)
  1657  	i.typ = x.Type()
  1658  	return i
  1659  }
  1660  
  1661  // AsExtractlane initializes this instruction as an extract lane instruction with OpcodeExtractlane on vector.
  1662  func (i *Instruction) AsExtractlane(x Value, index byte, lane VecLane, signed bool) *Instruction {
  1663  	i.opcode = OpcodeExtractlane
  1664  	i.v = x
  1665  	// We do not have a field for signedness, but `index` is a byte,
  1666  	// so we just encode the flag in the high bits of `u1`.
  1667  	i.u1 = uint64(index)
  1668  	if signed {
  1669  		i.u1 = i.u1 | 1<<32
  1670  	}
  1671  	i.u2 = uint64(lane)
  1672  	switch lane {
  1673  	case VecLaneI8x16, VecLaneI16x8, VecLaneI32x4:
  1674  		i.typ = TypeI32
  1675  	case VecLaneI64x2:
  1676  		i.typ = TypeI64
  1677  	case VecLaneF32x4:
  1678  		i.typ = TypeF32
  1679  	case VecLaneF64x2:
  1680  		i.typ = TypeF64
  1681  	}
  1682  	return i
  1683  }
  1684  
  1685  // AsInsertlane initializes this instruction as an insert lane instruction with OpcodeInsertlane on vector.
  1686  func (i *Instruction) AsInsertlane(x, y Value, index byte, lane VecLane) *Instruction {
  1687  	i.opcode = OpcodeInsertlane
  1688  	i.v = x
  1689  	i.v2 = y
  1690  	i.u1 = uint64(index)
  1691  	i.u2 = uint64(lane)
  1692  	i.typ = TypeV128
  1693  	return i
  1694  }
  1695  
  1696  // AsShuffle initializes this instruction as a shuffle instruction with OpcodeShuffle on vector.
  1697  func (i *Instruction) AsShuffle(x, y Value, lane []byte) *Instruction {
  1698  	i.opcode = OpcodeShuffle
  1699  	i.v = x
  1700  	i.v2 = y
  1701  	// Encode the 16 bytes as 8 bytes in u1, and 8 bytes in u2.
  1702  	i.u1 = uint64(lane[7])<<56 | uint64(lane[6])<<48 | uint64(lane[5])<<40 | uint64(lane[4])<<32 | uint64(lane[3])<<24 | uint64(lane[2])<<16 | uint64(lane[1])<<8 | uint64(lane[0])
  1703  	i.u2 = uint64(lane[15])<<56 | uint64(lane[14])<<48 | uint64(lane[13])<<40 | uint64(lane[12])<<32 | uint64(lane[11])<<24 | uint64(lane[10])<<16 | uint64(lane[9])<<8 | uint64(lane[8])
  1704  	i.typ = TypeV128
  1705  	return i
  1706  }
  1707  
  1708  // AsSwizzle initializes this instruction as an insert lane instruction with OpcodeSwizzle on vector.
  1709  func (i *Instruction) AsSwizzle(x, y Value, lane VecLane) *Instruction {
  1710  	i.opcode = OpcodeSwizzle
  1711  	i.v = x
  1712  	i.v2 = y
  1713  	i.u1 = uint64(lane)
  1714  	i.typ = TypeV128
  1715  	return i
  1716  }
  1717  
  1718  // AsSplat initializes this instruction as an insert lane instruction with OpcodeSplat on vector.
  1719  func (i *Instruction) AsSplat(x Value, lane VecLane) *Instruction {
  1720  	i.opcode = OpcodeSplat
  1721  	i.v = x
  1722  	i.u1 = uint64(lane)
  1723  	i.typ = TypeV128
  1724  	return i
  1725  }
  1726  
  1727  // AsRotl initializes this instruction as a word rotate left instruction with OpcodeRotl.
  1728  func (i *Instruction) AsRotl(x, amount Value) {
  1729  	i.opcode = OpcodeRotl
  1730  	i.v = x
  1731  	i.v2 = amount
  1732  	i.typ = x.Type()
  1733  }
  1734  
  1735  // AsRotr initializes this instruction as a word rotate right instruction with OpcodeRotr.
  1736  func (i *Instruction) AsRotr(x, amount Value) {
  1737  	i.opcode = OpcodeRotr
  1738  	i.v = x
  1739  	i.v2 = amount
  1740  	i.typ = x.Type()
  1741  }
  1742  
  1743  // IcmpData returns the operands and comparison condition of this integer comparison instruction.
  1744  func (i *Instruction) IcmpData() (x, y Value, c IntegerCmpCond) {
  1745  	return i.v, i.v2, IntegerCmpCond(i.u1)
  1746  }
  1747  
  1748  // FcmpData returns the operands and comparison condition of this floating-point comparison instruction.
  1749  func (i *Instruction) FcmpData() (x, y Value, c FloatCmpCond) {
  1750  	return i.v, i.v2, FloatCmpCond(i.u1)
  1751  }
  1752  
  1753  // VIcmpData returns the operands and comparison condition of this integer comparison instruction on vector.
  1754  func (i *Instruction) VIcmpData() (x, y Value, c IntegerCmpCond, l VecLane) {
  1755  	return i.v, i.v2, IntegerCmpCond(i.u1), VecLane(i.u2)
  1756  }
  1757  
  1758  // VFcmpData returns the operands and comparison condition of this float comparison instruction on vector.
  1759  func (i *Instruction) VFcmpData() (x, y Value, c FloatCmpCond, l VecLane) {
  1760  	return i.v, i.v2, FloatCmpCond(i.u1), VecLane(i.u2)
  1761  }
  1762  
  1763  // ExtractlaneData returns the operands and sign flag of Extractlane on vector.
  1764  func (i *Instruction) ExtractlaneData() (x Value, index byte, signed bool, l VecLane) {
  1765  	x = i.v
  1766  	index = byte(0b00001111 & i.u1)
  1767  	signed = i.u1>>32 != 0
  1768  	l = VecLane(i.u2)
  1769  	return
  1770  }
  1771  
  1772  // InsertlaneData returns the operands and sign flag of Insertlane on vector.
  1773  func (i *Instruction) InsertlaneData() (x, y Value, index byte, l VecLane) {
  1774  	x = i.v
  1775  	y = i.v2
  1776  	index = byte(i.u1)
  1777  	l = VecLane(i.u2)
  1778  	return
  1779  }
  1780  
  1781  // AsFadd initializes this instruction as a floating-point addition instruction with OpcodeFadd.
  1782  func (i *Instruction) AsFadd(x, y Value) {
  1783  	i.opcode = OpcodeFadd
  1784  	i.v = x
  1785  	i.v2 = y
  1786  	i.typ = x.Type()
  1787  }
  1788  
  1789  // AsFsub initializes this instruction as a floating-point subtraction instruction with OpcodeFsub.
  1790  func (i *Instruction) AsFsub(x, y Value) {
  1791  	i.opcode = OpcodeFsub
  1792  	i.v = x
  1793  	i.v2 = y
  1794  	i.typ = x.Type()
  1795  }
  1796  
  1797  // AsFmul initializes this instruction as a floating-point multiplication instruction with OpcodeFmul.
  1798  func (i *Instruction) AsFmul(x, y Value) {
  1799  	i.opcode = OpcodeFmul
  1800  	i.v = x
  1801  	i.v2 = y
  1802  	i.typ = x.Type()
  1803  }
  1804  
  1805  // AsFdiv initializes this instruction as a floating-point division instruction with OpcodeFdiv.
  1806  func (i *Instruction) AsFdiv(x, y Value) {
  1807  	i.opcode = OpcodeFdiv
  1808  	i.v = x
  1809  	i.v2 = y
  1810  	i.typ = x.Type()
  1811  }
  1812  
  1813  // AsFmin initializes this instruction to take the minimum of two floating-points with OpcodeFmin.
  1814  func (i *Instruction) AsFmin(x, y Value) {
  1815  	i.opcode = OpcodeFmin
  1816  	i.v = x
  1817  	i.v2 = y
  1818  	i.typ = x.Type()
  1819  }
  1820  
  1821  // AsFmax initializes this instruction to take the maximum of two floating-points with OpcodeFmax.
  1822  func (i *Instruction) AsFmax(x, y Value) {
  1823  	i.opcode = OpcodeFmax
  1824  	i.v = x
  1825  	i.v2 = y
  1826  	i.typ = x.Type()
  1827  }
  1828  
  1829  // AsF32const initializes this instruction as a 32-bit floating-point constant instruction with OpcodeF32const.
  1830  func (i *Instruction) AsF32const(f float32) *Instruction {
  1831  	i.opcode = OpcodeF32const
  1832  	i.typ = TypeF64
  1833  	i.u1 = uint64(math.Float32bits(f))
  1834  	return i
  1835  }
  1836  
  1837  // AsF64const initializes this instruction as a 64-bit floating-point constant instruction with OpcodeF64const.
  1838  func (i *Instruction) AsF64const(f float64) *Instruction {
  1839  	i.opcode = OpcodeF64const
  1840  	i.typ = TypeF64
  1841  	i.u1 = math.Float64bits(f)
  1842  	return i
  1843  }
  1844  
  1845  // AsVconst initializes this instruction as a vector constant instruction with OpcodeVconst.
  1846  func (i *Instruction) AsVconst(lo, hi uint64) *Instruction {
  1847  	i.opcode = OpcodeVconst
  1848  	i.typ = TypeV128
  1849  	i.u1 = lo
  1850  	i.u2 = hi
  1851  	return i
  1852  }
  1853  
  1854  // AsVbnot initializes this instruction as a vector negation instruction with OpcodeVbnot.
  1855  func (i *Instruction) AsVbnot(v Value) *Instruction {
  1856  	i.opcode = OpcodeVbnot
  1857  	i.typ = TypeV128
  1858  	i.v = v
  1859  	return i
  1860  }
  1861  
  1862  // AsVband initializes this instruction as an and vector instruction with OpcodeVband.
  1863  func (i *Instruction) AsVband(x, y Value) *Instruction {
  1864  	i.opcode = OpcodeVband
  1865  	i.typ = TypeV128
  1866  	i.v = x
  1867  	i.v2 = y
  1868  	return i
  1869  }
  1870  
  1871  // AsVbor initializes this instruction as an or vector instruction with OpcodeVbor.
  1872  func (i *Instruction) AsVbor(x, y Value) *Instruction {
  1873  	i.opcode = OpcodeVbor
  1874  	i.typ = TypeV128
  1875  	i.v = x
  1876  	i.v2 = y
  1877  	return i
  1878  }
  1879  
  1880  // AsVbxor initializes this instruction as a xor vector instruction with OpcodeVbxor.
  1881  func (i *Instruction) AsVbxor(x, y Value) *Instruction {
  1882  	i.opcode = OpcodeVbxor
  1883  	i.typ = TypeV128
  1884  	i.v = x
  1885  	i.v2 = y
  1886  	return i
  1887  }
  1888  
  1889  // AsVbandnot initializes this instruction as an and-not vector instruction with OpcodeVbandnot.
  1890  func (i *Instruction) AsVbandnot(x, y Value) *Instruction {
  1891  	i.opcode = OpcodeVbandnot
  1892  	i.typ = TypeV128
  1893  	i.v = x
  1894  	i.v2 = y
  1895  	return i
  1896  }
  1897  
  1898  // AsVbitselect initializes this instruction as a bit select vector instruction with OpcodeVbitselect.
  1899  func (i *Instruction) AsVbitselect(c, x, y Value) *Instruction {
  1900  	i.opcode = OpcodeVbitselect
  1901  	i.typ = TypeV128
  1902  	i.v = c
  1903  	i.v2 = x
  1904  	i.v3 = y
  1905  	return i
  1906  }
  1907  
  1908  // AsVanyTrue initializes this instruction as an anyTrue vector instruction with OpcodeVanyTrue.
  1909  func (i *Instruction) AsVanyTrue(x Value) *Instruction {
  1910  	i.opcode = OpcodeVanyTrue
  1911  	i.typ = TypeI32
  1912  	i.v = x
  1913  	return i
  1914  }
  1915  
  1916  // AsVallTrue initializes this instruction as an allTrue vector instruction with OpcodeVallTrue.
  1917  func (i *Instruction) AsVallTrue(x Value, lane VecLane) *Instruction {
  1918  	i.opcode = OpcodeVallTrue
  1919  	i.typ = TypeI32
  1920  	i.v = x
  1921  	i.u1 = uint64(lane)
  1922  	return i
  1923  }
  1924  
  1925  // AsVhighBits initializes this instruction as a highBits vector instruction with OpcodeVhighBits.
  1926  func (i *Instruction) AsVhighBits(x Value, lane VecLane) *Instruction {
  1927  	i.opcode = OpcodeVhighBits
  1928  	i.typ = TypeI32
  1929  	i.v = x
  1930  	i.u1 = uint64(lane)
  1931  	return i
  1932  }
  1933  
  1934  // VconstData returns the operands of this vector constant instruction.
  1935  func (i *Instruction) VconstData() (lo, hi uint64) {
  1936  	return i.u1, i.u2
  1937  }
  1938  
  1939  // AsReturn initializes this instruction as a return instruction with OpcodeReturn.
  1940  func (i *Instruction) AsReturn(vs wazevoapi.VarLength[Value]) *Instruction {
  1941  	i.opcode = OpcodeReturn
  1942  	i.vs = vs
  1943  	return i
  1944  }
  1945  
  1946  // AsIreduce initializes this instruction as a reduction instruction with OpcodeIreduce.
  1947  func (i *Instruction) AsIreduce(v Value, dstType Type) *Instruction {
  1948  	i.opcode = OpcodeIreduce
  1949  	i.v = v
  1950  	i.typ = dstType
  1951  	return i
  1952  }
  1953  
  1954  // AsWiden initializes this instruction as a signed or unsigned widen instruction
  1955  // on low half or high half of the given vector with OpcodeSwidenLow, OpcodeUwidenLow, OpcodeSwidenHigh, OpcodeUwidenHigh.
  1956  func (i *Instruction) AsWiden(v Value, lane VecLane, signed, low bool) *Instruction {
  1957  	switch {
  1958  	case signed && low:
  1959  		i.opcode = OpcodeSwidenLow
  1960  	case !signed && low:
  1961  		i.opcode = OpcodeUwidenLow
  1962  	case signed && !low:
  1963  		i.opcode = OpcodeSwidenHigh
  1964  	case !signed && !low:
  1965  		i.opcode = OpcodeUwidenHigh
  1966  	}
  1967  	i.v = v
  1968  	i.u1 = uint64(lane)
  1969  	return i
  1970  }
  1971  
  1972  // AsAtomicLoad initializes this instruction as an atomic load.
  1973  // The size is in bytes and must be 1, 2, 4, or 8.
  1974  func (i *Instruction) AsAtomicLoad(addr Value, size uint64, typ Type) *Instruction {
  1975  	i.opcode = OpcodeAtomicLoad
  1976  	i.u1 = size
  1977  	i.v = addr
  1978  	i.typ = typ
  1979  	return i
  1980  }
  1981  
  1982  // AsAtomicLoad initializes this instruction as an atomic store.
  1983  // The size is in bytes and must be 1, 2, 4, or 8.
  1984  func (i *Instruction) AsAtomicStore(addr, val Value, size uint64) *Instruction {
  1985  	i.opcode = OpcodeAtomicStore
  1986  	i.u1 = size
  1987  	i.v = addr
  1988  	i.v2 = val
  1989  	i.typ = val.Type()
  1990  	return i
  1991  }
  1992  
  1993  // AsAtomicRmw initializes this instruction as an atomic read-modify-write.
  1994  // The size is in bytes and must be 1, 2, 4, or 8.
  1995  func (i *Instruction) AsAtomicRmw(op AtomicRmwOp, addr, val Value, size uint64) *Instruction {
  1996  	i.opcode = OpcodeAtomicRmw
  1997  	i.u1 = uint64(op)
  1998  	i.u2 = size
  1999  	i.v = addr
  2000  	i.v2 = val
  2001  	i.typ = val.Type()
  2002  	return i
  2003  }
  2004  
  2005  // AsAtomicCas initializes this instruction as an atomic compare-and-swap.
  2006  // The size is in bytes and must be 1, 2, 4, or 8.
  2007  func (i *Instruction) AsAtomicCas(addr, exp, repl Value, size uint64) *Instruction {
  2008  	i.opcode = OpcodeAtomicCas
  2009  	i.u1 = size
  2010  	i.v = addr
  2011  	i.v2 = exp
  2012  	i.v3 = repl
  2013  	i.typ = repl.Type()
  2014  	return i
  2015  }
  2016  
  2017  // AsFence initializes this instruction as a memory fence.
  2018  // A single byte immediate may be used to indicate fence ordering in the future
  2019  // but is currently always 0 and ignored.
  2020  func (i *Instruction) AsFence(order byte) *Instruction {
  2021  	i.opcode = OpcodeFence
  2022  	i.u1 = uint64(order)
  2023  	return i
  2024  }
  2025  
  2026  // AtomicRmwData returns the data for this atomic read-modify-write instruction.
  2027  func (i *Instruction) AtomicRmwData() (op AtomicRmwOp, size uint64) {
  2028  	return AtomicRmwOp(i.u1), i.u2
  2029  }
  2030  
  2031  // AtomicTargetSize returns the target memory size of the atomic instruction.
  2032  func (i *Instruction) AtomicTargetSize() (size uint64) {
  2033  	return i.u1
  2034  }
  2035  
  2036  // ReturnVals returns the return values of OpcodeReturn.
  2037  func (i *Instruction) ReturnVals() []Value {
  2038  	return i.vs.View()
  2039  }
  2040  
  2041  // AsExitWithCode initializes this instruction as a trap instruction with OpcodeExitWithCode.
  2042  func (i *Instruction) AsExitWithCode(ctx Value, code wazevoapi.ExitCode) {
  2043  	i.opcode = OpcodeExitWithCode
  2044  	i.v = ctx
  2045  	i.u1 = uint64(code)
  2046  }
  2047  
  2048  // AsExitIfTrueWithCode initializes this instruction as a trap instruction with OpcodeExitIfTrueWithCode.
  2049  func (i *Instruction) AsExitIfTrueWithCode(ctx, c Value, code wazevoapi.ExitCode) *Instruction {
  2050  	i.opcode = OpcodeExitIfTrueWithCode
  2051  	i.v = ctx
  2052  	i.v2 = c
  2053  	i.u1 = uint64(code)
  2054  	return i
  2055  }
  2056  
  2057  // ExitWithCodeData returns the context and exit code of OpcodeExitWithCode.
  2058  func (i *Instruction) ExitWithCodeData() (ctx Value, code wazevoapi.ExitCode) {
  2059  	return i.v, wazevoapi.ExitCode(i.u1)
  2060  }
  2061  
  2062  // ExitIfTrueWithCodeData returns the context and exit code of OpcodeExitWithCode.
  2063  func (i *Instruction) ExitIfTrueWithCodeData() (ctx, c Value, code wazevoapi.ExitCode) {
  2064  	return i.v, i.v2, wazevoapi.ExitCode(i.u1)
  2065  }
  2066  
  2067  // InvertBrx inverts either OpcodeBrz or OpcodeBrnz to the other.
  2068  func (i *Instruction) InvertBrx() {
  2069  	switch i.opcode {
  2070  	case OpcodeBrz:
  2071  		i.opcode = OpcodeBrnz
  2072  	case OpcodeBrnz:
  2073  		i.opcode = OpcodeBrz
  2074  	default:
  2075  		panic("BUG")
  2076  	}
  2077  }
  2078  
  2079  // BranchData returns the branch data for this instruction necessary for backends.
  2080  func (i *Instruction) BranchData() (condVal Value, blockArgs []Value, target BasicBlock) {
  2081  	switch i.opcode {
  2082  	case OpcodeJump:
  2083  		condVal = ValueInvalid
  2084  	case OpcodeBrz, OpcodeBrnz:
  2085  		condVal = i.v
  2086  	default:
  2087  		panic("BUG")
  2088  	}
  2089  	blockArgs = i.vs.View()
  2090  	target = i.blk
  2091  	return
  2092  }
  2093  
  2094  // BrTableData returns the branch table data for this instruction necessary for backends.
  2095  func (i *Instruction) BrTableData() (index Value, targets []BasicBlock) {
  2096  	if i.opcode != OpcodeBrTable {
  2097  		panic("BUG: BrTableData only available for OpcodeBrTable")
  2098  	}
  2099  	index = i.v
  2100  	targets = i.targets
  2101  	return
  2102  }
  2103  
  2104  // AsJump initializes this instruction as a jump instruction with OpcodeJump.
  2105  func (i *Instruction) AsJump(vs Values, target BasicBlock) *Instruction {
  2106  	i.opcode = OpcodeJump
  2107  	i.vs = vs
  2108  	i.blk = target
  2109  	return i
  2110  }
  2111  
  2112  // IsFallthroughJump returns true if this instruction is a fallthrough jump.
  2113  func (i *Instruction) IsFallthroughJump() bool {
  2114  	if i.opcode != OpcodeJump {
  2115  		panic("BUG: IsFallthrough only available for OpcodeJump")
  2116  	}
  2117  	return i.opcode == OpcodeJump && i.u1 != 0
  2118  }
  2119  
  2120  // AsFallthroughJump marks this instruction as a fallthrough jump.
  2121  func (i *Instruction) AsFallthroughJump() {
  2122  	if i.opcode != OpcodeJump {
  2123  		panic("BUG: AsFallthroughJump only available for OpcodeJump")
  2124  	}
  2125  	i.u1 = 1
  2126  }
  2127  
  2128  // AsBrz initializes this instruction as a branch-if-zero instruction with OpcodeBrz.
  2129  func (i *Instruction) AsBrz(v Value, args Values, target BasicBlock) {
  2130  	i.opcode = OpcodeBrz
  2131  	i.v = v
  2132  	i.vs = args
  2133  	i.blk = target
  2134  }
  2135  
  2136  // AsBrnz initializes this instruction as a branch-if-not-zero instruction with OpcodeBrnz.
  2137  func (i *Instruction) AsBrnz(v Value, args Values, target BasicBlock) *Instruction {
  2138  	i.opcode = OpcodeBrnz
  2139  	i.v = v
  2140  	i.vs = args
  2141  	i.blk = target
  2142  	return i
  2143  }
  2144  
  2145  // AsBrTable initializes this instruction as a branch-table instruction with OpcodeBrTable.
  2146  func (i *Instruction) AsBrTable(index Value, targets []BasicBlock) {
  2147  	i.opcode = OpcodeBrTable
  2148  	i.v = index
  2149  	i.targets = targets
  2150  }
  2151  
  2152  // AsCall initializes this instruction as a call instruction with OpcodeCall.
  2153  func (i *Instruction) AsCall(ref FuncRef, sig *Signature, args Values) {
  2154  	i.opcode = OpcodeCall
  2155  	i.u1 = uint64(ref)
  2156  	i.vs = args
  2157  	i.u2 = uint64(sig.ID)
  2158  	sig.used = true
  2159  }
  2160  
  2161  // CallData returns the call data for this instruction necessary for backends.
  2162  func (i *Instruction) CallData() (ref FuncRef, sigID SignatureID, args []Value) {
  2163  	if i.opcode != OpcodeCall {
  2164  		panic("BUG: CallData only available for OpcodeCall")
  2165  	}
  2166  	ref = FuncRef(i.u1)
  2167  	sigID = SignatureID(i.u2)
  2168  	args = i.vs.View()
  2169  	return
  2170  }
  2171  
  2172  // AsCallIndirect initializes this instruction as a call-indirect instruction with OpcodeCallIndirect.
  2173  func (i *Instruction) AsCallIndirect(funcPtr Value, sig *Signature, args Values) *Instruction {
  2174  	i.opcode = OpcodeCallIndirect
  2175  	i.typ = TypeF64
  2176  	i.vs = args
  2177  	i.v = funcPtr
  2178  	i.u1 = uint64(sig.ID)
  2179  	sig.used = true
  2180  	return i
  2181  }
  2182  
  2183  // AsCallGoRuntimeMemmove is the same as AsCallIndirect, but with a special flag set to indicate that it is a call to the Go runtime memmove function.
  2184  func (i *Instruction) AsCallGoRuntimeMemmove(funcPtr Value, sig *Signature, args Values) *Instruction {
  2185  	i.AsCallIndirect(funcPtr, sig, args)
  2186  	i.u2 = 1
  2187  	return i
  2188  }
  2189  
  2190  // CallIndirectData returns the call indirect data for this instruction necessary for backends.
  2191  func (i *Instruction) CallIndirectData() (funcPtr Value, sigID SignatureID, args []Value, isGoMemmove bool) {
  2192  	if i.opcode != OpcodeCallIndirect {
  2193  		panic("BUG: CallIndirectData only available for OpcodeCallIndirect")
  2194  	}
  2195  	funcPtr = i.v
  2196  	sigID = SignatureID(i.u1)
  2197  	args = i.vs.View()
  2198  	isGoMemmove = i.u2 == 1
  2199  	return
  2200  }
  2201  
  2202  // AsClz initializes this instruction as a Count Leading Zeroes instruction with OpcodeClz.
  2203  func (i *Instruction) AsClz(x Value) {
  2204  	i.opcode = OpcodeClz
  2205  	i.v = x
  2206  	i.typ = x.Type()
  2207  }
  2208  
  2209  // AsCtz initializes this instruction as a Count Trailing Zeroes instruction with OpcodeCtz.
  2210  func (i *Instruction) AsCtz(x Value) {
  2211  	i.opcode = OpcodeCtz
  2212  	i.v = x
  2213  	i.typ = x.Type()
  2214  }
  2215  
  2216  // AsPopcnt initializes this instruction as a Population Count instruction with OpcodePopcnt.
  2217  func (i *Instruction) AsPopcnt(x Value) {
  2218  	i.opcode = OpcodePopcnt
  2219  	i.v = x
  2220  	i.typ = x.Type()
  2221  }
  2222  
  2223  // AsFneg initializes this instruction as an instruction with OpcodeFneg.
  2224  func (i *Instruction) AsFneg(x Value) *Instruction {
  2225  	i.opcode = OpcodeFneg
  2226  	i.v = x
  2227  	i.typ = x.Type()
  2228  	return i
  2229  }
  2230  
  2231  // AsSqrt initializes this instruction as an instruction with OpcodeSqrt.
  2232  func (i *Instruction) AsSqrt(x Value) *Instruction {
  2233  	i.opcode = OpcodeSqrt
  2234  	i.v = x
  2235  	i.typ = x.Type()
  2236  	return i
  2237  }
  2238  
  2239  // AsFabs initializes this instruction as an instruction with OpcodeFabs.
  2240  func (i *Instruction) AsFabs(x Value) *Instruction {
  2241  	i.opcode = OpcodeFabs
  2242  	i.v = x
  2243  	i.typ = x.Type()
  2244  	return i
  2245  }
  2246  
  2247  // AsFcopysign initializes this instruction as an instruction with OpcodeFcopysign.
  2248  func (i *Instruction) AsFcopysign(x, y Value) *Instruction {
  2249  	i.opcode = OpcodeFcopysign
  2250  	i.v = x
  2251  	i.v2 = y
  2252  	i.typ = x.Type()
  2253  	return i
  2254  }
  2255  
  2256  // AsCeil initializes this instruction as an instruction with OpcodeCeil.
  2257  func (i *Instruction) AsCeil(x Value) *Instruction {
  2258  	i.opcode = OpcodeCeil
  2259  	i.v = x
  2260  	i.typ = x.Type()
  2261  	return i
  2262  }
  2263  
  2264  // AsFloor initializes this instruction as an instruction with OpcodeFloor.
  2265  func (i *Instruction) AsFloor(x Value) *Instruction {
  2266  	i.opcode = OpcodeFloor
  2267  	i.v = x
  2268  	i.typ = x.Type()
  2269  	return i
  2270  }
  2271  
  2272  // AsTrunc initializes this instruction as an instruction with OpcodeTrunc.
  2273  func (i *Instruction) AsTrunc(x Value) *Instruction {
  2274  	i.opcode = OpcodeTrunc
  2275  	i.v = x
  2276  	i.typ = x.Type()
  2277  	return i
  2278  }
  2279  
  2280  // AsNearest initializes this instruction as an instruction with OpcodeNearest.
  2281  func (i *Instruction) AsNearest(x Value) *Instruction {
  2282  	i.opcode = OpcodeNearest
  2283  	i.v = x
  2284  	i.typ = x.Type()
  2285  	return i
  2286  }
  2287  
  2288  // AsBitcast initializes this instruction as an instruction with OpcodeBitcast.
  2289  func (i *Instruction) AsBitcast(x Value, dstType Type) *Instruction {
  2290  	i.opcode = OpcodeBitcast
  2291  	i.v = x
  2292  	i.typ = dstType
  2293  	return i
  2294  }
  2295  
  2296  // BitcastData returns the operands for a bitcast instruction.
  2297  func (i *Instruction) BitcastData() (x Value, dstType Type) {
  2298  	return i.v, i.typ
  2299  }
  2300  
  2301  // AsFdemote initializes this instruction as an instruction with OpcodeFdemote.
  2302  func (i *Instruction) AsFdemote(x Value) {
  2303  	i.opcode = OpcodeFdemote
  2304  	i.v = x
  2305  	i.typ = TypeF32
  2306  }
  2307  
  2308  // AsFpromote initializes this instruction as an instruction with OpcodeFpromote.
  2309  func (i *Instruction) AsFpromote(x Value) {
  2310  	i.opcode = OpcodeFpromote
  2311  	i.v = x
  2312  	i.typ = TypeF64
  2313  }
  2314  
  2315  // AsFcvtFromInt initializes this instruction as an instruction with either OpcodeFcvtFromUint or OpcodeFcvtFromSint
  2316  func (i *Instruction) AsFcvtFromInt(x Value, signed bool, dst64bit bool) *Instruction {
  2317  	if signed {
  2318  		i.opcode = OpcodeFcvtFromSint
  2319  	} else {
  2320  		i.opcode = OpcodeFcvtFromUint
  2321  	}
  2322  	i.v = x
  2323  	if dst64bit {
  2324  		i.typ = TypeF64
  2325  	} else {
  2326  		i.typ = TypeF32
  2327  	}
  2328  	return i
  2329  }
  2330  
  2331  // AsFcvtToInt initializes this instruction as an instruction with either OpcodeFcvtToUint or OpcodeFcvtToSint
  2332  func (i *Instruction) AsFcvtToInt(x, ctx Value, signed bool, dst64bit bool, sat bool) *Instruction {
  2333  	switch {
  2334  	case signed && !sat:
  2335  		i.opcode = OpcodeFcvtToSint
  2336  	case !signed && !sat:
  2337  		i.opcode = OpcodeFcvtToUint
  2338  	case signed && sat:
  2339  		i.opcode = OpcodeFcvtToSintSat
  2340  	case !signed && sat:
  2341  		i.opcode = OpcodeFcvtToUintSat
  2342  	}
  2343  	i.v = x
  2344  	i.v2 = ctx
  2345  	if dst64bit {
  2346  		i.typ = TypeI64
  2347  	} else {
  2348  		i.typ = TypeI32
  2349  	}
  2350  	return i
  2351  }
  2352  
  2353  // AsVFcvtToIntSat initializes this instruction as an instruction with either OpcodeVFcvtToSintSat or OpcodeVFcvtToUintSat
  2354  func (i *Instruction) AsVFcvtToIntSat(x Value, lane VecLane, signed bool) *Instruction {
  2355  	if signed {
  2356  		i.opcode = OpcodeVFcvtToSintSat
  2357  	} else {
  2358  		i.opcode = OpcodeVFcvtToUintSat
  2359  	}
  2360  	i.v = x
  2361  	i.u1 = uint64(lane)
  2362  	return i
  2363  }
  2364  
  2365  // AsVFcvtFromInt initializes this instruction as an instruction with either OpcodeVFcvtToSintSat or OpcodeVFcvtToUintSat
  2366  func (i *Instruction) AsVFcvtFromInt(x Value, lane VecLane, signed bool) *Instruction {
  2367  	if signed {
  2368  		i.opcode = OpcodeVFcvtFromSint
  2369  	} else {
  2370  		i.opcode = OpcodeVFcvtFromUint
  2371  	}
  2372  	i.v = x
  2373  	i.u1 = uint64(lane)
  2374  	return i
  2375  }
  2376  
  2377  // AsNarrow initializes this instruction as an instruction with either OpcodeSnarrow or OpcodeUnarrow
  2378  func (i *Instruction) AsNarrow(x, y Value, lane VecLane, signed bool) *Instruction {
  2379  	if signed {
  2380  		i.opcode = OpcodeSnarrow
  2381  	} else {
  2382  		i.opcode = OpcodeUnarrow
  2383  	}
  2384  	i.v = x
  2385  	i.v2 = y
  2386  	i.u1 = uint64(lane)
  2387  	return i
  2388  }
  2389  
  2390  // AsFvpromoteLow initializes this instruction as an instruction with OpcodeFvpromoteLow
  2391  func (i *Instruction) AsFvpromoteLow(x Value, lane VecLane) *Instruction {
  2392  	i.opcode = OpcodeFvpromoteLow
  2393  	i.v = x
  2394  	i.u1 = uint64(lane)
  2395  	return i
  2396  }
  2397  
  2398  // AsFvdemote initializes this instruction as an instruction with OpcodeFvdemote
  2399  func (i *Instruction) AsFvdemote(x Value, lane VecLane) *Instruction {
  2400  	i.opcode = OpcodeFvdemote
  2401  	i.v = x
  2402  	i.u1 = uint64(lane)
  2403  	return i
  2404  }
  2405  
  2406  // AsSExtend initializes this instruction as a sign extension instruction with OpcodeSExtend.
  2407  func (i *Instruction) AsSExtend(v Value, from, to byte) *Instruction {
  2408  	i.opcode = OpcodeSExtend
  2409  	i.v = v
  2410  	i.u1 = uint64(from)<<8 | uint64(to)
  2411  	if to == 64 {
  2412  		i.typ = TypeI64
  2413  	} else {
  2414  		i.typ = TypeI32
  2415  	}
  2416  	return i
  2417  }
  2418  
  2419  // AsUExtend initializes this instruction as an unsigned extension instruction with OpcodeUExtend.
  2420  func (i *Instruction) AsUExtend(v Value, from, to byte) *Instruction {
  2421  	i.opcode = OpcodeUExtend
  2422  	i.v = v
  2423  	i.u1 = uint64(from)<<8 | uint64(to)
  2424  	if to == 64 {
  2425  		i.typ = TypeI64
  2426  	} else {
  2427  		i.typ = TypeI32
  2428  	}
  2429  	return i
  2430  }
  2431  
  2432  func (i *Instruction) ExtendData() (from, to byte, signed bool) {
  2433  	if i.opcode != OpcodeSExtend && i.opcode != OpcodeUExtend {
  2434  		panic("BUG: ExtendData only available for OpcodeSExtend and OpcodeUExtend")
  2435  	}
  2436  	from = byte(i.u1 >> 8)
  2437  	to = byte(i.u1)
  2438  	signed = i.opcode == OpcodeSExtend
  2439  	return
  2440  }
  2441  
  2442  // AsSelect initializes this instruction as an unsigned extension instruction with OpcodeSelect.
  2443  func (i *Instruction) AsSelect(c, x, y Value) *Instruction {
  2444  	i.opcode = OpcodeSelect
  2445  	i.v = c
  2446  	i.v2 = x
  2447  	i.v3 = y
  2448  	i.typ = x.Type()
  2449  	return i
  2450  }
  2451  
  2452  // SelectData returns the select data for this instruction necessary for backends.
  2453  func (i *Instruction) SelectData() (c, x, y Value) {
  2454  	c = i.v
  2455  	x = i.v2
  2456  	y = i.v3
  2457  	return
  2458  }
  2459  
  2460  // ExtendFromToBits returns the from and to bit size for the extension instruction.
  2461  func (i *Instruction) ExtendFromToBits() (from, to byte) {
  2462  	from = byte(i.u1 >> 8)
  2463  	to = byte(i.u1)
  2464  	return
  2465  }
  2466  
  2467  // Format returns a string representation of this instruction with the given builder.
  2468  // For debugging purposes only.
  2469  func (i *Instruction) Format(b Builder) string {
  2470  	var instSuffix string
  2471  	switch i.opcode {
  2472  	case OpcodeExitWithCode:
  2473  		instSuffix = fmt.Sprintf(" %s, %s", i.v.Format(b), wazevoapi.ExitCode(i.u1))
  2474  	case OpcodeExitIfTrueWithCode:
  2475  		instSuffix = fmt.Sprintf(" %s, %s, %s", i.v2.Format(b), i.v.Format(b), wazevoapi.ExitCode(i.u1))
  2476  	case OpcodeIadd, OpcodeIsub, OpcodeImul, OpcodeFadd, OpcodeFsub, OpcodeFmin, OpcodeFmax, OpcodeFdiv, OpcodeFmul:
  2477  		instSuffix = fmt.Sprintf(" %s, %s", i.v.Format(b), i.v2.Format(b))
  2478  	case OpcodeIcmp:
  2479  		instSuffix = fmt.Sprintf(" %s, %s, %s", IntegerCmpCond(i.u1), i.v.Format(b), i.v2.Format(b))
  2480  	case OpcodeFcmp:
  2481  		instSuffix = fmt.Sprintf(" %s, %s, %s", FloatCmpCond(i.u1), i.v.Format(b), i.v2.Format(b))
  2482  	case OpcodeSExtend, OpcodeUExtend:
  2483  		instSuffix = fmt.Sprintf(" %s, %d->%d", i.v.Format(b), i.u1>>8, i.u1&0xff)
  2484  	case OpcodeCall, OpcodeCallIndirect:
  2485  		view := i.vs.View()
  2486  		vs := make([]string, len(view))
  2487  		for idx := range vs {
  2488  			vs[idx] = view[idx].Format(b)
  2489  		}
  2490  		if i.opcode == OpcodeCallIndirect {
  2491  			instSuffix = fmt.Sprintf(" %s:%s, %s", i.v.Format(b), SignatureID(i.u1), strings.Join(vs, ", "))
  2492  		} else {
  2493  			instSuffix = fmt.Sprintf(" %s:%s, %s", FuncRef(i.u1), SignatureID(i.u2), strings.Join(vs, ", "))
  2494  		}
  2495  	case OpcodeStore, OpcodeIstore8, OpcodeIstore16, OpcodeIstore32:
  2496  		instSuffix = fmt.Sprintf(" %s, %s, %#x", i.v.Format(b), i.v2.Format(b), uint32(i.u1))
  2497  	case OpcodeLoad, OpcodeVZeroExtLoad:
  2498  		instSuffix = fmt.Sprintf(" %s, %#x", i.v.Format(b), int32(i.u1))
  2499  	case OpcodeLoadSplat:
  2500  		instSuffix = fmt.Sprintf(".%s %s, %#x", VecLane(i.u2), i.v.Format(b), int32(i.u1))
  2501  	case OpcodeUload8, OpcodeUload16, OpcodeUload32, OpcodeSload8, OpcodeSload16, OpcodeSload32:
  2502  		instSuffix = fmt.Sprintf(" %s, %#x", i.v.Format(b), int32(i.u1))
  2503  	case OpcodeSelect, OpcodeVbitselect:
  2504  		instSuffix = fmt.Sprintf(" %s, %s, %s", i.v.Format(b), i.v2.Format(b), i.v3.Format(b))
  2505  	case OpcodeIconst:
  2506  		switch i.typ {
  2507  		case TypeI32:
  2508  			instSuffix = fmt.Sprintf("_32 %#x", uint32(i.u1))
  2509  		case TypeI64:
  2510  			instSuffix = fmt.Sprintf("_64 %#x", i.u1)
  2511  		}
  2512  	case OpcodeVconst:
  2513  		instSuffix = fmt.Sprintf(" %016x %016x", i.u1, i.u2)
  2514  	case OpcodeF32const:
  2515  		instSuffix = fmt.Sprintf(" %f", math.Float32frombits(uint32(i.u1)))
  2516  	case OpcodeF64const:
  2517  		instSuffix = fmt.Sprintf(" %f", math.Float64frombits(i.u1))
  2518  	case OpcodeReturn:
  2519  		view := i.vs.View()
  2520  		if len(view) == 0 {
  2521  			break
  2522  		}
  2523  		vs := make([]string, len(view))
  2524  		for idx := range vs {
  2525  			vs[idx] = view[idx].Format(b)
  2526  		}
  2527  		instSuffix = fmt.Sprintf(" %s", strings.Join(vs, ", "))
  2528  	case OpcodeJump:
  2529  		view := i.vs.View()
  2530  		vs := make([]string, len(view)+1)
  2531  		if i.IsFallthroughJump() {
  2532  			vs[0] = " fallthrough"
  2533  		} else {
  2534  			vs[0] = " " + i.blk.(*basicBlock).Name()
  2535  		}
  2536  		for idx := range view {
  2537  			vs[idx+1] = view[idx].Format(b)
  2538  		}
  2539  
  2540  		instSuffix = strings.Join(vs, ", ")
  2541  	case OpcodeBrz, OpcodeBrnz:
  2542  		view := i.vs.View()
  2543  		vs := make([]string, len(view)+2)
  2544  		vs[0] = " " + i.v.Format(b)
  2545  		vs[1] = i.blk.(*basicBlock).Name()
  2546  		for idx := range view {
  2547  			vs[idx+2] = view[idx].Format(b)
  2548  		}
  2549  		instSuffix = strings.Join(vs, ", ")
  2550  	case OpcodeBrTable:
  2551  		// `BrTable index, [label1, label2, ... labelN]`
  2552  		instSuffix = fmt.Sprintf(" %s", i.v.Format(b))
  2553  		instSuffix += ", ["
  2554  		for i, target := range i.targets {
  2555  			blk := target.(*basicBlock)
  2556  			if i == 0 {
  2557  				instSuffix += blk.Name()
  2558  			} else {
  2559  				instSuffix += ", " + blk.Name()
  2560  			}
  2561  		}
  2562  		instSuffix += "]"
  2563  	case OpcodeBand, OpcodeBor, OpcodeBxor, OpcodeRotr, OpcodeRotl, OpcodeIshl, OpcodeSshr, OpcodeUshr,
  2564  		OpcodeSdiv, OpcodeUdiv, OpcodeFcopysign, OpcodeSrem, OpcodeUrem,
  2565  		OpcodeVbnot, OpcodeVbxor, OpcodeVbor, OpcodeVband, OpcodeVbandnot, OpcodeVIcmp, OpcodeVFcmp:
  2566  		instSuffix = fmt.Sprintf(" %s, %s", i.v.Format(b), i.v2.Format(b))
  2567  	case OpcodeUndefined:
  2568  	case OpcodeClz, OpcodeCtz, OpcodePopcnt, OpcodeFneg, OpcodeFcvtToSint, OpcodeFcvtToUint, OpcodeFcvtFromSint,
  2569  		OpcodeFcvtFromUint, OpcodeFcvtToSintSat, OpcodeFcvtToUintSat, OpcodeFdemote, OpcodeFpromote, OpcodeIreduce, OpcodeBitcast, OpcodeSqrt, OpcodeFabs,
  2570  		OpcodeCeil, OpcodeFloor, OpcodeTrunc, OpcodeNearest:
  2571  		instSuffix = " " + i.v.Format(b)
  2572  	case OpcodeVIadd, OpcodeExtIaddPairwise, OpcodeVSaddSat, OpcodeVUaddSat, OpcodeVIsub, OpcodeVSsubSat, OpcodeVUsubSat,
  2573  		OpcodeVImin, OpcodeVUmin, OpcodeVImax, OpcodeVUmax, OpcodeVImul, OpcodeVAvgRound,
  2574  		OpcodeVFadd, OpcodeVFsub, OpcodeVFmul, OpcodeVFdiv,
  2575  		OpcodeVIshl, OpcodeVSshr, OpcodeVUshr,
  2576  		OpcodeVFmin, OpcodeVFmax, OpcodeVMinPseudo, OpcodeVMaxPseudo,
  2577  		OpcodeSnarrow, OpcodeUnarrow, OpcodeSwizzle, OpcodeSqmulRoundSat:
  2578  		instSuffix = fmt.Sprintf(".%s %s, %s", VecLane(i.u1), i.v.Format(b), i.v2.Format(b))
  2579  	case OpcodeVIabs, OpcodeVIneg, OpcodeVIpopcnt, OpcodeVhighBits, OpcodeVallTrue, OpcodeVanyTrue,
  2580  		OpcodeVFabs, OpcodeVFneg, OpcodeVSqrt, OpcodeVCeil, OpcodeVFloor, OpcodeVTrunc, OpcodeVNearest,
  2581  		OpcodeVFcvtToUintSat, OpcodeVFcvtToSintSat, OpcodeVFcvtFromUint, OpcodeVFcvtFromSint,
  2582  		OpcodeFvpromoteLow, OpcodeFvdemote, OpcodeSwidenLow, OpcodeUwidenLow, OpcodeSwidenHigh, OpcodeUwidenHigh,
  2583  		OpcodeSplat:
  2584  		instSuffix = fmt.Sprintf(".%s %s", VecLane(i.u1), i.v.Format(b))
  2585  	case OpcodeExtractlane:
  2586  		var signedness string
  2587  		if i.u1 != 0 {
  2588  			signedness = "signed"
  2589  		} else {
  2590  			signedness = "unsigned"
  2591  		}
  2592  		instSuffix = fmt.Sprintf(".%s %d, %s (%s)", VecLane(i.u2), 0x0000FFFF&i.u1, i.v.Format(b), signedness)
  2593  	case OpcodeInsertlane:
  2594  		instSuffix = fmt.Sprintf(".%s %d, %s, %s", VecLane(i.u2), i.u1, i.v.Format(b), i.v2.Format(b))
  2595  	case OpcodeShuffle:
  2596  		lanes := make([]byte, 16)
  2597  		for idx := 0; idx < 8; idx++ {
  2598  			lanes[idx] = byte(i.u1 >> (8 * idx))
  2599  		}
  2600  		for idx := 0; idx < 8; idx++ {
  2601  			lanes[idx+8] = byte(i.u2 >> (8 * idx))
  2602  		}
  2603  		// Prints Shuffle.[0 1 2 3 4 5 6 7 ...] v2, v3
  2604  		instSuffix = fmt.Sprintf(".%v %s, %s", lanes, i.v.Format(b), i.v2.Format(b))
  2605  	case OpcodeAtomicRmw:
  2606  		instSuffix = fmt.Sprintf(" %s_%d, %s, %s", AtomicRmwOp(i.u1), 8*i.u2, i.v.Format(b), i.v2.Format(b))
  2607  	case OpcodeAtomicLoad:
  2608  		instSuffix = fmt.Sprintf("_%d, %s", 8*i.u1, i.v.Format(b))
  2609  	case OpcodeAtomicStore:
  2610  		instSuffix = fmt.Sprintf("_%d, %s, %s", 8*i.u1, i.v.Format(b), i.v2.Format(b))
  2611  	case OpcodeAtomicCas:
  2612  		instSuffix = fmt.Sprintf("_%d, %s, %s, %s", 8*i.u1, i.v.Format(b), i.v2.Format(b), i.v3.Format(b))
  2613  	case OpcodeFence:
  2614  		instSuffix = fmt.Sprintf(" %d", i.u1)
  2615  	case OpcodeWideningPairwiseDotProductS:
  2616  		instSuffix = fmt.Sprintf(" %s, %s", i.v.Format(b), i.v2.Format(b))
  2617  	default:
  2618  		panic(fmt.Sprintf("TODO: format for %s", i.opcode))
  2619  	}
  2620  
  2621  	instr := i.opcode.String() + instSuffix
  2622  
  2623  	var rvs []string
  2624  	if rv := i.rValue; rv.Valid() {
  2625  		rvs = append(rvs, rv.formatWithType(b))
  2626  	}
  2627  
  2628  	for _, v := range i.rValues.View() {
  2629  		rvs = append(rvs, v.formatWithType(b))
  2630  	}
  2631  
  2632  	if len(rvs) > 0 {
  2633  		return fmt.Sprintf("%s = %s", strings.Join(rvs, ", "), instr)
  2634  	} else {
  2635  		return instr
  2636  	}
  2637  }
  2638  
  2639  // addArgumentBranchInst adds an argument to this instruction.
  2640  func (i *Instruction) addArgumentBranchInst(b *builder, v Value) {
  2641  	switch i.opcode {
  2642  	case OpcodeJump, OpcodeBrz, OpcodeBrnz:
  2643  		i.vs = i.vs.Append(&b.varLengthPool, v)
  2644  	default:
  2645  		panic("BUG: " + i.opcode.String())
  2646  	}
  2647  }
  2648  
  2649  // Constant returns true if this instruction is a constant instruction.
  2650  func (i *Instruction) Constant() bool {
  2651  	switch i.opcode {
  2652  	case OpcodeIconst, OpcodeF32const, OpcodeF64const:
  2653  		return true
  2654  	}
  2655  	return false
  2656  }
  2657  
  2658  // ConstantVal returns the constant value of this instruction.
  2659  // How to interpret the return value depends on the opcode.
  2660  func (i *Instruction) ConstantVal() (ret uint64) {
  2661  	switch i.opcode {
  2662  	case OpcodeIconst, OpcodeF32const, OpcodeF64const:
  2663  		ret = i.u1
  2664  	default:
  2665  		panic("TODO")
  2666  	}
  2667  	return
  2668  }
  2669  
  2670  // String implements fmt.Stringer.
  2671  func (o Opcode) String() (ret string) {
  2672  	switch o {
  2673  	case OpcodeInvalid:
  2674  		return "invalid"
  2675  	case OpcodeUndefined:
  2676  		return "Undefined"
  2677  	case OpcodeJump:
  2678  		return "Jump"
  2679  	case OpcodeBrz:
  2680  		return "Brz"
  2681  	case OpcodeBrnz:
  2682  		return "Brnz"
  2683  	case OpcodeBrTable:
  2684  		return "BrTable"
  2685  	case OpcodeExitWithCode:
  2686  		return "Exit"
  2687  	case OpcodeExitIfTrueWithCode:
  2688  		return "ExitIfTrue"
  2689  	case OpcodeReturn:
  2690  		return "Return"
  2691  	case OpcodeCall:
  2692  		return "Call"
  2693  	case OpcodeCallIndirect:
  2694  		return "CallIndirect"
  2695  	case OpcodeSplat:
  2696  		return "Splat"
  2697  	case OpcodeSwizzle:
  2698  		return "Swizzle"
  2699  	case OpcodeInsertlane:
  2700  		return "Insertlane"
  2701  	case OpcodeExtractlane:
  2702  		return "Extractlane"
  2703  	case OpcodeLoad:
  2704  		return "Load"
  2705  	case OpcodeLoadSplat:
  2706  		return "LoadSplat"
  2707  	case OpcodeStore:
  2708  		return "Store"
  2709  	case OpcodeUload8:
  2710  		return "Uload8"
  2711  	case OpcodeSload8:
  2712  		return "Sload8"
  2713  	case OpcodeIstore8:
  2714  		return "Istore8"
  2715  	case OpcodeUload16:
  2716  		return "Uload16"
  2717  	case OpcodeSload16:
  2718  		return "Sload16"
  2719  	case OpcodeIstore16:
  2720  		return "Istore16"
  2721  	case OpcodeUload32:
  2722  		return "Uload32"
  2723  	case OpcodeSload32:
  2724  		return "Sload32"
  2725  	case OpcodeIstore32:
  2726  		return "Istore32"
  2727  	case OpcodeIconst:
  2728  		return "Iconst"
  2729  	case OpcodeF32const:
  2730  		return "F32const"
  2731  	case OpcodeF64const:
  2732  		return "F64const"
  2733  	case OpcodeVconst:
  2734  		return "Vconst"
  2735  	case OpcodeShuffle:
  2736  		return "Shuffle"
  2737  	case OpcodeSelect:
  2738  		return "Select"
  2739  	case OpcodeVanyTrue:
  2740  		return "VanyTrue"
  2741  	case OpcodeVallTrue:
  2742  		return "VallTrue"
  2743  	case OpcodeVhighBits:
  2744  		return "VhighBits"
  2745  	case OpcodeIcmp:
  2746  		return "Icmp"
  2747  	case OpcodeIcmpImm:
  2748  		return "IcmpImm"
  2749  	case OpcodeVIcmp:
  2750  		return "VIcmp"
  2751  	case OpcodeIadd:
  2752  		return "Iadd"
  2753  	case OpcodeIsub:
  2754  		return "Isub"
  2755  	case OpcodeImul:
  2756  		return "Imul"
  2757  	case OpcodeUdiv:
  2758  		return "Udiv"
  2759  	case OpcodeSdiv:
  2760  		return "Sdiv"
  2761  	case OpcodeUrem:
  2762  		return "Urem"
  2763  	case OpcodeSrem:
  2764  		return "Srem"
  2765  	case OpcodeBand:
  2766  		return "Band"
  2767  	case OpcodeBor:
  2768  		return "Bor"
  2769  	case OpcodeBxor:
  2770  		return "Bxor"
  2771  	case OpcodeBnot:
  2772  		return "Bnot"
  2773  	case OpcodeRotl:
  2774  		return "Rotl"
  2775  	case OpcodeRotr:
  2776  		return "Rotr"
  2777  	case OpcodeIshl:
  2778  		return "Ishl"
  2779  	case OpcodeUshr:
  2780  		return "Ushr"
  2781  	case OpcodeSshr:
  2782  		return "Sshr"
  2783  	case OpcodeClz:
  2784  		return "Clz"
  2785  	case OpcodeCtz:
  2786  		return "Ctz"
  2787  	case OpcodePopcnt:
  2788  		return "Popcnt"
  2789  	case OpcodeFcmp:
  2790  		return "Fcmp"
  2791  	case OpcodeFadd:
  2792  		return "Fadd"
  2793  	case OpcodeFsub:
  2794  		return "Fsub"
  2795  	case OpcodeFmul:
  2796  		return "Fmul"
  2797  	case OpcodeFdiv:
  2798  		return "Fdiv"
  2799  	case OpcodeSqmulRoundSat:
  2800  		return "SqmulRoundSat"
  2801  	case OpcodeSqrt:
  2802  		return "Sqrt"
  2803  	case OpcodeFneg:
  2804  		return "Fneg"
  2805  	case OpcodeFabs:
  2806  		return "Fabs"
  2807  	case OpcodeFcopysign:
  2808  		return "Fcopysign"
  2809  	case OpcodeFmin:
  2810  		return "Fmin"
  2811  	case OpcodeFmax:
  2812  		return "Fmax"
  2813  	case OpcodeCeil:
  2814  		return "Ceil"
  2815  	case OpcodeFloor:
  2816  		return "Floor"
  2817  	case OpcodeTrunc:
  2818  		return "Trunc"
  2819  	case OpcodeNearest:
  2820  		return "Nearest"
  2821  	case OpcodeBitcast:
  2822  		return "Bitcast"
  2823  	case OpcodeIreduce:
  2824  		return "Ireduce"
  2825  	case OpcodeSnarrow:
  2826  		return "Snarrow"
  2827  	case OpcodeUnarrow:
  2828  		return "Unarrow"
  2829  	case OpcodeSwidenLow:
  2830  		return "SwidenLow"
  2831  	case OpcodeSwidenHigh:
  2832  		return "SwidenHigh"
  2833  	case OpcodeUwidenLow:
  2834  		return "UwidenLow"
  2835  	case OpcodeUwidenHigh:
  2836  		return "UwidenHigh"
  2837  	case OpcodeExtIaddPairwise:
  2838  		return "IaddPairwise"
  2839  	case OpcodeWideningPairwiseDotProductS:
  2840  		return "WideningPairwiseDotProductS"
  2841  	case OpcodeUExtend:
  2842  		return "UExtend"
  2843  	case OpcodeSExtend:
  2844  		return "SExtend"
  2845  	case OpcodeFpromote:
  2846  		return "Fpromote"
  2847  	case OpcodeFdemote:
  2848  		return "Fdemote"
  2849  	case OpcodeFvdemote:
  2850  		return "Fvdemote"
  2851  	case OpcodeFcvtToUint:
  2852  		return "FcvtToUint"
  2853  	case OpcodeFcvtToSint:
  2854  		return "FcvtToSint"
  2855  	case OpcodeFcvtToUintSat:
  2856  		return "FcvtToUintSat"
  2857  	case OpcodeFcvtToSintSat:
  2858  		return "FcvtToSintSat"
  2859  	case OpcodeFcvtFromUint:
  2860  		return "FcvtFromUint"
  2861  	case OpcodeFcvtFromSint:
  2862  		return "FcvtFromSint"
  2863  	case OpcodeAtomicRmw:
  2864  		return "AtomicRmw"
  2865  	case OpcodeAtomicCas:
  2866  		return "AtomicCas"
  2867  	case OpcodeAtomicLoad:
  2868  		return "AtomicLoad"
  2869  	case OpcodeAtomicStore:
  2870  		return "AtomicStore"
  2871  	case OpcodeFence:
  2872  		return "Fence"
  2873  	case OpcodeVbor:
  2874  		return "Vbor"
  2875  	case OpcodeVbxor:
  2876  		return "Vbxor"
  2877  	case OpcodeVband:
  2878  		return "Vband"
  2879  	case OpcodeVbandnot:
  2880  		return "Vbandnot"
  2881  	case OpcodeVbnot:
  2882  		return "Vbnot"
  2883  	case OpcodeVbitselect:
  2884  		return "Vbitselect"
  2885  	case OpcodeVIadd:
  2886  		return "VIadd"
  2887  	case OpcodeVSaddSat:
  2888  		return "VSaddSat"
  2889  	case OpcodeVUaddSat:
  2890  		return "VUaddSat"
  2891  	case OpcodeVSsubSat:
  2892  		return "VSsubSat"
  2893  	case OpcodeVUsubSat:
  2894  		return "VUsubSat"
  2895  	case OpcodeVAvgRound:
  2896  		return "OpcodeVAvgRound"
  2897  	case OpcodeVIsub:
  2898  		return "VIsub"
  2899  	case OpcodeVImin:
  2900  		return "VImin"
  2901  	case OpcodeVUmin:
  2902  		return "VUmin"
  2903  	case OpcodeVImax:
  2904  		return "VImax"
  2905  	case OpcodeVUmax:
  2906  		return "VUmax"
  2907  	case OpcodeVImul:
  2908  		return "VImul"
  2909  	case OpcodeVIabs:
  2910  		return "VIabs"
  2911  	case OpcodeVIneg:
  2912  		return "VIneg"
  2913  	case OpcodeVIpopcnt:
  2914  		return "VIpopcnt"
  2915  	case OpcodeVIshl:
  2916  		return "VIshl"
  2917  	case OpcodeVUshr:
  2918  		return "VUshr"
  2919  	case OpcodeVSshr:
  2920  		return "VSshr"
  2921  	case OpcodeVFabs:
  2922  		return "VFabs"
  2923  	case OpcodeVFmax:
  2924  		return "VFmax"
  2925  	case OpcodeVFmin:
  2926  		return "VFmin"
  2927  	case OpcodeVFneg:
  2928  		return "VFneg"
  2929  	case OpcodeVFadd:
  2930  		return "VFadd"
  2931  	case OpcodeVFsub:
  2932  		return "VFsub"
  2933  	case OpcodeVFmul:
  2934  		return "VFmul"
  2935  	case OpcodeVFdiv:
  2936  		return "VFdiv"
  2937  	case OpcodeVFcmp:
  2938  		return "VFcmp"
  2939  	case OpcodeVCeil:
  2940  		return "VCeil"
  2941  	case OpcodeVFloor:
  2942  		return "VFloor"
  2943  	case OpcodeVTrunc:
  2944  		return "VTrunc"
  2945  	case OpcodeVNearest:
  2946  		return "VNearest"
  2947  	case OpcodeVMaxPseudo:
  2948  		return "VMaxPseudo"
  2949  	case OpcodeVMinPseudo:
  2950  		return "VMinPseudo"
  2951  	case OpcodeVSqrt:
  2952  		return "VSqrt"
  2953  	case OpcodeVFcvtToUintSat:
  2954  		return "VFcvtToUintSat"
  2955  	case OpcodeVFcvtToSintSat:
  2956  		return "VFcvtToSintSat"
  2957  	case OpcodeVFcvtFromUint:
  2958  		return "VFcvtFromUint"
  2959  	case OpcodeVFcvtFromSint:
  2960  		return "VFcvtFromSint"
  2961  	case OpcodeFvpromoteLow:
  2962  		return "FvpromoteLow"
  2963  	case OpcodeVZeroExtLoad:
  2964  		return "VZeroExtLoad"
  2965  	}
  2966  	panic(fmt.Sprintf("unknown opcode %d", o))
  2967  }