package ssa

import (
	
	
	

	
)

// Opcode represents a SSA instruction.
type Opcode uint32

// Instruction represents an instruction whose opcode is specified by
// Opcode. Since Go doesn't have union type, we use this flattened type
// for all instructions, and therefore each field has different meaning
// depending on Opcode.
type Instruction struct {
	// id is the unique ID of this instruction which ascends from 0 following the order of program.
	id         int
	opcode     Opcode
	u1, u2     uint64
	v          Value
	v2         Value
	v3         Value
	vs         Values
	typ        Type
	prev, next *Instruction

	// rValue is the (first) return value of this instruction.
	// For branching instructions except for OpcodeBrTable, they hold BlockID to jump cast to Value.
	rValue Value
	// rValues are the rest of the return values of this instruction.
	// For OpcodeBrTable, it holds the list of BlockID to jump cast to Value.
	rValues        Values
	gid            InstructionGroupID
	sourceOffset   SourceOffset
	live           bool
	alreadyLowered bool
}

// SourceOffset represents the offset of the source of an instruction.
type SourceOffset int64

const sourceOffsetUnknown = -1

// Valid returns true if this source offset is valid.
func ( SourceOffset) () bool {
	return  != sourceOffsetUnknown
}

func ( *Instruction) ( SourceOffset) {
	.sourceOffset = 
}

// SourceOffset returns the source offset of this instruction.
func ( *Instruction) () SourceOffset {
	return .sourceOffset
}

// Opcode returns the opcode of this instruction.
func ( *Instruction) () Opcode {
	return .opcode
}

// GroupID returns the InstructionGroupID of this instruction.
func ( *Instruction) () InstructionGroupID {
	return .gid
}

// MarkLowered marks this instruction as already lowered.
func ( *Instruction) () {
	.alreadyLowered = true
}

// Lowered returns true if this instruction is already lowered.
func ( *Instruction) () bool {
	return .alreadyLowered
}

// resetInstruction resets this instruction to the initial state.
func resetInstruction( *Instruction) {
	* = Instruction{}
	.v = ValueInvalid
	.v2 = ValueInvalid
	.v3 = ValueInvalid
	.rValue = ValueInvalid
	.typ = typeInvalid
	.vs = ValuesNil
	.sourceOffset = sourceOffsetUnknown
}

// InstructionGroupID is assigned to each instruction and represents a group of instructions
// where each instruction is interchangeable with others except for the last instruction
// in the group which has side effects. In short, InstructionGroupID is determined by the side effects of instructions.
// That means, if there's an instruction with side effect between two instructions, then these two instructions
// will have different instructionGroupID. Note that each block always ends with branching, which is with side effects,
// therefore, instructions in different blocks always have different InstructionGroupID(s).
//
// The notable application of this is used in lowering SSA-level instruction to a ISA specific instruction,
// where we eagerly try to merge multiple instructions into single operation etc. Such merging cannot be done
// if these instruction have different InstructionGroupID since it will change the semantics of a program.
//
// See passDeadCodeElimination.
type InstructionGroupID uint32

// Returns Value(s) produced by this instruction if any.
// The `first` is the first return value, and `rest` is the rest of the values.
func ( *Instruction) () ( Value,  []Value) {
	if .IsBranching() {
		return ValueInvalid, nil
	}
	return .rValue, .rValues.View()
}

// Return returns a Value(s) produced by this instruction if any.
// If there's multiple return values, only the first one is returned.
func ( *Instruction) () ( Value) {
	return .rValue
}

// Args returns the arguments to this instruction.
func ( *Instruction) () (, ,  Value,  []Value) {
	return .v, .v2, .v3, .vs.View()
}

// Arg returns the first argument to this instruction.
func ( *Instruction) () Value {
	return .v
}

// Arg2 returns the first two arguments to this instruction.
func ( *Instruction) () (Value, Value) {
	return .v, .v2
}

// ArgWithLane returns the first argument to this instruction, and the lane type.
func ( *Instruction) () (Value, VecLane) {
	return .v, VecLane(.u1)
}

// Arg2WithLane returns the first two arguments to this instruction, and the lane type.
func ( *Instruction) () (Value, Value, VecLane) {
	return .v, .v2, VecLane(.u1)
}

// ShuffleData returns the first two arguments to this instruction and 2 uint64s `lo`, `hi`.
//
// Note: Each uint64 encodes a sequence of 8 bytes where each byte encodes a VecLane,
// so that the 128bit integer `hi<<64|lo` packs a slice `[16]VecLane`,
// where `lane[0]` is the least significant byte, and `lane[n]` is shifted to offset `n*8`.
func ( *Instruction) () ( Value,  Value,  uint64,  uint64) {
	return .v, .v2, .u1, .u2
}

// Arg3 returns the first three arguments to this instruction.
func ( *Instruction) () (Value, Value, Value) {
	return .v, .v2, .v3
}

// Next returns the next instruction laid out next to itself.
func ( *Instruction) () *Instruction {
	return .next
}

// Prev returns the previous instruction laid out prior to itself.
func ( *Instruction) () *Instruction {
	return .prev
}

// IsBranching returns true if this instruction is a branching instruction.
func ( *Instruction) () bool {
	switch .opcode {
	case OpcodeJump, OpcodeBrz, OpcodeBrnz, OpcodeBrTable:
		return true
	default:
		return false
	}
}

