A vector conversion must state whether it preserves bits, preserves numeric values, discards high bits, rounds, or clamps.
Do not rely on implicit vector conversions
The API does not implicitly convert signed and unsigned lanes, integer and floating lanes, different lane widths, or masks and value vectors.
This rule keeps a change of numeric domain separate from a change of representation.
Use Bit_Cast to preserve lane bits
Bit_Cast preserves each lane's bits and position. From_Lanes constructs the F32x4 input below, and the result type is U32x4.
Values : constant F32x4 := From_Lanes ([1.0, -0.0, 2.0, -2.0]);
Encodings : constant U32x4 := Bit_Cast (Values);
The result contains four IEEE binary32 encodings. It does not contain the integers 1, 0, 2, and -2.
The Flyology_SIMD.Wide package applies the same rule at 256 bits. For example, its Bit_Cast overload reinterprets F32x8 as U32x8 without changing any lane bit or position. Wide bit casts connect signed, unsigned, and floating types with the same lane width and lane count. They do not perform numeric conversion.
Use widening and narrowing for lane-width changes
| Operation | Rule |
|---|---|
Widen_Low and Widen_High | Select one source half and preserve its numeric values in wider lanes. |
Narrow_Truncate | Keep the low destination-width bits of integer lanes. |
Narrow_Saturate | Clamp integer lanes to the destination range. |
Narrow_Round | Round two F64x2 inputs into one F32x4 result. |
Each narrowing operation takes two source vectors. The Low input supplies the low result half, and High supplies the high result half.
The following U16x8 input shows the difference between discarding high bits and clamping values. The applicable From_Lanes constructs it, and Zero supplies the high half. The applicable Narrow_Truncate and Narrow_Saturate overloads both return U8x16.
Wide : constant U16x8 :=
From_Lanes ([254, 255, 256, 300, 0, 1, 2, 3]);
Empty : constant U16x8 := Zero;
Truncated : constant U8x16 := Narrow_Truncate (Wide, Empty);
Saturated : constant U8x16 := Narrow_Saturate (Wide, Empty);
-- Truncated lanes 0 .. 3: 254, 255, 0, 44
-- Saturated lanes 0 .. 3: 254, 255, 255, 255
Use Convert names for numeric-domain changes
| Operation | Rule |
|---|---|
Convert_Round | Convert integer lanes to floating lanes with the documented rounding mode. |
Convert_Truncate_Saturate | Convert floating lanes to integer lanes, truncate toward zero, and clamp. |
Convert_Saturate | Change integer signedness at the same width and clamp out-of-range values. |
For signed-to-unsigned Convert_Saturate, a negative input becomes zero. For unsigned-to-signed conversion, a value above the signed maximum becomes that maximum.
The From_Lanes overload constructs this I32x4 input. The applicable Convert_Saturate overload returns unsigned 32-bit lanes:
Signed_Input : constant I32x4 :=
From_Lanes ([-1, 0, 1, I32'Last]);
Unsigned_Result : constant U32x4 := Convert_Saturate (Signed_Input);
-- Unsigned_Result: 0, 0, 1, 2_147_483_647
The maintained example also crosses the 64-bit signed boundary. Its U64x2-to-F64x2 input contains 2**63 + 1 and U64'Last. Its F64x2-to-U64x2 input contains 2**63 and 2**64; the first is exact and the second clamps to U64'Last.
U64 rounded bits: 4890909195324358656 4895412794951729152
F64 to U64 boundary: 9223372036854775808 18446744073709551615
Apply the same rules to Wide values
The Wide profile provides 46 conversion overloads at 256-bit width. Each overload corresponds to a 128-bit overload. For example, F32x8-to-F64x4 widening corresponds to root F32x4-to-F64x2 widening. Both profiles use the same rounding, saturation, and exceptional-input rules. The operation reference lists every source and destination shape.
The Wide Widen_Low overload converts F32x8 lanes 0 through 3 to F64x4. The matching Widen_High overload converts lanes 4 through 7.
Wide narrowing uses two complete Wide inputs. For Narrow_Round, Low supplies result lanes 0 through 3, and High supplies result lanes 4 through 7. Same-width Wide numeric conversions preserve every lane position.
Flyology_SIMD.Wide.Native composes these operations from the selected 128-bit backend. Its private pair is not a public representation. The project does not claim that one 256-bit instruction implements each conversion.
Check the floating environment and exceptional inputs
Floating widening requires the platform's default gradual-underflow environment to preserve binary32 subnormal inputs. Narrow_Round requires both gradual underflow and the default round-to-nearest, ties-to-even mode. Convert_Round requires the default rounding mode. These operations do not change the rounding mode or exception controls. They can update floating-point exception-status flags.
Convert_Truncate_Saturate does not depend on the rounding mode, but it can update floating-point exception-status flags. Positive infinity becomes the destination maximum. Negative infinity becomes the signed minimum or unsigned zero. A NaN becomes zero.
The operation reference gives the supported source and destination shapes. The semantic compatibility document gives exact overflow, underflow, NaN, and signed-zero results.
Run examples/conversions.adb for maintained boundary examples. The same semantic rules apply to Wide values. The example already demonstrates the rounding, saturation, and exceptional-input rules, so a separate Wide example would repeat the same lesson.
For the 38 Wide widening, narrowing, and same-width signedness-conversion overloads, independent oracles compute expected scalar and Native lane values without calling those conversion operations. Integer oracles check extension, truncation, saturation, and lane placement. IEEE oracles check specified non-NaN widening and narrowing results bit for bit. When a NaN payload and signaling state are unspecified, they check NaN classification instead. Each shape retains fixed boundary cases and uses 128 deterministic vectors.
For the eight conversions between integer and floating lanes, independent bit-level oracles also compute the expected scalar and Native results. Each shape retains fixed boundary cases. It also uses 128 deterministic vectors whose integer lanes span their complete width or whose floating lanes come from raw bit patterns.
Separate caller-level code-generation gates cover all 46 conversion overloads. Each gate requires the matching selected 128-bit operations for both result halves. It rejects calls to a different conversion, a portable root operation, or the Wide Native dispatcher.