native: implement for-c and for-in range loops (#12155)
parent
05db3533d3
commit
1b691e7612
|
@ -71,7 +71,13 @@ fn get_all_commands() []Command {
|
|||
line: '$vexe run examples/v_script.vsh > /dev/null'
|
||||
okmsg: 'V can run the .VSH script file examples/v_script.vsh'
|
||||
}
|
||||
//
|
||||
$if linux {
|
||||
res << Command{
|
||||
line: '$vexe -b native run examples/native/hello_world.v > /dev/null'
|
||||
okmsg: 'V compiles and runs examples/native/hello_world.v on the native backend for linux'
|
||||
}
|
||||
}
|
||||
// only compilation:
|
||||
res << Command{
|
||||
line: '$vexe -os linux -b native -o hw.linux examples/hello_world.v'
|
||||
okmsg: 'V compiles hello_world.v on the native backend for linux'
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
// fn println(s string) { }
|
||||
|
||||
// fn test_fn() {
|
||||
// println('test fn')
|
||||
//}
|
||||
fn test_fn() {
|
||||
println('test fn')
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println('native test')
|
||||
// i := 0
|
||||
// for i < 5 {
|
||||
for _ in 1 .. 5 {
|
||||
println('Hello world from V native machine code generator!')
|
||||
// i++
|
||||
mut i := 0
|
||||
for i < 5 {
|
||||
println('Hello world from V native machine code generator, in a while style for loop!')
|
||||
i++
|
||||
}
|
||||
for _ in 1 .. 5 {
|
||||
println('Hello world from V native machine code generator, in a range loop!')
|
||||
}
|
||||
/*
|
||||
println('Hello again!')
|
||||
//test_fn()
|
||||
test_fn()
|
||||
println('done')
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -105,18 +105,36 @@ fn (mut g Gen) cmp(reg Register, size Size, val i64) {
|
|||
g.println('cmp $reg, $val')
|
||||
}
|
||||
|
||||
/*
|
||||
rax // 0
|
||||
rcx // 1
|
||||
rdx // 2
|
||||
rbx // 3
|
||||
rsp // 4
|
||||
rbp // 5
|
||||
rsi // 6
|
||||
rdi // 7
|
||||
*/
|
||||
// `a == 1`
|
||||
// `cmp DWORD [rbp-0x4],0x1`
|
||||
// `cmp rax, rbx`
|
||||
fn (mut g Gen) cmp_reg(reg Register, reg2 Register) {
|
||||
match reg {
|
||||
.rax {
|
||||
match reg2 {
|
||||
.rbx {
|
||||
g.write([byte(0x48), 0x39, 0xd8])
|
||||
}
|
||||
else {
|
||||
g.n_error('Cannot compare $reg and $reg2')
|
||||
}
|
||||
}
|
||||
}
|
||||
.rbx {
|
||||
match reg2 {
|
||||
.rax {
|
||||
g.write([byte(0x48), 0x39, 0xc3])
|
||||
}
|
||||
else {
|
||||
g.n_error('Cannot compare $reg and $reg2')
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
g.n_error('Cannot compare $reg and $reg2')
|
||||
}
|
||||
}
|
||||
g.println('cmp $reg, $reg2')
|
||||
}
|
||||
|
||||
fn (mut g Gen) cmp_var(var_name string, val int) {
|
||||
g.write8(0x81) // 83 for 1 byte?
|
||||
g.write8(0x7d)
|
||||
|
@ -126,6 +144,15 @@ fn (mut g Gen) cmp_var(var_name string, val int) {
|
|||
g.println('cmp var `$var_name` $val')
|
||||
}
|
||||
|
||||
// `sub DWORD [rbp-0x4], 1`
|
||||
fn (mut g Gen) dec_var(var_name string) {
|
||||
g.write16(0x6d81) // 83 for 1 byte
|
||||
offset := g.get_var_offset(var_name)
|
||||
g.write8(0xff - offset + 1)
|
||||
g.write32(1)
|
||||
g.println('dec_var `$var_name`')
|
||||
}
|
||||
|
||||
// `add DWORD [rbp-0x4], 1`
|
||||
fn (mut g Gen) inc_var(var_name string) {
|
||||
g.write16(0x4581) // 83 for 1 byte
|
||||
|
@ -258,9 +285,9 @@ fn (mut g Gen) mov_reg_to_var(var_offset int, reg Register) {
|
|||
}
|
||||
|
||||
fn (mut g Gen) mov_var_to_reg(reg Register, var_offset int) {
|
||||
// 8b 7d f8 mov edi,DWORD PTR [rbp-0x8]
|
||||
// 8b 7d f8 mov edi,DWORD PTR [rbp-0x8]
|
||||
match reg {
|
||||
.rax, .rsi {
|
||||
.rax, .rbx, .rsi {
|
||||
g.write8(0x48)
|
||||
}
|
||||
else {}
|
||||
|
@ -616,6 +643,7 @@ fn (mut g Gen) lea(reg Register, val int) {
|
|||
g.write8(0x8d)
|
||||
g.write8(0x15)
|
||||
g.write32(val)
|
||||
g.println('lea $reg, $val')
|
||||
}
|
||||
|
||||
fn (mut g Gen) mov(reg Register, val int) {
|
||||
|
@ -626,7 +654,7 @@ fn (mut g Gen) mov(reg Register, val int) {
|
|||
g.write8(0xc7)
|
||||
g.write8(0xc0)
|
||||
g.write32(-1)
|
||||
return
|
||||
g.println('mov $reg, $val')
|
||||
}
|
||||
.rcx {
|
||||
if val == -1 {
|
||||
|
@ -638,12 +666,14 @@ fn (mut g Gen) mov(reg Register, val int) {
|
|||
g.write8(0xff)
|
||||
g.write8(0xff) // mov rcx 0xffff5
|
||||
}
|
||||
return
|
||||
g.println('mov $reg, $val')
|
||||
}
|
||||
else {
|
||||
g.n_error('unhandled mov $reg, -1')
|
||||
}
|
||||
}
|
||||
g.println('mov $reg, $val')
|
||||
return
|
||||
}
|
||||
if val == 0 {
|
||||
// Optimise to xor reg, reg when val is 0
|
||||
|
@ -885,8 +915,7 @@ pub fn (mut g Gen) call_fn(node ast.CallExpr) {
|
|||
} else {
|
||||
g.call(int(addr))
|
||||
}
|
||||
g.println('fn call `${name}()`')
|
||||
// println('call $name $addr')
|
||||
g.println('call `${name}()`')
|
||||
}
|
||||
|
||||
fn (mut g Gen) patch_calls() {
|
||||
|
@ -953,17 +982,35 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
|||
g.mov_reg_to_var(dest, .rax)
|
||||
}
|
||||
.decl_assign {
|
||||
g.allocate_var(name, 4, right.val.int())
|
||||
g.allocate_var(name, 8, right.val.int())
|
||||
}
|
||||
.assign {
|
||||
match node.left_types[i] {
|
||||
7 { // ast.IndexExpr {
|
||||
// dump(g.typ(node.left_types[i]))
|
||||
match node.left[i] {
|
||||
ast.Ident {
|
||||
// lname := '${node.left[i]}'
|
||||
// g.expr(node.right[i])
|
||||
g.mov(.rax, right.val.int())
|
||||
offset := g.get_var_offset('i') // node.left[i])
|
||||
g.mov_reg_to_var(offset, .rax)
|
||||
}
|
||||
ast.InfixExpr {
|
||||
eprintln('assign')
|
||||
// dump(node.left[i])
|
||||
offset := g.get_var_offset('i') // node.left[i])
|
||||
g.mov_reg_to_var(offset, native.fn_arg_registers[i])
|
||||
}
|
||||
/*
|
||||
ast.int_type_idx {
|
||||
g.expr(node.left[i])
|
||||
match node.left[i] {
|
||||
ast.IndexExpr {
|
||||
ie := node.left[i] as ast.IndexExpr
|
||||
bracket := name.index('[') or {
|
||||
g.v_error('bracket expected', node.pos)
|
||||
exit(1)
|
||||
}
|
||||
var_name := name[0..bracket]
|
||||
var_name := name[0 .. bracket]
|
||||
mut dest := g.get_var_offset(var_name)
|
||||
index := ie.index as ast.IntegerLiteral
|
||||
dest += index.val.int() * 8
|
||||
|
@ -971,7 +1018,13 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
|||
g.mov(.rax, right.val.int())
|
||||
g.mov_reg_to_var(dest, .rax)
|
||||
// eprintln('${var_name}[$index] = ${right.val.int()}')
|
||||
} else {
|
||||
dump(node)
|
||||
g.v_error('oops', node.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
else {
|
||||
tn := node.left[i].type_name()
|
||||
dump(node.left_types)
|
||||
|
@ -988,12 +1041,12 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
|||
ast.InfixExpr {
|
||||
// eprintln('infix') dump(node) dump(right)
|
||||
g.infix_expr(right)
|
||||
offset := g.allocate_var(name, 4, 0)
|
||||
offset := g.allocate_var(name, 8, 0)
|
||||
// `mov DWORD PTR [rbp-0x8],eax`
|
||||
if g.pref.is_verbose {
|
||||
println('infix assignment $name offset=$offset.hex2()')
|
||||
}
|
||||
g.mov_reg_to_var(offset, .eax)
|
||||
g.mov_reg_to_var(offset, .rax)
|
||||
}
|
||||
ast.Ident {
|
||||
// eprintln('identr') dump(node) dump(right)
|
||||
|
@ -1020,7 +1073,7 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
|||
g.mov_reg_to_var(dest, .rax)
|
||||
}
|
||||
.decl_assign {
|
||||
dest := g.allocate_var(name, 4, 0)
|
||||
dest := g.allocate_var(name, 8, 0)
|
||||
g.mov_var_to_reg(.rax, g.get_var_offset(right.name))
|
||||
g.mov_reg_to_var(dest, .rax)
|
||||
}
|
||||
|
@ -1069,7 +1122,7 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
|||
}
|
||||
ast.IndexExpr {
|
||||
// a := arr[0]
|
||||
offset := g.allocate_var(name, 4, 0)
|
||||
offset := g.allocate_var(name, 8, 0)
|
||||
if g.pref.is_verbose {
|
||||
println('infix assignment $name offset=$offset.hex2()')
|
||||
}
|
||||
|
@ -1131,9 +1184,6 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
|||
}
|
||||
|
||||
fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||
if g.pref.is_verbose {
|
||||
println('infix expr op=$node.op')
|
||||
}
|
||||
// TODO
|
||||
if node.left is ast.InfixExpr {
|
||||
g.n_error('only simple expressions are supported right now (not more than 2 operands)')
|
||||
|
@ -1229,31 +1279,39 @@ fn (mut g Gen) gen_asm_stmt_amd64(asm_node ast.AsmStmt) {
|
|||
match t.name {
|
||||
'nop' {
|
||||
g.write8(byte(0x90))
|
||||
g.println('nop')
|
||||
}
|
||||
'syscall' {
|
||||
g.write8(byte(0x0f))
|
||||
g.write8(byte(0x05))
|
||||
g.println('syscall')
|
||||
}
|
||||
'ret' {
|
||||
g.write8(byte(0xc3))
|
||||
g.println('ret')
|
||||
}
|
||||
'int3' {
|
||||
g.write8(byte(0xcc))
|
||||
g.write8(byte(imm))
|
||||
g.println('int3')
|
||||
}
|
||||
'sti' {
|
||||
g.write8(byte(0xfb))
|
||||
g.println('sti')
|
||||
}
|
||||
'cli' {
|
||||
g.write8(byte(0xfa))
|
||||
g.println('cli')
|
||||
}
|
||||
'int' {
|
||||
g.write8(byte(0xcd))
|
||||
g.write8(byte(imm))
|
||||
g.println('int')
|
||||
}
|
||||
'cpuid' {
|
||||
g.write8(byte(0x0f))
|
||||
g.write8(byte(0xa2))
|
||||
g.println('cpuid')
|
||||
}
|
||||
'mov' {
|
||||
g.write8(byte(0xb8 + reg))
|
||||
|
@ -1261,6 +1319,7 @@ fn (mut g Gen) gen_asm_stmt_amd64(asm_node ast.AsmStmt) {
|
|||
g.write8(byt(imm, 1))
|
||||
g.write8(byt(imm, 2))
|
||||
g.write8(byt(imm, 3))
|
||||
g.println('mov $reg, $imm')
|
||||
}
|
||||
else {
|
||||
g.v_error('unsupported instruction $t.name', asm_node.pos)
|
||||
|
@ -1437,7 +1496,17 @@ 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.cjmp(.jge)
|
||||
match infix_expr.left.tok_kind {
|
||||
.lt {
|
||||
jump_addr = g.cjmp(.jge)
|
||||
}
|
||||
.gt {
|
||||
jump_addr = g.cjmp(.jle)
|
||||
}
|
||||
else {
|
||||
g.n_error('unhandled infix cond token')
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
g.n_error('unhandled infix.left')
|
||||
|
|
|
@ -446,25 +446,84 @@ fn (mut g Gen) println(comment string) {
|
|||
println(' ' + comment)
|
||||
}
|
||||
|
||||
fn (mut g Gen) for_in_stmt(node ast.ForInStmt) {
|
||||
g.v_error('for-in statement is not yet implemented', node.pos)
|
||||
/*
|
||||
if node.is_range {
|
||||
// `for x in 1..10 {`
|
||||
// i := if node.val_var == '_' { g.new_tmp_var() } else { c_name(node.val_var) }
|
||||
// val_typ := g.table.mktyp(node.val_type)
|
||||
g.write32(0x3131) // 'for (${g.typ(val_typ)} $i = ')
|
||||
fn (mut g Gen) gen_forc_stmt(node ast.ForCStmt) {
|
||||
if node.has_init {
|
||||
g.stmts([node.init])
|
||||
}
|
||||
start := g.pos()
|
||||
mut jump_addr := i64(0)
|
||||
if node.has_cond {
|
||||
cond := node.cond
|
||||
match cond {
|
||||
ast.InfixExpr {
|
||||
// g.infix_expr(node.cond)
|
||||
match mut cond.left {
|
||||
ast.Ident {
|
||||
lit := cond.right as ast.IntegerLiteral
|
||||
g.cmp_var(cond.left.name, lit.val.int())
|
||||
match cond.op {
|
||||
.gt {
|
||||
jump_addr = g.cjmp(.jle)
|
||||
}
|
||||
.lt {
|
||||
jump_addr = g.cjmp(.jge)
|
||||
}
|
||||
else {
|
||||
g.n_error('unsupported conditional in for-c loop')
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
g.n_error('unhandled infix.left')
|
||||
}
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
// dump(node.cond)
|
||||
g.expr(node.cond)
|
||||
g.write32(0x3232) // ; $i < ')
|
||||
g.expr(node.high)
|
||||
g.write32(0x3333) // '; ++$i) {')
|
||||
}
|
||||
g.stmts(node.stmts)
|
||||
if node.has_inc {
|
||||
g.stmts([node.inc])
|
||||
}
|
||||
g.jmp(int(0xffffffff - (g.pos() + 5 - start) + 1))
|
||||
g.write32_at(jump_addr, int(g.pos() - jump_addr - 4))
|
||||
|
||||
// loop back
|
||||
}
|
||||
|
||||
fn (mut g Gen) for_in_stmt(node ast.ForInStmt) {
|
||||
if node.stmts.len == 0 {
|
||||
// if no statements, just dont make it
|
||||
return
|
||||
}
|
||||
if node.is_range {
|
||||
// for a in node.cond .. node.high {
|
||||
i := g.allocate_var(node.val_var, 8, 0) // iterator variable
|
||||
g.expr(node.cond)
|
||||
g.mov_reg_to_var(i, .rax) // i = node.cond // initial value
|
||||
start := g.pos() // label-begin:
|
||||
g.mov_var_to_reg(.rbx, i) // rbx = iterator value
|
||||
g.expr(node.high) // final value
|
||||
g.cmp_reg(.rbx, .rax) // rbx = iterator, rax = max value
|
||||
jump_addr := g.cjmp(.jge) // leave loop if i is beyond end
|
||||
g.stmts(node.stmts)
|
||||
g.inc_var(node.val_var)
|
||||
g.jmp(int(0xffffffff - (g.pos() + 5 - start) + 1))
|
||||
g.write32_at(jump_addr, int(g.pos() - jump_addr - 4))
|
||||
/*
|
||||
} else if node.kind == .array {
|
||||
} else if node.kind == .array_fixed {
|
||||
} else if node.kind == .map {
|
||||
} else if node.kind == .string {
|
||||
} else if node.kind == .struct_ {
|
||||
} else if it.kind in [.array, .string] || it.cond_type.has_flag(.variadic) {
|
||||
} else if it.kind == .map {
|
||||
*/
|
||||
} else {
|
||||
g.v_error('for-in statement is not yet implemented', node.pos)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) gen_exit(node ast.Expr) {
|
||||
|
@ -487,6 +546,9 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
ast.FnDecl {
|
||||
g.fn_decl(node)
|
||||
}
|
||||
ast.ForCStmt {
|
||||
g.gen_forc_stmt(node)
|
||||
}
|
||||
ast.ForInStmt {
|
||||
g.for_in_stmt(node)
|
||||
}
|
||||
|
@ -619,7 +681,10 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||
ast.ArrayInit {
|
||||
g.n_error('array init expr not supported yet')
|
||||
}
|
||||
ast.BoolLiteral {}
|
||||
ast.BoolLiteral {
|
||||
g.mov64(.rax, if node.val { 1 } else { 0 })
|
||||
eprintln('bool literal')
|
||||
}
|
||||
ast.CallExpr {
|
||||
if node.name == 'C.syscall' {
|
||||
g.gen_syscall(node)
|
||||
|
@ -633,7 +698,12 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||
}
|
||||
}
|
||||
ast.FloatLiteral {}
|
||||
ast.Ident {}
|
||||
ast.Ident {
|
||||
offset := g.get_var_offset(node.obj.name) // i := 0
|
||||
// offset := g.get_var_offset(node.name)
|
||||
// XXX this is intel specific
|
||||
g.mov_var_to_reg(.rax, offset)
|
||||
}
|
||||
ast.IfExpr {
|
||||
if node.is_comptime {
|
||||
eprintln('Warning: ignored compile time conditional not yet supported for the native backend.')
|
||||
|
@ -641,8 +711,15 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||
g.if_expr(node)
|
||||
}
|
||||
}
|
||||
ast.InfixExpr {}
|
||||
ast.IntegerLiteral {}
|
||||
ast.InfixExpr {
|
||||
g.infix_expr(node)
|
||||
// get variable by name
|
||||
// save the result in rax
|
||||
}
|
||||
ast.IntegerLiteral {
|
||||
g.mov64(.rax, node.val.int())
|
||||
// g.gen_print_reg(.rax, 3, fd)
|
||||
}
|
||||
ast.PostfixExpr {
|
||||
g.postfix_expr(node)
|
||||
}
|
||||
|
@ -669,8 +746,14 @@ fn (mut g Gen) postfix_expr(node ast.PostfixExpr) {
|
|||
}
|
||||
ident := node.expr as ast.Ident
|
||||
var_name := ident.name
|
||||
if node.op == .inc {
|
||||
g.inc_var(var_name)
|
||||
match node.op {
|
||||
.inc {
|
||||
g.inc_var(var_name)
|
||||
}
|
||||
.dec {
|
||||
g.dec_var(var_name)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
fn main() {
|
||||
mut i := 0
|
||||
for i = 0; i < 3; i++ {
|
||||
println('loop0')
|
||||
}
|
||||
i = 0
|
||||
for i < 3 {
|
||||
println('loop1')
|
||||
i++
|
||||
}
|
||||
for _ in 0 .. 3 {
|
||||
println('loop2')
|
||||
}
|
||||
n := 3
|
||||
for _ in 0 .. n {
|
||||
println('loop3')
|
||||
}
|
||||
for i = 3; i > 0; i-- {
|
||||
println('loop4')
|
||||
}
|
||||
i = 3
|
||||
for i > 0 {
|
||||
println('loop5')
|
||||
i--
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
loop0
|
||||
loop0
|
||||
loop0
|
||||
loop1
|
||||
loop1
|
||||
loop1
|
||||
loop2
|
||||
loop2
|
||||
loop2
|
||||
loop3
|
||||
loop3
|
||||
loop3
|
||||
loop4
|
||||
loop4
|
||||
loop4
|
||||
loop5
|
||||
loop5
|
||||
loop5
|
Loading…
Reference in New Issue