コンパイラ作成(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レジスタの使用数がセットされてる。大丈夫かな。さて次は四則演算だな。