Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

native: implement rune type literals/printing, pointer comparison expressions and add some missing branches in functions #17839

Merged
merged 4 commits into from
Mar 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 30 additions & 7 deletions vlib/v/gen/native/amd64.v
Original file line number Diff line number Diff line change
Expand Up @@ -1521,11 +1521,16 @@ fn (mut g Gen) mul_reg(a Register, b Register) {
g.write8(0xf7)
g.write8(0xeb)
}
.rdx {
g.write8(0x48)
g.write8(0xf7)
g.write8(0xe2)
}
else {
panic('unhandled div ${a}')
panic('unhandled mul ${b}')
}
}
g.println('mul ${a}')
g.println('mul ${b}')
}

fn (mut g Gen) imul_reg(r Register) {
Expand Down Expand Up @@ -1558,11 +1563,16 @@ fn (mut g Gen) div_reg(a Register, b Register) {
g.write8(0xf7)
g.write8(0xfb) // idiv ebx
}
.rdx {
g.write8(0x48)
g.write8(0xf7)
g.write8(0xf2)
}
else {
panic('unhandled div ${a}')
panic('unhandled div ${b}')
}
}
g.println('div ${a}')
g.println('div ${b}')
}

fn (mut g Gen) mod_reg(a Register, b Register) {
Expand Down Expand Up @@ -2207,7 +2217,7 @@ fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, nam
}
ast.StringLiteral {
// TODO: use learel
str := g.eval_escape_codes(e)
str := g.eval_str_lit_escape_codes(e)
g.mov64(.rsi, g.allocate_string(str, 2, .abs64)) // for rsi its 2
g.mov_reg_to_var(LocalVar{pos, ast.u64_type_idx, ''}, .rsi)
pos += 8
Expand Down Expand Up @@ -2247,7 +2257,7 @@ fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, nam
ast.StringLiteral {
dest := g.allocate_var(name, 8, 0)
ie := right as ast.StringLiteral
str := g.eval_escape_codes(ie)
str := g.eval_str_lit_escape_codes(ie)
g.learel(.rsi, g.allocate_string(str, 3, .rel32))
g.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, .rsi)
}
Expand Down Expand Up @@ -2831,7 +2841,8 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
}
}
if node.left_type !in ast.integer_type_idxs && node.left_type != ast.bool_type_idx
&& g.table.sym(node.left_type).info !is ast.Enum {
&& g.table.sym(node.left_type).info !is ast.Enum && !node.left_type.is_ptr()
&& !node.left_type.is_voidptr() {
g.n_error('unsupported type for `${node.op}`: ${node.left_type}')
}
// left: rax, right: rdx
Expand Down Expand Up @@ -3203,6 +3214,18 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) {
.gt {
jump_addr = g.cjmp(.jle)
}
.le {
jump_addr = g.cjmp(.jg)
}
.ge {
jump_addr = g.cjmp(.jl)
}
.ne {
jump_addr = g.cjmp(.je)
}
.eq {
jump_addr = g.cjmp(.jne)
}
else {
g.n_error('unhandled infix cond token')
}
Expand Down
61 changes: 49 additions & 12 deletions vlib/v/gen/native/gen.v
Original file line number Diff line number Diff line change
Expand Up @@ -686,12 +686,15 @@ fn (mut g Gen) gen_match_expr(expr ast.MatchExpr) {
}
}

