为什么没有ICMP指令?

7

如你所知,我们有大量的操作码用于比较不同类型的原始值:

LCMP
FCMPL
FCMPG
DCMPL
DCMPG
IFEQ
IFNE
IFLT
IFGE
IFGT
IFLE
IF_ICMPEQ
IF_ICMPNE
IF_ICMPLT
IF_ICMPGE
IF_ICMPGT
IF_ICMPLE
IF_ACMPEQ
IF_ACMPNE
...

出于显而易见的原因,指令集的创造者没有费心添加所有的IF_LCMPEQIF_FCMPLT等指令,但我想知道为什么没有ICMP指令,因为它对布尔值或Integer.compare(int, int)特别有用。


这是个无关紧要的问题,使用哪种字节码并不重要。而且 Long.compare 并没有直接使用 lcmp;只是 long 类型的 <、> 等操作是基于 lcmp 实现的。 - Louis Wasserman
1个回答

7
已经有两个“主观性强”的关闭投票了。确实,没有人能够在这里给出一个确定的答案,当试图争论一群工程师25年前所做的决定时,可能会涉及到一些敷衍塞责的行为。但我会试着回答这个问题...
首先,我认为这个问题是有道理的:int类型是Java语言中最“突出”的类型(最后但并非最不重要的原因是它在数组索引中的作用)。这与它在Java虚拟机中的特殊角色相呼应,在该角色中,所有存在于语言中的(更小的)整数类型,如byte或short,在所有计算中都被有效地转换为int。或者,如Java虚拟机规范第2.11.7节中所述:
由于它强调int比较,Java虚拟机为类型int提供了丰富的条件分支指令。
现在合理地问,为什么这个“丰富的补充”似乎排除了对所有其他类型同等存在的指令的使用。
没有icmp指令的主要原因可能是它既不必要也没有好处。
使用它来比较Integer#compare(int, int)的建议应用案例几乎不能算作一个论据:即使存在icmp,这样一种方法的实现也不会是
return icmp, arg0, arg1;

将方法转换为字节码可以相当复杂,而且考虑到Java语言本身的可能性,这样的方法必须等效地实现。

if (x > y) return 1;
if (x < y) return -1;
return 0;

很显然,这可以被翻译成一系列现有的if_icmp<?>指令。

在此需要记住的是这些比较指令的主要目的是分支:它们会导致跳转到不同的位置。它们并不用于将一个值推送到堆栈上,然后“用作方法的返回值”。在这里,谈论语言和谈论虚拟机是两个完全不同的事情。


人们也可以反过来问:为什么longfloatdouble都有lcmpfcmp_dcmp_指令呢?

这里,答案明确得多:为longfloatdouble提供整套的eqneltlegtge比较指令将意味着增加18个附加指令(对于浮点类型的NaN处理可能还更多)。考虑到单字节最多只能使用256个指令,这是很多的。

通过为这些类型提供lcmpfcmp_dcmp_指令,可以使用剩余的指令来模拟所有其他可能的比较情况。但再次强调,这些主要用于分支,因此并不需要icmp指令,因为对于int,所有必要的分支指令(“跳转条件”)已经可用。


Integer.compare的目的在于,一个假想的编译器可以使用ICMP指令来内联此方法,同时避免繁重的字节码。 - Clashsoft
@Clashsoft 当然,没有冒犯的意思 :-) 人们确实可以想象,将被翻译为在 EAX 寄存器中存储结果(作为 x86 上的返回值)或在内联时存储在任意寄存器中的 icmp 可能是有益的。但在这里,我认为人们必须就实际(通常基于寄存器)的目标机器是否具有等效于 icmp 的指令以及虚拟机和实际机器代码之间的翻译过程进行讨论。同样,很难找到“THE”答案,所以这些只是一些(希望有说服力的)论点... - Marco13

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接