编辑:我已将我的问题重新表述为更有成效的内容,并将在下面提供答案。这个问题的旧版本仍在下面。
我正在 RVV 0.7.1 中为 CSR 格式实现优化的 SpMV 内核。在 C 语言中,SpMV 可以这样实现:
for (int i = 0; i < numRows; i++)
for (int j = rowPtr[i]; j < rowPtr[i+1]; j++)
y[i] += val[j] * x[colIdx[j]];
向量化最初很简单,通过加载
coldIdx
,使用它执行 x
的索引加载,加载 val
并将两者相乘。此后,必须在每一行中执行归约和 (v{f}redsum.vs
),将其中的所有乘积相加并将它们存储在 y
的相应索引中。挑战在于从 rowPtr
创建掩码,以便只有属于给定行的元素对于每次缩减都是活动的。
我最初的想法(应该提供有关原始问题的上下文)是使用
rowPtr
中的索引将 1 放入向量寄存器的各个元素中,然后使用 viota
和元素移位来创建包含该行的寄存器每个元素属于。然而,这显然是不可行的。
如何制作所需的掩模?
老问题
我正在尝试使用 RISC-V 向量扩展(0.7.1)来创建基于索引数组的掩码寄存器。例如,采用以下索引数组
idx array
。目标是使用其中存在的索引将 1 放入相应的掩码元素中,如下面的 mask
所示:
idx array | 0 2 3 4 4 6 8
elem idx | 0 1 2 3 4 5 6 7 8
mask | 1 0 1 1 1 0 1 0 1
起初我错误地查看了
vrgather.vx
指令,但它并没有完全达到我想要的效果,因为它填充了所有元素。我希望代码也具有很高的性能,因此如果它可能主要由向量指令组成,那将是理想的。如果有人能指出我正确的方向,我将不胜感激。
解决方案归功于camel-cdr!
采用以下
rowPtr
数组:
0 2 3 5 7
让我们考虑第三次迭代(
[3,5[
),它应该更具说明性。目标是达到以下掩码,启用元素 3 和 4:
00011000
第一步是使用
vid
将每个元素的索引写入向量。这样,我们就可以使用 vmseq
(如果相等则设置掩码)两次,其中 i
的元素为 i+1
和 rowPtr
,这将产生像这样的两个寄存器,元素 rowPtr[i]
或 中有一个寄存器rowPtr[i+1]
:
idx | 01234567
i | 00010000
i+1 | 00000100
之后我们可以在两者上使用
vmsbf.m
(先设置),这会设置第一个活动掩码位之前的所有位。通过对两者进行异或,我们得到最终所需的掩码:
sbf i | 11100000
sbf i+1 | 11111000
xor | 00011000
通过重复迭代
rowPtr
并重复此操作,可以为每个单独行的元素生成一个掩码。简而言之,我们可以将操作写为:
vmxor(vmsbf(vmseq(vid,rowPtr[i])), vmsbf(vmseq(vid,rowPtr[i+1])))