今天 GitHub 给我推了一个很有意思的东西 fwsGonzo/libriscv,从名字也能看出个大概,这是一个用户空间的 RISC-V 模拟器库,提供了常规的解释器实现。
但除此之外,它还有一个很有趣的东西:开启某个编译期选项后,libriscv 就会在运行 guest 程序前扫描它的所有代码,把可以被安全翻译的一些片段翻译成 plain C 代码,然后调用本地的 C 编译器编译后放到代码缓存中,供后续的运行时使用。
例如,下面的代码序列的前 4 条指令就可以被安全地翻译:
但最后的
以上是背景。
在扫描器开始工作之前,其实还有一遍可选的扫描,这个是今天的主题。
这遍可选的扫描会去尝试寻找
有人可能一眼就看出来了,这是在找
按照 RISC-V 的 ABI,
既然我们已经知道了这个常量的值,那么每当有指令需要读取
但开启这个优化后,生成的代码就变成了:
很明显,后者更优。
但除此之外,它还有一个很有趣的东西:开启某个编译期选项后,libriscv 就会在运行 guest 程序前扫描它的所有代码,把可以被安全翻译的一些片段翻译成 plain C 代码,然后调用本地的 C 编译器编译后放到代码缓存中,供后续的运行时使用。
例如,下面的代码序列的前 4 条指令就可以被安全地翻译:
1:
li a0, 100
beqz a0, 1f
addi a0, a0, -1
j 1b
1:
ret
但最后的
ret 则无法翻译,因为 ra 的值是编译期未知的,所以扫描器就会终止当前的代码块,跳过这条指令,然后再开始翻译下一段。以上是背景。
在扫描器开始工作之前,其实还有一遍可选的扫描,这个是今天的主题。
这遍可选的扫描会去尝试寻找
auipc gp,imm 指令以及它后面紧跟着的 addi[w] gp,gp,imm 。很明显这两条指令是在给 gp 赋值。然后 libriscv 会把要赋的值算出来,保存起来,这遍扫描就完成了。有人可能一眼就看出来了,这是在找
load_gp :
0000000000023572 <load_gp>:
23572: 0028e197 auipc gp,0x28e
23576: 30618193 addi gp,gp,774 # 2b1878 <__global_pointer$>
2357a: 8082 ret
...
按照 RISC-V 的 ABI,
gp 寄存器是 global pointer ,始终指向 .data 段中的一个固定的地方,用于做链接器的松弛。尽管这个设定非常的嵌入式,但编译器通常也不会把 gp 寄存器挪作他用。所以对于遵循 ABI 的绝大多数 RISC-V 程序而言, gp 寄存器打从程序运行的一开始,其中保存的便是一个常量。既然我们已经知道了这个常量的值,那么每当有指令需要读取
gp 寄存器时,我们就可以安全地替换成字面量。例如对于 addi a0,gp,32 ,通常情况下,生成的 C 代码是:
GPRs[a0] = GPRs[gp] + 32;
但开启这个优化后,生成的代码就变成了:
GPRs[a0] = 0x2b1878 + 32;
很明显,后者更优。
突然接了个 numpy rvv 1.0 的活,今天搭建了一下开发环境。因为没有可用的 rvv 1.0 硬件,所以最后使用的方案是 x86 archlinux + qemu user 8.2 + riscv archlinux rootfs。
VSCode Remote 直接通过 x86 连到 rootfs 的项目目录下,rootfs 里面配置好 clang、python、meson 以及 virtualenv 之类的开发环境,最后获得了一个接近原生的开发体验。
archriscv 的包版本都很新,clang 直接就有 rvv 1.0 instrinsic 的支持,完全不用折腾工具链。唯一的缺点是 qemu user 的性能确实不太够看,风扇狂转但编译并不快。
VSCode Remote 直接通过 x86 连到 rootfs 的项目目录下,rootfs 里面配置好 clang、python、meson 以及 virtualenv 之类的开发环境,最后获得了一个接近原生的开发体验。
archriscv 的包版本都很新,clang 直接就有 rvv 1.0 instrinsic 的支持,完全不用折腾工具链。唯一的缺点是 qemu user 的性能确实不太够看,风扇狂转但编译并不快。
🎉3🥰2🤔1
ksco 的工作日志
突然接了个 numpy rvv 1.0 的活,今天搭建了一下开发环境。因为没有可用的 rvv 1.0 硬件,所以最后使用的方案是 x86 archlinux + qemu user 8.2 + riscv archlinux rootfs。 VSCode Remote 直接通过 x86 连到 rootfs 的项目目录下,rootfs 里面配置好 clang、python、meson 以及 virtualenv 之类的开发环境,最后获得了一个接近原生的开发体验。 archriscv 的包版本都很新,clang…
继续 numpy,因为需要支持最新 rvv intrinsic 的编译器,但 gcc 需要等 14 才有,所以切换到了 clang 17。切换过去后编译完运行测试发现某个测例失败,最后整理出来下面这段代码:
在 clang 编译的 numpy 上,运行这段代码会报错:
于是怀疑是编译器的问题,尝试构造一个最小复现,然后就在 Python 和 C 代码里逛了一晚上,最后终于找到了
这段代码如果用 clang rv64 编译运行会输出 raised,用 gcc rv64 则不会,经过和 clang x64 交叉验证,发现 clang rv64 是有问题的。
import numpy as np
code = 'g' # long double
fnan = np.array(np.nan, dtype=code)
fone = np.array(1.0, dtype=code)
with np.errstate(all='raise'):
print(np.floor_divide(fnan, fone))
在 clang 编译的 numpy 上,运行这段代码会报错:
FloatingPointError: invalid value encountered in floor_divide ,而 gcc 编译器则可以输出预期的 nan 。于是怀疑是编译器的问题,尝试构造一个最小复现,然后就在 Python 和 C 代码里逛了一晚上,最后终于找到了
floor_divide 调用的底层函数 npy_divmodl() ,又一通精简后,构造出如下复现代码:
bool test(long double a, long double b)
{
long double m = fmodl(a, b);
return isless(m, (long double)0);
}
int main(void) {
fetestexcept(FE_INVALID);
long double a = NAN, b = 1.0;
printf("%d\n", test(a, b));
if(fetestexcept(FE_INVALID)) printf("raised\n");
return 0;
}
这段代码如果用 clang rv64 编译运行会输出 raised,用 gcc rv64 则不会,经过和 clang x64 交叉验证,发现 clang rv64 是有问题的。
🤯4
macOS Preview 怎么这么菜,M2 打开 v-intrinsic-spec.pdf 随便搜点东西都直接卡死,也就 4000 页而已。
👌1
刚刚看褪黑素的瓶子上面写着吃完不要驾驶,突然想起来前天晚上吃完之后开美卡,最后一把药劲上来了撞了个损坏度 100%,看来确实没瞎说。
🥱5🤔2
Forwarded from 刘阳
box64 LA64 已经实现了
详情:https://github.com/ptitSeb/box64/pull/1425#issuecomment-2041074951
7z b 所需的所有指令,结果出炉:60% native,127% latx 1.4.4。详情:https://github.com/ptitSeb/box64/pull/1425#issuecomment-2041074951
👏7🤔1🤯1
https://github.com/DynamoRIO/dynamorio/pull/6691
DynamoRIO 最近增加了一个新的 fake ISA,支持在内部的 IR 和这个新 ISA 之间相互转换,所以用户就可以通过 IR 把 x86/ARM/RV64 的指令转成这个 fake ISA。这个东西乍看起来有点奇怪,仔细探究之后发现,他们是想用这个新的 ISA 来保存 traces 数据:
We want to create a new tool to filter traces of Google workloads for public release.
The new public Google workload traces will contain more information compared to the previous version, while still preserving confidentiality of Google's IP.
但是更重要的一点是,为了公开发布 traces 数据但不泄漏私研指令集的细节。。
DynamoRIO 最近增加了一个新的 fake ISA,支持在内部的 IR 和这个新 ISA 之间相互转换,所以用户就可以通过 IR 把 x86/ARM/RV64 的指令转成这个 fake ISA。这个东西乍看起来有点奇怪,仔细探究之后发现,他们是想用这个新的 ISA 来保存 traces 数据:
We want to create a new tool to filter traces of Google workloads for public release.
The new public Google workload traces will contain more information compared to the previous version, while still preserving confidentiality of Google's IP.
但是更重要的一点是,为了公开发布 traces 数据但不泄漏私研指令集的细节。。
GitHub
i#6662 public traces, part 1: synthetic ISA by edeiana · Pull Request #6691 · DynamoRIO/dynamorio
A synthetic ISA that has the purpose of preserving register dependencies and giving
hints on the type of operation an instruction performs. This PR implements the
encoding/decoding functionalities...
hints on the type of operation an instruction performs. This PR implements the
encoding/decoding functionalities...