fn (mut g Gen) eval_escape_codes(str_lit ast.StringLiteral) string {
fn (mut g Gen) eval_str_lit_escape_codes(str_lit ast.StringLiteral) string {
if str_lit.is_raw {
return str_lit.val
} else {
return g.eval_escape_codes(str_lit.val)
}
}

str := str_lit.val
fn (mut g Gen) eval_escape_codes(str string) string {
mut buffer := []u8{}

mut i := 0
Expand All @@ -705,7 +708,7 @@ fn (mut g Gen) eval_escape_codes(str_lit ast.StringLiteral) string {
// skip \
i++
match str[i] {
`\\`, `'`, `"` {
`\\`, `'`, `"`, `\`` {
buffer << str[i]
i++
}
Expand Down Expand Up @@ -792,9 +795,23 @@ fn (mut g Gen) gen_to_string(reg Register, typ ast.Type) {
}
}

fn (mut g Gen) gen_var_to_string(reg Register, var Var, config VarConfig) {
fn (mut g Gen) gen_var_to_string(reg Register, expr ast.Expr, var Var, config VarConfig) {
typ := g.get_type_from_var(var)
if typ.is_int() {
if typ == ast.rune_type_idx {
buffer := g.allocate_var('rune-buffer', 8, 0)
g.lea_var_to_reg(reg, buffer)
match reg {
.rax {
g.mov_var_to_reg(.rdi, var, config)
g.write8(0x48)
g.write8(0x89)
g.write8(0x38)
}
else {
g.n_error('rune to string not implemented for ${reg}')
}
}
} else if typ.is_int() {
buffer := g.allocate_array('itoa-buffer', 1, 32) // 32 characters should be enough
g.mov_var_to_reg(g.get_builtin_arg_reg(.int_to_string, 0), var, config)
g.lea_var_to_reg(g.get_builtin_arg_reg(.int_to_string, 1), buffer)
Expand All @@ -804,7 +821,7 @@ fn (mut g Gen) gen_var_to_string(reg Register, var Var, config VarConfig) {
g.mov_var_to_reg(g.get_builtin_arg_reg(.bool_to_string, 0), var, config)
g.call_builtin(.bool_to_string)
} else if typ.is_string() {
g.mov_var_to_reg(.rax, var, config)
g.mov_var_to_reg(reg, var, config)
} else {
g.n_error('int-to-string conversion not implemented for type ${typ}')
}
Expand All @@ -815,7 +832,15 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string)
fd := if name in ['eprint', 'eprintln'] { 2 } else { 1 }
match expr {
ast.StringLiteral {
str := g.eval_escape_codes(expr)
str := g.eval_str_lit_escape_codes(expr)
if newline {
g.gen_print(str + '\n', fd)
} else {
g.gen_print(str, fd)
}
}
ast.CharLiteral {
str := g.eval_escape_codes(expr.val)
if newline {
g.gen_print(str + '\n', fd)
} else {
Expand All @@ -826,7 +851,7 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string)
vo := g.try_var_offset(expr.name)

if vo != -1 {
g.gen_var_to_string(.rax, expr as ast.Ident)
g.gen_var_to_string(.rax, expr, expr as ast.Ident)
g.gen_print_reg(.rax, -1, fd)
if newline {
g.gen_print('\n', fd)
Expand Down Expand Up @@ -1173,7 +1198,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
if node.exprs.len == 1 {
match node.exprs[0] {
ast.StringLiteral {
s = g.eval_escape_codes(node.exprs[0] as ast.StringLiteral)
s = g.eval_str_lit_escape_codes(node.exprs[0] as ast.StringLiteral)
g.expr(node.exprs[0])
g.mov64(.rax, g.allocate_string(s, 2, .abs64))
}
Expand Down Expand Up @@ -1383,7 +1408,7 @@ fn (mut g Gen) gen_syscall(node ast.CallExpr) {
if expr.field_name == 'str' {
match expr.expr {
ast.StringLiteral {
s := g.eval_escape_codes(expr.expr)
s := g.eval_str_lit_escape_codes(expr.expr)
g.allocate_string(s, 2, .abs64)
g.mov64(ra[i], 1)
done = true
Expand All @@ -1400,7 +1425,7 @@ fn (mut g Gen) gen_syscall(node ast.CallExpr) {
g.warning('C.syscall expects c"string" or "string".str, C backend will crash',
node.pos)
}
s := g.eval_escape_codes(expr)
s := g.eval_str_lit_escape_codes(expr)
g.allocate_string(s, 2, .abs64)
g.mov64(ra[i], 1)
}
Expand Down Expand Up @@ -1512,9 +1537,21 @@ fn (mut g Gen) expr(node ast.Expr) {
g.prefix_expr(node)
}
ast.StringLiteral {
str := g.eval_escape_codes(node)
str := g.eval_str_lit_escape_codes(node)
g.allocate_string(str, 3, .rel32)
}
ast.CharLiteral {
bytes := g.eval_escape_codes(node.val)
.bytes()
mut val := rune(0)
for i, v in bytes {
val |= v << (i * 8)
if i >= sizeof(rune) {
g.n_error('runes are only 4 bytes wide')
}
}
g.movabs(.rax, i64(val))
}
ast.StructInit {
pos := g.allocate_by_type('_anonstruct', node.typ)
g.init_struct(LocalVar{ offset: pos, typ: node.typ }, node)
Expand Down
68 changes: 68 additions & 0 deletions vlib/v/gen/native/tests/pointers.vv
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
fn main() {
test_eq_ne()
test_lt_gt()
test_ref_deref()
println("ok")
}

fn test_eq_ne() {
unsafe {
mut a := voidptr(0)
mut b := voidptr(0)
assert a == a
assert !(a != a)
assert a == b
assert !(a != b)

a = voidptr(0xdeadbeef)
assert a != b
assert !(a == b)

b = voidptr(0xdeadbeef)
assert a == b
assert !(a != b)
}
}

fn test_lt_gt() {
unsafe {
mut a := voidptr(0)
mut b := voidptr(1)

assert !(a < a)
assert !(a > a)
assert a >= a
assert a <= a

assert a < b
assert !(a > b)
assert a <= b
assert !(a >= b)

a = voidptr(0x42)
assert a > b
assert a >= b
assert !(a < b)
assert !(a <= b)

b = voidptr(0x42)
assert a >= b
assert a <= b
assert !(a > b)
assert !(a < b)
}
}

fn test_ref_deref() {
mut a := 42
b := &a
c := &b

assert *b == 42

a = 50
assert *b == 50

assert *c == b
assert **c == *b
}
1 change: 1 addition & 0 deletions vlib/v/gen/native/tests/pointers.vv.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ok
17 changes: 17 additions & 0 deletions vlib/v/gen/native/tests/string.vv
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,25 @@ fn test_raw_string() {
println(raw)
}

fn test_runes() {
mut a := `V`
println(a)

a = `😀`
println(a)

rocket := `🚀`
println(rocket)

// should all print `★`
print(`\u2605`)
print(`\xe2\x98\x85`)
println(`\xe2\x98\x85`)
}

fn main() {
test_unicode_characters()
test_escape_codes()
test_raw_string()
test_runes()
}
6 changes: 5 additions & 1 deletion vlib/v/gen/native/tests/string.vv.out
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@
aaa
## #
### #
hello\tworld\n
hello\tworld\n
V
😀
🚀
★★★