v.gen.native: support more `ifs` constructs for amd64 (#11007)
parent
cc9463401e
commit
dbf5c976a3
|
@ -49,6 +49,7 @@ fn (mut g Gen) dec(reg Register) {
|
||||||
.r12 { g.write8(0xc4) }
|
.r12 { g.write8(0xc4) }
|
||||||
else { panic('unhandled inc $reg') }
|
else { panic('unhandled inc $reg') }
|
||||||
}
|
}
|
||||||
|
g.println('dec $reg')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) inc(reg Register) {
|
fn (mut g Gen) inc(reg Register) {
|
||||||
|
@ -58,22 +59,44 @@ fn (mut g Gen) inc(reg Register) {
|
||||||
.r12 { g.write8(0xc4) }
|
.r12 { g.write8(0xc4) }
|
||||||
else { panic('unhandled inc $reg') }
|
else { panic('unhandled inc $reg') }
|
||||||
}
|
}
|
||||||
|
g.println('inc $reg')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) cmp(reg Register, size Size, val i64) {
|
fn (mut g Gen) cmp(reg Register, size Size, val i64) {
|
||||||
g.write8(0x49)
|
|
||||||
// Second byte depends on the size of the value
|
// Second byte depends on the size of the value
|
||||||
match size {
|
match size {
|
||||||
._8 { g.write8(0x83) }
|
._8 {
|
||||||
._32 { g.write8(0x81) }
|
g.write8(0x48)
|
||||||
else { panic('unhandled cmp') }
|
g.write8(0x83)
|
||||||
|
}
|
||||||
|
._32 {
|
||||||
|
g.write8(0x4a)
|
||||||
|
g.write8(0x81)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
panic('unhandled cmp')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Third byte depends on the register being compared to
|
// Third byte depends on the register being compared to
|
||||||
match reg {
|
match reg {
|
||||||
.r12 { g.write8(0xfc) }
|
.r12 { g.write8(0xfc) }
|
||||||
|
.rsi { g.write8(0x3f) }
|
||||||
|
.eax { g.write8(0xf8) }
|
||||||
|
.rbx { g.write8(0xfb) }
|
||||||
else { panic('unhandled cmp') }
|
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`')
|
g.println('inc_var `$var_name`')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the position of the address to jump to (set later).
|
enum JumpOp {
|
||||||
fn (mut g Gen) jne() int {
|
je = 0x840f
|
||||||
g.write16(0x850f)
|
jne = 0x850f
|
||||||
|
jge = 0x8d0f
|
||||||
|
jle = 0x8e0f
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) cjmp(op JumpOp) int {
|
||||||
|
g.write16(u16(op))
|
||||||
pos := g.pos()
|
pos := g.pos()
|
||||||
g.write32(placeholder)
|
g.write32(placeholder)
|
||||||
g.println('jne')
|
g.println('$op')
|
||||||
return int(pos)
|
return int(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) jge() int {
|
// Returns the position of the address to jump to (set later).
|
||||||
g.write16(0x8d0f)
|
|
||||||
pos := g.pos()
|
|
||||||
g.write32(placeholder)
|
|
||||||
g.println('jne')
|
|
||||||
return int(pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) jmp(addr int) {
|
fn (mut g Gen) jmp(addr int) {
|
||||||
g.write8(0xe9)
|
g.write8(0xe9)
|
||||||
|
@ -133,7 +156,7 @@ fn abs(a i64) i64 {
|
||||||
return if a < 0 { -a } else { a }
|
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
|
// Calculate the relative offset to jump to
|
||||||
// (`addr` is absolute address)
|
// (`addr` is absolute address)
|
||||||
offset := 0xff - int(abs(addr - g.buf.len)) - 1
|
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) {
|
fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||||
branch := node.branches[0]
|
branch := node.branches[0]
|
||||||
infix_expr := branch.cond as ast.InfixExpr
|
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 {
|
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 {
|
ast.Ident {
|
||||||
lit := infix_expr.right as ast.IntegerLiteral
|
match mut infix_expr.right {
|
||||||
g.cmp_var(infix_expr.left.name, lit.val.int())
|
ast.IntegerLiteral {
|
||||||
jne_addr = g.jne()
|
// 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 {
|
else {
|
||||||
|
dump(node)
|
||||||
verror('unhandled infix.left')
|
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)
|
g.stmts(branch.stmts)
|
||||||
// Now that we know where we need to jump if the condition is false, update the `jne` call.
|
// 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
|
// The value is the relative address, difference between current position and the location
|
||||||
// after `jne 00 00 00 00`
|
// after `jne 00 00 00 00`
|
||||||
// println('after if g.pos=$g.pos() jneaddr=$jne_addr')
|
// println('after if g.pos=$g.pos() jneaddr=$cjmp_addr')
|
||||||
g.write32_at(jne_addr, int(g.pos() - jne_addr - 4)) // 4 is for "00 00 00 00"
|
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) {
|
fn (mut g Gen) for_stmt(node ast.ForStmt) {
|
||||||
|
@ -1020,7 +1099,7 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) {
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
lit := infix_expr.right as ast.IntegerLiteral
|
lit := infix_expr.right as ast.IntegerLiteral
|
||||||
g.cmp_var(infix_expr.left.name, lit.val.int())
|
g.cmp_var(infix_expr.left.name, lit.val.int())
|
||||||
jump_addr = g.jge()
|
jump_addr = g.cjmp(.jge)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
verror('unhandled infix.left')
|
verror('unhandled infix.left')
|
||||||
|
|
|
@ -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')
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
start
|
||||||
|
print_number
|
||||||
|
var(3) > 1
|
||||||
|
1 < 3
|
||||||
|
1 == 1
|
||||||
|
1 != 3
|
||||||
|
end
|
|
@ -32,20 +32,21 @@ fn test_native() {
|
||||||
for test in tests {
|
for test in tests {
|
||||||
bench.step()
|
bench.step()
|
||||||
full_test_path := os.real_path(os.join_path(dir, test))
|
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 + '/', '')
|
relative_test_path := full_test_path.replace(vroot + '/', '')
|
||||||
work_test_path := '$wrkdir/x.v'
|
work_test_path := '$wrkdir/$test_file_name'
|
||||||
os.cp(full_test_path, work_test_path) or {}
|
exe_test_path := '$wrkdir/${test_file_name}.exe'
|
||||||
cmd := '$vexe -o exe -native $work_test_path'
|
cmd := '"$vexe" -o "$exe_test_path" -b native "$full_test_path"'
|
||||||
if is_verbose {
|
if is_verbose {
|
||||||
println(cmd)
|
println(cmd)
|
||||||
}
|
}
|
||||||
res_native := os.execute(cmd)
|
res_native := os.execute(cmd)
|
||||||
if res_native.exit_code != 0 {
|
if res_native.exit_code != 0 {
|
||||||
bench.fail()
|
bench.fail()
|
||||||
eprintln(bench.step_message_fail('native $test failed'))
|
eprintln(bench.step_message_fail(cmd))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
res := os.execute('./exe')
|
res := os.execute(exe_test_path)
|
||||||
if res.exit_code != 0 {
|
if res.exit_code != 0 {
|
||||||
bench.fail()
|
bench.fail()
|
||||||
eprintln(bench.step_message_fail('$full_test_path failed to run'))
|
eprintln(bench.step_message_fail('$full_test_path failed to run'))
|
||||||
|
|
Loading…
Reference in New Issue