// TODO: complete opcode comments.
const (
	OpcodeInvalid Opcode = iota

	// OpcodeUndefined is a placeholder for undefined opcode. This can be used for debugging to intentionally
	// cause a crash at certain point.
	OpcodeUndefined

	// OpcodeJump takes the list of args to the `block` and unconditionally jumps to it.
	OpcodeJump

	// OpcodeBrz branches into `blk` with `args`  if the value `c` equals zero: `Brz c, blk, args`.
	OpcodeBrz

	// OpcodeBrnz branches into `blk` with `args`  if the value `c` is not zero: `Brnz c, blk, args`.
	OpcodeBrnz

	// OpcodeBrTable takes the index value `index`, and branches into `labelX`. If the `index` is out of range,
	// it branches into the last labelN: `BrTable index, [label1, label2, ... labelN]`.
	OpcodeBrTable

	// OpcodeExitWithCode exit the execution immediately.
	OpcodeExitWithCode

	// OpcodeExitIfTrueWithCode exits the execution immediately if the value `c` is not zero.
	OpcodeExitIfTrueWithCode

	// OpcodeReturn returns from the function: `return rvalues`.
	OpcodeReturn

	// OpcodeCall calls a function specified by the symbol FN with arguments `args`: `returnvals = Call FN, args...`
	// This is a "near" call, which means the call target is known at compile time, and the target is relatively close
	// to this function. If the target cannot be reached by near call, the backend fails to compile.
	OpcodeCall

	// OpcodeCallIndirect calls a function specified by `callee` which is a function address: `returnvals = call_indirect SIG, callee, args`.
	// Note that this is different from call_indirect in Wasm, which also does type checking, etc.
	OpcodeCallIndirect

	// OpcodeSplat performs a vector splat operation: `v = Splat.lane x`.
	OpcodeSplat

	// OpcodeSwizzle performs a vector swizzle operation: `v = Swizzle.lane x, y`.
	OpcodeSwizzle

	// OpcodeInsertlane inserts a lane value into a vector: `v = InsertLane x, y, Idx`.
	OpcodeInsertlane

	// OpcodeExtractlane extracts a lane value from a vector: `v = ExtractLane x, Idx`.
	OpcodeExtractlane

	// OpcodeLoad loads a Type value from the [base + offset] address: `v = Load base, offset`.
	OpcodeLoad

	// OpcodeStore stores a Type value to the [base + offset] address: `Store v, base, offset`.
	OpcodeStore

	// OpcodeUload8 loads the 8-bit value from the [base + offset] address, zero-extended to 64 bits: `v = Uload8 base, offset`.
	OpcodeUload8

	// OpcodeSload8 loads the 8-bit value from the [base + offset] address, sign-extended to 64 bits: `v = Sload8 base, offset`.
	OpcodeSload8

	// OpcodeIstore8 stores the 8-bit value to the [base + offset] address, sign-extended to 64 bits: `Istore8 v, base, offset`.
	OpcodeIstore8

	// OpcodeUload16 loads the 16-bit value from the [base + offset] address, zero-extended to 64 bits: `v = Uload16 base, offset`.
	OpcodeUload16

	// OpcodeSload16 loads the 16-bit value from the [base + offset] address, sign-extended to 64 bits: `v = Sload16 base, offset`.
	OpcodeSload16

	// OpcodeIstore16 stores the 16-bit value to the [base + offset] address, zero-extended to 64 bits: `Istore16 v, base, offset`.
	OpcodeIstore16

	// OpcodeUload32 loads the 32-bit value from the [base + offset] address, zero-extended to 64 bits: `v = Uload32 base, offset`.
	OpcodeUload32

	// OpcodeSload32 loads the 32-bit value from the [base + offset] address, sign-extended to 64 bits: `v = Sload32 base, offset`.
	OpcodeSload32

	// OpcodeIstore32 stores the 32-bit value to the [base + offset] address, zero-extended to 64 bits: `Istore16 v, base, offset`.
	OpcodeIstore32

	// OpcodeLoadSplat represents a load that replicates the loaded value to all lanes `v = LoadSplat.lane p, Offset`.
	OpcodeLoadSplat

	// OpcodeVZeroExtLoad loads a scalar single/double precision floating point value from the [p + Offset] address,
	// and zero-extend it to the V128 value: `v = VExtLoad  p, Offset`.
	OpcodeVZeroExtLoad

	// OpcodeIconst represents the integer const.
	OpcodeIconst

	// OpcodeF32const represents the single-precision const.
	OpcodeF32const

	// OpcodeF64const represents the double-precision const.
	OpcodeF64const

	// OpcodeVconst represents the 128bit vector const.
	OpcodeVconst

	// OpcodeVbor computes binary or between two 128bit vectors: `v = bor x, y`.
	OpcodeVbor

	// OpcodeVbxor computes binary xor between two 128bit vectors: `v = bxor x, y`.
	OpcodeVbxor

	// OpcodeVband computes binary and between two 128bit vectors: `v = band x, y`.
	OpcodeVband

	// OpcodeVbandnot computes binary and-not between two 128bit vectors: `v = bandnot x, y`.
	OpcodeVbandnot

	// OpcodeVbnot negates a 128bit vector: `v = bnot x`.
	OpcodeVbnot

	// OpcodeVbitselect uses the bits in the control mask c to select the corresponding bit from x when 1
	// and y when 0: `v = bitselect c, x, y`.
	OpcodeVbitselect

	// OpcodeShuffle shuffles two vectors using the given 128-bit immediate: `v = shuffle imm, x, y`.
	// For each byte in the immediate, a value i in [0, 15] selects the i-th byte in vector x;
	// i in [16, 31] selects the (i-16)-th byte in vector y.
	OpcodeShuffle

	// OpcodeSelect chooses between two values based on a condition `c`: `v = Select c, x, y`.
	OpcodeSelect

	// OpcodeVanyTrue performs a any true operation: `s = VanyTrue a`.
	OpcodeVanyTrue

	// OpcodeVallTrue performs a lane-wise all true operation: `s = VallTrue.lane a`.
	OpcodeVallTrue

	// OpcodeVhighBits performs a lane-wise extract of the high bits: `v = VhighBits.lane a`.
	OpcodeVhighBits

	// OpcodeIcmp compares two integer values with the given condition: `v = icmp Cond, x, y`.
	OpcodeIcmp

	// OpcodeVIcmp compares two integer values with the given condition: `v = vicmp Cond, x, y` on vector.
	OpcodeVIcmp

	// OpcodeIcmpImm compares an integer value with the immediate value on the given condition: `v = icmp_imm Cond, x, Y`.
	OpcodeIcmpImm

	// OpcodeIadd performs an integer addition: `v = Iadd x, y`.
	OpcodeIadd

	// OpcodeVIadd performs an integer addition: `v = VIadd.lane x, y` on vector.
	OpcodeVIadd

	// OpcodeVSaddSat performs a signed saturating vector addition: `v = VSaddSat.lane x, y` on vector.
	OpcodeVSaddSat

	// OpcodeVUaddSat performs an unsigned saturating vector addition: `v = VUaddSat.lane x, y` on vector.
	OpcodeVUaddSat

	// OpcodeIsub performs an integer subtraction: `v = Isub x, y`.
	OpcodeIsub

	// OpcodeVIsub performs an integer subtraction: `v = VIsub.lane x, y` on vector.
	OpcodeVIsub

	// OpcodeVSsubSat performs a signed saturating vector subtraction: `v = VSsubSat.lane x, y` on vector.
	OpcodeVSsubSat

	// OpcodeVUsubSat performs an unsigned saturating vector subtraction: `v = VUsubSat.lane x, y` on vector.
	OpcodeVUsubSat

	// OpcodeVImin performs a signed integer min: `v = VImin.lane x, y` on vector.
	OpcodeVImin

	// OpcodeVUmin performs an unsigned integer min: `v = VUmin.lane x, y` on vector.
	OpcodeVUmin

	// OpcodeVImax performs a signed integer max: `v = VImax.lane x, y` on vector.
	OpcodeVImax

	// OpcodeVUmax performs an unsigned integer max: `v = VUmax.lane x, y` on vector.
	OpcodeVUmax

	// OpcodeVAvgRound performs an unsigned integer avg, truncating to zero: `v = VAvgRound.lane x, y` on vector.
	OpcodeVAvgRound

	// OpcodeVImul performs an integer multiplication: `v = VImul.lane x, y` on vector.
	OpcodeVImul

	// OpcodeVIneg negates the given integer vector value: `v = VIneg x`.
	OpcodeVIneg

	// OpcodeVIpopcnt counts the number of 1-bits in the given vector: `v = VIpopcnt x`.
	OpcodeVIpopcnt

	// OpcodeVIabs returns the absolute value for the given vector value: `v = VIabs.lane x`.
	OpcodeVIabs

	// OpcodeVIshl shifts x left by (y mod lane-width): `v = VIshl.lane x, y` on vector.
	OpcodeVIshl

	// OpcodeVUshr shifts x right by (y mod lane-width), unsigned: `v = VUshr.lane x, y` on vector.
	OpcodeVUshr

	// OpcodeVSshr shifts x right by (y mod lane-width), signed: `v = VSshr.lane x, y` on vector.
	OpcodeVSshr

	// OpcodeVFabs takes the absolute value of a floating point value: `v = VFabs.lane x on vector.
	OpcodeVFabs

	// OpcodeVFmax takes the maximum of two floating point values: `v = VFmax.lane x, y on vector.
	OpcodeVFmax

	// OpcodeVFmin takes the minimum of two floating point values: `v = VFmin.lane x, y on vector.
	OpcodeVFmin

	// OpcodeVFneg negates the given floating point vector value: `v = VFneg x`.
	OpcodeVFneg

	// OpcodeVFadd performs a floating point addition: `v = VFadd.lane x, y` on vector.
	OpcodeVFadd

	// OpcodeVFsub performs a floating point subtraction: `v = VFsub.lane x, y` on vector.
	OpcodeVFsub

	// OpcodeVFmul performs a floating point multiplication: `v = VFmul.lane x, y` on vector.
	OpcodeVFmul

	// OpcodeVFdiv performs a floating point division: `v = VFdiv.lane x, y` on vector.
	OpcodeVFdiv

	// OpcodeVFcmp compares two float values with the given condition: `v = VFcmp.lane Cond, x, y` on float.
	OpcodeVFcmp

	// OpcodeVCeil takes the ceiling of the given floating point value: `v = ceil.lane x` on vector.
	OpcodeVCeil

	// OpcodeVFloor takes the floor of the given floating point value: `v = floor.lane x` on vector.
	OpcodeVFloor

	// OpcodeVTrunc takes the truncation of the given floating point value: `v = trunc.lane x` on vector.
	OpcodeVTrunc

	// OpcodeVNearest takes the nearest integer of the given floating point value: `v = nearest.lane x` on vector.
	OpcodeVNearest

	// OpcodeVMaxPseudo computes the lane-wise maximum value `v = VMaxPseudo.lane x, y` on vector defined as `x < y ? x : y`.
	OpcodeVMaxPseudo

	// OpcodeVMinPseudo computes the lane-wise minimum value `v = VMinPseudo.lane x, y` on vector defined as `y < x ? x : y`.
	OpcodeVMinPseudo

	// OpcodeVSqrt takes the minimum of two floating point values: `v = VFmin.lane x, y` on vector.
	OpcodeVSqrt

	// OpcodeVFcvtToUintSat converts a floating point value to an unsigned integer: `v = FcvtToUintSat.lane x` on vector.
	OpcodeVFcvtToUintSat

	// OpcodeVFcvtToSintSat converts a floating point value to a signed integer: `v = VFcvtToSintSat.lane x` on vector.
	OpcodeVFcvtToSintSat

	// OpcodeVFcvtFromUint converts a floating point value from an unsigned integer: `v = FcvtFromUint.lane x` on vector.
	// x is always a 32-bit integer lane, and the result is either a 32-bit or 64-bit floating point-sized vector.
	OpcodeVFcvtFromUint

	// OpcodeVFcvtFromSint converts a floating point value from a signed integer: `v = VFcvtFromSint.lane x` on vector.
	// x is always a 32-bit integer lane, and the result is either a 32-bit or 64-bit floating point-sized vector.
	OpcodeVFcvtFromSint

	// OpcodeImul performs an integer multiplication: `v = Imul x, y`.
	OpcodeImul

	// OpcodeUdiv performs the unsigned integer division `v = Udiv x, y`.
	OpcodeUdiv

	// OpcodeSdiv performs the signed integer division `v = Sdiv x, y`.
	OpcodeSdiv

	// OpcodeUrem computes the remainder of the unsigned integer division `v = Urem x, y`.
	OpcodeUrem

	// OpcodeSrem computes the remainder of the signed integer division `v = Srem x, y`.
	OpcodeSrem

	// OpcodeBand performs a binary and: `v = Band x, y`.
	OpcodeBand

	// OpcodeBor performs a binary or: `v = Bor x, y`.
	OpcodeBor

	// OpcodeBxor performs a binary xor: `v = Bxor x, y`.
	OpcodeBxor

	// OpcodeBnot performs a binary not: `v = Bnot x`.
	OpcodeBnot

	// OpcodeRotl rotates the given integer value to the left: `v = Rotl x, y`.
	OpcodeRotl

	// OpcodeRotr rotates the given integer value to the right: `v = Rotr x, y`.
	OpcodeRotr

	// OpcodeIshl does logical shift left: `v = Ishl x, y`.
	OpcodeIshl

	// OpcodeUshr does logical shift right: `v = Ushr x, y`.
	OpcodeUshr

	// OpcodeSshr does arithmetic shift right: `v = Sshr x, y`.
	OpcodeSshr

	// OpcodeClz counts the number of leading zeros: `v = clz x`.
	OpcodeClz

	// OpcodeCtz counts the number of trailing zeros: `v = ctz x`.
	OpcodeCtz

	// OpcodePopcnt counts the number of 1-bits: `v = popcnt x`.
	OpcodePopcnt

	// OpcodeFcmp compares two floating point values: `v = fcmp Cond, x, y`.
	OpcodeFcmp

	// OpcodeFadd performs a floating point addition: / `v = Fadd x, y`.
	OpcodeFadd

	// OpcodeFsub performs a floating point subtraction: `v = Fsub x, y`.
	OpcodeFsub

	// OpcodeFmul performs a floating point multiplication: `v = Fmul x, y`.
	OpcodeFmul

	// OpcodeSqmulRoundSat performs a lane-wise saturating rounding multiplication
	// in Q15 format: `v = SqmulRoundSat.lane x,y` on vector.
	OpcodeSqmulRoundSat

	// OpcodeFdiv performs a floating point division: `v = Fdiv x, y`.
	OpcodeFdiv

	// OpcodeSqrt takes the square root of the given floating point value: `v = sqrt x`.
	OpcodeSqrt

	// OpcodeFneg negates the given floating point value: `v = Fneg x`.
	OpcodeFneg

	// OpcodeFabs takes the absolute value of the given floating point value: `v = fabs x`.
	OpcodeFabs

	// OpcodeFcopysign copies the sign of the second floating point value to the first floating point value:
	// `v = Fcopysign x, y`.
	OpcodeFcopysign

	// OpcodeFmin takes the minimum of two floating point values: `v = fmin x, y`.
	OpcodeFmin

	// OpcodeFmax takes the maximum of two floating point values: `v = fmax x, y`.
	OpcodeFmax

	// OpcodeCeil takes the ceiling of the given floating point value: `v = ceil x`.
	OpcodeCeil

	// OpcodeFloor takes the floor of the given floating point value: `v = floor x`.
	OpcodeFloor

	// OpcodeTrunc takes the truncation of the given floating point value: `v = trunc x`.
	OpcodeTrunc

	// OpcodeNearest takes the nearest integer of the given floating point value: `v = nearest x`.
	OpcodeNearest

	// OpcodeBitcast is a bitcast operation: `v = bitcast x`.
	OpcodeBitcast

	// OpcodeIreduce narrow the given integer: `v = Ireduce x`.
	OpcodeIreduce

	// OpcodeSnarrow converts two input vectors x, y into a smaller lane vector by narrowing each lane, signed `v = Snarrow.lane x, y`.
	OpcodeSnarrow

	// OpcodeUnarrow converts two input vectors x, y into a smaller lane vector by narrowing each lane, unsigned `v = Unarrow.lane x, y`.
	OpcodeUnarrow

	// OpcodeSwidenLow converts low half of the smaller lane vector to a larger lane vector, sign extended: `v = SwidenLow.lane x`.
	OpcodeSwidenLow

	// OpcodeSwidenHigh converts high half of the smaller lane vector to a larger lane vector, sign extended: `v = SwidenHigh.lane x`.
	OpcodeSwidenHigh

	// OpcodeUwidenLow converts low half of the smaller lane vector to a larger lane vector, zero (unsigned) extended: `v = UwidenLow.lane x`.
	OpcodeUwidenLow

	// OpcodeUwidenHigh converts high half of the smaller lane vector to a larger lane vector, zero (unsigned) extended: `v = UwidenHigh.lane x`.
	OpcodeUwidenHigh

	// 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.
	OpcodeExtIaddPairwise

	// OpcodeWideningPairwiseDotProductS is a lane-wise widening pairwise dot product with signed saturation: `v = WideningPairwiseDotProductS x, y` on vector.
	// Currently, the only lane is i16, and the result is i32.
	OpcodeWideningPairwiseDotProductS

	// OpcodeUExtend zero-extends the given integer: `v = UExtend x, from->to`.
	OpcodeUExtend

	// OpcodeSExtend sign-extends the given integer: `v = SExtend x, from->to`.
	OpcodeSExtend

	// OpcodeFpromote promotes the given floating point value: `v = Fpromote x`.
	OpcodeFpromote

	// OpcodeFvpromoteLow converts the two lower single-precision floating point lanes
	// to the two double-precision lanes of the result: `v = FvpromoteLow.lane x` on vector.
	OpcodeFvpromoteLow

	// OpcodeFdemote demotes the given float point value: `v = Fdemote x`.
	OpcodeFdemote

	// OpcodeFvdemote converts the two double-precision floating point lanes
	// to two lower single-precision lanes of the result `v = Fvdemote.lane x`.
	OpcodeFvdemote

	// OpcodeFcvtToUint converts a floating point value to an unsigned integer: `v = FcvtToUint x`.
	OpcodeFcvtToUint

	// OpcodeFcvtToSint converts a floating point value to a signed integer: `v = FcvtToSint x`.
	OpcodeFcvtToSint

	// OpcodeFcvtToUintSat converts a floating point value to an unsigned integer: `v = FcvtToUintSat x` which saturates on overflow.
	OpcodeFcvtToUintSat

	// OpcodeFcvtToSintSat converts a floating point value to a signed integer: `v = FcvtToSintSat x` which saturates on overflow.
	OpcodeFcvtToSintSat

	// OpcodeFcvtFromUint converts an unsigned integer to a floating point value: `v = FcvtFromUint x`.
	OpcodeFcvtFromUint

	// OpcodeFcvtFromSint converts a signed integer to a floating point value: `v = FcvtFromSint x`.
	OpcodeFcvtFromSint

	// OpcodeAtomicRmw is atomic read-modify-write operation: `v = atomic_rmw op, p, offset, value`.
	OpcodeAtomicRmw

	// OpcodeAtomicCas is atomic compare-and-swap operation.
	OpcodeAtomicCas

	// OpcodeAtomicLoad is atomic load operation.
	OpcodeAtomicLoad

	// OpcodeAtomicStore is atomic store operation.
	OpcodeAtomicStore

	// OpcodeFence is a memory fence operation.
	OpcodeFence

	// OpcodeTailCallReturnCall is the equivalent of OpcodeCall (a "near" call)
	// for tail calls. Semantically, it combines Call + Return into a single operation.
	OpcodeTailCallReturnCall

	// OpcodeTailCallReturnCallIndirect is the equivalent of OpcodeCallIndirect (a call to a function address)
	// for tail calls. Semantically, it combines CallIndirect + Return into a single operation.
	OpcodeTailCallReturnCallIndirect

	// opcodeEnd marks the end of the opcode list.
	opcodeEnd
)

// AtomicRmwOp represents the atomic read-modify-write operation.
type AtomicRmwOp byte

const (
	// AtomicRmwOpAdd is an atomic add operation.
	AtomicRmwOpAdd AtomicRmwOp = iota
	// AtomicRmwOpSub is an atomic sub operation.
	AtomicRmwOpSub
	// AtomicRmwOpAnd is an atomic and operation.
	AtomicRmwOpAnd
	// AtomicRmwOpOr is an atomic or operation.
	AtomicRmwOpOr
	// AtomicRmwOpXor is an atomic xor operation.
	AtomicRmwOpXor
	// AtomicRmwOpXchg is an atomic swap operation.
	AtomicRmwOpXchg
)

// String implements the fmt.Stringer.
func ( AtomicRmwOp) () string {
	switch  {
	case AtomicRmwOpAdd:
		return "add"
	case AtomicRmwOpSub:
		return "sub"
	case AtomicRmwOpAnd:
		return "and"
	case AtomicRmwOpOr:
		return "or"
	case AtomicRmwOpXor:
		return "xor"
	case AtomicRmwOpXchg:
		return "xchg"
	}
	panic(fmt.Sprintf("unknown AtomicRmwOp: %d", ))
}

