9
4

More than 5 years have passed since last update.

Ruby -> Julia -> LLVM IR -> たのしい

Posted at

先月のRubyConfのLTでA PoC-ish Trick: LLVM IR Generation with Rubyという題で発表してきた小ネタです。

TL;DR

  1. RubyのコードをJuliaに変換するJulializerというTranspilerを作った
  2. Juliaではcode_llvmcode_native等の組み込み関数でLLVM IRやアセンブリコードを簡単に吐き出せる
  3. 1と2から、Rubyのコードを書くとLLVM IRやアセンブリコードを簡単に吐き出せる

Disclaimer

Demo

最も単純な例として、Rubyの2+3(整数同士の加算)というプログラムを変換してみます。LLVM IRの結果として作成されている関数julia_+_21483の引数として、i64という整数型の引数が取られていることに着目してください。

bash-3.2# echo "2+3" | julializer # Ruby->Julia
2+3;
bash-3.2# echo "2+3" | julializer | sed 's/^/@code_llvm /' | julia # Ruby->Julia->LLVM IR

define i64 @"julia_+_21483"(i64, i64) {
top:
  %2 = add i64 %1, %0
  ret i64 %2
}

次にRubyで2.3+3(浮動小数点数と整数の加算)と表現されるプログラムを変換してみると、以下のようにJulia->LLVM IRの段階で型推論が効いてjulia_+_21484の引数として(double, i64)のように浮動小数点型が宣言されていることが確認できます。

bash-3.2# echo "2.3+3" | julializer # Ruby->Julia
2.3+3;
bash-3.2# echo "2.3+3" | julializer | sed 's/^/@code_llvm /' | julia # Ruby->Julia->LLVM IR

define double @"julia_+_21484"(double, i64) {
top:
  %2 = sitofp i64 %1 to double
  %3 = fadd double %0, %2
  ret double %3
}

これを使って、for文を使ったごく単純な算術演算プログラムであれば以下のようにRubyからJuliaを経由してLLVMの表現を作ることができます。以下は、LLVM IRの替わりにアセンブリコードの出力をしてみた例です。

bash-3.2# echo "
> def loop(list)
>   for i in 0.5.to_i..list.size-1
>     list[i] = (i-list.size/2).abs
>   end
> end
> " | julializer # Ruby->Julia
function loop(list);for i::Int64 = trunc(Int64,parse(string(0.5))):size(list)[1]-1;list[i+1]=abs((i-size(list)[1]/2));;end;;;end;;
bash-3.2# echo "
> def loop(list)
>   for i in 0.5.to_i..list.size-1
>     list[i] = (i-list.size/2).abs
>   end
> end
> " | julializer | sed 's/$/code_native(loop, (Array{Int64,1},))/' | julia # Ruby->Julia->Machine Code
    .section    __TEXT,__text,regular,pure_instructions
Filename: none
Source line: 1
    pushq   %rbp
    movq    %rsp, %rbp
    pushq   %r15
    pushq   %r14
    pushq   %r13
    pushq   %r12
    pushq   %rbx
    subq    $88, %rsp
    movq    %rdi, %r15
Source line: 1
    movq    %r15, -120(%rbp)
    movq    $14, -112(%rbp)
    movabsq $jl_pgcstack, %rax
    movq    (%rax), %rcx
    movq    %rcx, -104(%rbp)
    leaq    -112(%rbp), %rcx
    movq    %rcx, (%rax)
    movq    $0, -96(%rbp)
    movq    $0, -88(%rbp)
    movq    $0, -80(%rbp)
    leaq    -56(%rbp), %rbx
Source line: 1
    movabsq $print_to_string, %rax
    movabsq $4585538608, %rcx       ## imm = 0x11151C430
    movabsq $4554689512, %rdx       ## imm = 0x10F7B0BE8
    xorpd   %xmm0, %xmm0
Source line: 1
    movq    $0, -72(%rbp)
    movq    $0, -64(%rbp)
    movupd  %xmm0, -56(%rbp)
