【发布时间】:2012-06-06 16:21:23
【问题描述】:
我想知道在任何 SIMD 指令系列中是否可以执行以下操作。
我有一个 63 位有效位(从不为负)的 qword 输入。从 LSB 开始的每个连续 7 位都随机对齐到一个字节,左填充为 1(除了最重要的非零字节)。为了说明,为了清楚起见,我将使用字母。
结果只有有效字节,因此大小为 0 - 9,转换为字节数组。
In: 0|kjihgfe|dcbaZYX|WVUTSRQ|PONMLKJ|IHGFEDC|BAzyxwv|utsrqpo|nmlkjih|gfedcba
Out: 0kjihgfe|1dcbaZYX|1WVUTSRQ|1PONMLKJ|1IHGFEDC|1BAzyxwv|1utsrqpo|1nmlkjih|1gfedcba
大小 = 9
In: 00|nmlkjih|gfedcba
Out: |0nmlkjih|1gfedcba
大小 = 2
我明白填充是分开的。洗牌对齐是我的问题。 这可能吗?
编辑 2
这是我更新的代码。在单线程 Core 2 Duo 2 GHz、64 位上获得持续 46 M/秒的随机长度输入。
private static int DecodeIS8(long j, ref byte[] result)
{
if (j <= 0)
{
return 0;
}
int size;
// neater code: gives something to break out of
while (true)
{
result[0] = (byte)((j & 0x7F) | 0x80);
size = 0;
j >>= 7;
if (j == 0) break;
result[1] = (byte)((j & 0x7F) | 0x80);
size++;
j >>= 7;
if (j == 0) break;
result[2] = (byte)((j & 0x7F) | 0x80);
size++;
j >>= 7;
if (j == 0) break;
result[3] = (byte)((j & 0x7F) | 0x80);
size++;
j >>= 7;
if (j == 0) break;
result[4] = (byte)((j & 0x7F) | 0x80);
size++;
j >>= 7;
if (j == 0) break;
result[5] = (byte)((j & 0x7F) | 0x80);
size++;
j >>= 7;
if (j == 0) break;
result[6] = (byte)((j & 0x7F) | 0x80);
size++;
j >>= 7;
if (j == 0) break;
result[7] = (byte)((j & 0x7F) | 0x80);
size++;
j >>= 7;
if (j == 0) break;
result[8] = (byte)j;
return 9;
}
result[size] ^= 0x80;
return size + 1;
}
【问题讨论】:
-
这当然是可行的,但它会很丑。你需要一堆移位和掩码操作。您是否 100% 确定这是性能瓶颈?
-
唯一确定的方法是编写标量版本和 SIMD 版本并对其进行基准测试。如果您没有与此解包一起执行其他 SIMD 操作,那么我怀疑您不会获得太多收益。
-
您没有提到您是否正在对此数据执行其他 SIMD 操作。如果您只是从内存中加载打包数据并将解包数据存储回内存,那么 SIMD 不太可能有帮助。不过,在考虑 SIMD 之前,我会先尽可能优化现有的标量代码。
-
这似乎有点慢 - 每次解码大约 50 个时钟 - 我希望标量代码可以优化为运行得比这快得多。
-
遗憾的是您没有在 POWER/PowerPC 上执行此操作 - AltiVec 具有 128 位移位。但我认为使用 SSE 仍然可以使用比使用标量代码更少的指令 - 无论如何,祝你好运!
标签: x86 bit-manipulation sse simd avx