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) }
|
||||
else { panic('unhandled inc $reg') }
|
||||
}
|
||||
g.println('dec $reg')
|
||||
}
|
||||
|
||||
fn (mut g Gen) inc(reg Register) {
|
||||
|
@ -58,23 +59,45 @@ 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') }
|
||||
}
|
||||
match size {
|
||||
._8 {
|
||||
g.write8(int(val))
|
||||
}
|
||||
._32 {
|
||||
g.write32(int(val))
|
||||
}
|
||||
else {
|
||||
panic('unhandled cmp')
|
||||
}
|
||||
}
|
||||
g.println('cmp $reg, $val')
|
||||
}
|
||||
|
||||
/*
|
||||
rax // 0
|
||||
|
@ -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 {
|
||||
lit := infix_expr.right as ast.IntegerLiteral
|
||||
g.cmp_var(infix_expr.left.name, lit.val.int())
|
||||
jne_addr = g.jne()
|
||||
// 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 {
|
||||
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')
|
||||
|
|
|
@ -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 {
|
||||
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'))
|
||||
|
|
Loading…
Reference in New Issue