@@ -57,12 +57,30 @@ func init() {
5757 convertDTypePairMap .Register (dtypes .Uint4 , dtypes .Int64 , priorityTyped , execConvertPackedSubByte [int64 ](unpackUint4Nibbles , 2 ))
5858 convertDTypePairMap .Register (dtypes .Uint4 , dtypes .Uint8 , priorityTyped , execConvertPackedSubByte [uint8 ](unpackUint4Nibbles , 2 ))
5959
60+ // Register sub-byte type conversions (Int2, Uint2).
61+ // Each byte packs 4 values (2 bits each). Bit layout: bits 0-1 = first value,
62+ // bits 2-3 = second, bits 4-5 = third, bits 6-7 = fourth.
63+ convertDTypePairMap .Register (dtypes .Int2 , dtypes .Float32 , priorityTyped , execConvertPackedSubByte [float32 ](unpackInt2Bits , 4 ))
64+ convertDTypePairMap .Register (dtypes .Int2 , dtypes .Float64 , priorityTyped , execConvertPackedSubByte [float64 ](unpackInt2Bits , 4 ))
65+ convertDTypePairMap .Register (dtypes .Int2 , dtypes .Int32 , priorityTyped , execConvertPackedSubByte [int32 ](unpackInt2Bits , 4 ))
66+ convertDTypePairMap .Register (dtypes .Int2 , dtypes .Int64 , priorityTyped , execConvertPackedSubByte [int64 ](unpackInt2Bits , 4 ))
67+ convertDTypePairMap .Register (dtypes .Int2 , dtypes .Int8 , priorityTyped , execConvertPackedSubByte [int8 ](unpackInt2Bits , 4 ))
68+ convertDTypePairMap .Register (dtypes .Uint2 , dtypes .Float32 , priorityTyped , execConvertPackedSubByte [float32 ](unpackUint2Bits , 4 ))
69+ convertDTypePairMap .Register (dtypes .Uint2 , dtypes .Float64 , priorityTyped , execConvertPackedSubByte [float64 ](unpackUint2Bits , 4 ))
70+ convertDTypePairMap .Register (dtypes .Uint2 , dtypes .Int32 , priorityTyped , execConvertPackedSubByte [int32 ](unpackUint2Bits , 4 ))
71+ convertDTypePairMap .Register (dtypes .Uint2 , dtypes .Int64 , priorityTyped , execConvertPackedSubByte [int64 ](unpackUint2Bits , 4 ))
72+ convertDTypePairMap .Register (dtypes .Uint2 , dtypes .Uint8 , priorityTyped , execConvertPackedSubByte [uint8 ](unpackUint2Bits , 4 ))
73+
6074 // Register mutableBytes and fillBuffer for sub-byte types.
61- // Packed Int4/Uint4 buffers use []byte as the Go storage type.
75+ // Packed sub-byte buffers use []byte as the Go storage type.
6276 mutableBytesDTypeMap .Register (dtypes .Int4 , priorityTyped , mutableBytesGeneric [byte ])
6377 mutableBytesDTypeMap .Register (dtypes .Uint4 , priorityTyped , mutableBytesGeneric [byte ])
78+ mutableBytesDTypeMap .Register (dtypes .Int2 , priorityTyped , mutableBytesGeneric [byte ])
79+ mutableBytesDTypeMap .Register (dtypes .Uint2 , priorityTyped , mutableBytesGeneric [byte ])
6480 fillBufferDTypeMap .Register (dtypes .Int4 , priorityTyped , fillBufferGeneric [byte ])
6581 fillBufferDTypeMap .Register (dtypes .Uint4 , priorityTyped , fillBufferGeneric [byte ])
82+ fillBufferDTypeMap .Register (dtypes .Int2 , priorityTyped , fillBufferGeneric [byte ])
83+ fillBufferDTypeMap .Register (dtypes .Uint2 , priorityTyped , fillBufferGeneric [byte ])
6684
6785 // Manually register bool x bfloat16 conversion functions.
6886 convertDTypePairMap .Register (dtypes .BFloat16 , dtypes .Bool , priorityTyped , execConvertDTypeBFloat16ToBool )
@@ -225,7 +243,34 @@ func unpackUint4Nibbles(packed []byte, dst []int8) {
225243 }
226244}
227245
228- // execConvertPackedSubByte returns a converter for packed sub-byte types (Int4, Uint4).
246+ // unpackInt2Bits unpacks packed Int2 data ([]byte, 4 signed 2-bit values per byte)
247+ // into dst []int8 (one value per element). Bit layout per byte:
248+ // bits 0-1 = first, bits 2-3 = second, bits 4-5 = third, bits 6-7 = fourth.
249+ // Signed range: [-2, 1] (values 2,3 sign-extend to -2,-1).
250+ func unpackInt2Bits (packed []byte , dst []int8 ) {
251+ for i , b := range packed {
252+ for j := range 4 {
253+ v := int8 ((b >> uint (2 * j )) & 0x03 )
254+ if v >= 2 {
255+ v -= 4
256+ }
257+ dst [4 * i + j ] = v
258+ }
259+ }
260+ }
261+
262+ // unpackUint2Bits unpacks packed Uint2 data ([]byte, 4 unsigned 2-bit values per byte)
263+ // into dst []int8 (one value per element). Unsigned range: [0, 3].
264+ func unpackUint2Bits (packed []byte , dst []int8 ) {
265+ for i , b := range packed {
266+ dst [4 * i ] = int8 (b & 0x03 )
267+ dst [4 * i + 1 ] = int8 ((b >> 2 ) & 0x03 )
268+ dst [4 * i + 2 ] = int8 ((b >> 4 ) & 0x03 )
269+ dst [4 * i + 3 ] = int8 ((b >> 6 ) & 0x03 )
270+ }
271+ }
272+
273+ // execConvertPackedSubByte returns a converter for packed sub-byte types (Int4, Uint4, Int2, Uint2).
229274// The unpackFn parameter selects signed vs unsigned nibble interpretation.
230275// Sub-byte types are always stored packed as []byte.
231276// valuesPerByte is the number of logical values per packed byte (e.g. 2 for 4-bit, 4 for 2-bit).
0 commit comments