native: improve consts, support more assigns (#25277)
Some checks are pending
Graphics CI / gg-regressions (push) Waiting to run
vlib modules CI / build-module-docs (push) Waiting to run
native backend CI / native-backend-ubuntu (push) Waiting to run
native backend CI / native-backend-windows (push) Waiting to run
Shy and PV CI / v-compiles-puzzle-vibes (push) Waiting to run
Sanitized CI / sanitize-undefined-clang (push) Waiting to run
Sanitized CI / sanitize-undefined-gcc (push) Waiting to run
Sanitized CI / tests-sanitize-address-clang (push) Waiting to run
Sanitized CI / sanitize-address-msvc (push) Waiting to run
Sanitized CI / sanitize-address-gcc (push) Waiting to run
Sanitized CI / sanitize-memory-clang (push) Waiting to run
sdl CI / v-compiles-sdl-examples (push) Waiting to run
Time CI / time-linux (push) Waiting to run
Time CI / time-macos (push) Waiting to run
Time CI / time-windows (push) Waiting to run
toml CI / toml-module-pass-external-test-suites (push) Waiting to run
Tools CI / tools-linux (clang) (push) Waiting to run
Tools CI / tools-linux (gcc) (push) Waiting to run
Tools CI / tools-linux (tcc) (push) Waiting to run
Tools CI / tools-macos (clang) (push) Waiting to run
Tools CI / tools-windows (gcc) (push) Waiting to run
Tools CI / tools-windows (msvc) (push) Waiting to run
Tools CI / tools-windows (tcc) (push) Waiting to run
Tools CI / tools-docker-ubuntu-musl (push) Waiting to run
vab CI / vab-compiles-v-examples (push) Waiting to run
vab CI / v-compiles-os-android (push) Waiting to run
wasm backend CI / wasm-backend (ubuntu-22.04) (push) Waiting to run
wasm backend CI / wasm-backend (windows-2022) (push) Waiting to run

This commit is contained in:
Eliyaan (Nopana) 2025-09-10 19:22:13 +02:00 committed by GitHub
parent 177758ac53
commit 4ea05636fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 309 additions and 52 deletions

View file

@ -139,7 +139,7 @@ fn (mut c Amd64) dec(reg Amd64Register) {
.rsi { c.g.write8(0xce) } .rsi { c.g.write8(0xce) }
.rdi { c.g.write8(0xcf) } .rdi { c.g.write8(0xcf) }
.r12 { c.g.write8(0xc4) } .r12 { c.g.write8(0xc4) }
else { panic('unhandled inc ${reg}') } else { c.g.n_error('unhandled inc ${reg}') }
} }
c.g.println('dec ${reg}') c.g.println('dec ${reg}')
} }
@ -156,7 +156,7 @@ fn (mut c Amd64) neg(reg Amd64Register) {
c.g.write8(0xf7) c.g.write8(0xf7)
match reg { match reg {
.rax { c.g.write8(0xd8) } .rax { c.g.write8(0xd8) }
else { panic('unhandled neg ${reg}') } else { c.g.n_error('unhandled neg ${reg}') }
} }
c.g.println('neg ${reg}') c.g.println('neg ${reg}')
} }
@ -172,7 +172,7 @@ fn (mut c Amd64) cmp(reg Amd64Register, size Size, val i64) {
// see https://www.sandpile.org/x86/opc_rm.htm for a table for modr/m byte (at the bottom of the second one) // see https://www.sandpile.org/x86/opc_rm.htm for a table for modr/m byte (at the bottom of the second one)
if c.g.pref.arch != .amd64 { if c.g.pref.arch != .amd64 {
panic('cmp') c.g.n_error('cmp')
} }
// Second byte depends on the size of the value // Second byte depends on the size of the value
match size { match size {
@ -185,7 +185,7 @@ fn (mut c Amd64) cmp(reg Amd64Register, size Size, val i64) {
c.g.write8(0x81) // compares a 64bits register with a 32bits immediate value c.g.write8(0x81) // compares a 64bits register with a 32bits immediate value
} }
else { else {
panic('unhandled cmp size ${size}') c.g.n_error('unhandled cmp size ${size}')
} }
} }
// Third byte (modr/m byte) depends on the regiister being compared to // Third byte (modr/m byte) depends on the regiister being compared to
@ -196,7 +196,7 @@ fn (mut c Amd64) cmp(reg Amd64Register, size Size, val i64) {
.rcx { c.g.write8(0xf9) } .rcx { c.g.write8(0xf9) }
.rdx { c.g.write8(0xfa) } .rdx { c.g.write8(0xfa) }
.rbx { c.g.write8(0xfb) } .rbx { c.g.write8(0xfb) }
else { panic('unhandled cmp reg ${reg}') } else { c.g.n_error('unhandled cmp reg ${reg}') }
} }
match size { match size {
._8 { ._8 {
@ -206,7 +206,7 @@ fn (mut c Amd64) cmp(reg Amd64Register, size Size, val i64) {
c.g.write32(i32(val)) c.g.write32(i32(val))
} }
else { else {
panic('unhandled cmp size ${size}') c.g.n_error('unhandled cmp size ${size}')
} }
} }
c.g.println('cmp ${reg}, ${val}') c.g.println('cmp ${reg}, ${val}')
@ -317,6 +317,9 @@ fn (mut c Amd64) cmp_var_reg(var Var, reg Register, config VarConfig) {
PreprocVar { PreprocVar {
c.cmp_var_reg(var_object as PreprocVar, reg, config) c.cmp_var_reg(var_object as PreprocVar, reg, config)
} }
ConstVar {
c.cmp_var_reg(var_object as ConstVar, reg, config)
}
} }
} }
LocalVar { LocalVar {
@ -342,6 +345,9 @@ fn (mut c Amd64) cmp_var_reg(var Var, reg Register, config VarConfig) {
PreprocVar { PreprocVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}') c.g.n_error('${@LOCATION} unsupported var type ${var}')
} }
ConstVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}')
}
} }
} }
@ -366,6 +372,9 @@ fn (mut c Amd64) cmp_var(var Var, val i32, config VarConfig) {
PreprocVar { PreprocVar {
c.cmp_var(var_object as PreprocVar, val, config) c.cmp_var(var_object as PreprocVar, val, config)
} }
ConstVar {
c.cmp_var(var_object as ConstVar, val, config)
}
} }
} }
LocalVar { LocalVar {
@ -391,6 +400,9 @@ fn (mut c Amd64) cmp_var(var Var, val i32, config VarConfig) {
PreprocVar { PreprocVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}') c.g.n_error('${@LOCATION} unsupported var type ${var}')
} }
ConstVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}')
}
} }
} }
@ -416,6 +428,9 @@ fn (mut c Amd64) dec_var(var Var, config VarConfig) {
PreprocVar { PreprocVar {
c.dec_var(var_object as PreprocVar, config) c.dec_var(var_object as PreprocVar, config)
} }
ConstVar {
c.dec_var(var_object as ConstVar, config)
}
} }
} }
LocalVar { LocalVar {
@ -441,6 +456,9 @@ fn (mut c Amd64) dec_var(var Var, config VarConfig) {
PreprocVar { PreprocVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}') c.g.n_error('${@LOCATION} unsupported var type ${var}')
} }
ConstVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}')
}
} }
} }
@ -467,6 +485,9 @@ fn (mut c Amd64) inc_var(var Var, config VarConfig) {
PreprocVar { PreprocVar {
c.inc_var(var_object as PreprocVar, config) c.inc_var(var_object as PreprocVar, config)
} }
ConstVar {
c.inc_var(var_object as ConstVar, config)
}
} }
} }
LocalVar { LocalVar {
@ -515,6 +536,9 @@ fn (mut c Amd64) inc_var(var Var, config VarConfig) {
PreprocVar { PreprocVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}') c.g.n_error('${@LOCATION} unsupported var type ${var}')
} }
ConstVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}')
}
} }
} }
@ -715,6 +739,9 @@ fn (mut c Amd64) mov_reg_to_var(var Var, r Register, config VarConfig) {
PreprocVar { PreprocVar {
c.mov_reg_to_var(var_object as PreprocVar, reg, config) c.mov_reg_to_var(var_object as PreprocVar, reg, config)
} }
ConstVar {
c.mov_reg_to_var(var_object as ConstVar, reg, config)
}
} }
} }
LocalVar { LocalVar {
@ -818,6 +845,9 @@ fn (mut c Amd64) mov_reg_to_var(var Var, r Register, config VarConfig) {
PreprocVar { PreprocVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}') c.g.n_error('${@LOCATION} unsupported var type ${var}')
} }
ConstVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}')
}
} }
} }
@ -841,6 +871,9 @@ fn (mut c Amd64) mov_int_to_var(var Var, integer i32, config VarConfig) {
PreprocVar { PreprocVar {
c.mov_int_to_var(var_object as PreprocVar, integer, config) c.mov_int_to_var(var_object as PreprocVar, integer, config)
} }
ConstVar {
c.mov_int_to_var(var_object as ConstVar, integer, config)
}
} }
} }
LocalVar { LocalVar {
@ -909,6 +942,9 @@ fn (mut c Amd64) mov_int_to_var(var Var, integer i32, config VarConfig) {
PreprocVar { PreprocVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}') c.g.n_error('${@LOCATION} unsupported var type ${var}')
} }
ConstVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}')
}
} }
} }
@ -961,6 +997,9 @@ fn (mut c Amd64) mov_var_to_reg(reg Register, var Var, config VarConfig) {
PreprocVar { PreprocVar {
c.mov_var_to_reg(reg, var_object as PreprocVar, config) c.mov_var_to_reg(reg, var_object as PreprocVar, config)
} }
ConstVar {
c.mov_var_to_reg(reg, var_object as ConstVar, config)
}
} }
} }
LocalVar { LocalVar {
@ -1045,6 +1084,11 @@ fn (mut c Amd64) mov_var_to_reg(reg Register, var Var, config VarConfig) {
PreprocVar { PreprocVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}') c.g.n_error('${@LOCATION} unsupported var type ${var}')
} }
ConstVar {
c.g.expr(var.expr)
c.mov_reg(reg, c.main_reg())
c.g.println('; mov ${reg} const:`${var.name}`')
}
} }
} }
@ -1195,7 +1239,7 @@ fn (mut c Amd64) syscall() {
} }
fn (mut c Amd64) svc() { fn (mut c Amd64) svc() {
panic('the svc instruction is not available with amd64') c.g.n_error('the svc instruction is not available with amd64')
} }
fn (mut c Amd64) cdq() { fn (mut c Amd64) cdq() {
@ -1711,7 +1755,7 @@ fn (mut c Amd64) mov(r Register, val i32) {
fn (mut c Amd64) mul_reg(a Amd64Register, b Amd64Register) { fn (mut c Amd64) mul_reg(a Amd64Register, b Amd64Register) {
if a != .rax { if a != .rax {
panic('mul always operates on rax') c.g.n_error('mul always operates on rax')
} }
match b { match b {
.rax { .rax {
@ -1719,18 +1763,23 @@ fn (mut c Amd64) mul_reg(a Amd64Register, b Amd64Register) {
c.g.write8(0xf7) c.g.write8(0xf7)
c.g.write8(0xe8) c.g.write8(0xe8)
} }
.rcx {
c.g.write8(0x48)
c.g.write8(0xf7)
c.g.write8(0xe9)
}
.rdx {
c.g.write8(0x48)
c.g.write8(0xf7)
c.g.write8(0xea)
}
.rbx { .rbx {
c.g.write8(0x48) c.g.write8(0x48)
c.g.write8(0xf7) c.g.write8(0xf7)
c.g.write8(0xeb) c.g.write8(0xeb)
} }
.rdx {
c.g.write8(0x48)
c.g.write8(0xf7)
c.g.write8(0xe2)
}
else { else {
panic('unhandled mul ${b}') c.g.n_error('${@LOCATION} unhandled mul ${b}')
} }
} }
c.g.println('mul ${b}') c.g.println('mul ${b}')
@ -1745,14 +1794,14 @@ fn (mut c Amd64) imul_reg(r Amd64Register) {
c.g.println('imul ${r}') c.g.println('imul ${r}')
} }
else { else {
panic('unhandled imul ${r}') c.g.n_error('unhandled imul ${r}')
} }
} }
} }
fn (mut c Amd64) div_reg(a Amd64Register, b Amd64Register) { fn (mut c Amd64) div_reg(a Amd64Register, b Amd64Register) {
if a != .rax { if a != .rax {
panic('div always operates on rax') c.g.n_error('div always operates on rax')
} }
match b { match b {
.rax { .rax {
@ -1760,18 +1809,23 @@ fn (mut c Amd64) div_reg(a Amd64Register, b Amd64Register) {
c.g.write8(0xf7) c.g.write8(0xf7)
c.g.write8(0xf8) c.g.write8(0xf8)
} }
.rcx {
c.g.write8(0x48)
c.g.write8(0xf7)
c.g.write8(0xf9)
}
.rdx {
c.g.write8(0x48)
c.g.write8(0xf7)
c.g.write8(0xfa)
}
.rbx { .rbx {
c.g.write8(0x48) c.g.write8(0x48)
c.g.write8(0xf7) c.g.write8(0xf7)
c.g.write8(0xfb) c.g.write8(0xfb)
} }
.rdx {
c.g.write8(0x48)
c.g.write8(0xf7)
c.g.write8(0xf2)
}
else { else {
panic('unhandled div ${b}') c.g.n_error('unhandled div ${b}')
} }
} }
c.g.println('div ${b}') c.g.println('div ${b}')
@ -1879,7 +1933,7 @@ fn (mut c Amd64) sar8(r Amd64Register, val u8) {
c.g.write8(0xfa) c.g.write8(0xfa)
} }
else { else {
panic('unhandled sar ${r}, ${val}') c.g.n_error('unhandled sar ${r}, ${val}')
} }
} }
c.g.write8(val) c.g.write8(val)
@ -2220,23 +2274,29 @@ fn (mut c Amd64) assign_var(var IdentVar, raw_type ast.Type) {
PreprocVar { PreprocVar {
c.mov_reg_to_var(var as PreprocVar, Amd64Register.rax) c.mov_reg_to_var(var as PreprocVar, Amd64Register.rax)
} }
ConstVar {
c.mov_reg_to_var(var as ConstVar, Amd64Register.rax)
}
} }
} else { } else {
c.g.n_error('${@LOCATION} error assigning type ${typ} with size ${size}: ${info}') c.g.n_error('${@LOCATION} error assigning var ${var} type ${typ} with size ${size}: ${info}')
} }
} }
// Could be nice to have left as an expr to be able to take all int assigns // Could be nice to have left as an expr to be able to take all int assigns
// TODO: may have a problem if the literal is bigger than max_i64: needs u64
fn (mut c Amd64) assign_ident_int_lit(node ast.AssignStmt, i i32, int_lit ast.IntegerLiteral, left ast.Ident) { fn (mut c Amd64) assign_ident_int_lit(node ast.AssignStmt, i i32, int_lit ast.IntegerLiteral, left ast.Ident) {
match node.op { match node.op {
.plus_assign { .plus_assign {
c.mov_var_to_reg(Amd64Register.rax, left) c.mov_var_to_reg(Amd64Register.rax, left)
c.add(Amd64Register.rax, i32(int_lit.val.int())) c.mov64(Amd64Register.rdx, i64(int_lit.val.int()))
c.add_reg(Amd64Register.rax, Amd64Register.rdx)
c.mov_reg_to_var(left, Amd64Register.rax) c.mov_reg_to_var(left, Amd64Register.rax)
} }
.minus_assign { .minus_assign {
c.mov_var_to_reg(Amd64Register.rax, left) c.mov_var_to_reg(Amd64Register.rax, left)
c.sub(.rax, i32(int_lit.val.int())) c.mov64(Amd64Register.rdx, i64(int_lit.val.int()))
c.sub_reg(Amd64Register.rax, Amd64Register.rdx)
c.mov_reg_to_var(left, Amd64Register.rax) c.mov_reg_to_var(left, Amd64Register.rax)
} }
.mult_assign { .mult_assign {
@ -2261,7 +2321,55 @@ fn (mut c Amd64) assign_ident_int_lit(node ast.AssignStmt, i i32, int_lit ast.In
c.allocate_var(left.name, 8, i64(int_lit.val.int())) c.allocate_var(left.name, 8, i64(int_lit.val.int()))
} }
.assign { .assign {
c.mov(Amd64Register.rax, i32(int_lit.val.int())) c.mov64(Amd64Register.rax, i64(int_lit.val.int()))
c.mov_reg_to_var(left, Amd64Register.rax)
}
.left_shift_assign {
c.mov_var_to_reg(Amd64Register.rax, left)
c.mov64(Amd64Register.rcx, i64(int_lit.val.int()))
c.shl_reg(.rax, .rcx)
c.mov_reg_to_var(left, Amd64Register.rax)
}
.right_shift_assign {
c.mov_var_to_reg(Amd64Register.rax, left)
c.mov64(Amd64Register.rcx, i64(int_lit.val.int()))
c.sar_reg(.rax, .rcx)
c.mov_reg_to_var(left, Amd64Register.rax)
}
.unsigned_right_shift_assign {
c.mov_var_to_reg(Amd64Register.rax, left)
c.mov64(Amd64Register.rcx, i64(int_lit.val.int()))
c.shr_reg(.rax, .rcx)
c.mov_reg_to_var(left, Amd64Register.rax)
}
.xor_assign {
c.mov_var_to_reg(Amd64Register.rax, left)
c.mov64(Amd64Register.rcx, i64(int_lit.val.int()))
c.bitxor_reg(.rax, .rcx)
c.mov_reg_to_var(left, Amd64Register.rax)
}
.or_assign {
c.mov_var_to_reg(Amd64Register.rax, left)
c.mov64(Amd64Register.rcx, i64(int_lit.val.int()))
c.bitor_reg(.rax, .rcx)
c.mov_reg_to_var(left, Amd64Register.rax)
}
.and_assign {
c.mov_var_to_reg(Amd64Register.rax, left)
c.mov64(Amd64Register.rcx, i64(int_lit.val.int()))
c.bitand_reg(.rax, .rcx)
c.mov_reg_to_var(left, Amd64Register.rax)
}
.boolean_and_assign {
c.mov_var_to_reg(Amd64Register.rax, left)
c.mov64(Amd64Register.rcx, i64(int_lit.val.int()))
c.bitand_reg(.rax, .rcx)
c.mov_reg_to_var(left, Amd64Register.rax)
}
.boolean_or_assign {
c.mov_var_to_reg(Amd64Register.rax, left)
c.mov64(Amd64Register.rcx, i64(int_lit.val.int()))
c.bitor_reg(.rax, .rcx)
c.mov_reg_to_var(left, Amd64Register.rax) c.mov_reg_to_var(left, Amd64Register.rax)
} }
else { else {
@ -2915,10 +3023,12 @@ fn (mut c Amd64) assign_stmt(node ast.AssignStmt) {
c.assign_ident_right_expr(node, i32(i), val, left.name, left) c.assign_ident_right_expr(node, i32(i), val, left.name, left)
} else { } else {
if c.g.is_register_type(var_type) { if c.g.is_register_type(var_type) {
c.g.gen_left_value(left)
c.push(c.main_reg()) // rax here, stores effective address of the left expr
c.g.expr(val) c.g.expr(val)
c.pop(.rdx) // effective address of left expr c.push(c.main_reg())
c.g.gen_left_value(left)
c.mov_reg(Amd64Register.rbx, Amd64Register.rax) // effective address of the left expr
c.mov_deref(Amd64Register.rax, Amd64Register.rbx, var_type) // value of left expr
c.pop(.rcx) // value of right expr
c.gen_type_promotion(node.right_types[0], var_type) c.gen_type_promotion(node.right_types[0], var_type)
size := match c.g.get_type_size(var_type) { size := match c.g.get_type_size(var_type) {
@ -2929,27 +3039,61 @@ fn (mut c Amd64) assign_stmt(node ast.AssignStmt) {
} }
match node.op { match node.op {
.decl_assign, .assign { .decl_assign, .assign {
c.mov_store(.rdx, .rax, size) c.mov_store(.rbx, .rcx, size)
} }
.plus_assign { .plus_assign {
c.mov_deref(Amd64Register.rcx, Amd64Register.rdx, var_type)
c.add_reg(.rax, .rcx) c.add_reg(.rax, .rcx)
c.mov_store(.rdx, .rax, size) c.mov_store(.rbx, .rax, size)
} }
.minus_assign { .minus_assign {
c.mov_deref(Amd64Register.rcx, Amd64Register.rdx, var_type)
c.sub_reg(.rax, .rcx) c.sub_reg(.rax, .rcx)
c.mov_store(.rdx, .rax, size) c.mov_store(.rbx, .rax, size)
} }
.and_assign { .and_assign {
c.mov_deref(Amd64Register.rcx, Amd64Register.rdx, var_type)
c.bitand_reg(.rax, .rcx) c.bitand_reg(.rax, .rcx)
c.mov_store(.rdx, .rax, size) c.mov_store(.rbx, .rax, size)
} }
.mod_assign { .mod_assign {
c.mov_deref(Amd64Register.rcx, Amd64Register.rdx, var_type) c.mov(Amd64Register.rdx, i32(0)) // 64bits IDIV uses RDX:RAX
c.mod_reg(.rax, .rcx) c.mod_reg(.rax, .rcx)
c.mov_store(.rdx, .rax, size) c.mov_store(.rbx, .rax, size)
}
.mult_assign {
c.mul_reg(.rax, .rcx)
c.mov_store(.rbx, .rax, size)
}
.div_assign {
c.mov(Amd64Register.rdx, i32(0)) // 64bits IDIV uses RDX:RAX
c.div_reg(.rax, .rcx)
c.mov_store(.rbx, .rax, size)
}
.xor_assign {
c.bitxor_reg(.rax, .rcx)
c.mov_store(.rbx, .rax, size)
}
.or_assign {
c.bitor_reg(.rax, .rcx)
c.mov_store(.rbx, .rax, size)
}
.right_shift_assign {
c.shr_reg(.rax, .rcx)
c.mov_store(.rbx, .rax, size)
}
.left_shift_assign {
c.shl_reg(.rax, .rcx)
c.mov_store(.rbx, .rax, size)
}
.unsigned_right_shift_assign {
c.sar_reg(.rax, .rcx)
c.mov_store(.rbx, .rax, size)
}
.boolean_and_assign {
c.bitand_reg(.rax, .rcx)
c.mov_store(.rbx, .rax, size)
}
.boolean_or_assign {
c.bitor_reg(.rax, .rcx)
c.mov_store(.rbx, .rax, size)
} }
else { else {
c.g.n_error('${@LOCATION} Unsupported assign instruction (${node.op})') c.g.n_error('${@LOCATION} Unsupported assign instruction (${node.op})')
@ -3847,6 +3991,9 @@ fn (mut c Amd64) init_struct(var Var, init ast.StructInit) {
PreprocVar { PreprocVar {
c.init_struct(var_object as PreprocVar, init) c.init_struct(var_object as PreprocVar, init)
} }
ConstVar {
c.init_struct(var_object as ConstVar, init)
}
} }
} }
LocalVar { LocalVar {
@ -3895,6 +4042,9 @@ fn (mut c Amd64) init_struct(var Var, init ast.StructInit) {
PreprocVar { PreprocVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}') c.g.n_error('${@LOCATION} unsupported var type ${var}')
} }
ConstVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}')
}
} }
} }
@ -3949,6 +4099,9 @@ fn (mut c Amd64) init_array(var Var, node ast.ArrayInit) {
PreprocVar { PreprocVar {
c.init_array(var_object as PreprocVar, node) c.init_array(var_object as PreprocVar, node)
} }
ConstVar {
c.init_array(var_object as ConstVar, node)
}
} }
} }
LocalVar { LocalVar {
@ -3968,6 +4121,9 @@ fn (mut c Amd64) init_array(var Var, node ast.ArrayInit) {
PreprocVar { PreprocVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}') c.g.n_error('${@LOCATION} unsupported var type ${var}')
} }
ConstVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}')
}
} }
} }
@ -4270,6 +4426,9 @@ fn (mut c Amd64) mov_ssereg_to_var(var Var, reg Amd64SSERegister, config VarConf
PreprocVar { PreprocVar {
c.mov_ssereg_to_var(var_object as PreprocVar, reg, config) c.mov_ssereg_to_var(var_object as PreprocVar, reg, config)
} }
ConstVar {
c.mov_ssereg_to_var(var_object as ConstVar, reg, config)
}
} }
} }
LocalVar { LocalVar {
@ -4301,6 +4460,9 @@ fn (mut c Amd64) mov_ssereg_to_var(var Var, reg Amd64SSERegister, config VarConf
PreprocVar { PreprocVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}') c.g.n_error('${@LOCATION} unsupported var type ${var}')
} }
ConstVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}')
}
} }
} }
@ -4326,6 +4488,9 @@ fn (mut c Amd64) mov_var_to_ssereg(reg Amd64SSERegister, var Var, config VarConf
PreprocVar { PreprocVar {
c.mov_var_to_ssereg(reg, var_object as PreprocVar, config) c.mov_var_to_ssereg(reg, var_object as PreprocVar, config)
} }
ConstVar {
c.mov_var_to_ssereg(reg, var_object as ConstVar, config)
}
} }
} }
LocalVar { LocalVar {
@ -4357,6 +4522,9 @@ fn (mut c Amd64) mov_var_to_ssereg(reg Amd64SSERegister, var Var, config VarConf
PreprocVar { PreprocVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}') c.g.n_error('${@LOCATION} unsupported var type ${var}')
} }
ConstVar {
c.g.n_error('${@LOCATION} unsupported var type ${var}')
}
} }
} }
@ -4677,5 +4845,5 @@ fn (mut c Amd64) cmp_to_stack_top(reg Register) {
// Temporary! // Temporary!
fn (mut c Amd64) adr(r Arm64Register, delta i32) { fn (mut c Amd64) adr(r Arm64Register, delta i32) {
panic('`adr` instruction not supported with amd64') c.g.n_error('`adr` instruction not supported with amd64')
} }

View file

@ -55,13 +55,19 @@ const blacklist = {
'string.last_index': true 'string.last_index': true
'string.last_index_u8': false 'string.last_index_u8': false
'string.contains_u8': false 'string.contains_u8': false
'malloc_noscan': true 'malloc_noscan': false
'malloc': false
'is_nil': false
'memdup': false
'vcalloc': false
'vmemcpy': false 'vmemcpy': false
'eprint': false 'eprint': false
'eprintln': false 'eprintln': false
'_write_buf_to_fd': false '_write_buf_to_fd': false
'_writeln_to_fd': false '_writeln_to_fd': false
'_memory_panic': true '_memory_panic': false
'panic': false
'vcurrent_hash': false
} }
const windows_blacklist = { const windows_blacklist = {

View file

@ -32,7 +32,7 @@ fn (mut g Gen) comptime_is_truthy(cond ast.Expr) bool {
return !g.comptime_is_truthy(cond.right) return !g.comptime_is_truthy(cond.right)
} }
else { else {
g.n_error('Compile time infix expr `${cond}` is not handled by the native backed.') g.n_error('${@LOCATION} Compile time infix expr `${cond}` is not handled by the native backed.')
} }
} }
} }
@ -58,7 +58,7 @@ fn (mut g Gen) comptime_is_truthy(cond ast.Expr) bool {
return true return true
} }
else { else {
g.n_error('Compile time infix expr `${cond}` is not handled by the native backend.') g.n_error('${@LOCATION} Compile time infix expr `${cond}` is not handled by the native backend.')
} }
} }
} }
@ -66,11 +66,11 @@ fn (mut g Gen) comptime_is_truthy(cond ast.Expr) bool {
return g.comptime_ident(cond.name, false) return g.comptime_ident(cond.name, false)
} }
ast.ComptimeCall { ast.ComptimeCall {
g.n_error('Comptime calls are not implemented') g.n_error('${@LOCATION} Comptime calls are not implemented')
} }
else { else {
// should be unreachable // should be unreachable
g.n_error('Compile time conditional `${cond}` is not handled by the native backend.') g.n_error('${@LOCATION} Compile time conditional `${cond}` is not handled by the native backend.')
} }
} }
return false return false
@ -221,7 +221,7 @@ fn (mut g Gen) comptime_ident(name string, is_comptime_option bool) bool {
|| (g.pref.compile_defines_all.len > 0 && name in g.pref.compile_defines_all) { || (g.pref.compile_defines_all.len > 0 && name in g.pref.compile_defines_all) {
true true
} else { } else {
g.n_error('Unhandled os ifdef name "${name}".') g.n_error('${@LOCATION} Unhandled os ifdef name "${name}".')
false false
} }
} }

