Apple M1でJuliaコードのディスアセンブル(Julia 1.7)

marui.hatenablog.com

上記のJuliaでディスアセンブルをしたときはIntelチップだったので、M1(ARMチップ)でやったらどうなるかを試してみました。

julia> versioninfo()
Julia Version 1.7.2
Commit bf53498635 (2022-02-06 15:21 UTC)
Platform Info:
  OS: macOS (arm64-apple-darwin21.2.0)
  CPU: Apple M1 Max
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-12.0.1 (ORCJIT, cyclone)

同じコードを使います。

julia> function add1(x)
         return x+1
       end
add1 (generic function with 1 method)

@code_llvmの出力は以下のようになり、Intelチップを使ったときとほぼ同じです。

julia> @code_llvm add1(10)
;  @ REPL[1]:1 within `add1`
define i64 @julia_add1_124(i64 signext %0) #0 {
top:
;  @ REPL[1]:2 within `add1`
; ┌ @ int.jl:87 within `+`
   %1 = add i64 %0, 1
; └
  ret i64 %1
}

@code_nativeの結果はこんな感じ。

julia> @code_native add1(10)
        .section        __TEXT,__text,regular,pure_instructions
; ┌ @ REPL[1]:2 within `add1`
; │┌ @ int.jl:87 within `+`
        add     x0, x0, #1                      ; =1
; │└
        ret
; └

同じコードをIntelチップ用のJuliaでディスアセンブルすると以下のようになりました(Rosettaを使ってM1 Macで実行しています)。

julia> @code_native add1(10)
    .section    __TEXT,__text,regular,pure_instructions
; ┌ @ REPL[2]:2 within `add1`
; │┌ @ int.jl:87 within `+`
    leaq    1(%rdi), %rax
; │└
    retq
    nopw    %cs:(%rax,%rax)
    nop
; └

Intel用として生成されるコードがJulia 1.0のときからも変化しているのがわかりますが、ARMとIntel用とでもだいぶ違います。建て増しを続けてきたIntelチップの命令セットに比べて、ARMのほうがシンプルに見えますね。

2022-05-08追記

Windowsマシンでもやってみました。Mac用のIntelコードと若干違うけど、誤差の範囲?

julia> versioninfo()
Julia Version 1.7.2
Commit bf53498635 (2022-02-06 15:21 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: Intel(R) Core(TM) i5-10400 CPU @ 2.90GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-12.0.1 (ORCJIT, skylake)

julia> function add1(x)
  return x+1
end
add1 (generic function with 1 method)

julia> @code_llvm add1(10)
;  @ REPL[3]:1 within `add1`
; Function Attrs: uwtable
define i64 @julia_add1_202(i64 signext %0) #0 {
top:
;  @ REPL[3]:2 within `add1`
; ┌ @ int.jl:87 within `+`
   %1 = add i64 %0, 1
; └
  ret i64 %1
}

julia> @code_native add1(10)
        .text
; ┌ @ REPL[3]:1 within `add1`
        pushq   %rbp
        movq    %rsp, %rbp
; │ @ REPL[3]:2 within `add1`
; │┌ @ int.jl:87 within `+`
        leaq    1(%rcx), %rax
; │└
        popq    %rbp
        retq
        nopw    (%rax,%rax)
; └