// returnTypesFn provides the info to determine the type of instruction.
// t1 is the type of the first result, ts are the types of the remaining results.
type returnTypesFn func(b *builder, instr *Instruction) (t1 Type, ts []Type)

var (
	returnTypesFnNoReturns    returnTypesFn = func( *builder,  *Instruction) ( Type,  []Type) { return typeInvalid, nil }
	returnTypesFnSingle                     = func( *builder,  *Instruction) ( Type,  []Type) { return .typ, nil }
	returnTypesFnI32                        = func( *builder,  *Instruction) ( Type,  []Type) { return TypeI32, nil }
	returnTypesFnF32                        = func( *builder,  *Instruction) ( Type,  []Type) { return TypeF32, nil }
	returnTypesFnF64                        = func( *builder,  *Instruction) ( Type,  []Type) { return TypeF64, nil }
	returnTypesFnV128                       = func( *builder,  *Instruction) ( Type,  []Type) { return TypeV128, nil }
	returnTypesFnCallIndirect               = func( *builder,  *Instruction) ( Type,  []Type) {
		 := SignatureID(.u1)
		,  := .signatures[]
		if ! {
			panic("BUG")
		}
		switch len(.Results) {
		case 0:
			 = typeInvalid
		case 1:
			 = .Results[0]
		default:
			,  = .Results[0], .Results[1:]
		}
		return
	}
	returnTypesFnCall = func( *builder,  *Instruction) ( Type,  []Type) {
		 := SignatureID(.u2)
		,  := .signatures[]
		if ! {
			panic("BUG")
		}
		switch len(.Results) {
		case 0:
			 = typeInvalid
		case 1:
			 = .Results[0]
		default:
			,  = .Results[0], .Results[1:]
		}
		return
	}
)

// sideEffect provides the info to determine if an instruction has side effects which
// is used to determine if it can be optimized out, interchanged with others, etc.
type sideEffect byte

const (
	sideEffectUnknown sideEffect = iota
	// sideEffectStrict represents an instruction with side effects, and should be always alive plus cannot be reordered.
	sideEffectStrict
	// sideEffectTraps represents an instruction that can trap, and should be always alive but can be reordered within the group.
	sideEffectTraps
	// sideEffectNone represents an instruction without side effects, and can be eliminated if the result is not used, plus can be reordered within the group.
	sideEffectNone
)

// instructionSideEffects provides the info to determine if an instruction has side effects.
// Instructions with side effects must not be eliminated regardless whether the result is used or not.
var instructionSideEffects = [opcodeEnd]sideEffect{
	OpcodeUndefined:                   sideEffectStrict,
	OpcodeJump:                        sideEffectStrict,
	OpcodeIconst:                      sideEffectNone,
	OpcodeCall:                        sideEffectStrict,
	OpcodeCallIndirect:                sideEffectStrict,
	OpcodeIadd:                        sideEffectNone,
	OpcodeImul:                        sideEffectNone,
	OpcodeIsub:                        sideEffectNone,
	OpcodeIcmp:                        sideEffectNone,
	OpcodeExtractlane:                 sideEffectNone,
	OpcodeInsertlane:                  sideEffectNone,
	OpcodeBand:                        sideEffectNone,
	OpcodeBor:                         sideEffectNone,
	OpcodeBxor:                        sideEffectNone,
	OpcodeRotl:                        sideEffectNone,
	OpcodeRotr:                        sideEffectNone,
	OpcodeFcmp:                        sideEffectNone,
	OpcodeFadd:                        sideEffectNone,
	OpcodeClz:                         sideEffectNone,
	OpcodeCtz:                         sideEffectNone,
	OpcodePopcnt:                      sideEffectNone,
	OpcodeLoad:                        sideEffectNone,
	OpcodeLoadSplat:                   sideEffectNone,
	OpcodeUload8:                      sideEffectNone,
	OpcodeUload16:                     sideEffectNone,
	OpcodeUload32:                     sideEffectNone,
	OpcodeSload8:                      sideEffectNone,
	OpcodeSload16:                     sideEffectNone,
	OpcodeSload32:                     sideEffectNone,
	OpcodeSExtend:                     sideEffectNone,
	OpcodeUExtend:                     sideEffectNone,
	OpcodeSwidenLow:                   sideEffectNone,
	OpcodeUwidenLow:                   sideEffectNone,
	OpcodeSwidenHigh:                  sideEffectNone,
	OpcodeUwidenHigh:                  sideEffectNone,
	OpcodeSnarrow:                     sideEffectNone,
	OpcodeUnarrow:                     sideEffectNone,
	OpcodeSwizzle:                     sideEffectNone,
	OpcodeShuffle:                     sideEffectNone,
	OpcodeSplat:                       sideEffectNone,
	OpcodeFsub:                        sideEffectNone,
	OpcodeF32const:                    sideEffectNone,
	OpcodeF64const:                    sideEffectNone,
	OpcodeIshl:                        sideEffectNone,
	OpcodeSshr:                        sideEffectNone,
	OpcodeUshr:                        sideEffectNone,
	OpcodeStore:                       sideEffectStrict,
	OpcodeIstore8:                     sideEffectStrict,
	OpcodeIstore16:                    sideEffectStrict,
	OpcodeIstore32:                    sideEffectStrict,
	OpcodeExitWithCode:                sideEffectStrict,
	OpcodeExitIfTrueWithCode:          sideEffectStrict,
	OpcodeReturn:                      sideEffectStrict,
	OpcodeBrz:                         sideEffectStrict,
	OpcodeBrnz:                        sideEffectStrict,
	OpcodeBrTable:                     sideEffectStrict,
	OpcodeFdiv:                        sideEffectNone,
	OpcodeFmul:                        sideEffectNone,
	OpcodeFmax:                        sideEffectNone,
	OpcodeSqmulRoundSat:               sideEffectNone,
	OpcodeSelect:                      sideEffectNone,
	OpcodeFmin:                        sideEffectNone,
	OpcodeFneg:                        sideEffectNone,
	OpcodeFcvtToSint:                  sideEffectTraps,
	OpcodeFcvtToUint:                  sideEffectTraps,
	OpcodeFcvtFromSint:                sideEffectNone,
	OpcodeFcvtFromUint:                sideEffectNone,
	OpcodeFcvtToSintSat:               sideEffectNone,
	OpcodeFcvtToUintSat:               sideEffectNone,
	OpcodeVFcvtFromUint:               sideEffectNone,
	OpcodeVFcvtFromSint:               sideEffectNone,
	OpcodeFdemote:                     sideEffectNone,
	OpcodeFvpromoteLow:                sideEffectNone,
	OpcodeFvdemote:                    sideEffectNone,
	OpcodeFpromote:                    sideEffectNone,
	OpcodeBitcast:                     sideEffectNone,
	OpcodeIreduce:                     sideEffectNone,
	OpcodeSqrt:                        sideEffectNone,
	OpcodeCeil:                        sideEffectNone,
	OpcodeFloor:                       sideEffectNone,
	OpcodeTrunc:                       sideEffectNone,
	OpcodeNearest:                     sideEffectNone,
	OpcodeSdiv:                        sideEffectTraps,
	OpcodeSrem:                        sideEffectTraps,
	OpcodeUdiv:                        sideEffectTraps,
	OpcodeUrem:                        sideEffectTraps,
	OpcodeFabs:                        sideEffectNone,
	OpcodeFcopysign:                   sideEffectNone,
	OpcodeExtIaddPairwise:             sideEffectNone,
	OpcodeVconst:                      sideEffectNone,
	OpcodeVbor:                        sideEffectNone,
	OpcodeVbxor:                       sideEffectNone,
	OpcodeVband:                       sideEffectNone,
	OpcodeVbandnot:                    sideEffectNone,
	OpcodeVbnot:                       sideEffectNone,
	OpcodeVbitselect:                  sideEffectNone,
	OpcodeVanyTrue:                    sideEffectNone,
	OpcodeVallTrue:                    sideEffectNone,
	OpcodeVhighBits:                   sideEffectNone,
	OpcodeVIadd:                       sideEffectNone,
	OpcodeVSaddSat:                    sideEffectNone,
	OpcodeVUaddSat:                    sideEffectNone,
	OpcodeVIsub:                       sideEffectNone,
	OpcodeVSsubSat:                    sideEffectNone,
	OpcodeVUsubSat:                    sideEffectNone,
	OpcodeVIcmp:                       sideEffectNone,
	OpcodeVImin:                       sideEffectNone,
	OpcodeVUmin:                       sideEffectNone,
	OpcodeVImax:                       sideEffectNone,
	OpcodeVUmax:                       sideEffectNone,
	OpcodeVAvgRound:                   sideEffectNone,
	OpcodeVImul:                       sideEffectNone,
	OpcodeVIabs:                       sideEffectNone,
	OpcodeVIneg:                       sideEffectNone,
	OpcodeVIpopcnt:                    sideEffectNone,
	OpcodeVIshl:                       sideEffectNone,
	OpcodeVSshr:                       sideEffectNone,
	OpcodeVUshr:                       sideEffectNone,
	OpcodeVSqrt:                       sideEffectNone,
	OpcodeVFabs:                       sideEffectNone,
	OpcodeVFmin:                       sideEffectNone,
	OpcodeVFmax:                       sideEffectNone,
	OpcodeVFneg:                       sideEffectNone,
	OpcodeVFadd:                       sideEffectNone,
	OpcodeVFsub:                       sideEffectNone,
	OpcodeVFmul:                       sideEffectNone,
	OpcodeVFdiv:                       sideEffectNone,
	OpcodeVFcmp:                       sideEffectNone,
	OpcodeVCeil:                       sideEffectNone,
	OpcodeVFloor:                      sideEffectNone,
	OpcodeVTrunc:                      sideEffectNone,
	OpcodeVNearest:                    sideEffectNone,
	OpcodeVMaxPseudo:                  sideEffectNone,
	OpcodeVMinPseudo:                  sideEffectNone,
	OpcodeVFcvtToUintSat:              sideEffectNone,
	OpcodeVFcvtToSintSat:              sideEffectNone,
	OpcodeVZeroExtLoad:                sideEffectNone,
	OpcodeAtomicRmw:                   sideEffectStrict,
	OpcodeAtomicLoad:                  sideEffectStrict,
	OpcodeAtomicStore:                 sideEffectStrict,
	OpcodeAtomicCas:                   sideEffectStrict,
	OpcodeFence:                       sideEffectStrict,
	OpcodeTailCallReturnCall:          sideEffectStrict,
	OpcodeTailCallReturnCallIndirect:  sideEffectStrict,
	OpcodeWideningPairwiseDotProductS: sideEffectNone,
}

// sideEffect returns true if this instruction has side effects.
func ( *Instruction) () sideEffect {
	if  := instructionSideEffects[.opcode];  == sideEffectUnknown {
		panic("BUG: side effect info not registered for " + .opcode.String())
	} else {
		return 
	}
}

