library/src/main/java/kwasm/format/binary/instruction/NumericInstruction.kt
/*
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("EXPERIMENTAL_API_USAGE")
package kwasm.format.binary.instruction
import kwasm.ast.FloatLiteral
import kwasm.ast.IntegerLiteral
import kwasm.ast.instruction.Instruction
import kwasm.ast.instruction.NumericConstantInstruction
import kwasm.ast.instruction.NumericInstruction
import kwasm.format.binary.BinaryParser
import kwasm.format.binary.value.readDouble
import kwasm.format.binary.value.readFloat
import kwasm.format.binary.value.readInt
import kwasm.format.binary.value.readLong
import kwasm.format.binary.value.readUInt
internal val NUMERIC_OPCODE_RANGE = 0x41.toUByte().toInt()..0xC4.toUByte().toInt()
internal const val NUMERIC_SATURATING_TRUNCATION_OPCODE = 0xFC
/**
* From
* [the docs](https://webassembly.github.io/spec/core/binary/instructions.html#numeric-instructions)
* :
*
* All variants of numeric instructions are represented by separate byte codes.
*
* The `const` instructions are followed by the respective literal.
*
* ```
* instr ::= 0x41 n:i32 => i32.const n
* 0x42 n:i64 => i64.const n
* 0x43 z:f32 => f32.const z
* 0x44 z:f64 => f64.const z
* ```
*
* All other numeric instructions are plain opcodes without any immediates.
*
* ```
* instr ::= 0x45 => i32.eqz
* 0x46 => i32.eq
* 0x47 => i32.ne
* 0x48 => i32.lt_s
* 0x49 => i32.lt_u
* 0x4A => i32.gt_s
* 0x4B => i32.gt_u
* 0x4C => i32.le_s
* 0x4D => i32.le_u
* 0x4E => i32.ge_s
* 0x4F => i32.ge_u
*
* 0x50 => i64.eqz
* 0x51 => i64.eq
* 0x52 => i64.ne
* 0x53 => i64.lt_s
* 0x54 => i64.lt_u
* 0x55 => i64.gt_s
* 0x56 => i64.gt_u
* 0x57 => i64.le_s
* 0x58 => i64.le_u
* 0x59 => i64.ge_s
* 0x5A => i64.ge_u
*
* 0x5B => f32.eq
* 0x5C => f32.ne
* 0x5D => f32.lt
* 0x5E => f32.gt
* 0x5F => f32.le
* 0x60 => f32.ge
*
* 0x61 => f64.eq
* 0x62 => f64.ne
* 0x63 => f64.lt
* 0x64 => f64.gt
* 0x65 => f64.le
* 0x66 => f64.ge
*
* 0x67 => i32.clz
* 0x68 => i32.ctz
* 0x69 => i32.popcnt
* 0x6A => i32.add
* 0x6B => i32.sub
* 0x6C => i32.mul
* 0x6D => i32.div_s
* 0x6E => i32.div_u
* 0x6F => i32.rem_s
* 0x70 => i32.rem_u
* 0x71 => i32.and
* 0x72 => i32.or
* 0x73 => i32.xor
* 0x74 => i32.shl
* 0x75 => i32.shr_s
* 0x76 => i32.shr_u
* 0x77 => i32.rotl
* 0x78 => i32.rotr
*
* 0x79 => i64.clz
* 0x7A => i64.ctz
* 0x7B => i64.popcnt
* 0x7C => i64.add
* 0x7D => i64.sub
* 0x7E => i64.mul
* 0x7F => i64.div_s
* 0x80 => i64.div_u
* 0x81 => i64.rem_s
* 0x82 => i64.rem_u
* 0x83 => i64.and
* 0x84 => i64.or
* 0x85 => i64.xor
* 0x86 => i64.shl
* 0x87 => i64.shr_s
* 0x88 => i64.shr_u
* 0x89 => i64.rotl
* 0x8A => i64.rotr
*
* 0x8B => f32.abs
* 0x8C => f32.neg
* 0x8D => f32.ceil
* 0x8E => f32.floor
* 0x8F => f32.trunc
* 0x90 => f32.nearest
* 0x91 => f32.sqrt
* 0x92 => f32.add
* 0x93 => f32.sub
* 0x94 => f32.mul
* 0x95 => f32.div
* 0x96 => f32.min
* 0x97 => f32.max
* 0x98 => f32.copysign
*
* 0x99 => f64.abs
* 0x9A => f64.neg
* 0x9B => f64.ceil
* 0x9C => f64.floor
* 0x9D => f64.trunc
* 0x9E => f64.nearest
* 0x9F => f64.sqrt
* 0xA0 => f64.add
* 0xA1 => f64.sub
* 0xA2 => f64.mul
* 0xA3 => f64.div
* 0xA4 => f64.min
* 0xA5 => f64.max
* 0xA6 => f64.copysign
*
* 0xA7 => i32.wrap_i64
* 0xA8 => i32.trunc_f32_s
* 0xA9 => i32.trunc_f32_u
* 0xAA => i32.trunc_f64_s
* 0xAB => i32.trunc_f64_u
*
* 0xAC => i64.extend_i32_s
* 0xAD => i64.extend_i32_u
* 0xAE => i64.trunc_f32_s
* 0xAF => i64.trunc_f32_u
* 0xB0 => i64.trunc_f64_s
* 0xB1 => i64.trunc_f64_u
*
* 0xB2 => f32.convert_i32_s
* 0xB3 => f32.convert_i32_u
* 0xB4 => f32.convert_i64_s
* 0xB5 => f32.convert_i64_u
* 0xB6 => f32.demote_f64
*
* 0xB7 => f64.convert_i32_s
* 0xB8 => f64.convert_i32_u
* 0xB9 => f64.convert_i64_s
* 0xBA => f64.convert_i64_u
* 0xBB => f64.promote_f32
*
* 0xBC => i32.reinterpret_f32
* 0xBD => i64.reinterpret_f64
* 0xBE => f32.reinterpret_i32
* 0xBF => f64.reinterpret_i64
*
* 0xC0 => i32.extend8_s
* 0xC1 => i32.extend16_s
* 0xC2 => i64.extend8_s
* 0xC3 => i64.extend16_s
* 0xC4 => i64.extend32_s
* ```
*
* The saturating truncation instructions all have a one byte prefix, whereas the actual opcode is encoded by a variable-length unsigned integer.
*
* ```
* instr ::= 0xFC 0:u32 => i32.trunc_sat_f32_s
* 0xFC 1:u32 => i32.trunc_sat_f32_u
* 0xFC 2:u32 => i32.trunc_sat_f64_s
* 0xFC 3:u32 => i32.trunc_sat_f64_u
* 0xFC 4:u32 => i64.trunc_sat_f32_s
* 0xFC 5:u32 => i64.trunc_sat_f32_u
* 0xFC 6:u32 => i64.trunc_sat_f64_s
* 0xFC 7:u32 => i64.trunc_sat_f64_u
* ```
*/
fun BinaryParser.readNumericInstruction(opcode: Int): Instruction {
return when (opcode) {
0x41 -> NumericConstantInstruction.I32(IntegerLiteral.S32(readInt()))
0x42 -> NumericConstantInstruction.I64(IntegerLiteral.S64(readLong()))
0x43 -> NumericConstantInstruction.F32(FloatLiteral.SinglePrecision(readFloat()))
0x44 -> NumericConstantInstruction.F64(FloatLiteral.DoublePrecision(readDouble()))
0x45 -> NumericInstruction.I32EqualsZero
0x46 -> NumericInstruction.I32Equals
0x47 -> NumericInstruction.I32NotEquals
0x48 -> NumericInstruction.I32LessThanSigned
0x49 -> NumericInstruction.I32LessThanUnsigned
0x4A -> NumericInstruction.I32GreaterThanSigned
0x4B -> NumericInstruction.I32GreaterThanUnsigned
0x4C -> NumericInstruction.I32LessThanEqualToSigned
0x4D -> NumericInstruction.I32LessThanEqualToUnsigned
0x4E -> NumericInstruction.I32GreaterThanEqualToSigned
0x4F -> NumericInstruction.I32GreaterThanEqualToUnsigned
0x50 -> NumericInstruction.I64EqualsZero
0x51 -> NumericInstruction.I64Equals
0x52 -> NumericInstruction.I64NotEquals
0x53 -> NumericInstruction.I64LessThanSigned
0x54 -> NumericInstruction.I64LessThanUnsigned
0x55 -> NumericInstruction.I64GreaterThanSigned
0x56 -> NumericInstruction.I64GreaterThanUnsigned
0x57 -> NumericInstruction.I64LessThanEqualToSigned
0x58 -> NumericInstruction.I64LessThanEqualToUnsigned
0x59 -> NumericInstruction.I64GreaterThanEqualToSigned
0x5A -> NumericInstruction.I64GreaterThanEqualToUnsigned
0x5B -> NumericInstruction.F32Equals
0x5C -> NumericInstruction.F32NotEquals
0x5D -> NumericInstruction.F32LessThan
0x5E -> NumericInstruction.F32GreaterThan
0x5F -> NumericInstruction.F32LessThanEqualTo
0x60 -> NumericInstruction.F32GreaterThanEqualTo
0x61 -> NumericInstruction.F64Equals
0x62 -> NumericInstruction.F64NotEquals
0x63 -> NumericInstruction.F64LessThan
0x64 -> NumericInstruction.F64GreaterThan
0x65 -> NumericInstruction.F64LessThanEqualTo
0x66 -> NumericInstruction.F64GreaterThanEqualTo
0x67 -> NumericInstruction.I32CountLeadingZeroes
0x68 -> NumericInstruction.I32CountTrailingZeroes
0x69 -> NumericInstruction.I32CountNonZeroBits
0x6A -> NumericInstruction.I32Add
0x6B -> NumericInstruction.I32Subtract
0x6C -> NumericInstruction.I32Multiply
0x6D -> NumericInstruction.I32DivideSigned
0x6E -> NumericInstruction.I32DivideUnsigned
0x6F -> NumericInstruction.I32RemainderSigned
0x70 -> NumericInstruction.I32RemainderUnsigned
0x71 -> NumericInstruction.I32BitwiseAnd
0x72 -> NumericInstruction.I32BitwiseOr
0x73 -> NumericInstruction.I32BitwiseXor
0x74 -> NumericInstruction.I32ShiftLeft
0x75 -> NumericInstruction.I32ShiftRightSigned
0x76 -> NumericInstruction.I32ShiftRightUnsigned
0x77 -> NumericInstruction.I32RotateLeft
0x78 -> NumericInstruction.I32RotateRight
0x79 -> NumericInstruction.I64CountLeadingZeroes
0x7A -> NumericInstruction.I64CountTrailingZeroes
0x7B -> NumericInstruction.I64CountNonZeroBits
0x7C -> NumericInstruction.I64Add
0x7D -> NumericInstruction.I64Subtract
0x7E -> NumericInstruction.I64Multiply
0x7F -> NumericInstruction.I64DivideSigned
0x80 -> NumericInstruction.I64DivideUnsigned
0x81 -> NumericInstruction.I64RemainderSigned
0x82 -> NumericInstruction.I64RemainderUnsigned
0x83 -> NumericInstruction.I64BitwiseAnd
0x84 -> NumericInstruction.I64BitwiseOr
0x85 -> NumericInstruction.I64BitwiseXor
0x86 -> NumericInstruction.I64ShiftLeft
0x87 -> NumericInstruction.I64ShiftRightSigned
0x88 -> NumericInstruction.I64ShiftRightUnsigned
0x89 -> NumericInstruction.I64RotateLeft
0x8A -> NumericInstruction.I64RotateRight
0x8B -> NumericInstruction.F32AbsoluteValue
0x8C -> NumericInstruction.F32Negative
0x8D -> NumericInstruction.F32Ceiling
0x8E -> NumericInstruction.F32Floor
0x8F -> NumericInstruction.F32Truncate
0x90 -> NumericInstruction.F32Nearest
0x91 -> NumericInstruction.F32SquareRoot
0x92 -> NumericInstruction.F32Add
0x93 -> NumericInstruction.F32Subtract
0x94 -> NumericInstruction.F32Multiply
0x95 -> NumericInstruction.F32Divide
0x96 -> NumericInstruction.F32Min
0x97 -> NumericInstruction.F32Max
0x98 -> NumericInstruction.F32CopySign
0x99 -> NumericInstruction.F64AbsoluteValue
0x9A -> NumericInstruction.F64Negative
0x9B -> NumericInstruction.F64Ceiling
0x9C -> NumericInstruction.F64Floor
0x9D -> NumericInstruction.F64Truncate
0x9E -> NumericInstruction.F64Nearest
0x9F -> NumericInstruction.F64SquareRoot
0xA0 -> NumericInstruction.F64Add
0xA1 -> NumericInstruction.F64Subtract
0xA2 -> NumericInstruction.F64Multiply
0xA3 -> NumericInstruction.F64Divide
0xA4 -> NumericInstruction.F64Min
0xA5 -> NumericInstruction.F64Max
0xA6 -> NumericInstruction.F64CopySign
0xA7 -> NumericInstruction.I32WrapI64
0xA8 -> NumericInstruction.I32TruncateF32Signed
0xA9 -> NumericInstruction.I32TruncateF32Unsigned
0xAA -> NumericInstruction.I32TruncateF64Signed
0xAB -> NumericInstruction.I32TruncateF64Unsigned
0xAC -> NumericInstruction.I64ExtendI32Signed
0xAD -> NumericInstruction.I64ExtendI32Unsigned
0xAE -> NumericInstruction.I64TruncateF32Signed
0xAF -> NumericInstruction.I64TruncateF32Unsigned
0xB0 -> NumericInstruction.I64TruncateF64Signed
0xB1 -> NumericInstruction.I64TruncateF64Unsigned
0xB2 -> NumericInstruction.F32ConvertI32Signed
0xB3 -> NumericInstruction.F32ConvertI32Unsigned
0xB4 -> NumericInstruction.F32ConvertI64Signed
0xB5 -> NumericInstruction.F32ConvertI64Unsigned
0xB6 -> NumericInstruction.F32DemoteF64
0xB7 -> NumericInstruction.F64ConvertI32Signed
0xB8 -> NumericInstruction.F64ConvertI32Unsigned
0xB9 -> NumericInstruction.F64ConvertI64Signed
0xBA -> NumericInstruction.F64ConvertI64Unsigned
0xBB -> NumericInstruction.F64PromoteF32
0xBC -> NumericInstruction.I32ReinterpretF32
0xBD -> NumericInstruction.I64ReinterpretF64
0xBE -> NumericInstruction.F32ReinterpretI32
0xBF -> NumericInstruction.F64ReinterpretI64
0xC0 -> NumericInstruction.I32Extend8Signed
0xC1 -> NumericInstruction.I32Extend16Signed
0xC2 -> NumericInstruction.I64Extend8Signed
0xC3 -> NumericInstruction.I64Extend16Signed
0xC4 -> NumericInstruction.I64Extend32Signed
0xFC -> {
when (readUInt()) {
0 -> NumericInstruction.I32TruncateSaturatedF32Signed
1 -> NumericInstruction.I32TruncateSaturatedF32Unsigned
2 -> NumericInstruction.I32TruncateSaturatedF64Signed
3 -> NumericInstruction.I32TruncateSaturatedF64Unsigned
4 -> NumericInstruction.I64TruncateSaturatedF32Signed
5 -> NumericInstruction.I64TruncateSaturatedF32Unsigned
6 -> NumericInstruction.I64TruncateSaturatedF64Signed
7 -> NumericInstruction.I64TruncateSaturatedF64Unsigned
else -> throwException(
"Invalid mutex value for saturated truncation instruction",
-2
)
}
}
else -> throwException("Unknown numeric instruction", -1)
}
}