我将一个 32 位打包值传递给沙箱内的函数,然后我假装它是 guest 中的一个结构。一切都很好,但序言中有一些神秘的说明:
uint16_t stdCactusVisibility(Block src, Block dst, uint16_t facing)
{
// Only add sides if cacti meet
if (src.getID() == dst.getID())
return_fast(facing & (1 | 2 | 16 | 32));
return_fast(facing);
}
该结构是 2x 16 位整数的包装器:
struct Block {
uint16_t id;
uint16_t otherbits;
};
简化版本。
stdCactusVisibility():
4010c0: 03059593 slli a1,a1,0x30
4010c4: 03051513 slli a0,a0,0x30
4010c8: 0305d593 srli a1,a1,0x30
4010cc: 03055513 srli a0,a0,0x30
4010d0: ff010113 addi sp,sp,-16
4010d4: 00a58663 beq a1,a0,4010e0 <stdCactusVisibility+0x20>
4010d8: 00060513 mv a0,a2
...
我真正想知道的是这些 48 位移位想要实现什么?
我尝试过:使 Block 成为一个具有 2 个共享 16 位成员的 union 体。没有变化。
我尝试过:以正确的方式将寄存器解压到 block 中。没有变化。
我尝试过:返回完整的寄存器值。没有变化。
我的猜测是,这就是 RISC-V 创建 16 位值的方式,这是这里的返回值,也用于 ID 比较(a0 == a1)。如果是这样,那就太烦人了。
这是 RISC-V 的一个有问题的领域吗?有什么想法如何改进这个吗?这是一种在极低延迟模拟器中被调用约十亿次的函数。内部之所以有 C++,是为了通过适当抽象的魔力来减少指令数量。在最坏的情况下,调用的成本约为 3 纳秒,但如果函数中有很多指令,它会很快变得丑陋。
最佳答案
您将 src
和 dst
作为结构(而不是指针)传递。每个结构都在寄存器中传入:分别是 a0
和 a1
。
它们的布局如下:
[63-48] [47-32] [31-16] [15-0]
XXXX XXXX otherbits id
左移后,每个寄存器将如下所示:
[63-48] [47-32] [31-16] [15-0]
id 0000 0000 0000
然后右移后,如下所示:
[63-48] [47-32] [31-16] [15-0]
0000 0000 0000 id
基本上,它是从结构中提取 id
字段。这是执行 a0 &= 0xffff
的不同方式。我猜编译器认为这种方式比构造掩码并执行 AND
更有效。
关于c - RISC-V函数序言48位神秘转变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75591700/