// instructionReturnTypes provides the function to determine the return types of an instruction.
var instructionReturnTypes = [opcodeEnd]returnTypesFn{
	OpcodeExtIaddPairwise:             returnTypesFnV128,
	OpcodeVbor:                        returnTypesFnV128,
	OpcodeVbxor:                       returnTypesFnV128,
	OpcodeVband:                       returnTypesFnV128,
	OpcodeVbnot:                       returnTypesFnV128,
	OpcodeVbandnot:                    returnTypesFnV128,
	OpcodeVbitselect:                  returnTypesFnV128,
	OpcodeVanyTrue:                    returnTypesFnI32,
	OpcodeVallTrue:                    returnTypesFnI32,
	OpcodeVhighBits:                   returnTypesFnI32,
	OpcodeVIadd:                       returnTypesFnV128,
	OpcodeVSaddSat:                    returnTypesFnV128,
	OpcodeVUaddSat:                    returnTypesFnV128,
	OpcodeVIsub:                       returnTypesFnV128,
	OpcodeVSsubSat:                    returnTypesFnV128,
	OpcodeVUsubSat:                    returnTypesFnV128,
	OpcodeVIcmp:                       returnTypesFnV128,
	OpcodeVImin:                       returnTypesFnV128,
	OpcodeVUmin:                       returnTypesFnV128,
	OpcodeVImax:                       returnTypesFnV128,
	OpcodeVUmax:                       returnTypesFnV128,
	OpcodeVImul:                       returnTypesFnV128,
	OpcodeVAvgRound:                   returnTypesFnV128,
	OpcodeVIabs:                       returnTypesFnV128,
	OpcodeVIneg:                       returnTypesFnV128,
	OpcodeVIpopcnt:                    returnTypesFnV128,
	OpcodeVIshl:                       returnTypesFnV128,
	OpcodeVSshr:                       returnTypesFnV128,
	OpcodeVUshr:                       returnTypesFnV128,
	OpcodeExtractlane:                 returnTypesFnSingle,
	OpcodeInsertlane:                  returnTypesFnV128,
	OpcodeBand:                        returnTypesFnSingle,
	OpcodeFcopysign:                   returnTypesFnSingle,
	OpcodeBitcast:                     returnTypesFnSingle,
	OpcodeBor:                         returnTypesFnSingle,
	OpcodeBxor:                        returnTypesFnSingle,
	OpcodeRotl:                        returnTypesFnSingle,
	OpcodeRotr:                        returnTypesFnSingle,
	OpcodeIshl:                        returnTypesFnSingle,
	OpcodeSshr:                        returnTypesFnSingle,
	OpcodeSdiv:                        returnTypesFnSingle,
	OpcodeSrem:                        returnTypesFnSingle,
	OpcodeUdiv:                        returnTypesFnSingle,
	OpcodeUrem:                        returnTypesFnSingle,
	OpcodeUshr:                        returnTypesFnSingle,
	OpcodeJump:                        returnTypesFnNoReturns,
	OpcodeUndefined:                   returnTypesFnNoReturns,
	OpcodeIconst:                      returnTypesFnSingle,
	OpcodeSelect:                      returnTypesFnSingle,
	OpcodeSExtend:                     returnTypesFnSingle,
	OpcodeUExtend:                     returnTypesFnSingle,
	OpcodeSwidenLow:                   returnTypesFnV128,
	OpcodeUwidenLow:                   returnTypesFnV128,
	OpcodeSwidenHigh:                  returnTypesFnV128,
	OpcodeUwidenHigh:                  returnTypesFnV128,
	OpcodeSnarrow:                     returnTypesFnV128,
	OpcodeUnarrow:                     returnTypesFnV128,
	OpcodeSwizzle:                     returnTypesFnSingle,
	OpcodeShuffle:                     returnTypesFnV128,
	OpcodeSplat:                       returnTypesFnV128,
	OpcodeIreduce:                     returnTypesFnSingle,
	OpcodeFabs:                        returnTypesFnSingle,
	OpcodeSqrt:                        returnTypesFnSingle,
	OpcodeCeil:                        returnTypesFnSingle,
	OpcodeFloor:                       returnTypesFnSingle,
	OpcodeTrunc:                       returnTypesFnSingle,
	OpcodeNearest:                     returnTypesFnSingle,
	OpcodeCallIndirect:                returnTypesFnCallIndirect,
	OpcodeCall:                        returnTypesFnCall,
	OpcodeLoad:                        returnTypesFnSingle,
	OpcodeVZeroExtLoad:                returnTypesFnV128,
	OpcodeLoadSplat:                   returnTypesFnV128,
	OpcodeIadd:                        returnTypesFnSingle,
	OpcodeIsub:                        returnTypesFnSingle,
	OpcodeImul:                        returnTypesFnSingle,
	OpcodeIcmp:                        returnTypesFnI32,
	OpcodeFcmp:                        returnTypesFnI32,
	OpcodeFadd:                        returnTypesFnSingle,
	OpcodeFsub:                        returnTypesFnSingle,
	OpcodeFdiv:                        returnTypesFnSingle,
	OpcodeFmul:                        returnTypesFnSingle,
	OpcodeFmax:                        returnTypesFnSingle,
	OpcodeFmin:                        returnTypesFnSingle,
	OpcodeSqmulRoundSat:               returnTypesFnV128,
	OpcodeF32const:                    returnTypesFnF32,
	OpcodeF64const:                    returnTypesFnF64,
	OpcodeClz:                         returnTypesFnSingle,
	OpcodeCtz:                         returnTypesFnSingle,
	OpcodePopcnt:                      returnTypesFnSingle,
	OpcodeStore:                       returnTypesFnNoReturns,
	OpcodeIstore8:                     returnTypesFnNoReturns,
	OpcodeIstore16:                    returnTypesFnNoReturns,
	OpcodeIstore32:                    returnTypesFnNoReturns,
	OpcodeExitWithCode:                returnTypesFnNoReturns,
	OpcodeExitIfTrueWithCode:          returnTypesFnNoReturns,
	OpcodeReturn:                      returnTypesFnNoReturns,
	OpcodeBrz:                         returnTypesFnNoReturns,
	OpcodeBrnz:                        returnTypesFnNoReturns,
	OpcodeBrTable:                     returnTypesFnNoReturns,
	OpcodeUload8:                      returnTypesFnSingle,
	OpcodeUload16:                     returnTypesFnSingle,
	OpcodeUload32:                     returnTypesFnSingle,
	OpcodeSload8:                      returnTypesFnSingle,
	OpcodeSload16:                     returnTypesFnSingle,
	OpcodeSload32:                     returnTypesFnSingle,
	OpcodeFcvtToSint:                  returnTypesFnSingle,
	OpcodeFcvtToUint:                  returnTypesFnSingle,
	OpcodeFcvtFromSint:                returnTypesFnSingle,
	OpcodeFcvtFromUint:                returnTypesFnSingle,
	OpcodeFcvtToSintSat:               returnTypesFnSingle,
	OpcodeFcvtToUintSat:               returnTypesFnSingle,
	OpcodeVFcvtFromUint:               returnTypesFnV128,
	OpcodeVFcvtFromSint:               returnTypesFnV128,
	OpcodeFneg:                        returnTypesFnSingle,
	OpcodeFdemote:                     returnTypesFnF32,
	OpcodeFvdemote:                    returnTypesFnV128,
	OpcodeFvpromoteLow:                returnTypesFnV128,
	OpcodeFpromote:                    returnTypesFnF64,
	OpcodeVconst:                      returnTypesFnV128,
	OpcodeVFabs:                       returnTypesFnV128,
	OpcodeVSqrt:                       returnTypesFnV128,
	OpcodeVFmax:                       returnTypesFnV128,
	OpcodeVFmin:                       returnTypesFnV128,
	OpcodeVFneg:                       returnTypesFnV128,
	OpcodeVFadd:                       returnTypesFnV128,
	OpcodeVFsub:                       returnTypesFnV128,
	OpcodeVFmul:                       returnTypesFnV128,
	OpcodeVFdiv:                       returnTypesFnV128,
	OpcodeVFcmp:                       returnTypesFnV128,
	OpcodeVCeil:                       returnTypesFnV128,
	OpcodeVFloor:                      returnTypesFnV128,
	OpcodeVTrunc:                      returnTypesFnV128,
	OpcodeVNearest:                    returnTypesFnV128,
	OpcodeVMaxPseudo:                  returnTypesFnV128,
	OpcodeVMinPseudo:                  returnTypesFnV128,
	OpcodeVFcvtToUintSat:              returnTypesFnV128,
	OpcodeVFcvtToSintSat:              returnTypesFnV128,
	OpcodeAtomicRmw:                   returnTypesFnSingle,
	OpcodeAtomicLoad:                  returnTypesFnSingle,
	OpcodeAtomicStore:                 returnTypesFnNoReturns,
	OpcodeAtomicCas:                   returnTypesFnSingle,
	OpcodeFence:                       returnTypesFnNoReturns,
	OpcodeTailCallReturnCallIndirect:  returnTypesFnCallIndirect,
	OpcodeTailCallReturnCall:          returnTypesFnCall,
	OpcodeWideningPairwiseDotProductS: returnTypesFnV128,
}

// AsLoad initializes this instruction as a store instruction with OpcodeLoad.
func ( *Instruction) ( Value,  uint32,  Type) *Instruction {
	.opcode = OpcodeLoad
	.v = 
	.u1 = uint64()
	.typ = 
	return 
}

// AsExtLoad initializes this instruction as a store instruction with OpcodeLoad.
func ( *Instruction) ( Opcode,  Value,  uint32,  bool) *Instruction {
	.opcode = 
	.v = 
	.u1 = uint64()
	if  {
		.typ = TypeI64
	} else {
		.typ = TypeI32
	}
	return 
}

// AsVZeroExtLoad initializes this instruction as a store instruction with OpcodeVExtLoad.
func ( *Instruction) ( Value,  uint32,  Type) *Instruction {
	.opcode = OpcodeVZeroExtLoad
	.v = 
	.u1 = uint64()
	.u2 = uint64()
	.typ = TypeV128
	return 
}

// VZeroExtLoadData returns the operands for a load instruction. The returned `typ` is the scalar type of the load target.
func ( *Instruction) () ( Value,  uint32,  Type) {
	return .v, uint32(.u1), Type(.u2)
}

// AsLoadSplat initializes this instruction as a store instruction with OpcodeLoadSplat.
func ( *Instruction) ( Value,  uint32,  VecLane) *Instruction {
	.opcode = OpcodeLoadSplat
	.v = 
	.u1 = uint64()
	.u2 = uint64()
	.typ = TypeV128
	return 
}

// LoadData returns the operands for a load instruction.
func ( *Instruction) () ( Value,  uint32,  Type) {
	return .v, uint32(.u1), .typ
}

// LoadSplatData returns the operands for a load splat instruction.
func ( *Instruction) () ( Value,  uint32,  VecLane) {
	return .v, uint32(.u1), VecLane(.u2)
}

// AsStore initializes this instruction as a store instruction with OpcodeStore.
func ( *Instruction) ( Opcode, ,  Value,  uint32) *Instruction {
	.opcode = 
	.v = 
	.v2 = 

	var  uint64
	switch  {
	case OpcodeStore:
		 = uint64(.Type().Bits())
	case OpcodeIstore8:
		 = 8
	case OpcodeIstore16:
		 = 16
	case OpcodeIstore32:
		 = 32
	default:
		panic("invalid store opcode" + .String())
	}
	.u1 = uint64() | <<32
	return 
}

// StoreData returns the operands for a store instruction.
func ( *Instruction) () (,  Value,  uint32,  byte) {
	return .v, .v2, uint32(.u1), byte(.u1 >> 32)
}

// AsIconst64 initializes this instruction as a 64-bit integer constant instruction with OpcodeIconst.
func ( *Instruction) ( uint64) *Instruction {
	.opcode = OpcodeIconst
	.typ = TypeI64
	.u1 = 
	return 
}

// AsIconst32 initializes this instruction as a 32-bit integer constant instruction with OpcodeIconst.
func ( *Instruction) ( uint32) *Instruction {
	.opcode = OpcodeIconst
	.typ = TypeI32
	.u1 = uint64()
	return 
}

// AsIadd initializes this instruction as an integer addition instruction with OpcodeIadd.
func ( *Instruction) (,  Value) *Instruction {
	.opcode = OpcodeIadd
	.v = 
	.v2 = 
	.typ = .Type()
	return 
}

// AsVIadd initializes this instruction as an integer addition instruction with OpcodeVIadd on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVIadd
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsWideningPairwiseDotProductS initializes this instruction as a lane-wise integer extended pairwise addition instruction
// with OpcodeIaddPairwise on a vector.
func ( *Instruction) (,  Value) *Instruction {
	.opcode = OpcodeWideningPairwiseDotProductS
	.v = 
	.v2 = 
	.typ = TypeV128
	return 
}

// AsExtIaddPairwise initializes this instruction as a lane-wise integer extended pairwise addition instruction
// with OpcodeIaddPairwise on a vector.
func ( *Instruction) ( Value,  VecLane,  bool) *Instruction {
	.opcode = OpcodeExtIaddPairwise
	.v = 
	.u1 = uint64()
	if  {
		.u2 = 1
	}
	.typ = TypeV128
	return 
}

// ExtIaddPairwiseData returns the operands for a lane-wise integer extended pairwise addition instruction.
func ( *Instruction) () ( Value,  VecLane,  bool) {
	return .v, VecLane(.u1), .u2 != 0
}

