Skip to content

Commit 5376a55

Browse files
authored
native: add support for enums of different types (#23786)
1 parent ffdc1ab commit 5376a55

File tree

9 files changed

+306
-144
lines changed

9 files changed

+306
-144
lines changed

vlib/v/gen/native/amd64.v

Lines changed: 106 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -532,42 +532,7 @@ fn (mut c Amd64) mov32(reg Amd64Register, val i32) {
532532
c.g.println('mov32 ${reg}, ${val}')
533533
}
534534

535-
// moves unsigned 64 bits, explained better in mov64
536-
fn (mut c Amd64) mov64u(reg Register, val u64) {
537-
match reg as Amd64Register {
538-
.rax {
539-
c.g.write8(0x48)
540-
c.g.write8(0xb8)
541-
}
542-
.rcx {
543-
c.g.write8(0x48)
544-
c.g.write8(0xb9)
545-
}
546-
.rdx {
547-
c.g.write8(0x48)
548-
c.g.write8(0xba)
549-
}
550-
.rbx {
551-
c.g.write8(0x48)
552-
c.g.write8(0xbb)
553-
}
554-
.rsi {
555-
c.g.write8(0x48)
556-
c.g.write8(0xbe)
557-
}
558-
.rdi {
559-
c.g.write8(0x48)
560-
c.g.write8(0xbf)
561-
}
562-
else {
563-
eprintln('unhandled mov64u ${reg}')
564-
}
565-
}
566-
c.g.write64(val)
567-
c.g.println('mov64 ${reg}, ${val}')
568-
}
569-
570-
fn (mut c Amd64) mov64(reg Register, val i64) {
535+
fn (mut c Amd64) mov64(reg Register, val Number) {
571536
// see AMD64 Architecture Programmer's Manual Volume 3 about the MOV instruction to have a detailed explanation
572537
// about the BF (B8+rq) there is an explanation in Table 2-2 (and a bit above in 2.5.2 Opcode Syntax)
573538
// in short the 64 mov instruction is 0xB8 and after a 64 bits immediate value
@@ -945,7 +910,7 @@ fn (mut c Amd64) mov_var_to_reg(reg Register, var Var, config VarConfig) {
945910
c.g.println('${instruction} ${reg}, ${size_str} PTR [rbp-${int(offset).hex2()}] ; `${var.name}`')
946911
}
947912
GlobalVar {
948-
// TODO
913+
c.g.n_error('${@LOCATION} Unsupported GlobalVar')
949914
}
950915
}
951916
}
@@ -1057,7 +1022,7 @@ fn (mut c Amd64) gen_syscall(node ast.CallExpr) {
10571022
ast.StringLiteral {
10581023
s := c.g.eval_str_lit_escape_codes(expr.expr)
10591024
c.g.allocate_string(s, 2, .abs64)
1060-
c.mov64(ra[i], 1)
1025+
c.mov64(ra[i], i64(1))
10611026
done = true
10621027
}
10631028
else {}
@@ -1074,7 +1039,7 @@ fn (mut c Amd64) gen_syscall(node ast.CallExpr) {
10741039
}
10751040
s := c.g.eval_str_lit_escape_codes(expr)
10761041
c.g.allocate_string(s, 2, .abs64)
1077-
c.mov64(ra[i], 1)
1042+
c.mov64(ra[i], i64(1))
10781043
}
10791044
else {
10801045
c.g.v_error('Unknown syscall ${expr.type_name()} argument type ${expr}',
@@ -1741,6 +1706,7 @@ fn (mut c Amd64) sub_store(a Amd64Register, b Amd64Register, size Size) {
17411706

17421707
fn (mut c Amd64) mul_store(a Amd64Register, b Amd64Register, size Size) {
17431708
if size == ._8 {
1709+
c.g.n_error('${@LOCATION} Unsupported size')
17441710
} else {
17451711
if size == ._16 {
17461712
c.g.write8(0x66)
@@ -2096,7 +2062,7 @@ fn (mut c Amd64) assign_var(var IdentVar, raw_type ast.Type) {
20962062
}
20972063

20982064
// Could be nice to have left as an expr to be able to take all int assigns
2099-
fn (mut c Amd64) assign_ident_int(node ast.AssignStmt, i i32, int_lit ast.IntegerLiteral, left ast.Ident) {
2065+
fn (mut c Amd64) assign_ident_int_lit(node ast.AssignStmt, i i32, int_lit ast.IntegerLiteral, left ast.Ident) {
21002066
match node.op {
21012067
.plus_assign {
21022068
c.mov_var_to_reg(Amd64Register.rax, left)
@@ -2121,7 +2087,7 @@ fn (mut c Amd64) assign_ident_int(node ast.AssignStmt, i i32, int_lit ast.Intege
21212087
c.mov_reg_to_var(left, Amd64Register.rax)
21222088
}
21232089
.decl_assign {
2124-
c.allocate_var(left.name, 8, i32(int_lit.val.int()))
2090+
c.allocate_var(left.name, 8, i64(int_lit.val.int()))
21252091
}
21262092
.assign {
21272093
c.mov(Amd64Register.rax, i32(int_lit.val.int()))
@@ -2216,18 +2182,33 @@ fn (mut c Amd64) mov_float_xmm0_var(reg Amd64Register, var_type ast.Type) {
22162182
fn (mut c Amd64) assign_ident_right_expr(node ast.AssignStmt, i i32, right ast.Expr, name string, ident ast.Ident) {
22172183
match right {
22182184
ast.IntegerLiteral {
2185+
// a = 230 // no cast, just a int literal
2186+
// TODO: when V changes int (not fixed i32), change the size of the assigns
22192187
left_type := node.left_types[i]
22202188
if left_type.is_pure_float() {
22212189
c.assign_float(node, i, right, ident)
22222190
} else {
2223-
c.assign_ident_int(node, i, right, ident)
2191+
c.assign_ident_int_lit(node, i, right, ident)
2192+
}
2193+
}
2194+
ast.EnumVal {
2195+
type_name := c.g.table.get_type_name(right.typ)
2196+
enum_info := c.g.enum_vals[type_name]
2197+
val := enum_info.fields[right.val] or {
2198+
c.g.n_error('${@LOCATION} enum field not found ${right.val}')
2199+
}
2200+
if node.op == .decl_assign {
2201+
c.allocate_var(ident.name, enum_info.size, val)
2202+
} else {
2203+
c.mov64(Amd64Register.rax, val)
2204+
c.mov_reg_to_var(ident, Amd64Register.rax)
22242205
}
22252206
}
22262207
ast.FloatLiteral {
22272208
c.assign_float(node, i, right, ident)
22282209
}
22292210
ast.StringLiteral {
2230-
dest := c.allocate_var(name, 8, 0)
2211+
dest := c.allocate_var(name, 8, i64(0))
22312212
ie := right as ast.StringLiteral
22322213
str := c.g.eval_str_lit_escape_codes(ie)
22332214
c.learel(Amd64Register.rsi, c.g.allocate_string(str, 3, .rel32))
@@ -2270,7 +2251,7 @@ fn (mut c Amd64) assign_ident_right_expr(node ast.AssignStmt, i i32, right ast.E
22702251
return
22712252
}
22722253
ast.AtExpr {
2273-
dest := c.allocate_var(name, 8, 0)
2254+
dest := c.allocate_var(name, 8, i64(0))
22742255
c.learel(Amd64Register.rsi, c.g.allocate_string(c.g.comptime_at(right), 3,
22752256
.rel32))
22762257
c.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, Amd64Register.rsi)
@@ -2827,8 +2808,18 @@ fn (mut c Amd64) assign_stmt(node ast.AssignStmt) {
28272808
}
28282809
}
28292810
.enum {
2830-
// TODO: fix sizes
2831-
c.mov_store(.rdx, .rax, ._32)
2811+
size := c.g.get_type_size(var_type)
2812+
if size == 4 {
2813+
c.mov_store(.rdx, .rax, ._32)
2814+
} else if size == 8 {
2815+
c.mov_store(.rdx, .rax, ._64)
2816+
} else if size == 2 {
2817+
c.mov_store(.rdx, .rax, ._16)
2818+
} else if size == 1 {
2819+
c.mov_store(.rdx, .rax, ._8)
2820+
} else {
2821+
c.g.n_error('${@LOCATION} Unsupported enum size assignment')
2822+
}
28322823
}
28332824
else {
28342825
c.g.n_error('${@LOCATION} Unsupported expression SelectorExpr ${ts.kind}')
@@ -2893,7 +2884,7 @@ fn (mut c Amd64) prefix_expr(node ast.PrefixExpr) {
28932884
c.g.expr(node.right)
28942885
c.cmp_zero(Amd64Register.rax)
28952886
// TODO: mov_extend_reg
2896-
c.mov64(Amd64Register.rax, 0)
2887+
c.mov64(Amd64Register.rax, i64(0))
28972888
c.cset(.e)
28982889
}
28992890
.bit_not {
@@ -2930,7 +2921,7 @@ fn (mut c Amd64) fp_infix_expr(node ast.InfixExpr, left_type ast.Type) {
29302921
.gt, .lt, .ge, .le {
29312922
c.cmp_sse(.xmm0, .xmm1, left_type)
29322923
// TODO: mov_extend_reg
2933-
c.mov64(Amd64Register.rax, 0)
2924+
c.mov64(Amd64Register.rax, i64(0))
29342925
c.cset(match node.op {
29352926
.gt { .a }
29362927
.lt { .b }
@@ -3010,7 +3001,7 @@ fn (mut c Amd64) infix_expr(node ast.InfixExpr) {
30103001
.eq, .ne, .gt, .lt, .ge, .le {
30113002
c.cmp_reg(.rax, .rdx)
30123003
// TODO: mov_extend_reg
3013-
c.mov64(Amd64Register.rax, 0)
3004+
c.mov64(Amd64Register.rax, i64(0))
30143005
c.cset_op(node.op)
30153006
}
30163007
.plus {
@@ -3326,7 +3317,7 @@ fn (mut c Amd64) fn_decl(node ast.FnDecl) {
33263317
// define defer vars
33273318
for i in 0 .. node.defer_stmts.len {
33283319
name := '_defer${i}'
3329-
c.allocate_var(name, 8, 0)
3320+
c.allocate_var(name, 8, i64(0))
33303321
}
33313322
// body
33323323
c.g.stmts(node.stmts)
@@ -3366,13 +3357,12 @@ pub fn (mut c Amd64) builtin_decl(builtin BuiltinFn) {
33663357
c.leave()
33673358
}
33683359

3369-
pub fn (mut c Amd64) allocate_var_two_step(name string, size i32, initial_val i32) i32 {
3370-
// TODO: replace i32 by i64 or bigger
3371-
c.allocate_var(name, size - 8, 0)
3360+
pub fn (mut c Amd64) allocate_var_two_step(name string, size i32, initial_val Number) i32 {
3361+
c.allocate_var(name, size - 8, i64(0))
33723362
return c.allocate_var(name, 8, initial_val)
33733363
}
33743364

3375-
pub fn (mut c Amd64) allocate_var(name string, size i32, initial_val i32) i32 {
3365+
pub fn (mut c Amd64) allocate_var(name string, size i32, initial_val Number) i32 {
33763366
if size > 8 {
33773367
return c.allocate_var_two_step(name, size, initial_val)
33783368
}
@@ -3387,51 +3377,83 @@ pub fn (mut c Amd64) allocate_var(name string, size i32, initial_val i32) i32 {
33873377
// BYTE
33883378
c.g.write8(0xc6)
33893379
c.g.write8(i32(0x45) + far_var_offset)
3380+
// Generate N in `[rbp-N]`
3381+
if is_far_var {
3382+
c.g.write32(i32((0xffffffff - i64(n) + 1) % 0x100000000))
3383+
} else {
3384+
c.g.write8(i32((0xff - n + 1) % 0x100))
3385+
}
3386+
c.g.stack_var_pos += size + padding
3387+
c.g.var_offset[name] = c.g.stack_var_pos
3388+
c.g.var_alloc_size[name] = size
3389+
// Generate the value assigned to the variable
3390+
match initial_val {
3391+
i64 {
3392+
c.g.write8(i32(initial_val as i64))
3393+
}
3394+
u64 {
3395+
c.g.write8(i32(initial_val as u64))
3396+
}
3397+
}
33903398
}
33913399
2 {
33923400
// WORD
33933401
c.g.write8(0x66)
33943402
c.g.write8(0xc7)
33953403
c.g.write8(i32(0x45) + far_var_offset)
3404+
// Generate N in `[rbp-N]`
3405+
if is_far_var {
3406+
c.g.write32(i32((0xffffffff - i64(n) + 1) % 0x100000000))
3407+
} else {
3408+
c.g.write8(i32((0xff - n + 1) % 0x100))
3409+
}
3410+
c.g.stack_var_pos += size + padding
3411+
c.g.var_offset[name] = c.g.stack_var_pos
3412+
c.g.var_alloc_size[name] = size
3413+
// Generate the value assigned to the variable
3414+
match initial_val {
3415+
i64 {
3416+
c.g.write16(i32(initial_val as i64))
3417+
}
3418+
u64 {
3419+
c.g.write16(i32(initial_val as u64))
3420+
}
3421+
}
33963422
}
33973423
4 {
33983424
// DWORD
33993425
c.g.write8(0xc7)
34003426
c.g.write8(i32(0x45) + far_var_offset)
3427+
// Generate N in `[rbp-N]`
3428+
if is_far_var {
3429+
c.g.write32(i32((0xffffffff - i64(n) + 1) % 0x100000000))
3430+
} else {
3431+
c.g.write8(i32((0xff - n + 1) % 0x100))
3432+
}
3433+
c.g.stack_var_pos += size + padding
3434+
c.g.var_offset[name] = c.g.stack_var_pos
3435+
c.g.var_alloc_size[name] = size
3436+
// Generate the value assigned to the variable
3437+
match initial_val {
3438+
i64 {
3439+
c.g.write32(i32(initial_val as i64))
3440+
}
3441+
u64 {
3442+
c.g.write32(i32(initial_val as u64))
3443+
}
3444+
}
34013445
}
34023446
8 {
34033447
// QWORD
3404-
c.g.write8(0x48)
3405-
c.g.write8(0xc7)
3406-
c.g.write8(i32(0x45) + far_var_offset)
3407-
}
3408-
else {
3409-
c.g.n_error('${@LOCATION} bad size ${int(size)}')
3410-
}
3411-
}
3412-
// Generate N in `[rbp-N]`
3413-
if is_far_var {
3414-
c.g.write32(i32((0xffffffff - i64(n) + 1) % 0x100000000))
3415-
} else {
3416-
c.g.write8(i32((0xff - n + 1) % 0x100))
3417-
}
3418-
c.g.stack_var_pos += size + padding
3419-
c.g.var_offset[name] = c.g.stack_var_pos
3420-
c.g.var_alloc_size[name] = size
3448+
// Can not move directly an immediate value of 64 bits in a 64 bits register
34213449

3422-
// Generate the value assigned to the variable
3423-
match size {
3424-
1 {
3425-
c.g.write8(initial_val)
3426-
}
3427-
2 {
3428-
c.g.write16(initial_val)
3429-
}
3430-
4 {
3431-
c.g.write32(initial_val)
3432-
}
3433-
8 {
3434-
c.g.write32(initial_val) // fixme: 64-bit segfaulting
3450+
c.g.stack_var_pos += size + padding
3451+
c.g.var_offset[name] = c.g.stack_var_pos
3452+
c.g.var_alloc_size[name] = size
3453+
3454+
c.lea_var_to_reg(Amd64Register.rax, c.g.var_offset[name])
3455+
c.mov64(Amd64Register.rdx, initial_val)
3456+
c.mov_store(.rax, .rdx, ._64)
34353457
}
34363458
else {
34373459
c.g.n_error('${@LOCATION} bad size ${int(size)}')

vlib/v/gen/native/arm64.v

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ mut:
4545
// arm64 specific stuff for code generation
4646
}
4747

48-
fn (mut x Arm64) allocate_var(name string, size i32, initial_val i32) i32 {
48+
fn (mut x Arm64) allocate_var(name string, size i32, initial_val Number) i32 {
4949
eprintln('TODO: allocating var on arm64 (${name}) = ${size} = ${initial_val}')
5050
return 0
5151
}
@@ -376,11 +376,7 @@ fn (mut c Arm64) mov_reg(r1 Register, r2 Register) {
376376
panic('Arm64.mov_reg() not implemented')
377377
}
378378

379-
fn (mut c Arm64) mov64u(r Register, val u64) {
380-
panic('Arm64.mov64u() not implemented')
381-
}
382-
383-
fn (mut c Arm64) mov64(r Register, val i64) {
379+
fn (mut c Arm64) mov64(r Register, val Number) {
384380
panic('Arm64.mov64() not implemented')
385381
}
386382

vlib/v/gen/native/elf.v

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,15 +250,15 @@ fn (mut g Gen) gen_program_header(p ProgramHeader) {
250250
g.write64(p.offset) // p_offset
251251
g.println('; p_offset')
252252
g.write64(if p.vaddr == 0 {
253-
segment_start
253+
i64(segment_start)
254254
} else {
255-
p.vaddr
255+
i64(p.vaddr)
256256
}) // p_vaddr
257257
g.println('; p_vaddr')
258258
g.write64(if p.paddr == 0 {
259-
segment_start
259+
i64(segment_start)
260260
} else {
261-
p.paddr
261+
i64(p.paddr)
262262
}) // p_paddr
263263
g.println('; p_paddr')
264264
if p.filesz == 0 {
@@ -758,7 +758,7 @@ pub fn (mut g Gen) generate_linkable_elf_header() {
758758

759759
g.code_gen.call(placeholder)
760760
g.println('; call main.main')
761-
g.code_gen.mov64(g.code_gen.main_reg(), 0)
761+
g.code_gen.mov64(g.code_gen.main_reg(), i64(0))
762762
g.code_gen.ret()
763763
g.println('; return 0')
764764

0 commit comments

Comments
 (0)