Source line: 1
    movq    (%rdx), %rdx
    movq    %rdx, -64(%rbp)
    movq    %rcx, -56(%rbp)
    movabsq $4574850160, %rdi       ## imm = 0x110AEAC70
    movq    %rbx, %rsi
    movl    $1, %edx
    callq   *%rax
    movabsq $jl_apply_generic, %r14
    movq    %rax, -56(%rbp)
    movabsq $4582578128, %rdi       ## imm = 0x1112497D0
    movq    %rbx, %rsi
    movl    $1, %edx
    callq   *%r14
Source line: 1
    leaq    -64(%rbp), %rbx
Source line: 1
    movq    %rax, -56(%rbp)
    movabsq $4578677360, %rdi       ## imm = 0x110E91270
    movq    %rbx, %rsi
    movl    $2, %edx
    callq   *%r14
    movabsq $jl_box_int64, %rcx
    movq    %rax, -88(%rbp)
    movq    24(%r15), %rdi
    movq    %rbx, %r15
    movq    %rax, -64(%rbp)
    decq    %rdi
    callq   *%rcx
    movq    %rax, -56(%rbp)
    movabsq $4573878480, %rdi       ## imm = 0x1109FD8D0
    movq    %r15, %rsi
    movl    $2, %edx
    callq   *%r14
    movq    %rax, %rbx
    movq    %rbx, -80(%rbp)
    movq    %rbx, -64(%rbp)
    movabsq $4590321552, %rdi       ## imm = 0x1119ABF90
    movq    %r15, %rsi
    movl    $1, %edx
    callq   *%r14
    movq    %rax, -96(%rbp)
    movq    %rbx, -64(%rbp)
    movq    -96(%rbp), %rax
    movq    %rax, -56(%rbp)
    movabsq $4590048656, %rdi       ## imm = 0x111969590
    movq    %r15, %rsi
    movl    $2, %edx
    callq   *%r14
    movq    %rax, -64(%rbp)
    movabsq $4576747568, %rdi       ## imm = 0x110CBA030
    movq    %r15, %rsi
    movl    $1, %edx
    callq   *%r14
    movq    -8(%rax), %rcx
    shrq    $4, %rcx
    cmpq    $284661857, %rcx        ## imm = 0x10F79861
    jne L944
    movabsq $jl_false, %rcx
    cmpq    (%rcx), %rax
    je  L887
    movabsq $jl_apply_generic, %r14
    movabsq $13161910880, %rax      ## imm = 0x31082D260
    movsd   (%rax), %xmm0
    movsd   %xmm0, -128(%rbp)
    movabsq $jl_f_get_field, %r12
L462:   movq    %rbx, -64(%rbp)
    movq    %rbx, %r13
    movq    -96(%rbp), %rax
    movq    %rax, -56(%rbp)
    movabsq $4583657840, %rdi       ## imm = 0x111351170
    movq    %r15, %rsi
    movl    $2, %edx
    callq   *%r14
    movq    %rax, %rbx
    movq    %rbx, -72(%rbp)
    movabsq $4554689512, %rax       ## imm = 0x10F7B0BE8
    movq    (%rax), %rax
    movq    %rax, -64(%rbp)
    movq    %rbx, -56(%rbp)
    movabsq $4554711168, %rax       ## imm = 0x10F7B6080
    movq    %rax, -48(%rbp)
    xorl    %edi, %edi
Source line: 1
    leaq    -56(%rbp), %rsi
    movl    $2, %edx
