# Types The supported data types and their aliases are listed below: **Scalar:** - int8 (i8) - uint8 (u8) - int16 (i16) - uint16 (u16) - int32 (i32) - uint32 (u32) - float16 (fp16) - float32 (fp32) - bool **Vector:** - int8x32 (i8x32) - uint8x32 (u8x32) - int16x16 (i16x16) - uint16x16 (u16x16) - int32x8 (i32x8) - uint32x8 (u32x8) - float16x16 (fp16x16) - float32x8 (fp32x8) - boolx8 - boolx16 - boolx32 When vector data is visualized in one line, the sequence from the leftmost element to the rightmost element means the vector data from the lowest one to the highest one. See below: ```py x: 1 2 3 4 5 6 7 8 y: 1 2 3 4 5 6 7 8 mask: T T T T F F T T z: 9 8 7 6 4 3 2 1 ``` As mentioned above, the leftmost element of "x", "y", "mask" and "z" is the lowest element of them. Compass DSL is a strongly typed language. You can use the following APIs for type casting or type reinterpretation. ## Conversion **Scalar type casting**: - `s1 = S.cast(s0, new_dtype)` - `s1_signed = S.i(s0_unsigned)` - `s2_unsigned = S.u(s1_signed)` **Vector type casting**: Explicit cast/conversion - Cast to same bits: `v1 = S.cast(v0, new_dtype), v1_signed = S.i(v0_unsigned), v1_unsigned = S.u(v0_signed)` - Cast to wider bits: `v0_low = S.cast(v0, new_dtype, "low"), v1 = S.cast(v0, new_dtype)` - Cast to narrower bits: `v0 = S.cast((v0_low, v0_high), new_dtype), v1 = S.cast(v0, new_dtype)` The `S.i` and `S.u` are two convenient interfaces used for integer data, converting unsigned numbers to signed types and signed to unsigned respectively. Its internal implementation is based on `S.cast`. The `S.cast(x, dtype, part)` has abilities beyond basic type casting: - Support for broadcast when input is scalar and dtype is vector dtype. - Argument `part` (only for vector conversion): used to specify which part data of the given expression or value needs to be converted. - **all:** Represents all data, and this is the default value. - **low, high, even, odd:** Represent the corresponding half data. - **ll, lh, hl, hh:** Represent the corresponding quarter data. More examples about `S.cast`: Cast input x to type which has **same bitwidth**. ```py # int8_to_uint8 # integer signed and unsigned conversion v0 = a_int8[0:32] v1 = S.cast(v0, "uint8") # a_int8[0:32] with u8 dtype # float16_to_int16 # float and int conversion v0 = a_fp16[0:16] v1 = S.cast(v0, "int16") # a_fp16[0:16] with i16 dtype ``` Cast input x to type which has **double bitwidth**. ```py # int8_to_int16 v0 = a_int8[0:32] v0_all_i16 = S.cast(v0, "int16") # a_int8[0:32] with i16 dtype v0_low_i16 = S.cast(v0, "int16", "low") # a_int8[0:16] with i16 dtype v0_high_i16 = S.cast(v0, "int16", "high") # a_int8[16:32] with i16 dtype # int8_to_int32 v0 = a_int8[0:32] v0_all_i32 = S.cast(v0, "int32") # a_int8[0:32] with i32 dtype v0_ll_i32 = S.cast(v0, "int32", "ll") # a_int8[0:8] with i32 dtype v0_lh_i32 = S.cast(v0, "int32", "lh") # a_int8[8:16] with i32 dtype v0_hl_i32 = S.cast(v0, "int32", "hl") # a_int8[16:24] with i32 dtype v0_hh_i32 = S.cast(v0, "int32", "hh") # a_int8[24:32] with i32 dtype # float16_to_float32 v0_fp16 = a_fp16[0:16] v0_all_fp32 = S.cast(v0_fp16, "fp32") # a_fp16[0:16] with fp32 dtype v0_low_fp32 = S.cast(v0_fp16, "fp32", "low") # a_fp16[:8] with fp32 dtype v0_high_fp32 = S.cast(v0_fp16, "fp32", "high") # a_fp16[8:16] with fp32 dtype v0_even_fp32 = S.cast(v0_fp16, "fp32", "even") # a_fp16[0:16:2] with fp32 dtype v0_odd_fp32 = S.cast(v0_fp16, "fp32", "odd") # a_fp16[1:16:2] with fp32 dtype ``` Cast input x to type which has **half bitwidth**. ```py # int16_to_int8 vl, vh = a_int16[0:16], a_int16[16:32] v0_i8 = S.cast((vl, vh), "int8") # a_int16[0:32] with i8 dtype v0_i8 = S.cast(a_int16, "int8") # a_int16[0:32] with i8 dtype # float32_to_float16 vl, vh = a_fp32[0:8], a_fp32[8:16] v0_fp16 = S.cast((vl, vh), "fp16") # a_fp32[0:16] with fp16 dtype v0_fp16 = S.cast(a_fp32, "fp16") # a_fp32[0:16] with fp16 dtype ``` The `S.cast` has limitations below: 1. Unsupported direct cast pairs (first is from type, second is to type): - "uint32", "float32". - "float32", "uint32". If precision loss is tolerated, you need to call `S.cast` twice manually, such as "uint32" -> "int32" -> "float32". 2. No hardware instructions for direct conversion: - "float16", "int8"/"uint8"/"int16"/"uint16" - "int8"/"uint8"/"int16"/"uint16", "float16". You can call `S.cast` twice manually, such as "float16" -> "float32" -> "uint16". ## Reinterpret The `S.reinterpret` just takes the address of variable and reinterprets as new_dtype, while the binary of data is unchanged. ```py v1 = S.reinterpret(v0, "int16x16") ```