From 1247718cbda10d46f3c8c251ea04fadf22ee58ee Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 23 Apr 2020 20:27:29 +0200 Subject: [PATCH] x64: pass fn args --- vlib/v/gen/x64/gen.v | 62 ++++++++++++++++++++++++++-------- vlib/v/gen/x64/tests/if.vv | 18 ++++++++++ vlib/v/gen/x64/tests/if.vv.out | 5 +++ 3 files changed, 70 insertions(+), 15 deletions(-) diff --git a/vlib/v/gen/x64/gen.v b/vlib/v/gen/x64/gen.v index ec6017e867..1c74ffb289 100644 --- a/vlib/v/gen/x64/gen.v +++ b/vlib/v/gen/x64/gen.v @@ -48,6 +48,10 @@ enum Register { r15 } +const ( + fn_arg_registers = [x64.Register.rdi, .rsi, .rdx, .rcx, .r8, .r9] +) + /* rax // 0 rcx // 1 @@ -269,6 +273,17 @@ fn (mut g Gen) mov64(reg Register, val i64) { g.write64(val) } +fn (mut g Gen) mov_from_reg(var_offset int, reg Register) { + // 89 7d fc mov DWORD PTR [rbp-0x4],edi + g.write8(0x89) + match reg { + .edi, .rdi { g.write8(0x7d) } + .rsi { g.write8(0x75) } + else { verror('mov_from_reg $reg') } + } + g.write8(0xff - var_offset + 1) +} + fn (mut g Gen) call(addr int) { // Need to calculate the difference between current position (position after the e8 call) // and the function to call. @@ -378,7 +393,7 @@ fn (mut g Gen) mov(reg Register, val int) { .eax, .rax { g.write8(0xb8) } - .edi { + .edi, .rdi { g.write8(0xbf) } .edx { @@ -399,7 +414,6 @@ fn (mut g Gen) mov(reg Register, val int) { g.write32(val) } -/* fn (mut g Gen) mov_reg(a, b Register) { match a { .rbp { @@ -409,7 +423,7 @@ fn (mut g Gen) mov_reg(a, b Register) { else {} } } -*/ + // generates `mov rbp, rsp` fn (mut g Gen) mov_rbp_rsp() { g.write8(0x48) @@ -423,15 +437,23 @@ pub fn (mut g Gen) register_function_address(name string) { g.fn_addr[name] = addr } -pub fn (mut g Gen) call_fn(name string) { +pub fn (mut g Gen) call_fn(node ast.CallExpr) { + name := node.name println('call fn $name') - if !name.contains('__') { - // return - } addr := g.fn_addr[name] if addr == 0 { verror('fn addr of `$name` = 0') } + // Copy values to registers (calling convention) + g.mov(.eax, 0) + for i in 0 .. node.args.len { + expr := node.args[i].expr + int_lit := expr as ast.IntegerLiteral + g.mov(fn_arg_registers[i], int_lit.val.int()) + } + if node.args.len > 6 { + verror('more than 6 args not allowed for now') + } g.call(int(addr)) println('call $name $addr') } @@ -473,7 +495,7 @@ fn (mut g Gen) expr(node ast.Expr) { g.gen_print_from_expr(expr, it.name in ['println', 'eprintln']) return } - g.call_fn(it.name) + g.call_fn(it) } ast.FloatLiteral {} ast.Ident {} @@ -585,23 +607,33 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) { g.write32_at(jump_addr, g.pos() - jump_addr - 4) // 4 is for "00 00 00 00" } -fn (mut g Gen) fn_decl(it ast.FnDecl) { - is_main := it.name == 'main' - println('saving addr $it.name $g.buf.len.hex()') +fn (mut g Gen) fn_decl(node ast.FnDecl) { + is_main := node.name == 'main' + println('saving addr $node.name $g.buf.len.hex()') if is_main { g.save_main_fn_addr() } else { - g.register_function_address(it.name) + g.register_function_address(node.name) // g.write32(SEVENS) g.push(.rbp) g.mov_rbp_rsp() // g.sub32(.rsp, 0x10) } - for arg in it.args { + if node.args.len > 0 { + // g.mov(.r12, 0x77777777) } - for stmt in it.stmts { - g.stmt(stmt) + // Copy values from registers to local vars (calling convention) + mut offset := 0 + for i in 0 .. node.args.len { + name := node.args[i].name + // TODO optimize. Right now 2 mov's are used instead of 1. + g.allocate_var(name, 4, 0) + // `mov DWORD PTR [rbp-0x4],edi` + offset += 4 + g.mov_from_reg(offset, fn_arg_registers[i]) } + // + g.stmts(node.stmts) if is_main { println('end of main: gen exit') g.gen_exit() diff --git a/vlib/v/gen/x64/tests/if.vv b/vlib/v/gen/x64/tests/if.vv index 0b748ef428..ef555c08d8 100644 --- a/vlib/v/gen/x64/tests/if.vv +++ b/vlib/v/gen/x64/tests/if.vv @@ -27,7 +27,25 @@ fn loop() { } } +fn foo(a int) { + println('foo') + if a == 1 { + println('foo(1)') + } + a++ + if a == 1 { + println('foo(2)') + } +} + +fn args() { + println('===args===') + args(1) + args(2) +} + fn main() { test() loop() + args() } diff --git a/vlib/v/gen/x64/tests/if.vv.out b/vlib/v/gen/x64/tests/if.vv.out index 20a3ba5049..ac848b0988 100644 --- a/vlib/v/gen/x64/tests/if.vv.out +++ b/vlib/v/gen/x64/tests/if.vv.out @@ -6,3 +6,8 @@ hello hello hello hello +===args=== +foo +foo(1) +foo(2) +foo