WebAssembly Native Integer and Float Arithmetic
WebAssembly (Wasm) is designed as a low-level, high-performance compilation target that executes arithmetic operations near native machine speed. This article explores how Wasm natively handles integer and floating-point arithmetic, detailing its supported numeric types, instruction set design, overflow behaviors, and adherence to hardware standards.
Native Numeric Data Types
WebAssembly simplifies hardware abstraction by natively supporting only four basic numeric types. There are no specialized types for 8-bit or 16-bit values; instead, Wasm relies on:
i32: 32-bit integeri64: 64-bit integerf32: 32-bit single-precision floating-point numberf64: 64-bit double-precision floating-point number
When working with smaller data types (like 8-bit bytes or 16-bit
integers), WebAssembly loads them from memory, extends them into
i32 registers to perform arithmetic, and truncates them
back when saving to memory.
How Wasm Handles Integer Arithmetic
Integer arithmetic in WebAssembly is designed to map directly to modern CPU instruction sets.
Sign-Neutral Types
Wasm integers are sign-neutral. There are no separate “unsigned
integer” or “signed integer” types. Instead, the distinction is made
entirely at the instruction level. For operations where sign
matters—such as division, extension, or comparison—Wasm provides
distinct signed (_s) and unsigned (_u)
operators. For example: * i32.div_s performs signed 32-bit
division. * i32.div_u performs unsigned 32-bit division. *
Operators like i32.add and i32.sub do not have
signed or unsigned variants because the binary arithmetic is identical
for both in two’s complement representation.
Overflows and Traps
Wasm handle integer overflows in two distinct ways: *
Wrapping Arithmetic: Basic operations like addition
(add), subtraction (sub), and multiplication
(mul) do not trap (crash) on overflow. Instead, they
silently wrap around using two’s complement math. * Trapping
Operations: Division (div_s, div_u)
and remainder (rem_s, rem_u) operations will
trigger a runtime trap (instantly halting execution) if a division by
zero occurs, or if a signed division results in an overflow (such as
dividing the minimum possible signed integer by -1).
How Wasm Handles Floating-Point Arithmetic
Floating-point arithmetic in WebAssembly strictly adheres to the IEEE 754-2008 standard for binary floating-point representation. This ensures that floating-point calculations are highly predictable across different hardware architectures.
IEEE 754 Compliance
Wasm supports standard floating-point operations, including addition
(add), subtraction (sub), multiplication
(mul), division (div), square root
(sqrt), absolute value (abs), and copysign
(copysign). It also includes instructions for ceiling
(ceil), floor (floor), truncation
(trunc), and rounding to the nearest integer
(nearest).
No Runtime Traps
Unlike integers, floating-point operations in WebAssembly never cause
runtime traps. * Dividing a positive number by zero results in positive
infinity (inf). * Dividing a negative number by zero
results in negative infinity (-inf). * Mathematically
undefined operations, such as dividing zero by zero or taking the square
root of a negative number, return Not-a-Number (NaN).
NaN Determinism
While WebAssembly aims for complete determinism, IEEE 754 allows for
some hardware variation in the exact bit-pattern representation of
NaN values. Wasm specifies that while the presence of a
NaN is guaranteed, the specific sign bit and payload of the
resulting NaN can be non-deterministic across different
CPUs.
Conversions and Casts
WebAssembly provides explicit instructions for converting between integers and floating-point numbers.
- Promotion and Demotion: Converting between
f32andf64is done viaf32.demote_f64andf64.promote_f32. - Truncation: Converting floats to integers uses
truncation instructions (e.g.,
i32.trunc_f32_s). If the float value is too large to fit into the target integer type, or if it isNaNor infinity, a standard truncation instruction will trap. - Saturating Truncation: To prevent traps during
float-to-int conversions, Wasm provides “saturating” instructions (e.g.,
i32.trunc_sat_f32_s). Instead of trapping, these instructions cleanly clamp out-of-bounds values to the minimum or maximum integer limits, and convertNaNto zero.