Source line: 1
    callq   *%r12
    movq    %rax, -56(%rbp)
    movabsq $4591208368, %rdi       ## imm = 0x111A847B0
    movq    %r15, %rsi
    movl    $2, %edx
    callq   *%r14
    movq    -8(%rax), %rcx
    shrq    $4, %rcx
    cmpq    $284661845, %rcx        ## imm = 0x10F79855
    jne L989
    movq    %r15, %rsi
    movq    (%rax), %r15
    movq    %rbx, -64(%rbp)
    movabsq $4554711216, %rax       ## imm = 0x10F7B60B0
    movq    %rax, -56(%rbp)
    xorl    %edi, %edi
    movq    %rsi, %r14
    movl    $2, %edx
    callq   *%r12
    movq    %rax, -96(%rbp)
    movq    -120(%rbp), %rdi
    cmpq    8(%rdi), %r15
    jae L1034
    cvtsi2sdq   24(%rdi), %xmm0
    divsd   -128(%rbp), %xmm0
    cvtsi2sdq   %r15, %xmm1
    addsd   %xmm0, %xmm1
    movd    %xmm1, %rax
    movabsq $9223372036854775807, %rcx ## imm = 0x7FFFFFFFFFFFFFFF
    andq    %rcx, %rax
    movd    %rax, %xmm1
    cvttsd2si   %xmm1, %rax
    xorps   %xmm0, %xmm0
    cvtsi2sdq   %rax, %xmm0
    ucomisd %xmm0, %xmm1
    movq    %r13, %rbx
    jne L919
    jp  L919
    cvttsd2si   %xmm0, %rcx
    cmpq    %rcx, %rax
    jne L919
    movq    (%rdi), %rcx
    movq    %rax, (%rcx,%r15,8)
    movq    %rbx, -64(%rbp)
    movq    -96(%rbp), %rax
    movq    %rax, -56(%rbp)
    movabsq $4590048656, %rdi       ## imm = 0x111969590
    movq    %r14, %r15
    movq    %r15, %rsi
    movl    $2, %edx
    movabsq $jl_apply_generic, %r14
    callq   *%r14
    movq    %rax, -64(%rbp)
    movabsq $4576747568, %rdi       ## imm = 0x110CBA030
    movq    %r15, %rsi
    movl    $1, %edx
    callq   *%r14
    movq    %rax, -64(%rbp)
    movabsq $4576747568, %rdi       ## imm = 0x110CBA030
    movq    %r15, %rsi
    movl    $1, %edx
    callq   *%r14
    movq    -8(%rax), %rcx
    shrq    $4, %rcx
    cmpq    $284661857, %rcx        ## imm = 0x10F79861
    jne L1068
    movabsq $jl_false, %rcx
    cmpq    (%rcx), %rax
    je  L462
L887:   movq    -104(%rbp), %rax
    movabsq $jl_pgcstack, %rcx
    movq    %rax, (%rcx)
    leaq    -40(%rbp), %rsp
    popq    %rbx
    popq    %r12
    popq    %r13
    popq    %r14
    popq    %r15
    popq    %rbp
    ret
L919:   movabsq $jl_inexact_exception, %rax
    movq    (%rax), %rdi
    movabsq $jl_throw, %rax
    callq   *%rax
L944:   movabsq $jl_type_error_rt, %rbx
    movabsq $13317660823, %rdi      ## imm = 0x319CB6097
    movabsq $13317660724, %rsi      ## imm = 0x319CB6034
    movabsq $4554589712, %rdx       ## imm = 0x10F798610
    movq    %rax, %rcx
    callq   *%rbx
L989:   movabsq $jl_type_error_rt, %rbx
    movabsq $13317660823, %rdi      ## imm = 0x319CB6097
    movabsq $13317660754, %rsi      ## imm = 0x319CB6052
    movabsq $4554589520, %rdx       ## imm = 0x10F798550
    movq    %rax, %rcx
    callq   *%rbx
L1034:  movq    %rsp, %rax
    leaq    -16(%rax), %rsi
    movq    %rsi, %rsp
    incq    %r15
    movq    %r15, -16(%rax)
    movabsq $jl_bounds_error_ints, %rax
    movl    $1, %edx
    callq   *%rax
L1068:  movabsq $jl_type_error_rt, %rbx
    movabsq $13317660823, %rdi      ## imm = 0x319CB6097
    movabsq $13317660724, %rsi      ## imm = 0x319CB6034
    movabsq $4554589712, %rdx       ## imm = 0x10F798610
    movq    %rax, %rcx
    callq   *%rbx

まとめ

9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4