View file

@ -54,8 +54,14 @@ fn (mut g Gen) expr(node ast.Expr) {
PreprocVar { PreprocVar {
g.preproc_var_ident(var) g.preproc_var_ident(var)
} }
else { GlobalVar {
g.n_error('${@LOCATION} Unsupported variable kind') g.global_var_ident(node, var)
}
Register {
g.n_error('${@LOCATION} Unsupported variable kind ${var}')
}
ConstVar {
g.const_var_ident(node, var)
} }
} }
} }
@ -193,6 +199,22 @@ fn (mut g Gen) local_var_ident(ident ast.Ident, var LocalVar) {
} }
} }
fn (mut g Gen) global_var_ident(ident ast.Ident, var GlobalVar) {
if g.is_register_type(var.typ) {
g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), ident)
} else {
g.n_error('${@LOCATION} Unsupported variable type ${ident} ${var}')
}
}
fn (mut g Gen) const_var_ident(ident ast.Ident, var ConstVar) {
if g.is_register_type(var.typ) {
g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), ident)
} else {
g.n_error('${@LOCATION} Unsupported variable type ${ident} ${var}')
}
}
fn (mut g Gen) extern_var_ident(var ExternVar) { fn (mut g Gen) extern_var_ident(var ExternVar) {
if g.pref.os == .linux { if g.pref.os == .linux {
main_reg := g.code_gen.main_reg() main_reg := g.code_gen.main_reg()

View file

@ -261,6 +261,12 @@ struct GlobalVar {
typ ast.Type typ ast.Type
} }
struct ConstVar {
name string
expr ast.Expr
typ ast.Type
}
@[params] @[params]
struct VarConfig { struct VarConfig {
pub: pub:
@ -268,9 +274,9 @@ pub:
typ ast.Type // type of the value you want to process e.g. struct fields. typ ast.Type // type of the value you want to process e.g. struct fields.
} }
type Var = GlobalVar | ExternVar | LocalVar | PreprocVar | ast.Ident type Var = GlobalVar | ExternVar | LocalVar | PreprocVar | ConstVar | ast.Ident
type IdentVar = GlobalVar | ExternVar | LocalVar | Register | PreprocVar type IdentVar = GlobalVar | ExternVar | LocalVar | Register | PreprocVar | ConstVar
enum JumpOp { enum JumpOp {
je je
@ -322,6 +328,13 @@ fn (mut g Gen) get_var_from_ident(ident ast.Ident) IdentVar {
name: obj.name name: obj.name
} }
} }
ast.ConstField {
return ConstVar{
name: obj.name
expr: (obj as ast.ConstField).expr
typ: obj.typ
}
}
else { else {
g.n_error('${@LOCATION} unsupported variable type type:${obj} name:${ident.name}') g.n_error('${@LOCATION} unsupported variable type type:${obj} name:${ident.name}')
} }

View file

@ -1,3 +1,5 @@
const abc = 3
fn main() { fn main() {
test_int() test_int()
test_fp() test_fp()
@ -26,7 +28,7 @@ fn test_plus_assign() {
} }
fn test_int() { fn test_int() {
a := 100 mut a := 100
mut b := a mut b := a
b += b b += b
b += 50 b += 50
@ -46,6 +48,15 @@ fn test_int() {
unsafe{*f = 5} unsafe{*f = 5}
assert *f == 5 assert *f == 5
assert e == 5 assert e == 5
mut x := abc
assert x == 3
a = 16
a >>>= 2
a >>= 2
a <<= 4
assert a == 16
} }
fn test_fp() { fn test_fp() {

View file

@ -231,10 +231,47 @@ fn nested_test() {
assert x4.b.a == 3 assert x4.b.a == 3
} }
struct Foo {
mut:
mantissa u64
b bool
}
fn field_assign_test() {
mut b := Foo{1, true}
b.mantissa += 1
b.mantissa -= 1
assert b.mantissa == 1
b.mantissa |= 2
assert b.mantissa == 3
b.mantissa &= 1
assert b.mantissa == 1
b.mantissa ^= 5
assert b.mantissa == 4
b.mantissa %= 3
assert b.mantissa == 1
b.mantissa *= 10
b.mantissa /= 10
assert b.mantissa == 1
b.mantissa <<= 4
b.mantissa >>>= 2
b.mantissa >>= 2
assert b.mantissa == 1
b.b &&= true
assert b.b == true
b.b &&= false
assert b.b == false
b.b ||= true
assert b.b == true
b.b ||= false
assert b.b == true
}
fn main() { fn main() {
struct_test() struct_test()
return_test() return_test()
alias_test() alias_test()
assign_fields() assign_fields()
nested_test() nested_test()
field_assign_test()
} }