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