给定AVR或其他的set指令,可以从并行中的多个整数给出索引来提取特定位?

时间:2018-10-30 16:10:19

标签: bit-manipulation avx

示例:a = 11010 0 01,b = 0001 0 01,c = 11010 0 00,d = 11111 1 11

extract(a,b,c,d,2)== 0001

3 个答案:

答案 0 :(得分:1)

尝试使用

无符号__int64 _pext_u64(无符号__int64 a,无符号__int64掩码)

命令,尽管它不使用多个整数。

还有其他使用AND和可变SHIFT(以及其他命令)的方法。

答案 1 :(得分:1)

此算法不是最佳算法,因为32位寄存器的填充是串行完成的。但是,你应该得到要点。 BMI2指令集中的PEXT instruction可以有效地做到这一点。

这是MASM x86汇编中的解决方案(a,b,c,d是内存中的BYTE值):

mov ah, a
mov al, b
shl eax, 16
mov ah, c
mov al, d
; Now EAX = aaaaaaaabbbbbbbbccccccccdddddddd
mov ecx,  0b00000100000001000000010000000100    ; MASK value
pext eax, eax, ecx
; Now EAX = 00000000000000000000000000000001    ; result

为实际使用,请优化32位源寄存器(此处为EAX)的填充。

现在EAX的最低4位应包含0001

答案 2 :(得分:1)

有两种情况:1.感兴趣的位置是一个编译时常量,而2。 感兴趣的位置不是编译时常量。两种情况都被回答 在下面的代码中。

请注意,如果a,b,c,d在内存中是连续的,则只需将它们移动到xmm 由x = _mm_load_si128((_m128i*) &d);注册,这比有效得多 _mm_set_epi32()在这里使用。

代码:

/*  gcc -O3 -m64 -Wall -march=broadwell extract_2nd_bit.c  */
#include <immintrin.h>
#include <stdio.h>

/* If position i = 2 (for axample) is known at compile time: */
int extract_2nd_bit(int a, int b, int c, int d){
    __m128i x = _mm_set_epi32(a, b, c, d);
            x = _mm_slli_epi32(x, 31 - 2);       /* shift bit 2 to the highest position */
    return _mm_movemask_ps(_mm_castsi128_ps(x)); /* extract the MSB of the 4 elements   */
}

/* If position i is unknown at compile time: */
int extract_var(int a, int b, int c, int d, int i){
    __m128i x = _mm_set_epi32(a, b, c, d);
            x = _mm_sll_epi32(x, _mm_cvtsi32_si128(31 - i)); /* shift bit i to the highest position */
    return _mm_movemask_ps(_mm_castsi128_ps(x));             /* extract the MSB of the 4 elements   */
}


int print_32_bin(unsigned int x);

int main(){
    int a = 0b11010001; 
    int b = 0b0001001; 
    int c = 0b11010000; 
    int d = 0b11111111;
    int pos = 2;
    print_32_bin(extract_2nd_bit(a, b, c, d));
    print_32_bin(extract_var(a, b, c, d, pos));
    return 0;
}




int print_32_bin(unsigned int x){
    for (int i=31;i>=0;i--){
        printf("%1u",((x>>i)&1));
    }
    printf("\n");
    return 0;
}

输出为:

$ ./a.out
00000000000000000000000000000001
00000000000000000000000000000001

顺便问一下,为什么不在问题中设置avxsse标签?