mirror of
https://github.com/vlang/v.git
synced 2025-09-14 06:52:36 +03:00
native: implement for in string
for amd64 (#24613)
This commit is contained in:
parent
42a992775e
commit
f9a4f8f19f
9 changed files with 128 additions and 10 deletions
|
@ -212,6 +212,10 @@ fn (mut c Amd64) cmp(reg Amd64Register, size Size, val i64) {
|
||||||
c.g.println('cmp ${reg}, ${val}')
|
c.g.println('cmp ${reg}, ${val}')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut c Amd64) cmp_reg2(reg Register, reg2 Register) {
|
||||||
|
c.cmp_reg(reg as Amd64Register, reg2 as Amd64Register)
|
||||||
|
}
|
||||||
|
|
||||||
// `cmp rax, rbx`
|
// `cmp rax, rbx`
|
||||||
fn (mut c Amd64) cmp_reg(reg Amd64Register, reg2 Amd64Register) {
|
fn (mut c Amd64) cmp_reg(reg Amd64Register, reg2 Amd64Register) {
|
||||||
match reg {
|
match reg {
|
||||||
|
@ -1101,8 +1105,12 @@ fn (mut c Amd64) push(r Register) {
|
||||||
c.g.write8(0x50 + i32(reg) - 8)
|
c.g.write8(0x50 + i32(reg) - 8)
|
||||||
}
|
}
|
||||||
c.is_16bit_aligned = !c.is_16bit_aligned
|
c.is_16bit_aligned = !c.is_16bit_aligned
|
||||||
c.g.println('push ${reg}')
|
|
||||||
c.g.stack_depth++
|
c.g.stack_depth++
|
||||||
|
c.g.println('push ${reg}; stack_depth:${c.g.stack_depth}')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut c Amd64) pop2(r Register) {
|
||||||
|
c.pop(r as Amd64Register)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c Amd64) pop(reg Amd64Register) {
|
pub fn (mut c Amd64) pop(reg Amd64Register) {
|
||||||
|
@ -1111,8 +1119,8 @@ pub fn (mut c Amd64) pop(reg Amd64Register) {
|
||||||
}
|
}
|
||||||
c.g.write8(0x58 + i32(reg) % 8)
|
c.g.write8(0x58 + i32(reg) % 8)
|
||||||
c.is_16bit_aligned = !c.is_16bit_aligned
|
c.is_16bit_aligned = !c.is_16bit_aligned
|
||||||
c.g.println('pop ${reg}')
|
|
||||||
c.g.stack_depth--
|
c.g.stack_depth--
|
||||||
|
c.g.println('pop ${reg} ; stack_depth:${c.g.stack_depth}')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c Amd64) sub8(reg Amd64Register, val i32) {
|
pub fn (mut c Amd64) sub8(reg Amd64Register, val i32) {
|
||||||
|
@ -3620,7 +3628,7 @@ pub fn (mut c Amd64) allocate_var(name string, size i32, initial_val Number) i32
|
||||||
}
|
}
|
||||||
|
|
||||||
// println('allocate_var(size=$size, initial_val=$initial_val)')
|
// println('allocate_var(size=$size, initial_val=$initial_val)')
|
||||||
c.g.println('mov [rbp-${int(n).hex2()}], ${initial_val} ; Allocate var `${name}`')
|
c.g.println('mov [rbp-${int(n).hex2()}], ${initial_val} ; Allocate var `${name}` size: ${size}')
|
||||||
return c.g.stack_var_pos
|
return c.g.stack_var_pos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -535,6 +535,14 @@ pub fn (mut c Arm64) add_reg2(r Register, r2 Register) {
|
||||||
panic('Arm64.add_reg2() not implemented')
|
panic('Arm64.add_reg2() not implemented')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut c Arm64) pop2(r Register) {
|
||||||
|
panic('Arm64.pop2() not implemented')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut c Arm64) cmp_reg2(reg Register, reg2 Register) {
|
||||||
|
panic('Arm64.add_reg2() not implemented')
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut c Arm64) create_string_struct(typ ast.Type, name string, str string) {
|
fn (mut c Arm64) create_string_struct(typ ast.Type, name string, str string) {
|
||||||
panic('Arm64.add_reg2() not implemented')
|
panic('Arm64.add_reg2() not implemented')
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,12 @@ const whitelist = {
|
||||||
'string.is_capital': false
|
'string.is_capital': false
|
||||||
'string.is_ascii': false
|
'string.is_ascii': false
|
||||||
'string.is_identifier': false
|
'string.is_identifier': false
|
||||||
// 'string.is_blank': false need for in
|
'string.is_blank': false
|
||||||
|
'string.indent_width': false
|
||||||
|
'string.index_u8': false
|
||||||
|
'string.last_index': true
|
||||||
|
'string.last_index_u8': false
|
||||||
|
'string.contains_u8': false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g &Gen) is_blacklisted(name string, is_builtin bool) bool {
|
fn (g &Gen) is_blacklisted(name string, is_builtin bool) bool {
|
||||||
|
|
|
@ -95,6 +95,7 @@ mut:
|
||||||
cmp_to_stack_top(r Register)
|
cmp_to_stack_top(r Register)
|
||||||
cmp_var_reg(var Var, reg Register, config VarConfig)
|
cmp_var_reg(var Var, reg Register, config VarConfig)
|
||||||
cmp_var(var Var, val i32, config VarConfig)
|
cmp_var(var Var, val i32, config VarConfig)
|
||||||
|
cmp_reg2(reg Register, reg2 Register)
|
||||||
cmp_zero(reg Register)
|
cmp_zero(reg Register)
|
||||||
convert_bool_to_string(r Register)
|
convert_bool_to_string(r Register)
|
||||||
convert_int_to_string(a Register, b Register)
|
convert_int_to_string(a Register, b Register)
|
||||||
|
@ -131,6 +132,7 @@ mut:
|
||||||
mov64(r Register, val Number)
|
mov64(r Register, val Number)
|
||||||
movabs(reg Register, val i64)
|
movabs(reg Register, val i64)
|
||||||
patch_relative_jmp(pos i32, addr i64)
|
patch_relative_jmp(pos i32, addr i64)
|
||||||
|
pop2(r Register)
|
||||||
prefix_expr(node ast.PrefixExpr)
|
prefix_expr(node ast.PrefixExpr)
|
||||||
push(r Register)
|
push(r Register)
|
||||||
ret()
|
ret()
|
||||||
|
|
|
@ -255,6 +255,7 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that
|
fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that
|
||||||
|
main_reg := g.code_gen.main_reg()
|
||||||
if node.is_range {
|
if node.is_range {
|
||||||
g.println('; for ${node.val_var} in range {')
|
g.println('; for ${node.val_var} in range {')
|
||||||
// for a in node.cond .. node.high {
|
// for a in node.cond .. node.high {
|
||||||
|
@ -262,7 +263,6 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that
|
||||||
i := g.code_gen.allocate_var(node.val_var, 8, i64(0)) // iterator variable
|
i := g.code_gen.allocate_var(node.val_var, 8, i64(0)) // iterator variable
|
||||||
g.println('; evaluate node.cond for lower bound:')
|
g.println('; evaluate node.cond for lower bound:')
|
||||||
g.expr(node.cond) // outputs the lower loop bound (initial value) to the main reg
|
g.expr(node.cond) // outputs the lower loop bound (initial value) to the main reg
|
||||||
main_reg := g.code_gen.main_reg()
|
|
||||||
g.println('; move the result to i')
|
g.println('; move the result to i')
|
||||||
g.code_gen.mov_reg_to_var(LocalVar{i, ast.i64_type_idx, node.val_var}, main_reg) // i = node.cond // initial value
|
g.code_gen.mov_reg_to_var(LocalVar{i, ast.i64_type_idx, node.val_var}, main_reg) // i = node.cond // initial value
|
||||||
|
|
||||||
|
@ -299,11 +299,79 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that
|
||||||
g.labels.addrs[end_label] = g.pos()
|
g.labels.addrs[end_label] = g.pos()
|
||||||
g.println('; label ${end_label} (end_label)')
|
g.println('; label ${end_label} (end_label)')
|
||||||
g.println('; for ${node.val_var} in range }')
|
g.println('; for ${node.val_var} in range }')
|
||||||
|
} else if node.kind == .string {
|
||||||
|
g.println('; for ${node.val_var} in string {')
|
||||||
|
// for c in my_string {
|
||||||
|
|
||||||
|
key_var := if node.key_var == '' { 'i' } else { node.key_var }
|
||||||
|
i := g.code_gen.allocate_var(key_var, 8, i64(0)) // iterator variable
|
||||||
|
c := g.code_gen.allocate_var(node.val_var, 1, i64(0)) // char variable
|
||||||
|
|
||||||
|
g.expr(node.cond) // get the address of the string variable
|
||||||
|
g.code_gen.mov_deref(Amd64Register.rdx, main_reg, ast.charptr_type)
|
||||||
|
g.println('; push address of the string chars')
|
||||||
|
g.code_gen.push(Amd64Register.rdx) // address of the string
|
||||||
|
g.code_gen.add(main_reg, g.get_field_offset(ast.string_type, 'len'))
|
||||||
|
g.println('; push address of the len:')
|
||||||
|
g.code_gen.push(main_reg) // address of the len
|
||||||
|
|
||||||
|
start := g.pos() // label-begin:
|
||||||
|
|
||||||
|
g.println('; check iterator against upper loop bound')
|
||||||
|
g.code_gen.mov_var_to_reg(main_reg, LocalVar{i, ast.i64_type_idx, key_var})
|
||||||
|
g.println('; pop address of the len:')
|
||||||
|
g.code_gen.pop2(Amd64Register.rdx)
|
||||||
|
g.println('; push address of the len:')
|
||||||
|
g.code_gen.push(Amd64Register.rdx) // len
|
||||||
|
g.code_gen.mov_deref(Amd64Register.rdx, Amd64Register.rdx, ast.int_type)
|
||||||
|
g.code_gen.cmp_reg2(main_reg, Amd64Register.rdx)
|
||||||
|
jump_addr := g.code_gen.cjmp(.jge) // leave loop i >= len
|
||||||
|
|
||||||
|
g.println('; pop address of the len:')
|
||||||
|
g.code_gen.pop2(Amd64Register.rdx) // len
|
||||||
|
g.println('; pop address of the string chars')
|
||||||
|
g.code_gen.pop2(Amd64Register.rax) // address of the string
|
||||||
|
g.println('; push address of the string chars')
|
||||||
|
g.code_gen.push(Amd64Register.rax)
|
||||||
|
g.println('; push address of the len:')
|
||||||
|
g.code_gen.push(Amd64Register.rdx) // len
|
||||||
|
|
||||||
|
g.code_gen.mov_var_to_reg(Amd64Register.rdx, LocalVar{i, ast.i64_type_idx, key_var})
|
||||||
|
g.code_gen.add_reg2(Amd64Register.rax, Amd64Register.rdx)
|
||||||
|
g.code_gen.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.u8_type_idx)
|
||||||
|
g.code_gen.mov_reg_to_var(LocalVar{c, ast.u8_type_idx, node.val_var}, Amd64Register.rax) // store the char
|
||||||
|
|
||||||
|
end_label := g.labels.new_label()
|
||||||
|
g.labels.patches << LabelPatch{
|
||||||
|
id: end_label
|
||||||
|
pos: jump_addr
|
||||||
|
}
|
||||||
|
g.println('; jump to label ${end_label} (end_label)')
|
||||||
|
|
||||||
|
start_label := g.labels.new_label() // used for continue
|
||||||
|
g.labels.branches << BranchLabel{
|
||||||
|
name: node.label
|
||||||
|
start: start_label
|
||||||
|
end: end_label
|
||||||
|
}
|
||||||
|
g.stmts(node.stmts) // writes the actual body of the loop
|
||||||
|
|
||||||
|
g.labels.addrs[start_label] = g.pos() // used for continue (continue: jump before the inc)
|
||||||
|
g.println('; label ${start_label} (continue_label)')
|
||||||
|
|
||||||
|
g.code_gen.inc_var(LocalVar{i, ast.i64_type_idx, key_var})
|
||||||
|
g.labels.branches.pop()
|
||||||
|
g.code_gen.jmp_back(start) // loops
|
||||||
|
|
||||||
|
g.labels.addrs[end_label] = g.pos()
|
||||||
|
g.code_gen.pop2(Amd64Register.rdx) // len
|
||||||
|
g.code_gen.pop2(Amd64Register.rax) // address of the string
|
||||||
|
g.println('; label ${end_label} (end_label)')
|
||||||
|
g.println('; for ${node.val_var} in string }')
|
||||||
/*
|
/*
|
||||||
} else if node.kind == .array {
|
} else if node.kind == .array {
|
||||||
} else if node.kind == .array_fixed {
|
} else if node.kind == .array_fixed {
|
||||||
} else if node.kind == .map {
|
} else if node.kind == .map {
|
||||||
} else if node.kind == .string {
|
|
||||||
} else if node.kind == .struct {
|
} else if node.kind == .struct {
|
||||||
} else if it.kind in [.array, .string] || it.cond_type.has_flag(.variadic) {
|
} else if it.kind in [.array, .string] || it.cond_type.has_flag(.variadic) {
|
||||||
} else if it.kind == .map {
|
} else if it.kind == .map {
|
||||||
|
|
|
@ -22,7 +22,6 @@ assert !a.is_ascii()
|
||||||
assert '_9'.is_identifier() == true
|
assert '_9'.is_identifier() == true
|
||||||
assert 'a 9'.is_identifier() == false
|
assert 'a 9'.is_identifier() == false
|
||||||
assert 't'.is_identifier() == true
|
assert 't'.is_identifier() == true
|
||||||
/*
|
|
||||||
assert ''.is_blank()
|
assert ''.is_blank()
|
||||||
assert ' '.is_blank()
|
assert ' '.is_blank()
|
||||||
assert ' \t'.is_blank()
|
assert ' \t'.is_blank()
|
||||||
|
@ -48,18 +47,18 @@ assert !a.is_ascii()
|
||||||
assert 'abc'.index_u8(`A`) == -1
|
assert 'abc'.index_u8(`A`) == -1
|
||||||
assert 'abc'.index_u8(`B`) == -1
|
assert 'abc'.index_u8(`B`) == -1
|
||||||
assert 'abc'.index_u8(`C`) == -1
|
assert 'abc'.index_u8(`C`) == -1
|
||||||
|
/*
|
||||||
assert 'abcabca'.last_index('ca')? == 5
|
assert 'abcabca'.last_index('ca')? == 5
|
||||||
assert 'abcabca'.last_index('ab')? == 3
|
assert 'abcabca'.last_index('ab')? == 3
|
||||||
assert 'abcabca'.last_index('b')? == 4
|
assert 'abcabca'.last_index('b')? == 4
|
||||||
assert 'Zabcabca'.last_index('Z')? == 0
|
assert 'Zabcabca'.last_index('Z')? == 0
|
||||||
x := 'Zabcabca'.last_index('Y')
|
x := 'Zabcabca'.last_index('Y')
|
||||||
assert x == none
|
assert x == none
|
||||||
// TODO: `assert 'Zabcabca'.index_last('Y') == none` is a cgen error, 2023/12/04
|
*/
|
||||||
assert 'abcabca'.last_index_u8(`a`) == 6
|
assert 'abcabca'.last_index_u8(`a`) == 6
|
||||||
assert 'abcabca'.last_index_u8(`c`) == 5
|
assert 'abcabca'.last_index_u8(`c`) == 5
|
||||||
assert 'abcabca'.last_index_u8(`b`) == 4
|
assert 'abcabca'.last_index_u8(`b`) == 4
|
||||||
assert 'Zabcabca'.last_index_u8(`Z`) == 0
|
assert 'Zabcabca'.last_index_u8(`Z`) == 0
|
||||||
//
|
|
||||||
assert 'abc'.last_index_u8(`d`) == -1
|
assert 'abc'.last_index_u8(`d`) == -1
|
||||||
assert 'abc'.last_index_u8(`A`) == -1
|
assert 'abc'.last_index_u8(`A`) == -1
|
||||||
assert 'abc'.last_index_u8(`B`) == -1
|
assert 'abc'.last_index_u8(`B`) == -1
|
||||||
|
@ -69,6 +68,7 @@ assert !a.is_ascii()
|
||||||
assert 'abc abca'.contains_u8(`c`)
|
assert 'abc abca'.contains_u8(`c`)
|
||||||
assert 'abc abca'.contains_u8(` `)
|
assert 'abc abca'.contains_u8(` `)
|
||||||
assert !'abc abca'.contains_u8(`A`)
|
assert !'abc abca'.contains_u8(`A`)
|
||||||
|
/*
|
||||||
assert 'Abcd'.camel_to_snake() == 'abcd'
|
assert 'Abcd'.camel_to_snake() == 'abcd'
|
||||||
assert 'aBcd'.camel_to_snake() == 'a_bcd'
|
assert 'aBcd'.camel_to_snake() == 'a_bcd'
|
||||||
assert 'AAbb'.camel_to_snake() == 'aa_bb'
|
assert 'AAbb'.camel_to_snake() == 'aa_bb'
|
||||||
|
|
21
vlib/v/gen/native/tests/linux.vv
Normal file
21
vlib/v/gen/native/tests/linux.vv
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
fn test_for_c_in_string() {
|
||||||
|
$if windows {
|
||||||
|
println('0')
|
||||||
|
println('97')
|
||||||
|
println('1')
|
||||||
|
println('98')
|
||||||
|
println('2')
|
||||||
|
println('99')
|
||||||
|
} $else {
|
||||||
|
s := 'abc'
|
||||||
|
for i, c in s {
|
||||||
|
println(i)
|
||||||
|
println(int(c))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
test_for_c_in_string()
|
||||||
|
}
|
6
vlib/v/gen/native/tests/linux.vv.out
Normal file
6
vlib/v/gen/native/tests/linux.vv.out
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
0
|
||||||
|
97
|
||||||
|
1
|
||||||
|
98
|
||||||
|
2
|
||||||
|
99
|
|
@ -49,7 +49,7 @@ fn test_native() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if test == 'fibonacci_native.vv' {
|
if test == 'fibonacci_native.vv' || test.contains('linux') {
|
||||||
if user_os == 'windows' {
|
if user_os == 'windows' {
|
||||||
println('>>> SKIPPING ${test} on windows for now')
|
println('>>> SKIPPING ${test} on windows for now')
|
||||||
continue
|
continue
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue