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 {
|
match reg {
|
||||||
.rax {
|
.rax {
|
||||||
match reg2 {
|
match reg2 {
|
||||||
|
.rdx {
|
||||||
|
g.write([u8(0x48), 0x39, 0xd0])
|
||||||
|
}
|
||||||
.rbx {
|
.rbx {
|
||||||
g.write([u8(0x48), 0x39, 0xd8])
|
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 {
|
.rbx {
|
||||||
match reg2 {
|
match reg2 {
|
||||||
.rax {
|
.rax {
|
||||||
@ -309,7 +322,7 @@ enum JumpOp {
|
|||||||
jne = 0x850f
|
jne = 0x850f
|
||||||
jg = 0x8f0f
|
jg = 0x8f0f
|
||||||
jge = 0x8d0f
|
jge = 0x8d0f
|
||||||
lt = 0x8c0f
|
jl = 0x8c0f
|
||||||
jle = 0x8e0f
|
jle = 0x8e0f
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,6 +343,22 @@ fn (mut g Gen) jmp(addr int) int {
|
|||||||
return int(pos)
|
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 {
|
fn abs(a i64) i64 {
|
||||||
return if a < 0 { -a } else { a }
|
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)
|
g.write16(0x8966)
|
||||||
'WORD'
|
'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)
|
g.write8(0x88)
|
||||||
'BYTE'
|
'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])
|
g.write([u8(0x48), 0x0f, 0xbe])
|
||||||
'movsx', 'BYTE'
|
'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]
|
// movzx rax, BYTE PTR [rbp-0x8]
|
||||||
g.write([u8(0x48), 0x0f, 0xb6])
|
g.write([u8(0x48), 0x0f, 0xb6])
|
||||||
'movzx', 'BYTE'
|
'movzx', 'BYTE'
|
||||||
@ -1664,32 +1693,96 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// dump(node)
|
// 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) {
|
fn (mut g Gen) cset_op(op token.Kind) {
|
||||||
// TODO
|
match op {
|
||||||
if node.left is ast.InfixExpr {
|
.gt {
|
||||||
g.n_error('only simple expressions are supported right now (not more than 2 operands)')
|
g.cset(.g)
|
||||||
}
|
}
|
||||||
match node.left {
|
.lt {
|
||||||
ast.Ident {
|
g.cset(.l)
|
||||||
g.mov_var_to_reg(.eax, node.left as ast.Ident)
|
}
|
||||||
|
.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 {
|
fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||||
.plus { g.add8_var(.eax, var_offset) }
|
if node.left is ast.Ident && node.right is ast.Ident {
|
||||||
.mul { g.mul8_var(.eax, var_offset) }
|
left := node.left as ast.Ident
|
||||||
.div { g.div8_var(.eax, var_offset) }
|
right := node.right as ast.Ident
|
||||||
.minus { g.sub8_var(.eax, var_offset) }
|
g.mov_var_to_reg(.eax, left)
|
||||||
else {}
|
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)
|
g.cjmp(.jg)
|
||||||
}
|
}
|
||||||
.lt {
|
.lt {
|
||||||
g.cjmp(.lt)
|
g.cjmp(.jl)
|
||||||
}
|
}
|
||||||
.ne {
|
.ne {
|
||||||
g.cjmp(.jne)
|
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 {
|
match infix_expr.left {
|
||||||
ast.IntegerLiteral {
|
ast.IntegerLiteral {
|
||||||
match infix_expr.right {
|
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*`
|
// 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) {
|
fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||||
@ -1959,9 +2058,9 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
infix_expr := branch.cond as ast.InfixExpr
|
expr := branch.cond
|
||||||
label := g.labels.new_label()
|
label := g.labels.new_label()
|
||||||
cjmp_addr := g.condition(infix_expr, false)
|
cjmp_addr := g.condition(expr, false)
|
||||||
g.labels.patches << LabelPatch{
|
g.labels.patches << LabelPatch{
|
||||||
id: label
|
id: label
|
||||||
pos: cjmp_addr
|
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 {
|
if typ in ast.pointer_type_idxs {
|
||||||
return 8
|
return 8
|
||||||
}
|
}
|
||||||
|
if typ == ast.bool_type_idx {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
// g.n_error('unknown type size')
|
// g.n_error('unknown type size')
|
||||||
return 8
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) get_sizeof_ident(ident ast.Ident) int {
|
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)
|
// dump(node.types)
|
||||||
mut s := '?' //${node.exprs[0].val.str()}'
|
mut s := '?' //${node.exprs[0].val.str()}'
|
||||||
// TODO: void return
|
// TODO: void return
|
||||||
e0 := node.exprs[0]
|
if e0 := node.exprs[0] {
|
||||||
match e0 {
|
match e0 {
|
||||||
ast.IntegerLiteral {
|
ast.IntegerLiteral {
|
||||||
g.mov64(.rax, e0.val.int())
|
g.mov64(.rax, e0.val.int())
|
||||||
}
|
}
|
||||||
ast.InfixExpr {
|
ast.InfixExpr {
|
||||||
g.infix_expr(e0)
|
g.infix_expr(e0)
|
||||||
}
|
}
|
||||||
ast.CastExpr {
|
ast.CastExpr {
|
||||||
g.mov64(.rax, e0.expr.str().int())
|
g.mov64(.rax, e0.expr.str().int())
|
||||||
// do the job
|
// do the job
|
||||||
}
|
}
|
||||||
ast.StringLiteral {
|
ast.StringLiteral {
|
||||||
s = e0.val.str()
|
s = e0.val.str()
|
||||||
g.expr(node.exprs[0])
|
g.expr(node.exprs[0])
|
||||||
g.mov64(.rax, g.allocate_string(s, 2, .abs64))
|
g.mov64(.rax, g.allocate_string(s, 2, .abs64))
|
||||||
}
|
}
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
g.expr(e0)
|
g.expr(e0)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
g.n_error('unknown return type $e0.type_name()')
|
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 {
|
ast.BoolLiteral {
|
||||||
g.mov64(.rax, if node.val { 1 } else { 0 })
|
g.mov64(.rax, if node.val { 1 } else { 0 })
|
||||||
eprintln('bool literal')
|
|
||||||
}
|
}
|
||||||
ast.CallExpr {
|
ast.CallExpr {
|
||||||
if node.name == 'C.syscall' {
|
if node.name == 'C.syscall' {
|
||||||
|
@ -4,6 +4,10 @@ fn print_number(n int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_bool() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
fn test_add() {
|
fn test_add() {
|
||||||
n := 3
|
n := 3
|
||||||
print_number(0)
|
print_number(0)
|
||||||
@ -11,14 +15,12 @@ fn test_add() {
|
|||||||
if n > 1 {
|
if n > 1 {
|
||||||
println('var(3) > 1')
|
println('var(3) > 1')
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
if 1 < n {
|
if 1 < n {
|
||||||
println('1 < var(3)')
|
println('1 < var(3)')
|
||||||
}
|
}
|
||||||
if 1 > n {
|
if 1 > n {
|
||||||
println('1 > 3 ERROR')
|
println('1 > 3 ERROR')
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
if 1 < 3 {
|
if 1 < 3 {
|
||||||
println('1 < 3')
|
println('1 < 3')
|
||||||
}
|
}
|
||||||
@ -38,6 +40,14 @@ fn test_add() {
|
|||||||
println('1 > 3 ERROR')
|
println('1 > 3 ERROR')
|
||||||
// TODO assert here
|
// 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() {
|
fn test_elses() {
|
||||||
@ -55,9 +65,45 @@ fn test_elses() {
|
|||||||
println('end else')
|
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() {
|
fn main() {
|
||||||
println('start')
|
println('start')
|
||||||
test_add()
|
test_add()
|
||||||
test_elses()
|
test_elses()
|
||||||
|
test_logic_op()
|
||||||
println('end')
|
println('end')
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,18 @@
|
|||||||
start
|
start
|
||||||
print_number
|
print_number
|
||||||
var(3) > 1
|
var(3) > 1
|
||||||
|
1 < var(3)
|
||||||
1 < 3
|
1 < 3
|
||||||
1 == 1
|
1 == 1
|
||||||
1 != 3
|
1 != 3
|
||||||
|
bool is true
|
||||||
start else
|
start else
|
||||||
ok
|
ok
|
||||||
ok
|
ok
|
||||||
end else
|
end else
|
||||||
|
true && true
|
||||||
|
true || true
|
||||||
|
true || false
|
||||||
|
false || true
|
||||||
|
short circuit evaluation
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user