哪个在汇编级别,64个寄存器或三个操作数指令更有用?

fad*_*bee 5 c compiler-construction assembly

这个问题是在为16位自制CPU编写C编译器的背景下.

我有12位操作数用于ALU指令(例如ADD,SUB,AND等).

我可以给出来自16个寄存器的三个操作数或来自64个寄存器的两个操作数的指令.

例如

SUB A <- B - C  (registers r0-r15)
Run Code Online (Sandbox Code Playgroud)

VS

SUB A <- A - B  (registers r0-r63)
Run Code Online (Sandbox Code Playgroud)

C编译器及其作者是16个寄存器,带有三个操作数指令,比带有双操作数指令的64个寄存器更有用吗?

Pet*_*des 4

具有非破坏性 3 操作数指令的 16 个寄存器可能更好。

然而,您还应该考虑用这些指令位做一些其他有趣的事情。对于自制程序,您可能不关心为将来的扩展保留任何内容,并且不想添加大量额外的操作码(就像 PPC 那样)

ARM 采用了一种有趣的方法,即让每条指令的一个操作数通过桶式移位器,因此每条指令都是免费的“移位和其他”指令。即使在“thumb”模式下也支持这一点,其中最常见的指令只有 16 位。(ARM 模式具有传统的 RISC 32 位固定指令大小。它将其中 4 位专门用于每条指令的谓词执行。)


我记得看到过一项关于在理论架构中将寄存器数量加倍(对于 SPECint 之类的)所带来的性能增益的研究。8->16 可能是 5% 或 10%,16->32 只有几个%,32->64 甚至更小。

因此,大多数情况下 16 个整数寄存器就“足够”了,除非您要处理int32_t很多数据,因为每个这样的值将占用两个 16 位寄存器。x86-64 只有 16 个 GP 寄存器,大多数函数都可以轻松地将许多状态保存在寄存器中。即使在进行函数调用的循环中,ABI 中也有足够的调用保留寄存器,因此循环中通常不必发生溢出/重新加载。

3 操作数指令在代码大小和指令数方面的增益将比节省偶尔的溢出/重新加载更大。gcc 输出必须mov一直进行,并用作lea非破坏性添加/移位。


如果您想针对软件流水线优化 CPU 以隐藏内存加载延迟(这比完全乱序执行更简单),那么更多的寄存器就很棒,尤其是。如果您没有寄存器重命名。但是,我不确定编译器在静态指令调度方面有多好。这不再是一个热门话题,因为所有高性能 CPU 都出现了故障。(OTOH,人们实际使用的很多软件都在智能手机中的有序 ARM CPU 上运行。)我没有尝试让编译器针对有序 CPU 进行优化的经验,所以我不知道依赖它的可行性如何那。

如果您的 CPU 非常简单,以至于在负载运行时它无法执行任何其他操作,那么这可能并不重要。(这真的让人手足无措,因为我对简单设计的实用性了解不够。即使是“简单”的有序现代 CPU 也是流水线式的。)


64 个寄存器正进入“太多”的境地,保存/恢复它们需要大量代码。内存量可能仍然可以忽略不计,但由于无法循环寄存器,因此需要 64 条指令。


如果您从头开始设计 ISA,请查看Agner Fog 的 CRISC 提案以及由此产生的讨论。您的目标非常不同(高性能/功耗预算 64 位 CPU 与简单的 16 位 CPU),因此您的 ISA 当然也会非常不同。然而,讨论可能会让你想到你没有考虑过的事情,或者你想尝试的想法。