diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index a690d0511c..a6d7c67c0a 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -49,6 +49,7 @@ fn (mut g Gen) dec(reg Register) { .r12 { g.write8(0xc4) } else { panic('unhandled inc $reg') } } + g.println('dec $reg') } fn (mut g Gen) inc(reg Register) { @@ -58,22 +59,44 @@ fn (mut g Gen) inc(reg Register) { .r12 { g.write8(0xc4) } else { panic('unhandled inc $reg') } } + g.println('inc $reg') } fn (mut g Gen) cmp(reg Register, size Size, val i64) { - g.write8(0x49) // Second byte depends on the size of the value match size { - ._8 { g.write8(0x83) } - ._32 { g.write8(0x81) } - else { panic('unhandled cmp') } + ._8 { + g.write8(0x48) + g.write8(0x83) + } + ._32 { + g.write8(0x4a) + g.write8(0x81) + } + else { + panic('unhandled cmp') + } } // Third byte depends on the register being compared to match reg { .r12 { g.write8(0xfc) } + .rsi { g.write8(0x3f) } + .eax { g.write8(0xf8) } + .rbx { g.write8(0xfb) } else { panic('unhandled cmp') } } - g.write8(int(val)) + match size { + ._8 { + g.write8(int(val)) + } + ._32 { + g.write32(int(val)) + } + else { + panic('unhandled cmp') + } + } + g.println('cmp $reg, $val') } /* @@ -106,22 +129,22 @@ fn (mut g Gen) inc_var(var_name string) { g.println('inc_var `$var_name`') } -// Returns the position of the address to jump to (set later). -fn (mut g Gen) jne() int { - g.write16(0x850f) +enum JumpOp { + je = 0x840f + jne = 0x850f + jge = 0x8d0f + jle = 0x8e0f +} + +fn (mut g Gen) cjmp(op JumpOp) int { + g.write16(u16(op)) pos := g.pos() g.write32(placeholder) - g.println('jne') + g.println('$op') return int(pos) } -fn (mut g Gen) jge() int { - g.write16(0x8d0f) - pos := g.pos() - g.write32(placeholder) - g.println('jne') - return int(pos) -} +// Returns the position of the address to jump to (set later). fn (mut g Gen) jmp(addr int) { g.write8(0xe9) @@ -133,7 +156,7 @@ fn abs(a i64) i64 { return if a < 0 { -a } else { a } } -fn (mut g Gen) jle(addr i64) { +fn (mut g Gen) tmp_jle(addr i64) { // Calculate the relative offset to jump to // (`addr` is absolute address) offset := 0xff - int(abs(addr - g.buf.len)) - 1 @@ -992,23 +1015,79 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { fn (mut g Gen) if_expr(node ast.IfExpr) { branch := node.branches[0] infix_expr := branch.cond as ast.InfixExpr - mut jne_addr := 0 // location of `jne *00 00 00 00*` + mut cjmp_addr := 0 // location of `jne *00 00 00 00*` match mut infix_expr.left { + ast.IntegerLiteral { + match mut infix_expr.right { + ast.IntegerLiteral { + // 3 < 4 + a0 := infix_expr.left.val.int() + // a0 := (infix_expr.left as ast.IntegerLiteral).val.int() + a1 := (infix_expr.right as ast.IntegerLiteral).val.int() + // TODO. compute at compile time + g.mov(.eax, a0) + g.cmp(.eax, ._32, a1) + } + ast.Ident { + // 3 < var + // lit := infix_expr.right as ast.IntegerLiteral + // g.cmp_var(infix_expr.left.name, lit.val.int()) + // +not + verror('unsupported if construction') + } + else { + verror('unsupported if construction') + } + } + } ast.Ident { - lit := infix_expr.right as ast.IntegerLiteral - g.cmp_var(infix_expr.left.name, lit.val.int()) - jne_addr = g.jne() + match mut infix_expr.right { + ast.IntegerLiteral { + // var < 4 + lit := infix_expr.right as ast.IntegerLiteral + g.cmp_var(infix_expr.left.name, lit.val.int()) + } + ast.Ident { + // var < var2 + verror('unsupported if construction') + } + else { + verror('unsupported if construction') + } + } } else { + dump(node) verror('unhandled infix.left') } } + cjmp_addr = match infix_expr.op { + .gt { + g.cjmp(.jle) + } + .lt { + g.cjmp(.jge) + } + .ne { + g.cjmp(.je) + } + .eq { + g.cjmp(.jne) + } + else { + g.cjmp(.je) + } + } g.stmts(branch.stmts) // Now that we know where we need to jump if the condition is false, update the `jne` call. // The value is the relative address, difference between current position and the location // after `jne 00 00 00 00` - // println('after if g.pos=$g.pos() jneaddr=$jne_addr') - g.write32_at(jne_addr, int(g.pos() - jne_addr - 4)) // 4 is for "00 00 00 00" + // println('after if g.pos=$g.pos() jneaddr=$cjmp_addr') + g.write32_at(cjmp_addr, int(g.pos() - cjmp_addr - 4)) // 4 is for "00 00 00 00" + + if node.has_else { + verror('else statements not yet supported') + } } fn (mut g Gen) for_stmt(node ast.ForStmt) { @@ -1020,7 +1099,7 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) { ast.Ident { lit := infix_expr.right as ast.IntegerLiteral g.cmp_var(infix_expr.left.name, lit.val.int()) - jump_addr = g.jge() + jump_addr = g.cjmp(.jge) } else { verror('unhandled infix.left') diff --git a/vlib/v/gen/native/tests/ifs.vv b/vlib/v/gen/native/tests/ifs.vv new file mode 100644 index 0000000000..674d4aa905 --- /dev/null +++ b/vlib/v/gen/native/tests/ifs.vv @@ -0,0 +1,65 @@ +fn print_number(n int) { + if n == 0 { + println('print_number') + } +} + +fn test_add() { + n := 3 + print_number(0) + print_number(1) + if n > 1 { + println('var(3) > 1') + } + /* + if 1 < n { + println('1 < var(3)') + } + if 1 > n { + println('1 > 3 ERROR') + } + */ + if 1 < 3 { + println('1 < 3') + } + if 1 == 1 { + println('1 == 1') + // TODO assert here + } + if 1 != 3 { + println('1 != 3') + // TODO assert here + } + if 3 != 3 { + println('3 != 3 ERROR') + // TODO assert here + } + if 1 > 3 { + println('1 > 3 ERROR') + // TODO assert here + } +} + +/* +fn test_elses() { + println('start else') + if 1 < 2 { + println('ok') + } else { + println('1<2else ERROR') + } + if 1 > 2 { + println('1<2else ERROR') + } else { + println('ok') + } + println('end else') +} +*/ + +fn main() { + println('start') + test_add() + // test_elses() + println('end') +} diff --git a/vlib/v/gen/native/tests/ifs.vv.out b/vlib/v/gen/native/tests/ifs.vv.out new file mode 100644 index 0000000000..1298ea4729 --- /dev/null +++ b/vlib/v/gen/native/tests/ifs.vv.out @@ -0,0 +1,7 @@ +start +print_number +var(3) > 1 +1 < 3 +1 == 1 +1 != 3 +end diff --git a/vlib/v/gen/native/tests/native_test.v b/vlib/v/gen/native/tests/native_test.v index d4e938b997..1ae7bec27d 100644 --- a/vlib/v/gen/native/tests/native_test.v +++ b/vlib/v/gen/native/tests/native_test.v @@ -32,20 +32,21 @@ fn test_native() { for test in tests { bench.step() full_test_path := os.real_path(os.join_path(dir, test)) + test_file_name := os.file_name(test) relative_test_path := full_test_path.replace(vroot + '/', '') - work_test_path := '$wrkdir/x.v' - os.cp(full_test_path, work_test_path) or {} - cmd := '$vexe -o exe -native $work_test_path' + work_test_path := '$wrkdir/$test_file_name' + exe_test_path := '$wrkdir/${test_file_name}.exe' + cmd := '"$vexe" -o "$exe_test_path" -b native "$full_test_path"' if is_verbose { println(cmd) } res_native := os.execute(cmd) if res_native.exit_code != 0 { bench.fail() - eprintln(bench.step_message_fail('native $test failed')) + eprintln(bench.step_message_fail(cmd)) continue } - res := os.execute('./exe') + res := os.execute(exe_test_path) if res.exit_code != 0 { bench.fail() eprintln(bench.step_message_fail('$full_test_path failed to run'))