Skip to content

Commit d78dfab

Browse files
authored
native: support casting integer to/from enum values (#15928)
1 parent d694a26 commit d78dfab

File tree

4 files changed

+60
-18
lines changed

4 files changed

+60
-18
lines changed

vlib/v/gen/native/amd64.v

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,35 @@ fn (mut g Gen) mov_var_to_reg(reg Register, var Var, config VarConfig) {
807807
}
808808
}
809809

810+
fn (mut g Gen) mov_extend_reg(a Register, b Register, typ ast.Type) {
811+
size := g.get_type_size(typ)
812+
is_signed := !typ.is_real_pointer() && typ.is_signed()
813+
814+
if size in [1, 2, 4] {
815+
if size == 4 && !is_signed {
816+
g.write8(0x40 + if int(a) >= int(Register.r8) { 1 } else { 0 } +
817+
if int(b) >= int(Register.r8) { 4 } else { 0 })
818+
g.write8(0x89)
819+
} else {
820+
g.write8(0x48 + if int(a) >= int(Register.r8) { 1 } else { 0 } +
821+
if int(b) >= int(Register.r8) { 4 } else { 0 })
822+
if size in [1, 2] {
823+
g.write8(0x0f)
824+
}
825+
g.write8(match true {
826+
size == 1 && is_signed { 0xbe }
827+
size == 1 && !is_signed { 0xb6 }
828+
size == 2 && is_signed { 0xbf }
829+
size == 2 && !is_signed { 0xb7 }
830+
else { 0x63 }
831+
})
832+
}
833+
g.write8(0xc0 + int(a) % 8 * 8 + int(b) % 8)
834+
instruction := if is_signed { 's' } else { 'z' }
835+
g.println('mov${instruction}x $a, $b')
836+
}
837+
}
838+
810839
fn (mut g Gen) call_addr_at(addr int, at i64) i64 {
811840
// Need to calculate the difference between current position (position after the e8 call)
812841
// and the function to call.
@@ -2135,20 +2164,6 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
21352164
ast.GoExpr {
21362165
g.v_error('threads not implemented for the native backend', node.pos)
21372166
}
2138-
ast.CastExpr {
2139-
g.warning('cast expressions are work in progress', right.pos)
2140-
match right.typname {
2141-
'u64' {
2142-
g.allocate_var(name, 8, right.expr.str().int())
2143-
}
2144-
'int' {
2145-
g.allocate_var(name, 4, right.expr.str().int())
2146-
}
2147-
else {
2148-
g.v_error('unsupported cast type $right.typ', node.pos)
2149-
}
2150-
}
2151-
}
21522167
ast.FloatLiteral {
21532168
g.v_error('floating point arithmetic not yet implemented for the native backend',
21542169
node.pos)

vlib/v/gen/native/gen.v

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,10 +1086,6 @@ fn (mut g Gen) stmt(node ast.Stmt) {
10861086
mut s := '?' //${node.exprs[0].val.str()}'
10871087
if e0 := node.exprs[0] {
10881088
match e0 {
1089-
ast.CastExpr {
1090-
g.mov64(.rax, e0.expr.str().int())
1091-
// do the job
1092-
}
10931089
ast.StringLiteral {
10941090
s = g.eval_escape_codes(e0)
10951091
g.expr(node.exprs[0])
@@ -1326,6 +1322,10 @@ fn (mut g Gen) expr(node ast.Expr) {
13261322
g.add(.rax, offset)
13271323
g.mov_deref(.rax, .rax, node.typ)
13281324
}
1325+
ast.CastExpr {
1326+
g.expr(node.expr)
1327+
g.mov_extend_reg(.rax, .rax, node.typ)
1328+
}
13291329
ast.EnumVal {
13301330
type_name := g.table.get_type_name(node.typ)
13311331
g.mov(.rax, g.enum_vals[type_name].fields[node.val])

vlib/v/gen/native/tests/enum.vv

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,30 @@ fn test_enum_variant_and_method_name_clash() {
4747
x.baz()
4848
}
4949

50+
enum Value {
51+
a
52+
b
53+
c = 5 * 3
54+
d
55+
e = 3
56+
}
57+
58+
fn value_test() {
59+
assert int(Value.a) == 0
60+
assert int(Value.b) == 1
61+
assert int(Value.c) == 15
62+
assert int(Value.d) == 16
63+
assert int(Value.e) == 3
64+
assert Value.a == Value(0)
65+
assert Value.b == Value(1)
66+
assert Value.c == Value(15)
67+
assert Value.d == Value(16)
68+
assert Value.e == Value(3)
69+
}
70+
5071
fn main() {
72+
enum_test()
73+
match_test()
74+
test_enum_variant_and_method_name_clash()
75+
value_test()
5176
}

vlib/v/gen/native/tests/general.vv

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ fn cast_test() {
33
assert a == 1
44
b := u64(2)
55
assert b == 2
6+
c := int(u8(i64(u64(i16(4)))))
7+
assert c == 4
68
}
79

810
fn if_test() {

0 commit comments

Comments
 (0)