instructions.go

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