v.gen.native: add support for assert statements for amd64 (#11117)

pull/11127/head
pancake 2021-08-10 09:29:44 +02:00 committed by GitHub
parent 1588fe7967
commit e7b8cf17e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 99 additions and 31 deletions

View File

@ -1901,7 +1901,7 @@ pub fn (mut lx IndexExpr) recursive_mapset_is_setter(val bool) {
} }
} }
// return all the registers for a give architecture // return all the registers for the given architecture
pub fn all_registers(mut t Table, arch pref.Arch) map[string]ScopeObject { pub fn all_registers(mut t Table, arch pref.Arch) map[string]ScopeObject {
mut res := map[string]ScopeObject{} mut res := map[string]ScopeObject{}
match arch { match arch {

View File

@ -2,6 +2,7 @@ module native
import term import term
import v.ast import v.ast
import v.token
pub struct Amd64 { pub struct Amd64 {
mut: mut:
@ -132,7 +133,9 @@ fn (mut g Gen) inc_var(var_name string) {
enum JumpOp { enum JumpOp {
je = 0x840f je = 0x840f
jne = 0x850f jne = 0x850f
jg = 0x8f0f
jge = 0x8d0f jge = 0x8d0f
lt = 0x8c0f
jle = 0x8e0f jle = 0x8e0f
} }
@ -907,8 +910,6 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
} }
ast.StructInit { ast.StructInit {
sym := g.table.get_type_symbol(right.typ) sym := g.table.get_type_symbol(right.typ)
// println(sym)
// println(typeof(sym.info))
info := sym.info as ast.Struct info := sym.info as ast.Struct
for field in info.fields { for field in info.fields {
field_name := name + '.' + field.name field_name := name + '.' + field.name
@ -1012,10 +1013,70 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
} }
} }
fn (mut g Gen) if_expr(node ast.IfExpr) { fn (mut g Gen) trap() {
branch := node.branches[0] // funnily works on x86 and arm64
infix_expr := branch.cond as ast.InfixExpr g.write32(0xcccccccc)
mut cjmp_addr := 0 // location of `jne *00 00 00 00*` g.println('trap')
}
fn (mut g Gen) gen_assert(assert_node ast.AssertStmt) {
mut cjmp_addr := 0
mut ine := ast.InfixExpr{}
ane := assert_node.expr
if ane is ast.ParExpr { // assert(1==1)
ine = ane.expr as ast.InfixExpr
} else if ane is ast.InfixExpr { // assert 1==1
ine = ane
} else {
verror('Unsupported expression in assert')
}
cjmp_addr = g.condition(ine, true)
g.expr(assert_node.expr)
g.trap()
g.write32_at(cjmp_addr, int(g.pos() - cjmp_addr - 4)) // 4 is for "00 00 00 00"
}
fn (mut g Gen) cjmp_notop(op token.Kind) int {
return match op {
.gt {
g.cjmp(.jle)
}
.lt {
g.cjmp(.jge)
}
.ne {
g.cjmp(.je)
}
.eq {
g.cjmp(.jne)
}
else {
g.cjmp(.je)
}
}
}
fn (mut g Gen) cjmp_op(op token.Kind) int {
return match op {
.gt {
g.cjmp(.jg)
}
.lt {
g.cjmp(.lt)
}
.ne {
g.cjmp(.jne)
}
.eq {
g.cjmp(.je)
}
else {
g.cjmp(.jne)
}
}
}
fn (mut g Gen) condition(infix_expr ast.InfixExpr, neg bool) int {
match mut infix_expr.left { match mut infix_expr.left {
ast.IntegerLiteral { ast.IntegerLiteral {
match mut infix_expr.right { match mut infix_expr.right {
@ -1057,27 +1118,19 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
} }
} }
else { else {
dump(node) dump(infix_expr)
verror('unhandled infix.left') verror('unhandled infix.left')
} }
} }
cjmp_addr = match infix_expr.op {
.gt { // mut cjmp_addr := 0 // location of `jne *00 00 00 00*`
g.cjmp(.jle) return if neg { g.cjmp_op(infix_expr.op) } else { g.cjmp_notop(infix_expr.op) }
}
.lt {
g.cjmp(.jge)
}
.ne {
g.cjmp(.je)
}
.eq {
g.cjmp(.jne)
}
else {
g.cjmp(.je)
}
} }
fn (mut g Gen) if_expr(node ast.IfExpr) {
branch := node.branches[0]
infix_expr := branch.cond as ast.InfixExpr
cjmp_addr := g.condition(infix_expr, false)
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

View File

@ -12,7 +12,7 @@ import v.errors
import v.pref import v.pref
import term import term
pub const builtins = ['print', 'eprint', 'println', 'eprintln', 'exit'] pub const builtins = ['assert', 'print', 'eprint', 'println', 'eprintln', 'exit']
interface CodeGen { interface CodeGen {
mut: mut:
@ -369,6 +369,9 @@ fn (mut g Gen) stmt(node ast.Stmt) {
g.pop(.rbp) g.pop(.rbp)
g.ret() g.ret()
} }
ast.AssertStmt {
g.gen_assert(node)
}
ast.StructDecl {} ast.StructDecl {}
else { else {
println('native.stmt(): bad node: ' + node.type_name()) println('native.stmt(): bad node: ' + node.type_name())
@ -380,6 +383,9 @@ fn C.strtol(str &char, endptr &&char, base int) int
fn (mut g Gen) expr(node ast.Expr) { fn (mut g Gen) expr(node ast.Expr) {
match node { match node {
ast.ParExpr {
g.expr(node.expr)
}
ast.ArrayInit { ast.ArrayInit {
verror('array init expr not supported yet') verror('array init expr not supported yet')
} }
@ -387,15 +393,13 @@ fn (mut g Gen) expr(node ast.Expr) {
ast.CallExpr { ast.CallExpr {
if node.name == 'exit' { if node.name == 'exit' {
g.gen_exit(node.args[0].expr) g.gen_exit(node.args[0].expr)
return } else if node.name in ['println', 'print', 'eprintln', 'eprint'] {
}
if node.name in ['println', 'print', 'eprintln', 'eprint'] {
expr := node.args[0].expr expr := node.args[0].expr
g.gen_print_from_expr(expr, node.name) g.gen_print_from_expr(expr, node.name)
return } else {
}
g.call_fn(node) g.call_fn(node)
} }
}
ast.FloatLiteral {} ast.FloatLiteral {}
ast.Ident {} ast.Ident {}
ast.IfExpr { ast.IfExpr {

View File

@ -0,0 +1,10 @@
fn main() {
assert 1 == 1
assert 3 == 3
assert 1 == 1
assert 3 == 3
if 1 == 2 {
assert 1 == 2
}
println('assert pass')
}

View File

@ -0,0 +1 @@
assert pass