x64: pass fn args

pull/4567/head
Alexander Medvednikov 2020-04-23 20:27:29 +02:00
parent 0f4c5fb1c9
commit 1247718cbd
3 changed files with 70 additions and 15 deletions

View File

@ -48,6 +48,10 @@ enum Register {
r15 r15
} }
const (
fn_arg_registers = [x64.Register.rdi, .rsi, .rdx, .rcx, .r8, .r9]
)
/* /*
rax // 0 rax // 0
rcx // 1 rcx // 1
@ -269,6 +273,17 @@ fn (mut g Gen) mov64(reg Register, val i64) {
g.write64(val) 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) { fn (mut g Gen) call(addr int) {
// Need to calculate the difference between current position (position after the e8 call) // Need to calculate the difference between current position (position after the e8 call)
// and the function to call. // and the function to call.
@ -378,7 +393,7 @@ fn (mut g Gen) mov(reg Register, val int) {
.eax, .rax { .eax, .rax {
g.write8(0xb8) g.write8(0xb8)
} }
.edi { .edi, .rdi {
g.write8(0xbf) g.write8(0xbf)
} }
.edx { .edx {
@ -399,7 +414,6 @@ fn (mut g Gen) mov(reg Register, val int) {
g.write32(val) g.write32(val)
} }
/*
fn (mut g Gen) mov_reg(a, b Register) { fn (mut g Gen) mov_reg(a, b Register) {
match a { match a {
.rbp { .rbp {
@ -409,7 +423,7 @@ fn (mut g Gen) mov_reg(a, b Register) {
else {} else {}
} }
} }
*/
// generates `mov rbp, rsp` // generates `mov rbp, rsp`
fn (mut g Gen) mov_rbp_rsp() { fn (mut g Gen) mov_rbp_rsp() {
g.write8(0x48) g.write8(0x48)
@ -423,15 +437,23 @@ pub fn (mut g Gen) register_function_address(name string) {
g.fn_addr[name] = addr 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') println('call fn $name')
if !name.contains('__') {
// return
}
addr := g.fn_addr[name] addr := g.fn_addr[name]
if addr == 0 { if addr == 0 {
verror('fn addr of `$name` = 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)) g.call(int(addr))
println('call $name $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']) g.gen_print_from_expr(expr, it.name in ['println', 'eprintln'])
return return
} }
g.call_fn(it.name) g.call_fn(it)
} }
ast.FloatLiteral {} ast.FloatLiteral {}
ast.Ident {} 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" 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) { fn (mut g Gen) fn_decl(node ast.FnDecl) {
is_main := it.name == 'main' is_main := node.name == 'main'
println('saving addr $it.name $g.buf.len.hex()') println('saving addr $node.name $g.buf.len.hex()')
if is_main { if is_main {
g.save_main_fn_addr() g.save_main_fn_addr()
} else { } else {
g.register_function_address(it.name) g.register_function_address(node.name)
// g.write32(SEVENS) // g.write32(SEVENS)
g.push(.rbp) g.push(.rbp)
g.mov_rbp_rsp() g.mov_rbp_rsp()
// g.sub32(.rsp, 0x10) // g.sub32(.rsp, 0x10)
} }
for arg in it.args { if node.args.len > 0 {
// g.mov(.r12, 0x77777777)
} }
for stmt in it.stmts { // Copy values from registers to local vars (calling convention)
g.stmt(stmt) 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 { if is_main {
println('end of main: gen exit') println('end of main: gen exit')
g.gen_exit() g.gen_exit()

View File

@ -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() { fn main() {
test() test()
loop() loop()
args()
} }

View File

@ -6,3 +6,8 @@ hello
hello hello
hello hello
hello hello
===args===
foo
foo(1)
foo(2)
foo