@@ -531,58 +531,104 @@ static zend_always_inline void zend_ffi_cdata_to_zval(zend_ffi_cdata *cdata, voi
531
531
}
532
532
/* }}} */
533
533
534
- static void zend_ffi_bit_field_to_zval (void * ptr , zend_ffi_field * field , zval * rv ) /* {{{ */
534
+ static uint64_t zend_ffi_bit_field_read (void * ptr , zend_ffi_field * field ) /* {{{ */
535
535
{
536
- uint64_t * p1 = (uint64_t * )((char * )ptr + (field -> first_bit / 64 ) * 8 );
537
- uint64_t * p2 = (uint64_t * )((char * )ptr + ((field -> first_bit + field -> bits - 1 ) / 64 ) * 8 );
538
- uint64_t pos = field -> first_bit % 64 ;
539
- uint64_t shift = 64 - (field -> bits % 64 );
540
- uint64_t val ;
536
+ size_t bit = field -> first_bit ;
537
+ size_t last_bit = bit + field -> bits - 1 ;
538
+ uint8_t * p = (uint8_t * ) ptr + bit / 8 ;
539
+ uint8_t * last_p = (uint8_t * ) ptr + last_bit / 8 ;
540
+ size_t pos = bit % 8 ;
541
+ size_t insert_pos = 0 ;
542
+ uint8_t mask ;
543
+ uint64_t val = 0 ;
541
544
542
- if (p1 == p2 ) {
543
- if (field -> bits == 64 ) {
544
- val = * p1 ;
545
- shift = 0 ;
546
- } else {
547
- val = * p1 << (shift - pos );
548
- }
549
- } else {
550
- val = (* p1 >> pos ) | (* p2 << (64 - pos ));
545
+ /* Bitfield fits into a single byte */
546
+ if (p == last_p ) {
547
+ mask = (1U << field -> bits ) - 1U ;
548
+ return (* p >> pos ) & mask ;
549
+ }
550
+
551
+ /* Read partial prefix byte */
552
+ if (pos != 0 ) {
553
+ size_t num_bits = 8 - pos ;
554
+ mask = ((1U << num_bits ) - 1U ) << pos ;
555
+ val = (* p ++ >> pos ) & mask ;
556
+ insert_pos += num_bits ;
557
+ }
558
+
559
+ /* Read full bytes */
560
+ while (p < last_p ) {
561
+ val |= * p ++ << insert_pos ;
562
+ insert_pos += 8 ;
563
+ }
564
+
565
+ /* Read partial suffix byte */
566
+ if (p == last_p ) {
567
+ size_t num_bits = last_bit % 8 + 1 ;
568
+ mask = (1U << num_bits ) - 1U ;
569
+ val |= (* p & mask ) << insert_pos ;
551
570
}
571
+
572
+ return val ;
573
+ }
574
+
575
+ static void zend_ffi_bit_field_to_zval (void * ptr , zend_ffi_field * field , zval * rv ) /* {{{ */
576
+ {
577
+ uint64_t val = zend_ffi_bit_field_read (ptr , field );
552
578
if (ZEND_FFI_TYPE (field -> type )-> kind == ZEND_FFI_TYPE_CHAR
553
579
|| ZEND_FFI_TYPE (field -> type )-> kind == ZEND_FFI_TYPE_SINT8
554
580
|| ZEND_FFI_TYPE (field -> type )-> kind == ZEND_FFI_TYPE_SINT16
555
581
|| ZEND_FFI_TYPE (field -> type )-> kind == ZEND_FFI_TYPE_SINT32
556
582
|| ZEND_FFI_TYPE (field -> type )-> kind == ZEND_FFI_TYPE_SINT64 ) {
557
- val = (int64_t )val >> shift ;
558
- } else {
559
- val = val >> shift ;
583
+ /* Sign extend */
584
+ uint64_t shift = 64 - (field -> bits % 64 );
585
+ if (shift != 0 ) {
586
+ val = (int64_t )(val << shift ) >> shift ;
587
+ }
560
588
}
561
589
ZVAL_LONG (rv , val );
562
590
}
563
591
/* }}} */
564
592
565
593
static int zend_ffi_zval_to_bit_field (void * ptr , zend_ffi_field * field , zval * value ) /* {{{ */
566
594
{
567
- uint64_t * p1 = (uint64_t * )((char * )ptr + (field -> first_bit / 64 ) * 8 );
568
- uint64_t * p2 = (uint64_t * )((char * )ptr + ((field -> first_bit + field -> bits - 1 ) / (8 * 8 )) * 8 );
569
- uint64_t pos = field -> first_bit % 64 ;
570
- uint64_t mask ;
571
595
uint64_t val = zval_get_long (value );
596
+ size_t bit = field -> first_bit ;
597
+ size_t last_bit = bit + field -> bits - 1 ;
598
+ uint8_t * p = (uint8_t * ) ptr + bit / 8 ;
599
+ uint8_t * last_p = (uint8_t * ) ptr + last_bit / 8 ;
600
+ size_t pos = bit % 8 ;
601
+ uint8_t mask ;
602
+
603
+ /* Bitfield fits into a single byte */
604
+ if (p == last_p ) {
605
+ mask = ((1U << field -> bits ) - 1U ) << pos ;
606
+ * p = (* p & ~mask ) | ((val << pos ) & mask );
607
+ return SUCCESS ;
608
+ }
572
609
573
- if (p1 == p2 ) {
574
- if (field -> bits == 64 ) {
575
- * p1 = val ;
576
- } else {
577
- mask = ((1ULL << field -> bits ) - 1ULL ) << pos ;
578
- * p1 = (* p1 & ~mask ) | ((val << pos ) & mask );
579
- }
580
- } else {
581
- mask = ((1ULL << (64 - pos )) - 1ULL ) << pos ;
582
- * p1 = (* p1 & ~mask ) | ((val << pos ) & mask );
583
- mask = (1ULL << pos ) - 1ULL ;
584
- * p2 = (* p2 & ~mask ) | ((val >> (64 - pos )) & mask );
610
+ /* Write partial prefix byte */
611
+ if (pos != 0 ) {
612
+ size_t num_bits = 8 - pos ;
613
+ mask = ((1U << num_bits ) - 1U ) << pos ;
614
+ * p = (* p & ~mask ) | ((val << pos ) & mask );
615
+ p ++ ;
616
+ val >>= num_bits ;
617
+ }
618
+
619
+ /* Write full bytes */
620
+ while (p < last_p ) {
621
+ * p ++ = val ;
622
+ val >>= 8 ;
585
623
}
624
+
625
+ /* Write partial suffix byte */
626
+ if (p == last_p ) {
627
+ size_t num_bits = last_bit % 8 + 1 ;
628
+ mask = (1U << num_bits ) - 1U ;
629
+ * p = (* p & ~mask ) | (val & mask );
630
+ }
631
+
586
632
return SUCCESS ;
587
633
}
588
634
/* }}} */
0 commit comments