将int乘以30、31、32-编译器是否真的对它们进行了优化?(有效的Java这样说)

Cheolho Jeon:

我一直在阅读3 / E的有效Java。

在阅读有关哈希码的部分时,(第51页)我注意到书中说

31的一个不错的特性是乘法可以用移位和减法代替,以在某些体系结构上获得更好的性能:31 * i == (i << 5) - i现代VM自动执行这种优化。

我认为这很有意义。我想知道这种优化发生时代码将变得更快。因此,我编写了一个简短的代码来查看此类优化的影响。

但是,似乎没有明显的差异。因此,我编写了更简单的代码,以检查是否进行了这种优化。

以下是我的示例代码。

fun main() {
    val num = Random.nextInt()
    val a = num * 30
    val b = num * 31
    val c = num * 32

    println("$a, $b, $c")
}

这是从IntelliJ的Kotlin字节码功能获得的编译后的机器代码。

   L1
    LINENUMBER 5 L1
    ILOAD 0
    BIPUSH 30
    IMUL
    ISTORE 1
   L2
    LINENUMBER 6 L2
    ILOAD 0
    BIPUSH 31
    IMUL
    ISTORE 2
   L3
    LINENUMBER 7 L3
    ILOAD 0
    BIPUSH 32
    IMUL
    ISTORE 3

显然,没有区别。我们按每个号码,然后致电IMUL我认为优化可能是在将Java字节码编译成实际的机器代码时进行的,但是我从未检查过这一方面,所以我不知道如何确认我的理论。我搜索了一下,似乎我要寻找的关键字是JIT编译器,它似乎将.class转换为特定于CPU的机器代码。

我以为,也许我可以尝试通过JIT编译器将此代码转换为特定于CPU的机器代码,但是那意味着我在一个特定的CPU(而非所有CPU)上检查了这一理论。我想看看它是否“通常是真的”,但这将花费太多时间。

因此,是否有任何方法可以确认上述代码实际上(通常)由编译器进行了优化?如果将来我有类似的问题,应该去哪里找?我的意思是,当我对Java行为感到好奇时,我去了oracle并检查JVM参考或Java se参考。但是,编译器行为如何?我应该从哪里开始?

这是一个很长的问题。感谢您花费宝贵的时间阅读此问题。

(只是一个补充说明)

我在https://godbolt.org/上检查了C和python ,并确认对于C,它实际上已经优化。

int test(int num) {
    int n = rand();
    int a= n*30;
    int b= n*31;
    int c= n*32;
    return a * b * c;
}
test:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 32
        mov     DWORD PTR [rbp-20], edi
        call    rand
        mov     DWORD PTR [rbp-4], eax
        mov     eax, DWORD PTR [rbp-4]
        imul    eax, eax, 30
        mov     DWORD PTR [rbp-8], eax
        mov     edx, DWORD PTR [rbp-4]
        mov     eax, edx
        sal     eax, 5
        sub     eax, edx
        mov     DWORD PTR [rbp-12], eax
        mov     eax, DWORD PTR [rbp-4]
        sal     eax, 5
        mov     DWORD PTR [rbp-16], eax
        mov     eax, DWORD PTR [rbp-8]
        imul    eax, DWORD PTR [rbp-12]
        imul    eax, DWORD PTR [rbp-16]
        leave
        ret

但是,python不是。

num = randint()

a = num * 30
b = num * 31
c = num * 32
  5          18 LOAD_NAME                2 (num)
             20 LOAD_CONST               2 (30)
             22 BINARY_MULTIPLY
             24 STORE_NAME               3 (a)

  6          26 LOAD_NAME                2 (num)
             28 LOAD_CONST               3 (31)
             30 BINARY_MULTIPLY
             32 STORE_NAME               4 (b)

  7          34 LOAD_NAME                2 (num)
             36 LOAD_CONST               4 (32)
             38 BINARY_MULTIPLY
             40 STORE_NAME               5 (c)
             42 LOAD_CONST               5 (None)
             44 RETURN_VALUE
Enterman:

C这样的语言Ahead-Of-Time编译的,这意味着所有优化都在编译时完成,因为它们被编译为汇编代码并由本地计算机解释。

KotlinScalaJava。JVM语言Java虚拟机上运行JVM的实现会进行运行时优化。这被称为即时编译JIT编译器的一个示例是HotSpot,就像它的名字一样,它可以找到JVM代码的“热点”,然后对其进行编译和优化以进行汇编。OpenJ9是HotSpot的替代JIT

我相信Python这样的语言在运行时解释的,这意味着根本不涉及优化。但是用于python的AOT编译器实际上可能会进行一些优化,但是我真的不知道这些编译器的实现细节。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Saxon XSLT 处理器是否针对将隧道参数设置为其当前值进行了优化?

ML系列编译器是否对尾部调用进行了任何复杂的优化?

是否对不使用模板参数的模板化类的方法进行了编译器优化?

Kotlin的Float,Int等是否已针对JVM中的内置类型进行了优化?

将数据框投射到数据集后的选择是否进行了优化?

Java编译器是否针对不同的语言环境进行了翻译?

为什么int&a = 10; 在古代C ++编译器中有效吗?

在Java中将double与int进行比较是否有效?

如何确定Swift是否使用优化进行了编译

链接器错误:“针对符号'xmlFree'重新定位R_X86_64_PC32 ...使用-fPIC重新编译”,但是具有问题的库已经使用-fPIC进行了编译

当前是否使用带有int超过32位宽的C ++编译器的系统?

现代编译器是否优化for循环中的unsigned int使用?

IEnumerable <T>,Task <T>和IDisposable是否在C#编译器中进行了硬编码?

Rust编译器使用“ loop”和“ while true”进行了哪些优化?

将多个文件传递给 C/C++ 编译器是否允许过程间优化?

是否对克隆语句进行了优化?

Java编译器是否可以有效地处理内联字符串?

将数据帧乘以向量的最有效方法

Rust优化器为什么不删除那些无用的指令(在Godbolt编译器资源管理器上进行了测试)?

为什么只有在使用gcc编译器进行优化时,我错误地将指针返回到堆栈上的值,printf才会打印0?

微观优化,是否已通过现代浏览器进行了优化?

通过Java编译器进行优化

在不同的C ++编译器上,int8_t,int16_t,int32_t和int64_t是否具有相同的范围?

编译器如何有效地优化getline()?

是否有一个测试将“未定义的行为”显示为错误,或者仅通过检查源代码进行了测试?

Java Finals是否有助于编译器创建更有效的字节码?

编译器是否将数据放在PE或ELF文件的.text部分中?如果是这样,为什么?

在Linq谓词中,编译器将优化对Enumerable.Min()的“标量”调用还是对每个项目都进行调用?

是否有可能说服Golang编译器接受类型为Foo int的int?