9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JuliaAdvent Calendar 2016

Day 12

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?