// AsVSaddSat initializes this instruction as a vector addition with saturation instruction with OpcodeVSaddSat on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVSaddSat
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVUaddSat initializes this instruction as a vector addition with saturation instruction with OpcodeVUaddSat on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVUaddSat
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVIsub initializes this instruction as an integer subtraction instruction with OpcodeVIsub on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVIsub
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVSsubSat initializes this instruction as a vector addition with saturation instruction with OpcodeVSsubSat on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVSsubSat
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVUsubSat initializes this instruction as a vector addition with saturation instruction with OpcodeVUsubSat on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVUsubSat
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVImin initializes this instruction as a signed integer min instruction with OpcodeVImin on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVImin
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVUmin initializes this instruction as an unsigned integer min instruction with OpcodeVUmin on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVUmin
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVImax initializes this instruction as a signed integer max instruction with OpcodeVImax on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVImax
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVUmax initializes this instruction as an unsigned integer max instruction with OpcodeVUmax on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVUmax
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVAvgRound initializes this instruction as an unsigned integer avg instruction, truncating to zero with OpcodeVAvgRound on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVAvgRound
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVImul initializes this instruction as an integer multiplication with OpcodeVImul on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVImul
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsSqmulRoundSat initializes this instruction as a lane-wise saturating rounding multiplication
// in Q15 format with OpcodeSqmulRoundSat on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeSqmulRoundSat
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVIabs initializes this instruction as a vector absolute value with OpcodeVIabs.
func ( *Instruction) ( Value,  VecLane) *Instruction {
	.opcode = OpcodeVIabs
	.v = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVIneg initializes this instruction as a vector negation with OpcodeVIneg.
func ( *Instruction) ( Value,  VecLane) *Instruction {
	.opcode = OpcodeVIneg
	.v = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVIpopcnt initializes this instruction as a Population Count instruction with OpcodeVIpopcnt on a vector.
func ( *Instruction) ( Value,  VecLane) *Instruction {
	if  != VecLaneI8x16 {
		panic("Unsupported lane type " + .String())
	}
	.opcode = OpcodeVIpopcnt
	.v = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVSqrt initializes this instruction as a sqrt instruction with OpcodeVSqrt on a vector.
func ( *Instruction) ( Value,  VecLane) *Instruction {
	.opcode = OpcodeVSqrt
	.v = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVFabs initializes this instruction as a float abs instruction with OpcodeVFabs on a vector.
func ( *Instruction) ( Value,  VecLane) *Instruction {
	.opcode = OpcodeVFabs
	.v = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVFneg initializes this instruction as a float neg instruction with OpcodeVFneg on a vector.
func ( *Instruction) ( Value,  VecLane) *Instruction {
	.opcode = OpcodeVFneg
	.v = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVFmax initializes this instruction as a float max instruction with OpcodeVFmax on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVFmax
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVFmin initializes this instruction as a float min instruction with OpcodeVFmin on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVFmin
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVFadd initializes this instruction as a floating point add instruction with OpcodeVFadd on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVFadd
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVFsub initializes this instruction as a floating point subtraction instruction with OpcodeVFsub on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVFsub
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVFmul initializes this instruction as a floating point multiplication instruction with OpcodeVFmul on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVFmul
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsVFdiv initializes this instruction as a floating point division instruction with OpcodeVFdiv on a vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVFdiv
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsImul initializes this instruction as an integer addition instruction with OpcodeImul.
func ( *Instruction) (,  Value) *Instruction {
	.opcode = OpcodeImul
	.v = 
	.v2 = 
	.typ = .Type()
	return 
}

func ( *Instruction) ( Builder) *Instruction {
	.InsertInstruction()
	return 
}

// AsIsub initializes this instruction as an integer subtraction instruction with OpcodeIsub.
func ( *Instruction) (,  Value) *Instruction {
	.opcode = OpcodeIsub
	.v = 
	.v2 = 
	.typ = .Type()
	return 
}

// AsIcmp initializes this instruction as an integer comparison instruction with OpcodeIcmp.
func ( *Instruction) (,  Value,  IntegerCmpCond) *Instruction {
	.opcode = OpcodeIcmp
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeI32
	return 
}

// AsFcmp initializes this instruction as an integer comparison instruction with OpcodeFcmp.
func ( *Instruction) (,  Value,  FloatCmpCond) {
	.opcode = OpcodeFcmp
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeI32
}

// AsVIcmp initializes this instruction as an integer vector comparison instruction with OpcodeVIcmp.
func ( *Instruction) (,  Value,  IntegerCmpCond,  VecLane) *Instruction {
	.opcode = OpcodeVIcmp
	.v = 
	.v2 = 
	.u1 = uint64()
	.u2 = uint64()
	.typ = TypeV128
	return 
}

// AsVFcmp initializes this instruction as a float comparison instruction with OpcodeVFcmp on Vector.
func ( *Instruction) (,  Value,  FloatCmpCond,  VecLane) *Instruction {
	.opcode = OpcodeVFcmp
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	.u2 = uint64()
	return 
}

// AsVCeil initializes this instruction as an instruction with OpcodeCeil.
func ( *Instruction) ( Value,  VecLane) *Instruction {
	.opcode = OpcodeVCeil
	.v = 
	.typ = .Type()
	.u1 = uint64()
	return 
}

// AsVFloor initializes this instruction as an instruction with OpcodeFloor.
func ( *Instruction) ( Value,  VecLane) *Instruction {
	.opcode = OpcodeVFloor
	.v = 
	.typ = .Type()
	.u1 = uint64()
	return 
}

// AsVTrunc initializes this instruction as an instruction with OpcodeTrunc.
func ( *Instruction) ( Value,  VecLane) *Instruction {
	.opcode = OpcodeVTrunc
	.v = 
	.typ = .Type()
	.u1 = uint64()
	return 
}

// AsVNearest initializes this instruction as an instruction with OpcodeNearest.
func ( *Instruction) ( Value,  VecLane) *Instruction {
	.opcode = OpcodeVNearest
	.v = 
	.typ = .Type()
	.u1 = uint64()
	return 
}

// AsVMaxPseudo initializes this instruction as an instruction with OpcodeVMaxPseudo.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVMaxPseudo
	.typ = .Type()
	.v = 
	.v2 = 
	.u1 = uint64()
	return 
}

// AsVMinPseudo initializes this instruction as an instruction with OpcodeVMinPseudo.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVMinPseudo
	.typ = .Type()
	.v = 
	.v2 = 
	.u1 = uint64()
	return 
}

// AsSDiv initializes this instruction as an integer bitwise and instruction with OpcodeSdiv.
func ( *Instruction) (, ,  Value) *Instruction {
	.opcode = OpcodeSdiv
	.v = 
	.v2 = 
	.v3 = 
	.typ = .Type()
	return 
}

// AsUDiv initializes this instruction as an integer bitwise and instruction with OpcodeUdiv.
func ( *Instruction) (, ,  Value) *Instruction {
	.opcode = OpcodeUdiv
	.v = 
	.v2 = 
	.v3 = 
	.typ = .Type()
	return 
}

// AsSRem initializes this instruction as an integer bitwise and instruction with OpcodeSrem.
func ( *Instruction) (, ,  Value) *Instruction {
	.opcode = OpcodeSrem
	.v = 
	.v2 = 
	.v3 = 
	.typ = .Type()
	return 
}

// AsURem initializes this instruction as an integer bitwise and instruction with OpcodeUrem.
func ( *Instruction) (, ,  Value) *Instruction {
	.opcode = OpcodeUrem
	.v = 
	.v2 = 
	.v3 = 
	.typ = .Type()
	return 
}

// AsBand initializes this instruction as an integer bitwise and instruction with OpcodeBand.
func ( *Instruction) (,  Value) *Instruction {
	.opcode = OpcodeBand
	.v = 
	.v2 = 
	.typ = .Type()
	return 
}

// AsBor initializes this instruction as an integer bitwise or instruction with OpcodeBor.
func ( *Instruction) (,  Value) {
	.opcode = OpcodeBor
	.v = 
	.v2 = 
	.typ = .Type()
}

// AsBxor initializes this instruction as an integer bitwise xor instruction with OpcodeBxor.
func ( *Instruction) (,  Value) {
	.opcode = OpcodeBxor
	.v = 
	.v2 = 
	.typ = .Type()
}

// AsIshl initializes this instruction as an integer shift left instruction with OpcodeIshl.
func ( *Instruction) (,  Value) *Instruction {
	.opcode = OpcodeIshl
	.v = 
	.v2 = 
	.typ = .Type()
	return 
}

// AsVIshl initializes this instruction as an integer shift left instruction with OpcodeVIshl on vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVIshl
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = .Type()
	return 
}

// AsUshr initializes this instruction as an integer unsigned shift right (logical shift right) instruction with OpcodeUshr.
func ( *Instruction) (,  Value) *Instruction {
	.opcode = OpcodeUshr
	.v = 
	.v2 = 
	.typ = .Type()
	return 
}

// AsVUshr initializes this instruction as an integer unsigned shift right (logical shift right) instruction with OpcodeVUshr on vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVUshr
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = .Type()
	return 
}

// AsSshr initializes this instruction as an integer signed shift right (arithmetic shift right) instruction with OpcodeSshr.
func ( *Instruction) (,  Value) *Instruction {
	.opcode = OpcodeSshr
	.v = 
	.v2 = 
	.typ = .Type()
	return 
}

// AsVSshr initializes this instruction as an integer signed shift right (arithmetic shift right) instruction with OpcodeVSshr on vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeVSshr
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = .Type()
	return 
}

// AsExtractlane initializes this instruction as an extract lane instruction with OpcodeExtractlane on vector.
func ( *Instruction) ( Value,  byte,  VecLane,  bool) *Instruction {
	.opcode = OpcodeExtractlane
	.v = 
	// We do not have a field for signedness, but `index` is a byte,
	// so we just encode the flag in the high bits of `u1`.
	.u1 = uint64()
	if  {
		.u1 = .u1 | 1<<32
	}
	.u2 = uint64()
	switch  {
	case VecLaneI8x16, VecLaneI16x8, VecLaneI32x4:
		.typ = TypeI32
	case VecLaneI64x2:
		.typ = TypeI64
	case VecLaneF32x4:
		.typ = TypeF32
	case VecLaneF64x2:
		.typ = TypeF64
	}
	return 
}

// AsInsertlane initializes this instruction as an insert lane instruction with OpcodeInsertlane on vector.
func ( *Instruction) (,  Value,  byte,  VecLane) *Instruction {
	.opcode = OpcodeInsertlane
	.v = 
	.v2 = 
	.u1 = uint64()
	.u2 = uint64()
	.typ = TypeV128
	return 
}

// AsShuffle initializes this instruction as a shuffle instruction with OpcodeShuffle on vector.
func ( *Instruction) (,  Value,  []byte) *Instruction {
	.opcode = OpcodeShuffle
	.v = 
	.v2 = 
	// Encode the 16 bytes as 8 bytes in u1, and 8 bytes in u2.
	.u1 = uint64([7])<<56 | uint64([6])<<48 | uint64([5])<<40 | uint64([4])<<32 | uint64([3])<<24 | uint64([2])<<16 | uint64([1])<<8 | uint64([0])
	.u2 = uint64([15])<<56 | uint64([14])<<48 | uint64([13])<<40 | uint64([12])<<32 | uint64([11])<<24 | uint64([10])<<16 | uint64([9])<<8 | uint64([8])
	.typ = TypeV128
	return 
}

// AsSwizzle initializes this instruction as an insert lane instruction with OpcodeSwizzle on vector.
func ( *Instruction) (,  Value,  VecLane) *Instruction {
	.opcode = OpcodeSwizzle
	.v = 
	.v2 = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsSplat initializes this instruction as an insert lane instruction with OpcodeSplat on vector.
func ( *Instruction) ( Value,  VecLane) *Instruction {
	.opcode = OpcodeSplat
	.v = 
	.u1 = uint64()
	.typ = TypeV128
	return 
}

// AsRotl initializes this instruction as a word rotate left instruction with OpcodeRotl.
func ( *Instruction) (,  Value) {
	.opcode = OpcodeRotl
	.v = 
	.v2 = 
	.typ = .Type()
}

// AsRotr initializes this instruction as a word rotate right instruction with OpcodeRotr.
func ( *Instruction) (,  Value) {
	.opcode = OpcodeRotr
	.v = 
	.v2 = 
	.typ = .Type()
}

// IcmpData returns the operands and comparison condition of this integer comparison instruction.
func ( *Instruction) () (,  Value,  IntegerCmpCond) {
	return .v, .v2, IntegerCmpCond(.u1)
}

// FcmpData returns the operands and comparison condition of this floating-point comparison instruction.
func ( *Instruction) () (,  Value,  FloatCmpCond) {
	return .v, .v2, FloatCmpCond(.u1)
}

// VIcmpData returns the operands and comparison condition of this integer comparison instruction on vector.
func ( *Instruction) () (,  Value,  IntegerCmpCond,  VecLane) {
	return .v, .v2, IntegerCmpCond(.u1), VecLane(.u2)
}

// VFcmpData returns the operands and comparison condition of this float comparison instruction on vector.
func ( *Instruction) () (,  Value,  FloatCmpCond,  VecLane) {
	return .v, .v2, FloatCmpCond(.u1), VecLane(.u2)
}

// ExtractlaneData returns the operands and sign flag of Extractlane on vector.
func ( *Instruction) () ( Value,  byte,  bool,  VecLane) {
	 = .v
	 = byte(0b00001111 & .u1)
	 = .u1>>32 != 0
	 = VecLane(.u2)
	return
}

// InsertlaneData returns the operands and sign flag of Insertlane on vector.
func ( *Instruction) () (,  Value,  byte,  VecLane) {
	 = .v
	 = .v2
	 = byte(.u1)
	 = VecLane(.u2)
	return
}

// AsFadd initializes this instruction as a floating-point addition instruction with OpcodeFadd.
func ( *Instruction) (,  Value) {
	.opcode = OpcodeFadd
	.v = 
	.v2 = 
	.typ = .Type()
}

// AsFsub initializes this instruction as a floating-point subtraction instruction with OpcodeFsub.
func ( *Instruction) (,  Value) {
	.opcode = OpcodeFsub
	.v = 
	.v2 = 
	.typ = .Type()
}

// AsFmul initializes this instruction as a floating-point multiplication instruction with OpcodeFmul.
func ( *Instruction) (,  Value) {
	.opcode = OpcodeFmul
	.v = 
	.v2 = 
	.typ = .Type()
}

// AsFdiv initializes this instruction as a floating-point division instruction with OpcodeFdiv.
func ( *Instruction) (,  Value) {
	.opcode = OpcodeFdiv
	.v = 
	.v2 = 
	.typ = .Type()
}

// AsFmin initializes this instruction to take the minimum of two floating-points with OpcodeFmin.
func ( *Instruction) (,  Value) {
	.opcode = OpcodeFmin
	.v = 
	.v2 = 
	.typ = .Type()
}

// AsFmax initializes this instruction to take the maximum of two floating-points with OpcodeFmax.
func ( *Instruction) (,  Value) {
	.opcode = OpcodeFmax
	.v = 
	.v2 = 
	.typ = .Type()
}

// AsF32const initializes this instruction as a 32-bit floating-point constant instruction with OpcodeF32const.
func ( *Instruction) ( float32) *Instruction {
	.opcode = OpcodeF32const
	.typ = TypeF64
	.u1 = uint64(math.Float32bits())
	return 
}

// AsF64const initializes this instruction as a 64-bit floating-point constant instruction with OpcodeF64const.
func ( *Instruction) ( float64) *Instruction {
	.opcode = OpcodeF64const
	.typ = TypeF64
	.u1 = math.Float64bits()
	return 
}

// AsVconst initializes this instruction as a vector constant instruction with OpcodeVconst.
func ( *Instruction) (,  uint64) *Instruction {
	.opcode = OpcodeVconst
	.typ = TypeV128
	.u1 = 
	.u2 = 
	return 
}

// AsVbnot initializes this instruction as a vector negation instruction with OpcodeVbnot.
func ( *Instruction) ( Value) *Instruction {
	.opcode = OpcodeVbnot
	.typ = TypeV128
	.v = 
	return 
}

// AsVband initializes this instruction as an and vector instruction with OpcodeVband.
func ( *Instruction) (,  Value) *Instruction {
	.opcode = OpcodeVband
	.typ = TypeV128
	.v = 
	.v2 = 
	return 
}

// AsVbor initializes this instruction as an or vector instruction with OpcodeVbor.
func ( *Instruction) (,  Value) *Instruction {
	.opcode = OpcodeVbor
	.typ = TypeV128
	.v = 
	.v2 = 
	return 
}

// AsVbxor initializes this instruction as a xor vector instruction with OpcodeVbxor.
func ( *Instruction) (,  Value) *Instruction {
	.opcode = OpcodeVbxor
	.typ = TypeV128
	.v = 
	.v2 = 
	return 
}

// AsVbandnot initializes this instruction as an and-not vector instruction with OpcodeVbandnot.
func ( *Instruction) (,  Value) *Instruction {
	.opcode = OpcodeVbandnot
	.typ = TypeV128
	.v = 
	.v2 = 
	return 
}

// AsVbitselect initializes this instruction as a bit select vector instruction with OpcodeVbitselect.
func ( *Instruction) (, ,  Value) *Instruction {
	.opcode = OpcodeVbitselect
	.typ = TypeV128
	.v = 
	.v2 = 
	.v3 = 
	return 
}

// AsVanyTrue initializes this instruction as an anyTrue vector instruction with OpcodeVanyTrue.
func ( *Instruction) ( Value) *Instruction {
	.opcode = OpcodeVanyTrue
	.typ = TypeI32
	.v = 
	return 
}

// AsVallTrue initializes this instruction as an allTrue vector instruction with OpcodeVallTrue.
func ( *Instruction) ( Value,  VecLane) *Instruction {
	.opcode = OpcodeVallTrue
	.typ = TypeI32
	.v = 
	.u1 = uint64()
	return 
}

// AsVhighBits initializes this instruction as a highBits vector instruction with OpcodeVhighBits.
func ( *Instruction) ( Value,  VecLane) *Instruction {
	.opcode = OpcodeVhighBits
	.typ = TypeI32
	.v = 
	.u1 = uint64()
	return 
}

// VconstData returns the operands of this vector constant instruction.
func ( *Instruction) () (,  uint64) {
	return .u1, .u2
}

// AsReturn initializes this instruction as a return instruction with OpcodeReturn.
func ( *Instruction) ( wazevoapi.VarLength[Value]) *Instruction {
	.opcode = OpcodeReturn
	.vs = 
	return 
}

// AsIreduce initializes this instruction as a reduction instruction with OpcodeIreduce.
func ( *Instruction) ( Value,  Type) *Instruction {
	.opcode = OpcodeIreduce
	.v = 
	.typ = 
	return 
}

// AsWiden initializes this instruction as a signed or unsigned widen instruction
// on low half or high half of the given vector with OpcodeSwidenLow, OpcodeUwidenLow, OpcodeSwidenHigh, OpcodeUwidenHigh.
func ( *Instruction) ( Value,  VecLane, ,  bool) *Instruction {
	switch {
	case  && :
		.opcode = OpcodeSwidenLow
	case ! && :
		.opcode = OpcodeUwidenLow
	case  && !:
		.opcode = OpcodeSwidenHigh
	case ! && !:
		.opcode = OpcodeUwidenHigh
	}
	.v = 
	.u1 = uint64()
	return 
}

// AsAtomicLoad initializes this instruction as an atomic load.
// The size is in bytes and must be 1, 2, 4, or 8.
func ( *Instruction) ( Value,  uint64,  Type) *Instruction {
	.opcode = OpcodeAtomicLoad
	.u1 = 
	.v = 
	.typ = 
	return 
}

// AsAtomicLoad initializes this instruction as an atomic store.
// The size is in bytes and must be 1, 2, 4, or 8.
func ( *Instruction) (,  Value,  uint64) *Instruction {
	.opcode = OpcodeAtomicStore
	.u1 = 
	.v = 
	.v2 = 
	.typ = .Type()
	return 
}

// AsAtomicRmw initializes this instruction as an atomic read-modify-write.
// The size is in bytes and must be 1, 2, 4, or 8.
func ( *Instruction) ( AtomicRmwOp, ,  Value,  uint64) *Instruction {
	.opcode = OpcodeAtomicRmw
	.u1 = uint64()
	.u2 = 
	.v = 
	.v2 = 
	.typ = .Type()
	return 
}

// AsAtomicCas initializes this instruction as an atomic compare-and-swap.
// The size is in bytes and must be 1, 2, 4, or 8.
func ( *Instruction) (, ,  Value,  uint64) *Instruction {
	.opcode = OpcodeAtomicCas
	.u1 = 
	.v = 
	.v2 = 
	.v3 = 
	.typ = .Type()
	return 
}

// AsFence initializes this instruction as a memory fence.
// A single byte immediate may be used to indicate fence ordering in the future
// but is currently always 0 and ignored.
func ( *Instruction) ( byte) *Instruction {
	.opcode = OpcodeFence
	.u1 = uint64()
	return 
}

// AtomicRmwData returns the data for this atomic read-modify-write instruction.
func ( *Instruction) () ( AtomicRmwOp,  uint64) {
	return AtomicRmwOp(.u1), .u2
}

// AtomicTargetSize returns the target memory size of the atomic instruction.
func ( *Instruction) () ( uint64) {
	return .u1
}

// AsTailCallReturnCall initializes this instruction as a call instruction with OpcodeTailCallReturnCall.
func ( *Instruction) ( FuncRef,  *Signature,  Values) {
	.opcode = OpcodeTailCallReturnCall
	.u1 = uint64()
	.vs = 
	.u2 = uint64(.ID)
	.used = true
}

// AsTailCallReturnCallIndirect initializes this instruction as a call-indirect instruction with OpcodeTailCallReturnCallIndirect.
func ( *Instruction) ( Value,  *Signature,  Values) *Instruction {
	.opcode = OpcodeTailCallReturnCallIndirect
	.vs = 
	.v = 
	.u1 = uint64(.ID)
	.used = true
	return 
}

// ReturnVals returns the return values of OpcodeReturn.
func ( *Instruction) () []Value {
	return .vs.View()
}

// AsExitWithCode initializes this instruction as a trap instruction with OpcodeExitWithCode.
func ( *Instruction) ( Value,  wazevoapi.ExitCode) {
	.opcode = OpcodeExitWithCode
	.v = 
	.u1 = uint64()
}

// AsExitIfTrueWithCode initializes this instruction as a trap instruction with OpcodeExitIfTrueWithCode.
func ( *Instruction) (,  Value,  wazevoapi.ExitCode) *Instruction {
	.opcode = OpcodeExitIfTrueWithCode
	.v = 
	.v2 = 
	.u1 = uint64()
	return 
}

// ExitWithCodeData returns the context and exit code of OpcodeExitWithCode.
func ( *Instruction) () ( Value,  wazevoapi.ExitCode) {
	return .v, wazevoapi.ExitCode(.u1)
}

// ExitIfTrueWithCodeData returns the context and exit code of OpcodeExitWithCode.
func ( *Instruction) () (,  Value,  wazevoapi.ExitCode) {
	return .v, .v2, wazevoapi.ExitCode(.u1)
}

// InvertBrx inverts either OpcodeBrz or OpcodeBrnz to the other.
func ( *Instruction) () {
	switch .opcode {
	case OpcodeBrz:
		.opcode = OpcodeBrnz
	case OpcodeBrnz:
		.opcode = OpcodeBrz
	default:
		panic("BUG")
	}
}

// BranchData returns the branch data for this instruction necessary for backends.
func ( *Instruction) () ( Value,  []Value,  BasicBlockID) {
	switch .opcode {
	case OpcodeJump:
		 = ValueInvalid
	case OpcodeBrz, OpcodeBrnz:
		 = .v
	default:
		panic("BUG")
	}
	 = .vs.View()
	 = BasicBlockID(.rValue)
	return
}

// BrTableData returns the branch table data for this instruction necessary for backends.
func ( *Instruction) () ( Value,  Values) {
	if .opcode != OpcodeBrTable {
		panic("BUG: BrTableData only available for OpcodeBrTable")
	}
	 = .v
	 = .rValues
	return
}

// AsJump initializes this instruction as a jump instruction with OpcodeJump.
func ( *Instruction) ( Values,  BasicBlock) *Instruction {
	.opcode = OpcodeJump
	.vs = 
	.rValue = Value(.ID())
	return 
}

// IsFallthroughJump returns true if this instruction is a fallthrough jump.
func ( *Instruction) () bool {
	if .opcode != OpcodeJump {
		panic("BUG: IsFallthrough only available for OpcodeJump")
	}
	return .opcode == OpcodeJump && .u1 != 0
}

// AsFallthroughJump marks this instruction as a fallthrough jump.
func ( *Instruction) () {
	if .opcode != OpcodeJump {
		panic("BUG: AsFallthroughJump only available for OpcodeJump")
	}
	.u1 = 1
}

// AsBrz initializes this instruction as a branch-if-zero instruction with OpcodeBrz.
func ( *Instruction) ( Value,  Values,  BasicBlock) {
	.opcode = OpcodeBrz
	.v = 
	.vs = 
	.rValue = Value(.ID())
}

// AsBrnz initializes this instruction as a branch-if-not-zero instruction with OpcodeBrnz.
func ( *Instruction) ( Value,  Values,  BasicBlock) *Instruction {
	.opcode = OpcodeBrnz
	.v = 
	.vs = 
	.rValue = Value(.ID())
	return 
}

// AsBrTable initializes this instruction as a branch-table instruction with OpcodeBrTable.
// targets is a list of basic block IDs cast to Values.
func ( *Instruction) ( Value,  Values) {
	.opcode = OpcodeBrTable
	.v = 
	.rValues = 
}

// AsCall initializes this instruction as a call instruction with OpcodeCall.
func ( *Instruction) ( FuncRef,  *Signature,  Values) {
	.opcode = OpcodeCall
	.u1 = uint64()
	.vs = 
	.u2 = uint64(.ID)
	.used = true
}

// CallData returns the call data for this instruction necessary for backends.
func ( *Instruction) () ( FuncRef,  SignatureID,  []Value) {
	if .opcode != OpcodeCall && .opcode != OpcodeTailCallReturnCall {
		panic("BUG: CallData only available for OpcodeCall")
	}
	 = FuncRef(.u1)
	 = SignatureID(.u2)
	 = .vs.View()
	return
}

// AsCallIndirect initializes this instruction as a call-indirect instruction with OpcodeCallIndirect.
func ( *Instruction) ( Value,  *Signature,  Values) *Instruction {
	.opcode = OpcodeCallIndirect
	.typ = TypeF64
	.vs = 
	.v = 
	.u1 = uint64(.ID)
	.used = true
	return 
}

// 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.
func ( *Instruction) ( Value,  *Signature,  Values) *Instruction {
	.AsCallIndirect(, , )
	.u2 = 1
	return 
}

// CallIndirectData returns the call indirect data for this instruction necessary for backends.
func ( *Instruction) () ( Value,  SignatureID,  []Value,  bool) {
	if .opcode != OpcodeCallIndirect && .opcode != OpcodeTailCallReturnCallIndirect {
		panic("BUG: CallIndirectData only available for OpcodeCallIndirect and OpcodeTailCallReturnCallIndirect")
	}
	 = .v
	 = SignatureID(.u1)
	 = .vs.View()
	 = .u2 == 1
	return
}

// AsClz initializes this instruction as a Count Leading Zeroes instruction with OpcodeClz.
func ( *Instruction) ( Value) {
	.opcode = OpcodeClz
	.v = 
	.typ = .Type()
}

// AsCtz initializes this instruction as a Count Trailing Zeroes instruction with OpcodeCtz.
func ( *Instruction) ( Value) {
	.opcode = OpcodeCtz
	.v = 
	.typ = .Type()
}

// AsPopcnt initializes this instruction as a Population Count instruction with OpcodePopcnt.
func ( *Instruction) ( Value) {
	.opcode = OpcodePopcnt
	.v = 
	.typ = .Type()
}

// AsFneg initializes this instruction as an instruction with OpcodeFneg.
func ( *Instruction) ( Value) *Instruction {
	.opcode = OpcodeFneg
	.v = 
	.typ = .Type()
	return 
}

// AsSqrt initializes this instruction as an instruction with OpcodeSqrt.
func ( *Instruction) ( Value) *Instruction {
	.opcode = OpcodeSqrt
	.v = 
	.typ = .Type()
	return 
}

// AsFabs initializes this instruction as an instruction with OpcodeFabs.
func ( *Instruction) ( Value) *Instruction {
	.opcode = OpcodeFabs
	.v = 
	.typ = .Type()
	return 
}

// AsFcopysign initializes this instruction as an instruction with OpcodeFcopysign.
func ( *Instruction) (,  Value) *Instruction {
	.opcode = OpcodeFcopysign
	.v = 
	.v2 = 
	.typ = .Type()
	return 
}

// AsCeil initializes this instruction as an instruction with OpcodeCeil.
func ( *Instruction) ( Value) *Instruction {
	.opcode = OpcodeCeil
	.v = 
	.typ = .Type()
	return 
}

// AsFloor initializes this instruction as an instruction with OpcodeFloor.
func ( *Instruction) ( Value) *Instruction {
	.opcode = OpcodeFloor
	.v = 
	.typ = .Type()
	return 
}

// AsTrunc initializes this instruction as an instruction with OpcodeTrunc.
func ( *Instruction) ( Value) *Instruction {
	.opcode = OpcodeTrunc
	.v = 
	.typ = .Type()
	return 
}

// AsNearest initializes this instruction as an instruction with OpcodeNearest.
func ( *Instruction) ( Value) *Instruction {
	.opcode = OpcodeNearest
	.v = 
	.typ = .Type()
	return 
}

// AsBitcast initializes this instruction as an instruction with OpcodeBitcast.
func ( *Instruction) ( Value,  Type) *Instruction {
	.opcode = OpcodeBitcast
	.v = 
	.typ = 
	return 
}

// BitcastData returns the operands for a bitcast instruction.
func ( *Instruction) () ( Value,  Type) {
	return .v, .typ
}

// AsFdemote initializes this instruction as an instruction with OpcodeFdemote.
func ( *Instruction) ( Value) {
	.opcode = OpcodeFdemote
	.v = 
	.typ = TypeF32
}

// AsFpromote initializes this instruction as an instruction with OpcodeFpromote.
func ( *Instruction) ( Value) {
	.opcode = OpcodeFpromote
	.v = 
	.typ = TypeF64
}

// AsFcvtFromInt initializes this instruction as an instruction with either OpcodeFcvtFromUint or OpcodeFcvtFromSint
func ( *Instruction) ( Value,  bool,  bool) *Instruction {
	if  {
		.opcode = OpcodeFcvtFromSint
	} else {
		.opcode = OpcodeFcvtFromUint
	}
	.v = 
	if  {
		.typ = TypeF64
	} else {
		.typ = TypeF32
	}
	return 
}

// AsFcvtToInt initializes this instruction as an instruction with either OpcodeFcvtToUint or OpcodeFcvtToSint
func ( *Instruction) (,  Value,  bool,  bool,  bool) *Instruction {
	switch {
	case  && !:
		.opcode = OpcodeFcvtToSint
	case ! && !:
		.opcode = OpcodeFcvtToUint
	case  && :
		.opcode = OpcodeFcvtToSintSat
	case ! && :
		.opcode = OpcodeFcvtToUintSat
	}
	.v = 
	.v2 = 
	if  {
		.typ = TypeI64
	} else {
		.typ = TypeI32
	}
	return 
}

// AsVFcvtToIntSat initializes this instruction as an instruction with either OpcodeVFcvtToSintSat or OpcodeVFcvtToUintSat
func ( *Instruction) ( Value,  VecLane,  bool) *Instruction {
	if  {
		.opcode = OpcodeVFcvtToSintSat
	} else {
		.opcode = OpcodeVFcvtToUintSat
	}
	.v = 
	.u1 = uint64()
	return 
}

// AsVFcvtFromInt initializes this instruction as an instruction with either OpcodeVFcvtToSintSat or OpcodeVFcvtToUintSat
func ( *Instruction) ( Value,  VecLane,  bool) *Instruction {
	if  {
		.opcode = OpcodeVFcvtFromSint
	} else {
		.opcode = OpcodeVFcvtFromUint
	}
	.v = 
	.u1 = uint64()
	return 
}

// AsNarrow initializes this instruction as an instruction with either OpcodeSnarrow or OpcodeUnarrow
func ( *Instruction) (,  Value,  VecLane,  bool) *Instruction {
	if  {
		.opcode = OpcodeSnarrow
	} else {
		.opcode = OpcodeUnarrow
	}
	.v = 
	.v2 = 
	.u1 = uint64()
	return 
}

// AsFvpromoteLow initializes this instruction as an instruction with OpcodeFvpromoteLow
func ( *Instruction) ( Value,  VecLane) *Instruction {
	.opcode = OpcodeFvpromoteLow
	.v = 
	.u1 = uint64()
	return 
}

// AsFvdemote initializes this instruction as an instruction with OpcodeFvdemote
func ( *Instruction) ( Value,  VecLane) *Instruction {
	.opcode = OpcodeFvdemote
	.v = 
	.u1 = uint64()
	return 
}

// AsSExtend initializes this instruction as a sign extension instruction with OpcodeSExtend.
func ( *Instruction) ( Value, ,  byte) *Instruction {
	.opcode = OpcodeSExtend
	.v = 
	.u1 = uint64()<<8 | uint64()
	if  == 64 {
		.typ = TypeI64
	} else {
		.typ = TypeI32
	}
	return 
}

// AsUExtend initializes this instruction as an unsigned extension instruction with OpcodeUExtend.
func ( *Instruction) ( Value, ,  byte) *Instruction {
	.opcode = OpcodeUExtend
	.v = 
	.u1 = uint64()<<8 | uint64()
	if  == 64 {
		.typ = TypeI64
	} else {
		.typ = TypeI32
	}
	return 
}

func ( *Instruction) () (,  byte,  bool) {
	if .opcode != OpcodeSExtend && .opcode != OpcodeUExtend {
		panic("BUG: ExtendData only available for OpcodeSExtend and OpcodeUExtend")
	}
	 = byte(.u1 >> 8)
	 = byte(.u1)
	 = .opcode == OpcodeSExtend
	return
}

// AsSelect initializes this instruction as an unsigned extension instruction with OpcodeSelect.
func ( *Instruction) (, ,  Value) *Instruction {
	.opcode = OpcodeSelect
	.v = 
	.v2 = 
	.v3 = 
	.typ = .Type()
	return 
}

// SelectData returns the select data for this instruction necessary for backends.
func ( *Instruction) () (, ,  Value) {
	 = .v
	 = .v2
	 = .v3
	return
}

// ExtendFromToBits returns the from and to bit size for the extension instruction.
func ( *Instruction) () (,  byte) {
	 = byte(.u1 >> 8)
	 = byte(.u1)
	return
}

// Format returns a string representation of this instruction with the given builder.
// For debugging purposes only.
func ( *Instruction) ( Builder) string {
	var  string
	switch .opcode {
	case OpcodeExitWithCode:
		 = fmt.Sprintf(" %s, %s", .v.Format(), wazevoapi.ExitCode(.u1))
	case OpcodeExitIfTrueWithCode:
		 = fmt.Sprintf(" %s, %s, %s", .v2.Format(), .v.Format(), wazevoapi.ExitCode(.u1))
	case OpcodeIadd, OpcodeIsub, OpcodeImul, OpcodeFadd, OpcodeFsub, OpcodeFmin, OpcodeFmax, OpcodeFdiv, OpcodeFmul:
		 = fmt.Sprintf(" %s, %s", .v.Format(), .v2.Format())
	case OpcodeIcmp:
		 = fmt.Sprintf(" %s, %s, %s", IntegerCmpCond(.u1), .v.Format(), .v2.Format())
	case OpcodeFcmp:
		 = fmt.Sprintf(" %s, %s, %s", FloatCmpCond(.u1), .v.Format(), .v2.Format())
	case OpcodeSExtend, OpcodeUExtend:
		 = fmt.Sprintf(" %s, %d->%d", .v.Format(), .u1>>8, .u1&0xff)
	case OpcodeCall, OpcodeCallIndirect:
		 := .vs.View()
		 := make([]string, len())
		for  := range  {
			[] = [].Format()
		}
		if .opcode == OpcodeCallIndirect {
			 = fmt.Sprintf(" %s:%s, %s", .v.Format(), SignatureID(.u1), strings.Join(, ", "))
		} else {
			 = fmt.Sprintf(" %s:%s, %s", FuncRef(.u1), SignatureID(.u2), strings.Join(, ", "))
		}
	case OpcodeStore, OpcodeIstore8, OpcodeIstore16, OpcodeIstore32:
		 = fmt.Sprintf(" %s, %s, %#x", .v.Format(), .v2.Format(), uint32(.u1))
	case OpcodeLoad, OpcodeVZeroExtLoad:
		 = fmt.Sprintf(" %s, %#x", .v.Format(), int32(.u1))
	case OpcodeLoadSplat:
		 = fmt.Sprintf(".%s %s, %#x", VecLane(.u2), .v.Format(), int32(.u1))
	case OpcodeUload8, OpcodeUload16, OpcodeUload32, OpcodeSload8, OpcodeSload16, OpcodeSload32:
		 = fmt.Sprintf(" %s, %#x", .v.Format(), int32(.u1))
	case OpcodeSelect, OpcodeVbitselect:
		 = fmt.Sprintf(" %s, %s, %s", .v.Format(), .v2.Format(), .v3.Format())
	case OpcodeIconst:
		switch .typ {
		case TypeI32:
			 = fmt.Sprintf("_32 %#x", uint32(.u1))
		case TypeI64:
			 = fmt.Sprintf("_64 %#x", .u1)
		}
	case OpcodeVconst:
		 = fmt.Sprintf(" %016x %016x", .u1, .u2)
	case OpcodeF32const:
		 = fmt.Sprintf(" %f", math.Float32frombits(uint32(.u1)))
	case OpcodeF64const:
		 = fmt.Sprintf(" %f", math.Float64frombits(.u1))
	case OpcodeReturn:
		 := .vs.View()
		if len() == 0 {
			break
		}
		 := make([]string, len())
		for  := range  {
			[] = [].Format()
		}
		 = fmt.Sprintf(" %s", strings.Join(, ", "))
	case OpcodeJump:
		 := .vs.View()
		 := make([]string, len()+1)
		if .IsFallthroughJump() {
			[0] = " fallthrough"
		} else {
			 := BasicBlockID(.rValue)
			[0] = " " + .BasicBlock().Name()
		}
		for  := range  {
			[+1] = [].Format()
		}

		 = strings.Join(, ", ")
	case OpcodeBrz, OpcodeBrnz:
		 := .vs.View()
		 := make([]string, len()+2)
		[0] = " " + .v.Format()
		 := BasicBlockID(.rValue)
		[1] = .BasicBlock().Name()
		for  := range  {
			[+2] = [].Format()
		}
		 = strings.Join(, ", ")
	case OpcodeBrTable:
		// `BrTable index, [label1, label2, ... labelN]`
		 = fmt.Sprintf(" %s", .v.Format())
		 += ", ["
		for ,  := range .rValues.View() {
			 := .BasicBlock(BasicBlockID())
			if  == 0 {
				 += .Name()
			} else {
				 += ", " + .Name()
			}
		}
		 += "]"
	case OpcodeBand, OpcodeBor, OpcodeBxor, OpcodeRotr, OpcodeRotl, OpcodeIshl, OpcodeSshr, OpcodeUshr,
		OpcodeSdiv, OpcodeUdiv, OpcodeFcopysign, OpcodeSrem, OpcodeUrem,
		OpcodeVbnot, OpcodeVbxor, OpcodeVbor, OpcodeVband, OpcodeVbandnot, OpcodeVIcmp, OpcodeVFcmp:
		 = fmt.Sprintf(" %s, %s", .v.Format(), .v2.Format())
	case OpcodeUndefined:
	case OpcodeClz, OpcodeCtz, OpcodePopcnt, OpcodeFneg, OpcodeFcvtToSint, OpcodeFcvtToUint, OpcodeFcvtFromSint,
		OpcodeFcvtFromUint, OpcodeFcvtToSintSat, OpcodeFcvtToUintSat, OpcodeFdemote, OpcodeFpromote, OpcodeIreduce, OpcodeBitcast, OpcodeSqrt, OpcodeFabs,
		OpcodeCeil, OpcodeFloor, OpcodeTrunc, OpcodeNearest:
		 = " " + .v.Format()
	case OpcodeVIadd, OpcodeExtIaddPairwise, OpcodeVSaddSat, OpcodeVUaddSat, OpcodeVIsub, OpcodeVSsubSat, OpcodeVUsubSat,
		OpcodeVImin, OpcodeVUmin, OpcodeVImax, OpcodeVUmax, OpcodeVImul, OpcodeVAvgRound,
		OpcodeVFadd, OpcodeVFsub, OpcodeVFmul, OpcodeVFdiv,
		OpcodeVIshl, OpcodeVSshr, OpcodeVUshr,
		OpcodeVFmin, OpcodeVFmax, OpcodeVMinPseudo, OpcodeVMaxPseudo,
		OpcodeSnarrow, OpcodeUnarrow, OpcodeSwizzle, OpcodeSqmulRoundSat:
		 = fmt.Sprintf(".%s %s, %s", VecLane(.u1), .v.Format(), .v2.Format())
	case OpcodeVIabs, OpcodeVIneg, OpcodeVIpopcnt, OpcodeVhighBits, OpcodeVallTrue, OpcodeVanyTrue,
		OpcodeVFabs, OpcodeVFneg, OpcodeVSqrt, OpcodeVCeil, OpcodeVFloor, OpcodeVTrunc, OpcodeVNearest,
		OpcodeVFcvtToUintSat, OpcodeVFcvtToSintSat, OpcodeVFcvtFromUint, OpcodeVFcvtFromSint,
		OpcodeFvpromoteLow, OpcodeFvdemote, OpcodeSwidenLow, OpcodeUwidenLow, OpcodeSwidenHigh, OpcodeUwidenHigh,
		OpcodeSplat:
		 = fmt.Sprintf(".%s %s", VecLane(.u1), .v.Format())
	case OpcodeExtractlane:
		var  string
		if .u1 != 0 {
			 = "signed"
		} else {
			 = "unsigned"
		}
		 = fmt.Sprintf(".%s %d, %s (%s)", VecLane(.u2), 0x0000FFFF&.u1, .v.Format(), )
	case OpcodeInsertlane:
		 = fmt.Sprintf(".%s %d, %s, %s", VecLane(.u2), .u1, .v.Format(), .v2.Format())
	case OpcodeShuffle:
		 := make([]byte, 16)
		for  := 0;  < 8; ++ {
			[] = byte(.u1 >> (8 * ))
		}
		for  := 0;  < 8; ++ {
			[+8] = byte(.u2 >> (8 * ))
		}
		// Prints Shuffle.[0 1 2 3 4 5 6 7 ...] v2, v3
		 = fmt.Sprintf(".%v %s, %s", , .v.Format(), .v2.Format())
	case OpcodeAtomicRmw:
		 = fmt.Sprintf(" %s_%d, %s, %s", AtomicRmwOp(.u1), 8*.u2, .v.Format(), .v2.Format())
	case OpcodeAtomicLoad:
		 = fmt.Sprintf("_%d, %s", 8*.u1, .v.Format())
	case OpcodeAtomicStore:
		 = fmt.Sprintf("_%d, %s, %s", 8*.u1, .v.Format(), .v2.Format())
	case OpcodeAtomicCas:
		 = fmt.Sprintf("_%d, %s, %s, %s", 8*.u1, .v.Format(), .v2.Format(), .v3.Format())
	case OpcodeFence:
		 = fmt.Sprintf(" %d", .u1)
	case OpcodeTailCallReturnCall, OpcodeTailCallReturnCallIndirect:
		 := .vs.View()
		 := make([]string, len())
		for  := range  {
			[] = [].Format()
		}
		if .opcode == OpcodeCallIndirect {
			 = fmt.Sprintf(" %s:%s, %s", .v.Format(), SignatureID(.u1), strings.Join(, ", "))
		} else {
			 = fmt.Sprintf(" %s:%s, %s", FuncRef(.u1), SignatureID(.u2), strings.Join(, ", "))
		}
	case OpcodeWideningPairwiseDotProductS:
		 = fmt.Sprintf(" %s, %s", .v.Format(), .v2.Format())
	default:
		panic(fmt.Sprintf("TODO: format for %s", .opcode))
	}

	 := .opcode.String() + 

	var  []string
	,  := .Returns()
	if .Valid() {
		 = append(, .formatWithType())
	}

	for ,  := range  {
		 = append(, .formatWithType())
	}

	if len() > 0 {
		return fmt.Sprintf("%s = %s", strings.Join(, ", "), )
	} else {
		return 
	}
}

// addArgumentBranchInst adds an argument to this instruction.
func ( *Instruction) ( *builder,  Value) {
	switch .opcode {
	case OpcodeJump, OpcodeBrz, OpcodeBrnz:
		.vs = .vs.Append(&.varLengthPool, )
	default:
		panic("BUG: " + .opcode.String())
	}
}

// Constant returns true if this instruction is a constant instruction.
func ( *Instruction) () bool {
	switch .opcode {
	case OpcodeIconst, OpcodeF32const, OpcodeF64const:
		return true
	}
	return false
}

// ConstantVal returns the constant value of this instruction.
// How to interpret the return value depends on the opcode.
func ( *Instruction) () ( uint64) {
	switch .opcode {
	case OpcodeIconst, OpcodeF32const, OpcodeF64const:
		 = .u1
	default:
		panic("TODO")
	}
	return
}

// String implements fmt.Stringer.
func ( Opcode) () ( string) {
	switch  {
	case OpcodeInvalid:
		return "invalid"
	case OpcodeUndefined:
		return "Undefined"
	case OpcodeJump:
		return "Jump"
	case OpcodeBrz:
		return "Brz"
	case OpcodeBrnz:
		return "Brnz"
	case OpcodeBrTable:
		return "BrTable"
	case OpcodeExitWithCode:
		return "Exit"
	case OpcodeExitIfTrueWithCode:
		return "ExitIfTrue"
	case OpcodeReturn:
		return "Return"
	case OpcodeCall:
		return "Call"
	case OpcodeCallIndirect:
		return "CallIndirect"
	case OpcodeSplat:
		return "Splat"
	case OpcodeSwizzle:
		return "Swizzle"
	case OpcodeInsertlane:
		return "Insertlane"
	case OpcodeExtractlane:
		return "Extractlane"
	case OpcodeLoad:
		return "Load"
	case OpcodeLoadSplat:
		return "LoadSplat"
	case OpcodeStore:
		return "Store"
	case OpcodeUload8:
		return "Uload8"
	case OpcodeSload8:
		return "Sload8"
	case OpcodeIstore8:
		return "Istore8"
	case OpcodeUload16:
		return "Uload16"
	case OpcodeSload16:
		return "Sload16"
	case OpcodeIstore16:
		return "Istore16"
	case OpcodeUload32:
		return "Uload32"
	case OpcodeSload32:
		return "Sload32"
	case OpcodeIstore32:
		return "Istore32"
	case OpcodeIconst:
		return "Iconst"
	case OpcodeF32const:
		return "F32const"
	case OpcodeF64const:
		return "F64const"
	case OpcodeVconst:
		return "Vconst"
	case OpcodeShuffle:
		return "Shuffle"
	case OpcodeSelect:
		return "Select"
	case OpcodeVanyTrue:
		return "VanyTrue"
	case OpcodeVallTrue:
		return "VallTrue"
	case OpcodeVhighBits:
		return "VhighBits"
	case OpcodeIcmp:
		return "Icmp"
	case OpcodeIcmpImm:
		return "IcmpImm"
	case OpcodeVIcmp:
		return "VIcmp"
	case OpcodeIadd:
		return "Iadd"
	case OpcodeIsub:
		return "Isub"
	case OpcodeImul:
		return "Imul"
	case OpcodeUdiv:
		return "Udiv"
	case OpcodeSdiv:
		return "Sdiv"
	case OpcodeUrem:
		return "Urem"
	case OpcodeSrem:
		return "Srem"
	case OpcodeBand:
		return "Band"
	case OpcodeBor:
		return "Bor"
	case OpcodeBxor:
		return "Bxor"
	case OpcodeBnot:
		return "Bnot"
	case OpcodeRotl:
		return "Rotl"
	case OpcodeRotr:
		return "Rotr"
	case OpcodeIshl:
		return "Ishl"
	case OpcodeUshr:
		return "Ushr"
	case OpcodeSshr:
		return "Sshr"
	case OpcodeClz:
		return "Clz"
	case OpcodeCtz:
		return "Ctz"
	case OpcodePopcnt:
		return "Popcnt"
	case OpcodeFcmp:
		return "Fcmp"
	case OpcodeFadd:
		return "Fadd"
	case OpcodeFsub:
		return "Fsub"
	case OpcodeFmul:
		return "Fmul"
	case OpcodeFdiv:
		return "Fdiv"
	case OpcodeSqmulRoundSat:
		return "SqmulRoundSat"
	case OpcodeSqrt:
		return "Sqrt"
	case OpcodeFneg:
		return "Fneg"
	case OpcodeFabs:
		return "Fabs"
	case OpcodeFcopysign:
		return "Fcopysign"
	case OpcodeFmin:
		return "Fmin"
	case OpcodeFmax:
		return "Fmax"
	case OpcodeCeil:
		return "Ceil"
	case OpcodeFloor:
		return "Floor"
	case OpcodeTrunc:
		return "Trunc"
	case OpcodeNearest:
		return "Nearest"
	case OpcodeBitcast:
		return "Bitcast"
	case OpcodeIreduce:
		return "Ireduce"
	case OpcodeSnarrow:
		return "Snarrow"
	case OpcodeUnarrow:
		return "Unarrow"
	case OpcodeSwidenLow:
		return "SwidenLow"
	case OpcodeSwidenHigh:
		return "SwidenHigh"
	case OpcodeUwidenLow:
		return "UwidenLow"
	case OpcodeUwidenHigh:
		return "UwidenHigh"
	case OpcodeExtIaddPairwise:
		return "IaddPairwise"
	case OpcodeWideningPairwiseDotProductS:
		return "WideningPairwiseDotProductS"
	case OpcodeUExtend:
		return "UExtend"
	case OpcodeSExtend:
		return "SExtend"
	case OpcodeFpromote:
		return "Fpromote"
	case OpcodeFdemote:
		return "Fdemote"
	case OpcodeFvdemote:
		return "Fvdemote"
	case OpcodeFcvtToUint:
		return "FcvtToUint"
	case OpcodeFcvtToSint:
		return "FcvtToSint"
	case OpcodeFcvtToUintSat:
		return "FcvtToUintSat"
	case OpcodeFcvtToSintSat:
		return "FcvtToSintSat"
	case OpcodeFcvtFromUint:
		return "FcvtFromUint"
	case OpcodeFcvtFromSint:
		return "FcvtFromSint"
	case OpcodeAtomicRmw:
		return "AtomicRmw"
	case OpcodeAtomicCas:
		return "AtomicCas"
	case OpcodeAtomicLoad:
		return "AtomicLoad"
	case OpcodeAtomicStore:
		return "AtomicStore"
	case OpcodeFence:
		return "Fence"
	case OpcodeTailCallReturnCall:
		return "ReturnCall"
	case OpcodeTailCallReturnCallIndirect:
		return "ReturnCallIndirect"
	case OpcodeVbor:
		return "Vbor"
	case OpcodeVbxor:
		return "Vbxor"
	case OpcodeVband:
		return "Vband"
	case OpcodeVbandnot:
		return "Vbandnot"
	case OpcodeVbnot:
		return "Vbnot"
	case OpcodeVbitselect:
		return "Vbitselect"
	case OpcodeVIadd:
		return "VIadd"
	case OpcodeVSaddSat:
		return "VSaddSat"
	case OpcodeVUaddSat:
		return "VUaddSat"
	case OpcodeVSsubSat:
		return "VSsubSat"
	case OpcodeVUsubSat:
		return "VUsubSat"
	case OpcodeVAvgRound:
		return "OpcodeVAvgRound"
	case OpcodeVIsub:
		return "VIsub"
	case OpcodeVImin:
		return "VImin"
	case OpcodeVUmin:
		return "VUmin"
	case OpcodeVImax:
		return "VImax"
	case OpcodeVUmax:
		return "VUmax"
	case OpcodeVImul:
		return "VImul"
	case OpcodeVIabs:
		return "VIabs"
	case OpcodeVIneg:
		return "VIneg"
	case OpcodeVIpopcnt:
		return "VIpopcnt"
	case OpcodeVIshl:
		return "VIshl"
	case OpcodeVUshr:
		return "VUshr"
	case OpcodeVSshr:
		return "VSshr"
	case OpcodeVFabs:
		return "VFabs"
	case OpcodeVFmax:
		return "VFmax"
	case OpcodeVFmin:
		return "VFmin"
	case OpcodeVFneg:
		return "VFneg"
	case OpcodeVFadd:
		return "VFadd"
	case OpcodeVFsub:
		return "VFsub"
	case OpcodeVFmul:
		return "VFmul"
	case OpcodeVFdiv:
		return "VFdiv"
	case OpcodeVFcmp:
		return "VFcmp"
	case OpcodeVCeil:
		return "VCeil"
	case OpcodeVFloor:
		return "VFloor"
	case OpcodeVTrunc:
		return "VTrunc"
	case OpcodeVNearest:
		return "VNearest"
	case OpcodeVMaxPseudo:
		return "VMaxPseudo"
	case OpcodeVMinPseudo:
		return "VMinPseudo"
	case OpcodeVSqrt:
		return "VSqrt"
	case OpcodeVFcvtToUintSat:
		return "VFcvtToUintSat"
	case OpcodeVFcvtToSintSat:
		return "VFcvtToSintSat"
	case OpcodeVFcvtFromUint:
		return "VFcvtFromUint"
	case OpcodeVFcvtFromSint:
		return "VFcvtFromSint"
	case OpcodeFvpromoteLow:
		return "FvpromoteLow"
	case OpcodeVZeroExtLoad:
		return "VZeroExtLoad"
	}
	panic(fmt.Sprintf("unknown opcode %d", ))
}