我正在尝试将 OpenJDK 交叉编译到旧的 32 位 VIA Geode LX 处理器,并且我一直点击 这个断言:
assert(VM_Version::is_P6() || dest_reg->has_byte_register(),
"must use byte registers if not P6");
显然我没有通过这两项测试,但是如果我用
-XX:c1_LIRAssembler.cpp:1313
覆盖警告,应用程序运行得很好,所以我假设我以某种方式错误配置了我的内核,但我不知道我错了。其中之一必须为真,断言才能通过。
第 1 部分 - VM_Version::is_P6()
VIA Geode LX 应该是一款 686 处理器(减去一条指令),但这不会影响这里所做的决定,即它可以访问的寄存器数量,而不是指令集。不过,OpenJDK 确实会测试某些类型的寄存器,以确定处理器系列。
它定义了 CPU 如评论中所列:
// 6 - PentiumPro, Pentium II, Celeron, Xeon, Pentium III, Athlon,
// Pentium M, Core Solo, Core Duo, Core2 Duo
我已经为“Pentium Pro”编译了内核,所以这应该会成功,但是:
static int cpu_family() { return _cpu;}
static bool is_P6() { return cpu_family() >= 6; }
_cpu
由 extended_cpu_family()
: 分配
static uint32_t extended_cpu_family() {
uint32_t result = _cpuid_info.std_cpuid1_eax.bits.family;
result += _cpuid_info.std_cpuid1_eax.bits.ext_family;
return result;
}
然后我们就进入了兔子洞......足以说我可以理解为什么断言的这一部分会失败。 VIA Geode LX 模仿 Intel x86 的指令集,但在很多情况下都会失败,所以我理解为什么它“技术上”不符合 P6 的资格,正如 函数 extended_cpu_family()
所定义的那样意味着它回落到 4 级。第 2 部分 - has_byte_register()
这是
检查字节寄存器的代码:
public:
enum {
#ifndef AMD64
number_of_registers = 8,
number_of_byte_registers = 4,
max_slots_per_register = 1
#else
number_of_registers = 16,
number_of_byte_registers = 16,
max_slots_per_register = 1
#endif // AMD64
};
...
bool has_byte_register() const
{ return 0 <= (intptr_t)this && (intptr_t)this < number_of_byte_registers; }
...
其中
intptr_t
定义为:
typedef int intptr_t;
所以基本上看起来是
has_byte_registers()
失败了。不过,我不知道它如何能够成功,因为看起来“this”必须解析为一个内存位置,该位置始终高于 16。
非 64 位处理器的预期字节寄存器数量是 64 位处理器的 4 倍
,这似乎很奇怪。
我的内核配置是否错误,这些测试之一是否错误(以便我可以提交补丁),或者只是 OpenJDK 没有考虑像这样的旧的“不完全兼容”CPU?
是的,但在某种程度上确实发生了。
没有 REX 前缀,有 8 个字节寄存器,分为两组:
低字节寄存器:
AL
DL
、CL
、BL
(AX
等的低字节)高字节寄存器:AH
DH
、CH
、BH
(AX
等的高字节)
带有REX前缀(64位模式下,否则没有REX),所有16个GPR的最低字节都可以用作字节寄存器。
高字节寄存器在 64 位模式下仍然存在(因此在某种意义上,64 位模式下有 16+4 字节寄存器),但不能由具有 REX 前缀的指令访问(即使没有设置任何 REX 标志) 。高字节寄存器在 64 位中使用起来非常痛苦,因为例如
add ah, sil
是不可能的,因为
sil
需要 REX 前缀,而 ah
需要缺少 REX 前缀。将计数设置为 16 与从不使用高字节寄存器是一致的。我不确定其余的怎么样。