Перераспределить младшие значащие биты из 4-байтового массива в клочок - PullRequest
1 голос
/ 10 января 2012

Я хочу переместить биты 0,8,16,24 32-битного значения в биты 0,1,2,3 соответственно. Все остальные биты на входе и выходе будут равны нулю.

Очевидно, я могу сделать это так:

c = c>>21 + c>>14 + c>>7 + c;
c &= 0xF;

Но есть ли более быстрый (меньше инструкций) способ?

Ответы [ 3 ]

2 голосов
/ 10 января 2012
c = (((c&BITS_0_8_16_24) * BITS_0_7_14_21) >> 21) & 0xF;

Или дождитесь процессора Intel Haswell, выполняя все это в одной инструкции (pext).

Обновление

С учетом clarified constraints ипри условии 32-bit unsigned values, код может быть упрощен до этого:

c = (c * BITS_7_14_21_28) >> 28;
1 голос
/ 10 января 2012

Если вас не волнует переносимость, и вы можете использовать инструкции SSE, посмотрите инструкцию PMOVMSKB и ее встроенный компилятор. [Я заметил, что ваши битовые позиции являются наиболее значимыми (знаковыми) битами 4 байтов, составляющих 32-битное слово.]

0 голосов
/ 10 января 2012

Вместо того, чтобы писать какую-то запутанную однострочную сгущёнку, приведенный ниже код - это то, что я написал бы для максимальной переносимости и удобства обслуживания.Я бы позволил оптимизатору беспокоиться о том, является ли он наиболее эффективным кодом.

#include <stdint.h>
#include <limits.h>
#include <stdio.h>

#define BITS_TO_MOVE  4

static const uint32_t OLD_MASK [BITS_TO_MOVE] =
{
  0x0008u,
  0x0080u,
  0x0800u,
  0x8000u
};

static const uint32_t NEW_MASK [BITS_TO_MOVE] =
{
  0x1000u,
  0x2000u,
  0x4000u,
  0x8000u
};


int main()
{
  uint32_t  c     = 0xAAAAu;
  uint32_t  new_c = 0;
  uint8_t   i;

  printf("%.4X\n", c);


  for(i=0; i<BITS_TO_MOVE; i++)
  {
    if ( (c & OLD_MASK[i]) > 0 )
    {
      new_c |= NEW_MASK[i];
    }
  }


  printf("%.4X\n", new_c);
  getchar();

  return 0;
}
...