mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
native: support ||
, &&
and simple boolean expression evaluation (#15256)
This commit is contained in:
parent
04b28d11be
commit
927ec1fadb
@ -120,6 +120,9 @@ fn (mut g Gen) cmp_reg(reg Register, reg2 Register) {
|
||||
match reg {
|
||||
.rax {
|
||||
match reg2 {
|
||||
.rdx {
|
||||
g.write([u8(0x48), 0x39, 0xd0])
|
||||
}
|
||||
.rbx {
|
||||
g.write([u8(0x48), 0x39, 0xd8])
|
||||
}
|
||||
@ -128,6 +131,16 @@ fn (mut g Gen) cmp_reg(reg Register, reg2 Register) {
|
||||
}
|
||||
}
|
||||
}
|
||||
.rdx {
|
||||
match reg2 {
|
||||
.rax {
|
||||
g.write([u8(0x48), 0x39, 0xc2])
|
||||
}
|
||||
else {
|
||||
g.n_error('Cannot compare $reg and $reg2')
|
||||
}
|
||||
}
|
||||
}
|
||||
.rbx {
|
||||
match reg2 {
|
||||
.rax {
|
||||
@ -309,7 +322,7 @@ enum JumpOp {
|
||||
jne = 0x850f
|
||||
jg = 0x8f0f
|
||||
jge = 0x8d0f
|
||||
lt = 0x8c0f
|
||||
jl = 0x8c0f
|
||||
jle = 0x8e0f
|
||||
}
|
||||
|
||||
@ -330,6 +343,22 @@ fn (mut g Gen) jmp(addr int) int {
|
||||
return int(pos)
|
||||
}
|
||||
|
||||
enum SetOp {
|
||||
e = 0x940f
|
||||
ne = 0x950f
|
||||
g = 0x9f0f
|
||||
ge = 0x9d0f
|
||||
l = 0x9c0f
|
||||
le = 0x9e0f
|
||||
}
|
||||
|
||||
// SETcc al
|
||||
fn (mut g Gen) cset(op SetOp) {
|
||||
g.write16(u16(op))
|
||||
g.write8(0xc0)
|
||||
g.println('set$op al')
|
||||
}
|
||||
|
||||
fn abs(a i64) i64 {
|
||||
return if a < 0 { -a } else { a }
|
||||
}
|
||||
@ -486,7 +515,7 @@ fn (mut g Gen) mov_reg_to_var(var Var, reg Register, config VarConfig) {
|
||||
g.write16(0x8966)
|
||||
'WORD'
|
||||
}
|
||||
ast.i8_type_idx, ast.u8_type_idx, ast.char_type_idx {
|
||||
ast.i8_type_idx, ast.u8_type_idx, ast.char_type_idx, ast.bool_type_idx {
|
||||
g.write8(0x88)
|
||||
'BYTE'
|
||||
}
|
||||
@ -634,7 +663,7 @@ fn (mut g Gen) mov_var_to_reg(reg Register, var Var, config VarConfig) {
|
||||
g.write([u8(0x48), 0x0f, 0xbe])
|
||||
'movsx', 'BYTE'
|
||||
}
|
||||
ast.u8_type_idx, ast.char_type_idx {
|
||||
ast.u8_type_idx, ast.char_type_idx, ast.bool_type_idx {
|
||||
// movzx rax, BYTE PTR [rbp-0x8]
|
||||
g.write([u8(0x48), 0x0f, 0xb6])
|
||||
'movzx', 'BYTE'
|
||||
@ -1664,32 +1693,96 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
||||
}
|
||||
else {
|
||||
// dump(node)
|
||||
g.v_error('unhandled assign_stmt expression: $right.type_name()', right.pos())
|
||||
size := g.get_type_size(node.left_types[i])
|
||||
if size !in [1, 2, 4, 8] || node.op !in [.assign, .decl_assign] {
|
||||
g.v_error('unhandled assign_stmt expression: $right.type_name()',
|
||||
right.pos())
|
||||
}
|
||||
if node.op == .decl_assign {
|
||||
g.allocate_var(name, size, 0)
|
||||
}
|
||||
g.expr(right)
|
||||
var := g.get_var_from_ident(ident)
|
||||
match var {
|
||||
LocalVar { g.mov_reg_to_var(var as LocalVar, .rax) }
|
||||
GlobalVar { g.mov_reg_to_var(var as GlobalVar, .rax) }
|
||||
Register { g.mov_reg(var as Register, .rax) }
|
||||
}
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||
// TODO
|
||||
if node.left is ast.InfixExpr {
|
||||
g.n_error('only simple expressions are supported right now (not more than 2 operands)')
|
||||
}
|
||||
match node.left {
|
||||
ast.Ident {
|
||||
g.mov_var_to_reg(.eax, node.left as ast.Ident)
|
||||
fn (mut g Gen) cset_op(op token.Kind) {
|
||||
match op {
|
||||
.gt {
|
||||
g.cset(.g)
|
||||
}
|
||||
.lt {
|
||||
g.cset(.l)
|
||||
}
|
||||
.ne {
|
||||
g.cset(.ne)
|
||||
}
|
||||
.eq {
|
||||
g.cset(.e)
|
||||
}
|
||||
.ge {
|
||||
g.cset(.ge)
|
||||
}
|
||||
.le {
|
||||
g.cset(.le)
|
||||
}
|
||||
else {
|
||||
g.cset(.ne)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
if node.right is ast.Ident {
|
||||
var_offset := g.get_var_offset(node.right.name)
|
||||
match node.op {
|
||||
.plus { g.add8_var(.eax, var_offset) }
|
||||
.mul { g.mul8_var(.eax, var_offset) }
|
||||
.div { g.div8_var(.eax, var_offset) }
|
||||
.minus { g.sub8_var(.eax, var_offset) }
|
||||
else {}
|
||||
}
|
||||
|
||||
fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||
if node.left is ast.Ident && node.right is ast.Ident {
|
||||
left := node.left as ast.Ident
|
||||
right := node.right as ast.Ident
|
||||
g.mov_var_to_reg(.eax, left)
|
||||
var_offset := g.get_var_offset(right.name)
|
||||
for {
|
||||
match node.op {
|
||||
.plus { g.add8_var(.eax, var_offset) }
|
||||
.mul { g.mul8_var(.eax, var_offset) }
|
||||
.div { g.div8_var(.eax, var_offset) }
|
||||
.minus { g.sub8_var(.eax, var_offset) }
|
||||
else { break }
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
g.expr(node.left)
|
||||
mut label := 0
|
||||
g.push(.rax)
|
||||
if node.op in [.logical_or, .and] {
|
||||
label = g.labels.new_label()
|
||||
g.cmp_zero(.rax)
|
||||
jump_addr := g.cjmp(if node.op == .logical_or { .jne } else { .je })
|
||||
g.labels.patches << LabelPatch{
|
||||
id: label
|
||||
pos: jump_addr
|
||||
}
|
||||
}
|
||||
g.expr(node.right)
|
||||
g.pop(.rdx)
|
||||
// left: rdx, right: rax
|
||||
match node.op {
|
||||
.logical_or, .and {
|
||||
g.labels.addrs[label] = g.pos()
|
||||
}
|
||||
.eq, .ne, .gt, .lt, .ge, .le {
|
||||
g.cmp_reg(.rdx, .rax)
|
||||
g.mov64(.rax, 0)
|
||||
g.cset_op(node.op)
|
||||
}
|
||||
else {
|
||||
g.n_error('`$node.op` expression is not supported right now')
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1870,7 +1963,7 @@ fn (mut g Gen) cjmp_op(op token.Kind) int {
|
||||
g.cjmp(.jg)
|
||||
}
|
||||
.lt {
|
||||
g.cjmp(.lt)
|
||||
g.cjmp(.jl)
|
||||
}
|
||||
.ne {
|
||||
g.cjmp(.jne)
|
||||
@ -1884,7 +1977,13 @@ fn (mut g Gen) cjmp_op(op token.Kind) int {
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) condition(infix_expr ast.InfixExpr, neg bool) int {
|
||||
fn (mut g Gen) condition(expr ast.Expr, neg bool) int {
|
||||
// if infix_expr.op !in [.eq, .ne, .gt, .lt, .ge, .le] {
|
||||
g.expr(expr)
|
||||
g.cmp_zero(.rax)
|
||||
return g.cjmp(if neg { .jne } else { .je })
|
||||
//}
|
||||
/*
|
||||
match infix_expr.left {
|
||||
ast.IntegerLiteral {
|
||||
match infix_expr.right {
|
||||
@ -1933,7 +2032,7 @@ fn (mut g Gen) condition(infix_expr ast.InfixExpr, neg bool) int {
|
||||
}
|
||||
|
||||
// mut cjmp_addr := 0 // location of `jne *00 00 00 00*`
|
||||
return if neg { g.cjmp_op(infix_expr.op) } else { g.cjmp_notop(infix_expr.op) }
|
||||
return if neg { g.cjmp_op(infix_expr.op) } else { g.cjmp_notop(infix_expr.op) }*/
|
||||
}
|
||||
|
||||
fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||
@ -1959,9 +2058,9 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||
}
|
||||
continue
|
||||
}
|
||||
infix_expr := branch.cond as ast.InfixExpr
|
||||
expr := branch.cond
|
||||
label := g.labels.new_label()
|
||||
cjmp_addr := g.condition(infix_expr, false)
|
||||
cjmp_addr := g.condition(expr, false)
|
||||
g.labels.patches << LabelPatch{
|
||||
id: label
|
||||
pos: cjmp_addr
|
||||
|
@ -416,8 +416,11 @@ fn (mut g Gen) get_type_size(typ ast.Type) int {
|
||||
if typ in ast.pointer_type_idxs {
|
||||
return 8
|
||||
}
|
||||
if typ == ast.bool_type_idx {
|
||||
return 1
|
||||
}
|
||||
// g.n_error('unknown type size')
|
||||
return 8
|
||||
return 0
|
||||
}
|
||||
|
||||
fn (mut g Gen) get_sizeof_ident(ident ast.Ident) int {
|
||||
@ -853,28 +856,33 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
// dump(node.types)
|
||||
mut s := '?' //${node.exprs[0].val.str()}'
|
||||
// TODO: void return
|
||||
e0 := node.exprs[0]
|
||||
match e0 {
|
||||
ast.IntegerLiteral {
|
||||
g.mov64(.rax, e0.val.int())
|
||||
}
|
||||
ast.InfixExpr {
|
||||
g.infix_expr(e0)
|
||||
}
|
||||
ast.CastExpr {
|
||||
g.mov64(.rax, e0.expr.str().int())
|
||||
// do the job
|
||||
}
|
||||
ast.StringLiteral {
|
||||
s = e0.val.str()
|
||||
g.expr(node.exprs[0])
|
||||
g.mov64(.rax, g.allocate_string(s, 2, .abs64))
|
||||
}
|
||||
ast.Ident {
|
||||
g.expr(e0)
|
||||
}
|
||||
else {
|
||||
g.n_error('unknown return type $e0.type_name()')
|
||||
if e0 := node.exprs[0] {
|
||||
match e0 {
|
||||
ast.IntegerLiteral {
|
||||
g.mov64(.rax, e0.val.int())
|
||||
}
|
||||
ast.InfixExpr {
|
||||
g.infix_expr(e0)
|
||||
}
|
||||
ast.CastExpr {
|
||||
g.mov64(.rax, e0.expr.str().int())
|
||||
// do the job
|
||||
}
|
||||
ast.StringLiteral {
|
||||
s = e0.val.str()
|
||||
g.expr(node.exprs[0])
|
||||
g.mov64(.rax, g.allocate_string(s, 2, .abs64))
|
||||
}
|
||||
ast.Ident {
|
||||
g.expr(e0)
|
||||
}
|
||||
else {
|
||||
size := g.get_type_size(node.types[0])
|
||||
if size !in [1, 2, 4, 8] {
|
||||
g.n_error('unknown return type $e0.type_name()')
|
||||
}
|
||||
g.expr(e0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -965,7 +973,6 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||
}
|
||||
ast.BoolLiteral {
|
||||
g.mov64(.rax, if node.val { 1 } else { 0 })
|
||||
eprintln('bool literal')
|
||||
}
|
||||
ast.CallExpr {
|
||||
if node.name == 'C.syscall' {
|
||||
|
@ -4,6 +4,10 @@ fn print_number(n int) {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_bool() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
fn test_add() {
|
||||
n := 3
|
||||
print_number(0)
|
||||
@ -11,14 +15,12 @@ fn test_add() {
|
||||
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')
|
||||
}
|
||||
@ -38,6 +40,14 @@ fn test_add() {
|
||||
println('1 > 3 ERROR')
|
||||
// TODO assert here
|
||||
}
|
||||
if get_bool() {
|
||||
println('bool is true')
|
||||
}
|
||||
}
|
||||
|
||||
fn do_not_call() bool {
|
||||
println('must not be called ERROR')
|
||||
return false
|
||||
}
|
||||
|
||||
fn test_elses() {
|
||||
@ -55,9 +65,45 @@ fn test_elses() {
|
||||
println('end else')
|
||||
}
|
||||
|
||||
fn test_logic_op() {
|
||||
a := true
|
||||
b := false
|
||||
if a && a {
|
||||
println('true && true')
|
||||
}
|
||||
if a && b {
|
||||
println('true && false ERROR')
|
||||
}
|
||||
if b && a {
|
||||
println('false && true ERROR')
|
||||
}
|
||||
if b && b {
|
||||
println('false && false ERROR')
|
||||
}
|
||||
if a || a {
|
||||
println('true || true')
|
||||
}
|
||||
if a || b {
|
||||
println('true || false')
|
||||
}
|
||||
if b || a {
|
||||
println('false || true')
|
||||
}
|
||||
if b || b {
|
||||
println('false || false ERROR')
|
||||
}
|
||||
if b && do_not_call() {
|
||||
println('call ERROR')
|
||||
}
|
||||
if a || do_not_call() {
|
||||
println('short circuit evaluation')
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println('start')
|
||||
test_add()
|
||||
test_elses()
|
||||
test_logic_op()
|
||||
println('end')
|
||||
}
|
||||
|
@ -1,11 +1,18 @@
|
||||
start
|
||||
print_number
|
||||
var(3) > 1
|
||||
1 < var(3)
|
||||
1 < 3
|
||||
1 == 1
|
||||
1 != 3
|
||||
bool is true
|
||||
start else
|
||||
ok
|
||||
ok
|
||||
end else
|
||||
true && true
|
||||
true || true
|
||||
true || false
|
||||
false || true
|
||||
short circuit evaluation
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user