コンパイラ作成(80) double型引数の関数呼出
今回の目標
前回サボった関数呼出を頑張るよ。
// double型 int main() { int a = 15, b = 25; double d = 10.78; double e = 0.13e-3; printf("a = %d d = %f e = %e b = %d\n", a, d, e, b); }
int型、double型を混ぜてprintfに渡してる。
関数コール
# 関数コールのコード生成 def codegen_func operand rettype = "int" xmm = 0 # xmmレジスタの使用数 f = @functions[operand[0].str] if @numuseregs != 0 then if @numuseregs % 2 == 1 then codegen " sub rsp, 8" end (0...@numuseregs).each do |i| codegen " push #{@regs64[i]}" end end if f != nil then if operand.size - 2 != f[1].size then perror "wrong number of parameters" end end (0...operand.size-2).each do |i| save = @numuseregs @numuseregs = i-xmm type = codegen_el operand[i+2] @numuseregs = save if f != nil then if f[1][i] == "size_t" then codegen " movsx rax, eax" type = f[1][i] elsif f[1][i] == "void*" && is_pointer_type?(type) then type = f[1][i] end if type != f[1][i] then perror "incompatible type parameter" end end if type == "int" || type == "char" then codegen " mov #{@regs32[i-xmm]}, eax" elsif type == "size_t" codegen " mov #{@regs64[i-xmm]}, rax" elsif is_pointer_type?(type) then codegen " mov #{@regs64[i-xmm]}, rax" elsif type == "double" then codegen " movsd xmm#{xmm}, xmm8" xmm += 1 else perror end end if f == nil then codegen " mov al, #{xmm}" end codegen " call " + operand[0].str if f != nil then rettype = f[0] end if @numuseregs != 0 then (0...@numuseregs).reverse_each do |i| codegen " pop #{@regs64[i]}" end if @numuseregs % 2 == 1 then codegen " add rsp, 8" end end return rettype end
前回と比べると大分まともになったけど、ネストした関数には対応できてないよ。
動作テスト
~/myc$ myc p8.myc ~/myc$ ./p8 a = 15 d = 10.780000 e = 1.300000e-04 b = 25 ~/myc$
ちゃんと表示された。アセンブリコードもチェック。
.intel_syntax noprefix .global main main: push rbp mov rbp, rsp sub rsp, 32 mov eax, 15 mov dword ptr [rbp - 4], eax mov eax, 25 mov dword ptr [rbp - 8], eax movsd xmm8, qword ptr [.L.float.0] movsd qword ptr [rbp - 16], xmm8 movsd xmm8, qword ptr [.L.float.1] movsd qword ptr [rbp - 24], xmm8 lea rax, .L.str.2 mov rdi, rax mov eax, dword ptr [rbp - 4] mov esi, eax movsd xmm8, qword ptr [rbp - 16] movsd xmm0, xmm8 movsd xmm8, qword ptr [rbp - 24] movsd xmm1, xmm8 mov eax, dword ptr [rbp - 8] mov edx, eax mov al, 2 call printf .RET_main: add rsp, 32 pop rbp ret .L.float.0: .quad 40258f5c28f5c28fH # 10.78 .L.float.1: .quad 3f210a137f38c543H # 0.13e-3 .L.str.2: .asciz "a = %d d = %f e = %e b = %d\n"
ちゃんとレジスタの使い分けができてるし、alにもxmmレジスタの使用数がセットされてる。大丈夫かな。さて次は四則演算だな。