Files
wazero/internal/engine/wazevo/ssa/instructions.go
2023-10-18 07:09:36 +09:00

2826 lines
85 KiB
Go

package ssa
import (
"fmt"
"math"
"strings"
"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
)
// 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 {
opcode Opcode
u1, u2 uint64
v Value
v2 Value
v3 Value
vs []Value
typ Type
blk BasicBlock
targets []BasicBlock
prev, next *Instruction
rValue Value
rValues []Value
gid InstructionGroupID
sourceOffset SourceOffset
live 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 (l SourceOffset) Valid() bool {
return l != sourceOffsetUnknown
}
func (i *Instruction) annotateSourceOffset(line SourceOffset) {
i.sourceOffset = line
}
// SourceOffset returns the source offset of this instruction.
func (i *Instruction) SourceOffset() SourceOffset {
return i.sourceOffset
}
// Opcode returns the opcode of this instruction.
func (i *Instruction) Opcode() Opcode {
return i.opcode
}
// GroupID returns the InstructionGroupID of this instruction.
func (i *Instruction) GroupID() InstructionGroupID {
return i.gid
}
// reset resets this instruction to the initial state.
func (i *Instruction) reset() {
*i = Instruction{}
i.v = ValueInvalid
i.v2 = ValueInvalid
i.v3 = ValueInvalid
i.rValue = ValueInvalid
i.typ = typeInvalid
i.vs = nil
i.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 (i *Instruction) Returns() (first Value, rest []Value) {
return i.rValue, i.rValues
}
// Return returns a Value(s) produced by this instruction if any.
// If there's multiple return values, only the first one is returned.
func (i *Instruction) Return() (first Value) {
return i.rValue
}
// Args returns the arguments to this instruction.
func (i *Instruction) Args() (v1, v2, v3 Value, vs []Value) {
return i.v, i.v2, i.v3, i.vs
}
// Arg returns the first argument to this instruction.
func (i *Instruction) Arg() Value {
return i.v
}
// Arg2 returns the first two arguments to this instruction.
func (i *Instruction) Arg2() (Value, Value) {
return i.v, i.v2
}
// ArgWithLane returns the first argument to this instruction, and the lane type.
func (i *Instruction) ArgWithLane() (Value, VecLane) {
return i.v, VecLane(i.u1)
}
// Arg2WithLane returns the first two arguments to this instruction, and the lane type.
func (i *Instruction) Arg2WithLane() (Value, Value, VecLane) {
return i.v, i.v2, VecLane(i.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 (i *Instruction) ShuffleData() (v Value, v2 Value, lo uint64, hi uint64) {
return i.v, i.v2, i.u1, i.u2
}
// Arg3 returns the first three arguments to this instruction.
func (i *Instruction) Arg3() (Value, Value, Value) {
return i.v, i.v2, i.v3
}
// Next returns the next instruction laid out next to itself.
func (i *Instruction) Next() *Instruction {
return i.next
}
// Prev returns the previous instruction laid out prior to itself.
func (i *Instruction) Prev() *Instruction {
return i.prev
}
// IsBranching returns true if this instruction is a branching instruction.
func (i *Instruction) IsBranching() bool {
switch i.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 ...
// `v = insertlane x, y, Idx`. (TernaryImm8)
OpcodeInsertlane
// OpcodeExtractlane ...
// `v = extractlane x, Idx`. (BinaryImm8)
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.
OpcodeVFcvtFromUint
// OpcodeVFcvtFromSint converts a floating point value from a signed integer: `v = VFcvtFromSint.lane x` on 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
// OpcodeBmask ...
// `v = bmask x`.
OpcodeBmask
// OpcodeIreduce ...
// `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
// OpcodeIaddPairwise is a lane-wise integer extended pairwise addition producing extended results (twice wider results than the inputs): `v = iadd_pairwise x, y` on vector.
OpcodeIaddPairwise
// OpcodeWideningPairwiseDotProductS ...
// `v = widening_pairwise_dot_product_s x, y`.
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 ...
// `v = fcvt_to_uint 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`.
OpcodeFcvtToUintSat
// OpcodeFcvtToSintSat ...
// `v = fcvt_to_sint_sat x`.
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
// OpcodeIsplit ...
// `lo, hi = isplit x`.
OpcodeIsplit
// OpcodeIconcat ...
// `v = iconcat lo, hi`.
OpcodeIconcat
// OpcodeAtomicRmw ...
// `v = atomic_rmw MemFlags, AtomicRmwOp, p, x`.
OpcodeAtomicRmw
// OpcodeAtomicCas ...
// `v = atomic_cas MemFlags, p, e, x`.
OpcodeAtomicCas
// OpcodeAtomicLoad ...
// `v = atomic_load MemFlags, p`.
OpcodeAtomicLoad
// OpcodeAtomicStore ...
// `atomic_store MemFlags, x, p`.
OpcodeAtomicStore
// OpcodeFence ...
// `fence`.
OpcodeFence
// opcodeEnd marks the end of the opcode list.
opcodeEnd
)
// 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(b *builder, instr *Instruction) (t1 Type, ts []Type) { return typeInvalid, nil }
returnTypesFnSingle = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return instr.typ, nil }
returnTypesFnI32 = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return TypeI32, nil }
returnTypesFnF32 = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return TypeF32, nil }
returnTypesFnF64 = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return TypeF64, nil }
returnTypesFnV128 = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return TypeV128, nil }
)
// 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,
OpcodeIaddPairwise: 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,
}
// sideEffect returns true if this instruction has side effects.
func (i *Instruction) sideEffect() sideEffect {
if e := instructionSideEffects[i.opcode]; e == sideEffectUnknown {
panic("BUG: side effect info not registered for " + i.opcode.String())
} else {
return e
}
}
// instructionReturnTypes provides the function to determine the return types of an instruction.
var instructionReturnTypes = [opcodeEnd]returnTypesFn{
OpcodeIaddPairwise: 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: func(b *builder, instr *Instruction) (t1 Type, ts []Type) {
sigID := SignatureID(instr.u1)
sig, ok := b.signatures[sigID]
if !ok {
panic("BUG")
}
switch len(sig.Results) {
case 0:
t1 = typeInvalid
case 1:
t1 = sig.Results[0]
default:
t1, ts = sig.Results[0], sig.Results[1:]
}
return
},
OpcodeCall: func(b *builder, instr *Instruction) (t1 Type, ts []Type) {
sigID := SignatureID(instr.u2)
sig, ok := b.signatures[sigID]
if !ok {
panic("BUG")
}
switch len(sig.Results) {
case 0:
t1 = typeInvalid
case 1:
t1 = sig.Results[0]
default:
t1, ts = sig.Results[0], sig.Results[1:]
}
return
},
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,
}
// AsLoad initializes this instruction as a store instruction with OpcodeLoad.
func (i *Instruction) AsLoad(ptr Value, offset uint32, typ Type) *Instruction {
i.opcode = OpcodeLoad
i.v = ptr
i.u1 = uint64(offset)
i.typ = typ
return i
}
// AsExtLoad initializes this instruction as a store instruction with OpcodeLoad.
func (i *Instruction) AsExtLoad(op Opcode, ptr Value, offset uint32, dst64bit bool) *Instruction {
i.opcode = op
i.v = ptr
i.u1 = uint64(offset)
if dst64bit {
i.typ = TypeI64
} else {
i.typ = TypeI32
}
return i
}
// AsVZeroExtLoad initializes this instruction as a store instruction with OpcodeVExtLoad.
func (i *Instruction) AsVZeroExtLoad(ptr Value, offset uint32, scalarType Type) *Instruction {
i.opcode = OpcodeVZeroExtLoad
i.v = ptr
i.u1 = uint64(offset)
i.u2 = uint64(scalarType)
i.typ = TypeV128
return i
}
// VZeroExtLoadData returns the operands for a load instruction. The returned `typ` is the scalar type of the load target.
func (i *Instruction) VZeroExtLoadData() (ptr Value, offset uint32, typ Type) {
return i.v, uint32(i.u1), Type(i.u2)
}
// AsLoadSplat initializes this instruction as a store instruction with OpcodeLoadSplat.
func (i *Instruction) AsLoadSplat(ptr Value, offset uint32, lane VecLane) *Instruction {
i.opcode = OpcodeLoadSplat
i.v = ptr
i.u1 = uint64(offset)
i.u2 = uint64(lane)
i.typ = TypeV128
return i
}
// LoadData returns the operands for a load instruction.
func (i *Instruction) LoadData() (ptr Value, offset uint32, typ Type) {
return i.v, uint32(i.u1), i.typ
}
// LoadSplatData returns the operands for a load splat instruction.
func (i *Instruction) LoadSplatData() (ptr Value, offset uint32, lane VecLane) {
return i.v, uint32(i.u1), VecLane(i.u2)
}
// AsStore initializes this instruction as a store instruction with OpcodeStore.
func (i *Instruction) AsStore(storeOp Opcode, value, ptr Value, offset uint32) *Instruction {
i.opcode = storeOp
i.v = value
i.v2 = ptr
var dstSize uint64
switch storeOp {
case OpcodeStore:
dstSize = uint64(value.Type().Bits())
case OpcodeIstore8:
dstSize = 8
case OpcodeIstore16:
dstSize = 16
case OpcodeIstore32:
dstSize = 32
default:
panic("invalid store opcode" + storeOp.String())
}
i.u1 = uint64(offset) | dstSize<<32
return i
}
// StoreData returns the operands for a store instruction.
func (i *Instruction) StoreData() (value, ptr Value, offset uint32, storeSizeInBits byte) {
return i.v, i.v2, uint32(i.u1), byte(i.u1 >> 32)
}
// AsIconst64 initializes this instruction as a 64-bit integer constant instruction with OpcodeIconst.
func (i *Instruction) AsIconst64(v uint64) *Instruction {
i.opcode = OpcodeIconst
i.typ = TypeI64
i.u1 = v
return i
}
// AsIconst32 initializes this instruction as a 32-bit integer constant instruction with OpcodeIconst.
func (i *Instruction) AsIconst32(v uint32) *Instruction {
i.opcode = OpcodeIconst
i.typ = TypeI32
i.u1 = uint64(v)
return i
}
// AsIadd initializes this instruction as an integer addition instruction with OpcodeIadd.
func (i *Instruction) AsIadd(x, y Value) *Instruction {
i.opcode = OpcodeIadd
i.v = x
i.v2 = y
i.typ = x.Type()
return i
}
// AsVIadd initializes this instruction as an integer addition instruction with OpcodeVIadd on a vector.
func (i *Instruction) AsVIadd(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVIadd
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsIaddPairwise initializes this instruction as a lane-wise integer extended pairwise addition instruction
// with OpcodeIaddPairwise on a vector.
func (i *Instruction) AsIaddPairwise(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeIaddPairwise
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVSaddSat initializes this instruction as a vector addition with saturation instruction with OpcodeVSaddSat on a vector.
func (i *Instruction) AsVSaddSat(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVSaddSat
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVUaddSat initializes this instruction as a vector addition with saturation instruction with OpcodeVUaddSat on a vector.
func (i *Instruction) AsVUaddSat(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVUaddSat
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVIsub initializes this instruction as an integer subtraction instruction with OpcodeVIsub on a vector.
func (i *Instruction) AsVIsub(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVIsub
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVSsubSat initializes this instruction as a vector addition with saturation instruction with OpcodeVSsubSat on a vector.
func (i *Instruction) AsVSsubSat(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVSsubSat
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVUsubSat initializes this instruction as a vector addition with saturation instruction with OpcodeVUsubSat on a vector.
func (i *Instruction) AsVUsubSat(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVUsubSat
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVImin initializes this instruction as a signed integer min instruction with OpcodeVImin on a vector.
func (i *Instruction) AsVImin(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVImin
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVUmin initializes this instruction as an unsigned integer min instruction with OpcodeVUmin on a vector.
func (i *Instruction) AsVUmin(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVUmin
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVImax initializes this instruction as a signed integer max instruction with OpcodeVImax on a vector.
func (i *Instruction) AsVImax(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVImax
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVUmax initializes this instruction as an unsigned integer max instruction with OpcodeVUmax on a vector.
func (i *Instruction) AsVUmax(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVUmax
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVAvgRound initializes this instruction as an unsigned integer avg instruction, truncating to zero with OpcodeVAvgRound on a vector.
func (i *Instruction) AsVAvgRound(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVAvgRound
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVImul initializes this instruction as an integer multiplication with OpcodeVImul on a vector.
func (i *Instruction) AsVImul(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVImul
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsSqmulRoundSat initializes this instruction as a lane-wise saturating rounding multiplication
// in Q15 format with OpcodeSqmulRoundSat on a vector.
func (i *Instruction) AsSqmulRoundSat(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeSqmulRoundSat
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVIabs initializes this instruction as a vector absolute value with OpcodeVIabs.
func (i *Instruction) AsVIabs(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeVIabs
i.v = x
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVIneg initializes this instruction as a vector negation with OpcodeVIneg.
func (i *Instruction) AsVIneg(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeVIneg
i.v = x
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVIpopcnt initializes this instruction as a Population Count instruction with OpcodeVIpopcnt on a vector.
func (i *Instruction) AsVIpopcnt(x Value, lane VecLane) *Instruction {
if lane != VecLaneI8x16 {
panic("Unsupported lane type " + lane.String())
}
i.opcode = OpcodeVIpopcnt
i.v = x
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVSqrt initializes this instruction as a sqrt instruction with OpcodeVSqrt on a vector.
func (i *Instruction) AsVSqrt(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeVSqrt
i.v = x
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVFabs initializes this instruction as a float abs instruction with OpcodeVFabs on a vector.
func (i *Instruction) AsVFabs(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeVFabs
i.v = x
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVFneg initializes this instruction as a float neg instruction with OpcodeVFneg on a vector.
func (i *Instruction) AsVFneg(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeVFneg
i.v = x
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVFmax initializes this instruction as a float max instruction with OpcodeVFmax on a vector.
func (i *Instruction) AsVFmax(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVFmax
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVFmin initializes this instruction as a float min instruction with OpcodeVFmin on a vector.
func (i *Instruction) AsVFmin(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVFmin
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVFadd initializes this instruction as a floating point add instruction with OpcodeVFadd on a vector.
func (i *Instruction) AsVFadd(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVFadd
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVFsub initializes this instruction as a floating point subtraction instruction with OpcodeVFsub on a vector.
func (i *Instruction) AsVFsub(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVFsub
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVFmul initializes this instruction as a floating point multiplication instruction with OpcodeVFmul on a vector.
func (i *Instruction) AsVFmul(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVFmul
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVFdiv initializes this instruction as a floating point division instruction with OpcodeVFdiv on a vector.
func (i *Instruction) AsVFdiv(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVFdiv
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsImul initializes this instruction as an integer addition instruction with OpcodeImul.
func (i *Instruction) AsImul(x, y Value) *Instruction {
i.opcode = OpcodeImul
i.v = x
i.v2 = y
i.typ = x.Type()
return i
}
func (i *Instruction) Insert(b Builder) *Instruction {
b.InsertInstruction(i)
return i
}
// AsIsub initializes this instruction as an integer subtraction instruction with OpcodeIsub.
func (i *Instruction) AsIsub(x, y Value) *Instruction {
i.opcode = OpcodeIsub
i.v = x
i.v2 = y
i.typ = x.Type()
return i
}
// AsIcmp initializes this instruction as an integer comparison instruction with OpcodeIcmp.
func (i *Instruction) AsIcmp(x, y Value, c IntegerCmpCond) *Instruction {
i.opcode = OpcodeIcmp
i.v = x
i.v2 = y
i.u1 = uint64(c)
i.typ = TypeI32
return i
}
// AsFcmp initializes this instruction as an integer comparison instruction with OpcodeFcmp.
func (i *Instruction) AsFcmp(x, y Value, c FloatCmpCond) {
i.opcode = OpcodeFcmp
i.v = x
i.v2 = y
i.u1 = uint64(c)
i.typ = TypeI32
}
// AsVIcmp initializes this instruction as an integer vector comparison instruction with OpcodeVIcmp.
func (i *Instruction) AsVIcmp(x, y Value, c IntegerCmpCond, lane VecLane) *Instruction {
i.opcode = OpcodeVIcmp
i.v = x
i.v2 = y
i.u1 = uint64(c)
i.u2 = uint64(lane)
i.typ = TypeV128
return i
}
// AsVFcmp initializes this instruction as a float comparison instruction with OpcodeVFcmp on Vector.
func (i *Instruction) AsVFcmp(x, y Value, c FloatCmpCond, lane VecLane) *Instruction {
i.opcode = OpcodeVFcmp
i.v = x
i.v2 = y
i.u1 = uint64(c)
i.typ = TypeV128
i.u2 = uint64(lane)
return i
}
// AsVCeil initializes this instruction as an instruction with OpcodeCeil.
func (i *Instruction) AsVCeil(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeVCeil
i.v = x
i.typ = x.Type()
i.u1 = uint64(lane)
return i
}
// AsVFloor initializes this instruction as an instruction with OpcodeFloor.
func (i *Instruction) AsVFloor(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeVFloor
i.v = x
i.typ = x.Type()
i.u1 = uint64(lane)
return i
}
// AsVTrunc initializes this instruction as an instruction with OpcodeTrunc.
func (i *Instruction) AsVTrunc(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeVTrunc
i.v = x
i.typ = x.Type()
i.u1 = uint64(lane)
return i
}
// AsVNearest initializes this instruction as an instruction with OpcodeNearest.
func (i *Instruction) AsVNearest(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeVNearest
i.v = x
i.typ = x.Type()
i.u1 = uint64(lane)
return i
}
// AsVMaxPseudo initializes this instruction as an instruction with OpcodeVMaxPseudo.
func (i *Instruction) AsVMaxPseudo(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVMaxPseudo
i.typ = x.Type()
i.v = x
i.v2 = y
i.u1 = uint64(lane)
return i
}
// AsVMinPseudo initializes this instruction as an instruction with OpcodeVMinPseudo.
func (i *Instruction) AsVMinPseudo(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeVMinPseudo
i.typ = x.Type()
i.v = x
i.v2 = y
i.u1 = uint64(lane)
return i
}
// AsSDiv initializes this instruction as an integer bitwise and instruction with OpcodeSdiv.
func (i *Instruction) AsSDiv(x, y, ctx Value) *Instruction {
i.opcode = OpcodeSdiv
i.v = x
i.v2 = y
i.v3 = ctx
i.typ = x.Type()
return i
}
// AsUDiv initializes this instruction as an integer bitwise and instruction with OpcodeUdiv.
func (i *Instruction) AsUDiv(x, y, ctx Value) *Instruction {
i.opcode = OpcodeUdiv
i.v = x
i.v2 = y
i.v3 = ctx
i.typ = x.Type()
return i
}
// AsSRem initializes this instruction as an integer bitwise and instruction with OpcodeSrem.
func (i *Instruction) AsSRem(x, y, ctx Value) *Instruction {
i.opcode = OpcodeSrem
i.v = x
i.v2 = y
i.v3 = ctx
i.typ = x.Type()
return i
}
// AsURem initializes this instruction as an integer bitwise and instruction with OpcodeUrem.
func (i *Instruction) AsURem(x, y, ctx Value) *Instruction {
i.opcode = OpcodeUrem
i.v = x
i.v2 = y
i.v3 = ctx
i.typ = x.Type()
return i
}
// AsBand initializes this instruction as an integer bitwise and instruction with OpcodeBand.
func (i *Instruction) AsBand(x, amount Value) {
i.opcode = OpcodeBand
i.v = x
i.v2 = amount
i.typ = x.Type()
}
// AsBor initializes this instruction as an integer bitwise or instruction with OpcodeBor.
func (i *Instruction) AsBor(x, amount Value) {
i.opcode = OpcodeBor
i.v = x
i.v2 = amount
i.typ = x.Type()
}
// AsBxor initializes this instruction as an integer bitwise xor instruction with OpcodeBxor.
func (i *Instruction) AsBxor(x, amount Value) {
i.opcode = OpcodeBxor
i.v = x
i.v2 = amount
i.typ = x.Type()
}
// AsIshl initializes this instruction as an integer shift left instruction with OpcodeIshl.
func (i *Instruction) AsIshl(x, amount Value) *Instruction {
i.opcode = OpcodeIshl
i.v = x
i.v2 = amount
i.typ = x.Type()
return i
}
// AsVIshl initializes this instruction as an integer shift left instruction with OpcodeVIshl on vector.
func (i *Instruction) AsVIshl(x, amount Value, lane VecLane) *Instruction {
i.opcode = OpcodeVIshl
i.v = x
i.v2 = amount
i.u1 = uint64(lane)
i.typ = x.Type()
return i
}
// AsUshr initializes this instruction as an integer unsigned shift right (logical shift right) instruction with OpcodeUshr.
func (i *Instruction) AsUshr(x, amount Value) *Instruction {
i.opcode = OpcodeUshr
i.v = x
i.v2 = amount
i.typ = x.Type()
return i
}
// AsVUshr initializes this instruction as an integer unsigned shift right (logical shift right) instruction with OpcodeVUshr on vector.
func (i *Instruction) AsVUshr(x, amount Value, lane VecLane) *Instruction {
i.opcode = OpcodeVUshr
i.v = x
i.v2 = amount
i.u1 = uint64(lane)
i.typ = x.Type()
return i
}
// AsSshr initializes this instruction as an integer signed shift right (arithmetic shift right) instruction with OpcodeSshr.
func (i *Instruction) AsSshr(x, amount Value) *Instruction {
i.opcode = OpcodeSshr
i.v = x
i.v2 = amount
i.typ = x.Type()
return i
}
// AsVSshr initializes this instruction as an integer signed shift right (arithmetic shift right) instruction with OpcodeVSshr on vector.
func (i *Instruction) AsVSshr(x, amount Value, lane VecLane) *Instruction {
i.opcode = OpcodeVSshr
i.v = x
i.v2 = amount
i.u1 = uint64(lane)
i.typ = x.Type()
return i
}
// AsExtractlane initializes this instruction as an extract lane instruction with OpcodeExtractlane on vector.
func (i *Instruction) AsExtractlane(x Value, index byte, lane VecLane, signed bool) *Instruction {
i.opcode = OpcodeExtractlane
i.v = x
// 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`.
i.u1 = uint64(index)
if signed {
i.u1 = i.u1 | 1<<32
}
i.u2 = uint64(lane)
switch lane {
case VecLaneI8x16, VecLaneI16x8, VecLaneI32x4:
i.typ = TypeI32
case VecLaneI64x2:
i.typ = TypeI64
case VecLaneF32x4:
i.typ = TypeF32
case VecLaneF64x2:
i.typ = TypeF64
}
return i
}
// AsInsertlane initializes this instruction as an insert lane instruction with OpcodeInsertlane on vector.
func (i *Instruction) AsInsertlane(x, y Value, index byte, lane VecLane) *Instruction {
i.opcode = OpcodeInsertlane
i.v = x
i.v2 = y
i.u1 = uint64(index)
i.u2 = uint64(lane)
i.typ = TypeV128
return i
}
// AsShuffle initializes this instruction as a shuffle instruction with OpcodeShuffle on vector.
func (i *Instruction) AsShuffle(x, y Value, lane []byte) *Instruction {
i.opcode = OpcodeShuffle
i.v = x
i.v2 = y
// Encode the 16 bytes as 8 bytes in u1, and 8 bytes in u2.
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])
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])
i.typ = TypeV128
return i
}
// AsSwizzle initializes this instruction as an insert lane instruction with OpcodeSwizzle on vector.
func (i *Instruction) AsSwizzle(x, y Value, lane VecLane) *Instruction {
i.opcode = OpcodeSwizzle
i.v = x
i.v2 = y
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsSplat initializes this instruction as an insert lane instruction with OpcodeSplat on vector.
func (i *Instruction) AsSplat(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeSplat
i.v = x
i.u1 = uint64(lane)
i.typ = TypeV128
return i
}
// AsRotl initializes this instruction as a word rotate left instruction with OpcodeRotl.
func (i *Instruction) AsRotl(x, amount Value) {
i.opcode = OpcodeRotl
i.v = x
i.v2 = amount
i.typ = x.Type()
}
// AsRotr initializes this instruction as a word rotate right instruction with OpcodeRotr.
func (i *Instruction) AsRotr(x, amount Value) {
i.opcode = OpcodeRotr
i.v = x
i.v2 = amount
i.typ = x.Type()
}
// IcmpData returns the operands and comparison condition of this integer comparison instruction.
func (i *Instruction) IcmpData() (x, y Value, c IntegerCmpCond) {
return i.v, i.v2, IntegerCmpCond(i.u1)
}
// FcmpData returns the operands and comparison condition of this floating-point comparison instruction.
func (i *Instruction) FcmpData() (x, y Value, c FloatCmpCond) {
return i.v, i.v2, FloatCmpCond(i.u1)
}
// VIcmpData returns the operands and comparison condition of this integer comparison instruction on vector.
func (i *Instruction) VIcmpData() (x, y Value, c IntegerCmpCond, l VecLane) {
return i.v, i.v2, IntegerCmpCond(i.u1), VecLane(i.u2)
}
// VFcmpData returns the operands and comparison condition of this float comparison instruction on vector.
func (i *Instruction) VFcmpData() (x, y Value, c FloatCmpCond, l VecLane) {
return i.v, i.v2, FloatCmpCond(i.u1), VecLane(i.u2)
}
// ExtractlaneData returns the operands and sign flag of Extractlane on vector.
func (i *Instruction) ExtractlaneData() (x Value, index byte, signed bool, l VecLane) {
x = i.v
index = byte(0b00001111 & i.u1)
signed = i.u1>>32 != 0
l = VecLane(i.u2)
return
}
// InsertlaneData returns the operands and sign flag of Insertlane on vector.
func (i *Instruction) InsertlaneData() (x, y Value, index byte, l VecLane) {
x = i.v
y = i.v2
index = byte(i.u1)
l = VecLane(i.u2)
return
}
// AsFadd initializes this instruction as a floating-point addition instruction with OpcodeFadd.
func (i *Instruction) AsFadd(x, y Value) {
i.opcode = OpcodeFadd
i.v = x
i.v2 = y
i.typ = x.Type()
}
// AsFsub initializes this instruction as a floating-point subtraction instruction with OpcodeFsub.
func (i *Instruction) AsFsub(x, y Value) {
i.opcode = OpcodeFsub
i.v = x
i.v2 = y
i.typ = x.Type()
}
// AsFmul initializes this instruction as a floating-point multiplication instruction with OpcodeFmul.
func (i *Instruction) AsFmul(x, y Value) {
i.opcode = OpcodeFmul
i.v = x
i.v2 = y
i.typ = x.Type()
}
// AsFdiv initializes this instruction as a floating-point division instruction with OpcodeFdiv.
func (i *Instruction) AsFdiv(x, y Value) {
i.opcode = OpcodeFdiv
i.v = x
i.v2 = y
i.typ = x.Type()
}
// AsFmin initializes this instruction to take the minimum of two floating-points with OpcodeFmin.
func (i *Instruction) AsFmin(x, y Value) {
i.opcode = OpcodeFmin
i.v = x
i.v2 = y
i.typ = x.Type()
}
// AsFmax initializes this instruction to take the maximum of two floating-points with OpcodeFmax.
func (i *Instruction) AsFmax(x, y Value) {
i.opcode = OpcodeFmax
i.v = x
i.v2 = y
i.typ = x.Type()
}
// AsF32const initializes this instruction as a 32-bit floating-point constant instruction with OpcodeF32const.
func (i *Instruction) AsF32const(f float32) *Instruction {
i.opcode = OpcodeF32const
i.typ = TypeF64
i.u1 = uint64(math.Float32bits(f))
return i
}
// AsF64const initializes this instruction as a 64-bit floating-point constant instruction with OpcodeF64const.
func (i *Instruction) AsF64const(f float64) *Instruction {
i.opcode = OpcodeF64const
i.typ = TypeF64
i.u1 = math.Float64bits(f)
return i
}
// AsVconst initializes this instruction as a vector constant instruction with OpcodeVconst.
func (i *Instruction) AsVconst(lo, hi uint64) *Instruction {
i.opcode = OpcodeVconst
i.typ = TypeV128
i.u1 = lo
i.u2 = hi
return i
}
// AsVbnot initializes this instruction as a vector negation instruction with OpcodeVbnot.
func (i *Instruction) AsVbnot(v Value) *Instruction {
i.opcode = OpcodeVbnot
i.typ = TypeV128
i.v = v
return i
}
// AsVband initializes this instruction as an and vector instruction with OpcodeVband.
func (i *Instruction) AsVband(x, y Value) *Instruction {
i.opcode = OpcodeVband
i.typ = TypeV128
i.v = x
i.v2 = y
return i
}
// AsVbor initializes this instruction as an or vector instruction with OpcodeVbor.
func (i *Instruction) AsVbor(x, y Value) *Instruction {
i.opcode = OpcodeVbor
i.typ = TypeV128
i.v = x
i.v2 = y
return i
}
// AsVbxor initializes this instruction as a xor vector instruction with OpcodeVbxor.
func (i *Instruction) AsVbxor(x, y Value) *Instruction {
i.opcode = OpcodeVbxor
i.typ = TypeV128
i.v = x
i.v2 = y
return i
}
// AsVbandnot initializes this instruction as an and-not vector instruction with OpcodeVbandnot.
func (i *Instruction) AsVbandnot(x, y Value) *Instruction {
i.opcode = OpcodeVbandnot
i.typ = TypeV128
i.v = x
i.v2 = y
return i
}
// AsVbitselect initializes this instruction as a bit select vector instruction with OpcodeVbitselect.
func (i *Instruction) AsVbitselect(c, x, y Value) *Instruction {
i.opcode = OpcodeVbitselect
i.typ = TypeV128
i.v = c
i.v2 = x
i.v3 = y
return i
}
// AsVanyTrue initializes this instruction as an anyTrue vector instruction with OpcodeVanyTrue.
func (i *Instruction) AsVanyTrue(x Value) *Instruction {
i.opcode = OpcodeVanyTrue
i.typ = TypeI32
i.v = x
return i
}
// AsVallTrue initializes this instruction as an allTrue vector instruction with OpcodeVallTrue.
func (i *Instruction) AsVallTrue(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeVallTrue
i.typ = TypeI32
i.v = x
i.u1 = uint64(lane)
return i
}
// AsVhighBits initializes this instruction as a highBits vector instruction with OpcodeVhighBits.
func (i *Instruction) AsVhighBits(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeVhighBits
i.typ = TypeI32
i.v = x
i.u1 = uint64(lane)
return i
}
// VconstData returns the operands of this vector constant instruction.
func (i *Instruction) VconstData() (lo, hi uint64) {
return i.u1, i.u2
}
// AsReturn initializes this instruction as a return instruction with OpcodeReturn.
func (i *Instruction) AsReturn(vs []Value) *Instruction {
i.opcode = OpcodeReturn
i.vs = vs
return i
}
// AsIreduce initializes this instruction as a reduction instruction with OpcodeIreduce.
func (i *Instruction) AsIreduce(v Value, dstType Type) *Instruction {
i.opcode = OpcodeIreduce
i.v = v
i.typ = dstType
return i
}
// 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 (i *Instruction) AsWiden(v Value, lane VecLane, signed, low bool) *Instruction {
switch {
case signed && low:
i.opcode = OpcodeSwidenLow
case !signed && low:
i.opcode = OpcodeUwidenLow
case signed && !low:
i.opcode = OpcodeSwidenHigh
case !signed && !low:
i.opcode = OpcodeUwidenHigh
}
i.v = v
i.u1 = uint64(lane)
return i
}
// ReturnVals returns the return values of OpcodeReturn.
func (i *Instruction) ReturnVals() []Value {
return i.vs
}
// AsExitWithCode initializes this instruction as a trap instruction with OpcodeExitWithCode.
func (i *Instruction) AsExitWithCode(ctx Value, code wazevoapi.ExitCode) {
i.opcode = OpcodeExitWithCode
i.v = ctx
i.u1 = uint64(code)
}
// AsExitIfTrueWithCode initializes this instruction as a trap instruction with OpcodeExitIfTrueWithCode.
func (i *Instruction) AsExitIfTrueWithCode(ctx, c Value, code wazevoapi.ExitCode) *Instruction {
i.opcode = OpcodeExitIfTrueWithCode
i.v = ctx
i.v2 = c
i.u1 = uint64(code)
return i
}
// ExitWithCodeData returns the context and exit code of OpcodeExitWithCode.
func (i *Instruction) ExitWithCodeData() (ctx Value, code wazevoapi.ExitCode) {
return i.v, wazevoapi.ExitCode(i.u1)
}
// ExitIfTrueWithCodeData returns the context and exit code of OpcodeExitWithCode.
func (i *Instruction) ExitIfTrueWithCodeData() (ctx, c Value, code wazevoapi.ExitCode) {
return i.v, i.v2, wazevoapi.ExitCode(i.u1)
}
// InvertBrx inverts either OpcodeBrz or OpcodeBrnz to the other.
func (i *Instruction) InvertBrx() {
switch i.opcode {
case OpcodeBrz:
i.opcode = OpcodeBrnz
case OpcodeBrnz:
i.opcode = OpcodeBrz
default:
panic("BUG")
}
}
// BranchData returns the branch data for this instruction necessary for backends.
func (i *Instruction) BranchData() (condVal Value, blockArgs []Value, target BasicBlock) {
switch i.opcode {
case OpcodeJump:
condVal = ValueInvalid
case OpcodeBrz, OpcodeBrnz:
condVal = i.v
default:
panic("BUG")
}
blockArgs = i.vs
target = i.blk
return
}
// BrTableData returns the branch table data for this instruction necessary for backends.
func (i *Instruction) BrTableData() (index Value, targets []BasicBlock) {
if i.opcode != OpcodeBrTable {
panic("BUG: BrTableData only available for OpcodeBrTable")
}
index = i.v
targets = i.targets
return
}
// AsJump initializes this instruction as a jump instruction with OpcodeJump.
func (i *Instruction) AsJump(vs []Value, target BasicBlock) {
i.opcode = OpcodeJump
i.vs = vs
i.blk = target
}
// IsFallthroughJump returns true if this instruction is a fallthrough jump.
func (i *Instruction) IsFallthroughJump() bool {
if i.opcode != OpcodeJump {
panic("BUG: IsFallthrough only available for OpcodeJump")
}
return i.opcode == OpcodeJump && i.u1 != 0
}
// AsFallthroughJump marks this instruction as a fallthrough jump.
func (i *Instruction) AsFallthroughJump() {
if i.opcode != OpcodeJump {
panic("BUG: AsFallthroughJump only available for OpcodeJump")
}
i.u1 = 1
}
// AsBrz initializes this instruction as a branch-if-zero instruction with OpcodeBrz.
func (i *Instruction) AsBrz(v Value, args []Value, target BasicBlock) {
i.opcode = OpcodeBrz
i.v = v
i.vs = args
i.blk = target
}
// AsBrnz initializes this instruction as a branch-if-not-zero instruction with OpcodeBrnz.
func (i *Instruction) AsBrnz(v Value, args []Value, target BasicBlock) *Instruction {
i.opcode = OpcodeBrnz
i.v = v
i.vs = args
i.blk = target
return i
}
// AsBrTable initializes this instruction as a branch-table instruction with OpcodeBrTable.
func (i *Instruction) AsBrTable(index Value, targets []BasicBlock) {
i.opcode = OpcodeBrTable
i.v = index
i.targets = targets
}
// AsCall initializes this instruction as a call instruction with OpcodeCall.
func (i *Instruction) AsCall(ref FuncRef, sig *Signature, args []Value) {
i.opcode = OpcodeCall
i.u1 = uint64(ref)
i.vs = args
i.u2 = uint64(sig.ID)
sig.used = true
}
// CallData returns the call data for this instruction necessary for backends.
func (i *Instruction) CallData() (ref FuncRef, sigID SignatureID, args []Value) {
if i.opcode != OpcodeCall {
panic("BUG: CallData only available for OpcodeCall")
}
ref = FuncRef(i.u1)
sigID = SignatureID(i.u2)
args = i.vs
return
}
// AsCallIndirect initializes this instruction as a call-indirect instruction with OpcodeCallIndirect.
func (i *Instruction) AsCallIndirect(funcPtr Value, sig *Signature, args []Value) *Instruction {
i.opcode = OpcodeCallIndirect
i.typ = TypeF64
i.vs = args
i.v = funcPtr
i.u1 = uint64(sig.ID)
sig.used = true
return i
}
// CallIndirectData returns the call indirect data for this instruction necessary for backends.
func (i *Instruction) CallIndirectData() (funcPtr Value, sigID SignatureID, args []Value) {
if i.opcode != OpcodeCallIndirect {
panic("BUG: CallIndirectData only available for OpcodeCallIndirect")
}
funcPtr = i.v
sigID = SignatureID(i.u1)
args = i.vs
return
}
// AsClz initializes this instruction as a Count Leading Zeroes instruction with OpcodeClz.
func (i *Instruction) AsClz(x Value) {
i.opcode = OpcodeClz
i.v = x
i.typ = x.Type()
}
// AsCtz initializes this instruction as a Count Trailing Zeroes instruction with OpcodeCtz.
func (i *Instruction) AsCtz(x Value) {
i.opcode = OpcodeCtz
i.v = x
i.typ = x.Type()
}
// AsPopcnt initializes this instruction as a Population Count instruction with OpcodePopcnt.
func (i *Instruction) AsPopcnt(x Value) {
i.opcode = OpcodePopcnt
i.v = x
i.typ = x.Type()
}
// AsFneg initializes this instruction as an instruction with OpcodeFneg.
func (i *Instruction) AsFneg(x Value) *Instruction {
i.opcode = OpcodeFneg
i.v = x
i.typ = x.Type()
return i
}
// AsSqrt initializes this instruction as an instruction with OpcodeSqrt.
func (i *Instruction) AsSqrt(x Value) *Instruction {
i.opcode = OpcodeSqrt
i.v = x
i.typ = x.Type()
return i
}
// AsFabs initializes this instruction as an instruction with OpcodeFabs.
func (i *Instruction) AsFabs(x Value) *Instruction {
i.opcode = OpcodeFabs
i.v = x
i.typ = x.Type()
return i
}
// AsFcopysign initializes this instruction as an instruction with OpcodeFcopysign.
func (i *Instruction) AsFcopysign(x, y Value) *Instruction {
i.opcode = OpcodeFcopysign
i.v = x
i.v2 = y
i.typ = x.Type()
return i
}
// AsCeil initializes this instruction as an instruction with OpcodeCeil.
func (i *Instruction) AsCeil(x Value) *Instruction {
i.opcode = OpcodeCeil
i.v = x
i.typ = x.Type()
return i
}
// AsFloor initializes this instruction as an instruction with OpcodeFloor.
func (i *Instruction) AsFloor(x Value) *Instruction {
i.opcode = OpcodeFloor
i.v = x
i.typ = x.Type()
return i
}
// AsTrunc initializes this instruction as an instruction with OpcodeTrunc.
func (i *Instruction) AsTrunc(x Value) *Instruction {
i.opcode = OpcodeTrunc
i.v = x
i.typ = x.Type()
return i
}
// AsNearest initializes this instruction as an instruction with OpcodeNearest.
func (i *Instruction) AsNearest(x Value) *Instruction {
i.opcode = OpcodeNearest
i.v = x
i.typ = x.Type()
return i
}
// AsBitcast initializes this instruction as an instruction with OpcodeBitcast.
func (i *Instruction) AsBitcast(x Value, dstType Type) *Instruction {
i.opcode = OpcodeBitcast
i.v = x
i.typ = dstType
return i
}
// BitcastData returns the operands for a bitcast instruction.
func (i *Instruction) BitcastData() (x Value, dstType Type) {
return i.v, i.typ
}
// AsFdemote initializes this instruction as an instruction with OpcodeFdemote.
func (i *Instruction) AsFdemote(x Value) {
i.opcode = OpcodeFdemote
i.v = x
i.typ = TypeF32
}
// AsFpromote initializes this instruction as an instruction with OpcodeFpromote.
func (i *Instruction) AsFpromote(x Value) {
i.opcode = OpcodeFpromote
i.v = x
i.typ = TypeF64
}
// AsFcvtFromInt initializes this instruction as an instruction with either OpcodeFcvtFromUint or OpcodeFcvtFromSint
func (i *Instruction) AsFcvtFromInt(x Value, signed bool, dst64bit bool) *Instruction {
if signed {
i.opcode = OpcodeFcvtFromSint
} else {
i.opcode = OpcodeFcvtFromUint
}
i.v = x
if dst64bit {
i.typ = TypeF64
} else {
i.typ = TypeF32
}
return i
}
// AsFcvtToInt initializes this instruction as an instruction with either OpcodeFcvtToUint or OpcodeFcvtToSint
func (i *Instruction) AsFcvtToInt(x, ctx Value, signed bool, dst64bit bool, sat bool) *Instruction {
switch {
case signed && !sat:
i.opcode = OpcodeFcvtToSint
case !signed && !sat:
i.opcode = OpcodeFcvtToUint
case signed && sat:
i.opcode = OpcodeFcvtToSintSat
case !signed && sat:
i.opcode = OpcodeFcvtToUintSat
}
i.v = x
i.v2 = ctx
if dst64bit {
i.typ = TypeI64
} else {
i.typ = TypeI32
}
return i
}
// AsVFcvtToIntSat initializes this instruction as an instruction with either OpcodeVFcvtToSintSat or OpcodeVFcvtToUintSat
func (i *Instruction) AsVFcvtToIntSat(x Value, lane VecLane, signed bool) *Instruction {
if signed {
i.opcode = OpcodeVFcvtToSintSat
} else {
i.opcode = OpcodeVFcvtToUintSat
}
i.v = x
i.u1 = uint64(lane)
return i
}
// AsVFcvtFromInt initializes this instruction as an instruction with either OpcodeVFcvtToSintSat or OpcodeVFcvtToUintSat
func (i *Instruction) AsVFcvtFromInt(x Value, lane VecLane, signed bool) *Instruction {
if signed {
i.opcode = OpcodeVFcvtFromSint
} else {
i.opcode = OpcodeVFcvtFromUint
}
i.v = x
i.u1 = uint64(lane)
return i
}
// AsNarrow initializes this instruction as an instruction with either OpcodeSnarrow or OpcodeUnarrow
func (i *Instruction) AsNarrow(x, y Value, lane VecLane, signed bool) *Instruction {
if signed {
i.opcode = OpcodeSnarrow
} else {
i.opcode = OpcodeUnarrow
}
i.v = x
i.v2 = y
i.u1 = uint64(lane)
return i
}
// AsFvpromoteLow initializes this instruction as an instruction with OpcodeFvpromoteLow
func (i *Instruction) AsFvpromoteLow(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeFvpromoteLow
i.v = x
i.u1 = uint64(lane)
return i
}
// AsFvdemote initializes this instruction as an instruction with OpcodeFvdemote
func (i *Instruction) AsFvdemote(x Value, lane VecLane) *Instruction {
i.opcode = OpcodeFvdemote
i.v = x
i.u1 = uint64(lane)
return i
}
// AsSExtend initializes this instruction as a sign extension instruction with OpcodeSExtend.
func (i *Instruction) AsSExtend(v Value, from, to byte) *Instruction {
i.opcode = OpcodeSExtend
i.v = v
i.u1 = uint64(from)<<8 | uint64(to)
if to == 64 {
i.typ = TypeI64
} else {
i.typ = TypeI32
}
return i
}
// AsUExtend initializes this instruction as an unsigned extension instruction with OpcodeUExtend.
func (i *Instruction) AsUExtend(v Value, from, to byte) *Instruction {
i.opcode = OpcodeUExtend
i.v = v
i.u1 = uint64(from)<<8 | uint64(to)
if to == 64 {
i.typ = TypeI64
} else {
i.typ = TypeI32
}
return i
}
func (i *Instruction) ExtendData() (from, to byte, signed bool) {
if i.opcode != OpcodeSExtend && i.opcode != OpcodeUExtend {
panic("BUG: ExtendData only available for OpcodeSExtend and OpcodeUExtend")
}
from = byte(i.u1 >> 8)
to = byte(i.u1)
signed = i.opcode == OpcodeSExtend
return
}
// AsSelect initializes this instruction as an unsigned extension instruction with OpcodeSelect.
func (i *Instruction) AsSelect(c, x, y Value) *Instruction {
i.opcode = OpcodeSelect
i.v = c
i.v2 = x
i.v3 = y
i.typ = x.Type()
return i
}
// SelectData returns the select data for this instruction necessary for backends.
func (i *Instruction) SelectData() (c, x, y Value) {
c = i.v
x = i.v2
y = i.v3
return
}
// ExtendFromToBits returns the from and to bit size for the extension instruction.
func (i *Instruction) ExtendFromToBits() (from, to byte) {
from = byte(i.u1 >> 8)
to = byte(i.u1)
return
}
// Format returns a string representation of this instruction with the given builder.
// For debugging purposes only.
func (i *Instruction) Format(b Builder) string {
var instSuffix string
switch i.opcode {
case OpcodeExitWithCode:
instSuffix = fmt.Sprintf(" %s, %s", i.v.Format(b), wazevoapi.ExitCode(i.u1))
case OpcodeExitIfTrueWithCode:
instSuffix = fmt.Sprintf(" %s, %s, %s", i.v2.Format(b), i.v.Format(b), wazevoapi.ExitCode(i.u1))
case OpcodeIadd, OpcodeIsub, OpcodeImul, OpcodeFadd, OpcodeFsub, OpcodeFmin, OpcodeFmax, OpcodeFdiv, OpcodeFmul:
instSuffix = fmt.Sprintf(" %s, %s", i.v.Format(b), i.v2.Format(b))
case OpcodeIcmp:
instSuffix = fmt.Sprintf(" %s, %s, %s", IntegerCmpCond(i.u1), i.v.Format(b), i.v2.Format(b))
case OpcodeFcmp:
instSuffix = fmt.Sprintf(" %s, %s, %s", FloatCmpCond(i.u1), i.v.Format(b), i.v2.Format(b))
case OpcodeSExtend, OpcodeUExtend:
instSuffix = fmt.Sprintf(" %s, %d->%d", i.v.Format(b), i.u1>>8, i.u1&0xff)
case OpcodeCall, OpcodeCallIndirect:
vs := make([]string, len(i.vs))
for idx := range vs {
vs[idx] = i.vs[idx].Format(b)
}
if i.opcode == OpcodeCallIndirect {
instSuffix = fmt.Sprintf(" %s:%s, %s", i.v.Format(b), SignatureID(i.u1), strings.Join(vs, ", "))
} else {
instSuffix = fmt.Sprintf(" %s:%s, %s", FuncRef(i.u1), SignatureID(i.u2), strings.Join(vs, ", "))
}
case OpcodeStore, OpcodeIstore8, OpcodeIstore16, OpcodeIstore32:
instSuffix = fmt.Sprintf(" %s, %s, %#x", i.v.Format(b), i.v2.Format(b), int32(i.u1))
case OpcodeLoad, OpcodeVZeroExtLoad:
instSuffix = fmt.Sprintf(" %s, %#x", i.v.Format(b), int32(i.u1))
case OpcodeLoadSplat:
instSuffix = fmt.Sprintf(".%s %s, %#x", VecLane(i.u2), i.v.Format(b), int32(i.u1))
case OpcodeUload8, OpcodeUload16, OpcodeUload32, OpcodeSload8, OpcodeSload16, OpcodeSload32:
instSuffix = fmt.Sprintf(" %s, %#x", i.v.Format(b), int32(i.u1))
case OpcodeSelect, OpcodeVbitselect:
instSuffix = fmt.Sprintf(" %s, %s, %s", i.v.Format(b), i.v2.Format(b), i.v3.Format(b))
case OpcodeIconst:
switch i.typ {
case TypeI32:
instSuffix = fmt.Sprintf("_32 %#x", uint32(i.u1))
case TypeI64:
instSuffix = fmt.Sprintf("_64 %#x", i.u1)
}
case OpcodeVconst:
instSuffix = fmt.Sprintf(" %016x %016x", i.u1, i.u2)
case OpcodeF32const:
instSuffix = fmt.Sprintf(" %f", math.Float32frombits(uint32(i.u1)))
case OpcodeF64const:
instSuffix = fmt.Sprintf(" %f", math.Float64frombits(i.u1))
case OpcodeReturn:
if len(i.vs) == 0 {
break
}
vs := make([]string, len(i.vs))
for idx := range vs {
vs[idx] = i.vs[idx].Format(b)
}
instSuffix = fmt.Sprintf(" %s", strings.Join(vs, ", "))
case OpcodeJump:
vs := make([]string, len(i.vs)+1)
if i.IsFallthroughJump() {
vs[0] = " fallthrough"
} else {
vs[0] = " " + i.blk.(*basicBlock).Name()
}
for idx := range i.vs {
vs[idx+1] = i.vs[idx].Format(b)
}
instSuffix = strings.Join(vs, ", ")
case OpcodeBrz, OpcodeBrnz:
vs := make([]string, len(i.vs)+2)
vs[0] = " " + i.v.Format(b)
vs[1] = i.blk.(*basicBlock).Name()
for idx := range i.vs {
vs[idx+2] = i.vs[idx].Format(b)
}
instSuffix = strings.Join(vs, ", ")
case OpcodeBrTable:
// `BrTable index, [label1, label2, ... labelN]`
instSuffix = fmt.Sprintf(" %s", i.v.Format(b))
instSuffix += ", ["
for i, target := range i.targets {
blk := target.(*basicBlock)
if i == 0 {
instSuffix += blk.Name()
} else {
instSuffix += ", " + blk.Name()
}
}
instSuffix += "]"
case OpcodeBand, OpcodeBor, OpcodeBxor, OpcodeRotr, OpcodeRotl, OpcodeIshl, OpcodeSshr, OpcodeUshr,
OpcodeSdiv, OpcodeUdiv, OpcodeFcopysign, OpcodeSrem, OpcodeUrem,
OpcodeVbnot, OpcodeVbxor, OpcodeVbor, OpcodeVband, OpcodeVbandnot, OpcodeVIcmp, OpcodeVFcmp:
instSuffix = fmt.Sprintf(" %s, %s", i.v.Format(b), i.v2.Format(b))
case OpcodeUndefined:
case OpcodeClz, OpcodeCtz, OpcodePopcnt, OpcodeFneg, OpcodeFcvtToSint, OpcodeFcvtToUint, OpcodeFcvtFromSint,
OpcodeFcvtFromUint, OpcodeFcvtToSintSat, OpcodeFcvtToUintSat, OpcodeFdemote, OpcodeFpromote, OpcodeIreduce, OpcodeBitcast, OpcodeSqrt, OpcodeFabs,
OpcodeCeil, OpcodeFloor, OpcodeTrunc, OpcodeNearest:
instSuffix = " " + i.v.Format(b)
case OpcodeVIadd, OpcodeIaddPairwise, 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:
instSuffix = fmt.Sprintf(".%s %s, %s", VecLane(i.u1), i.v.Format(b), i.v2.Format(b))
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:
instSuffix = fmt.Sprintf(".%s %s", VecLane(i.u1), i.v.Format(b))
case OpcodeExtractlane:
var signedness string
if i.u1 != 0 {
signedness = "signed"
} else {
signedness = "unsigned"
}
instSuffix = fmt.Sprintf(".%s %d, %s (%s)", VecLane(i.u2), 0x0000FFFF&i.u1, i.v.Format(b), signedness)
case OpcodeInsertlane:
instSuffix = fmt.Sprintf(".%s %d, %s, %s", VecLane(i.u2), i.u1, i.v.Format(b), i.v2.Format(b))
case OpcodeShuffle:
lanes := make([]byte, 16)
for idx := 0; idx < 8; idx++ {
lanes[idx] = byte(i.u1 >> (8 * idx))
}
for idx := 0; idx < 8; idx++ {
lanes[idx+8] = byte(i.u2 >> (8 * idx))
}
// Prints Shuffle.[0 1 2 3 4 5 6 7 ...] v2, v3
instSuffix = fmt.Sprintf(".%v %s, %s", lanes, i.v.Format(b), i.v2.Format(b))
default:
panic(fmt.Sprintf("TODO: format for %s", i.opcode))
}
instr := i.opcode.String() + instSuffix
var rvs []string
if rv := i.rValue; rv.Valid() {
rvs = append(rvs, rv.formatWithType(b))
}
for _, v := range i.rValues {
rvs = append(rvs, v.formatWithType(b))
}
if len(rvs) > 0 {
return fmt.Sprintf("%s = %s", strings.Join(rvs, ", "), instr)
} else {
return instr
}
}
// addArgumentBranchInst adds an argument to this instruction.
func (i *Instruction) addArgumentBranchInst(v Value) {
switch i.opcode {
case OpcodeJump, OpcodeBrz, OpcodeBrnz:
i.vs = append(i.vs, v)
default:
panic("BUG: " + i.opcode.String())
}
}
// Constant returns true if this instruction is a constant instruction.
func (i *Instruction) Constant() bool {
switch i.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 (i *Instruction) ConstantVal() (ret uint64) {
switch i.opcode {
case OpcodeIconst, OpcodeF32const, OpcodeF64const:
ret = i.u1
default:
panic("TODO")
}
return
}
// String implements fmt.Stringer.
func (o Opcode) String() (ret string) {
switch o {
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 OpcodeBmask:
return "Bmask"
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 OpcodeIaddPairwise:
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 OpcodeIsplit:
return "Isplit"
case OpcodeIconcat:
return "Iconcat"
case OpcodeAtomicRmw:
return "AtomicRmw"
case OpcodeAtomicCas:
return "AtomicCas"
case OpcodeAtomicLoad:
return "AtomicLoad"
case OpcodeAtomicStore:
return "AtomicStore"
case OpcodeFence:
return "Fence"
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", o))
}