1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

native: support integer infix arithmetics (#15536)

This commit is contained in:
lemon 2022-08-26 13:07:15 +09:00 committed by GitHub
parent dbf28c5bfb
commit 939e9245db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 190 additions and 45 deletions

View File

@ -850,6 +850,57 @@ fn (mut g Gen) mul8_var(reg Register, var_offset int) {
g.println('mul8 $reg,DWORD PTR[rbp-$var_offset.hex2()]')
}
fn (mut g Gen) bitand_reg(a Register, b Register) {
g.write8(0x48 + if int(a) >= int(Register.r8) { 1 } else { 0 } +
if int(b) >= int(Register.r8) { 4 } else { 0 })
g.write8(0x21)
g.write8(0xc0 + int(a) % 8 + int(b) % 8 * 8)
}
fn (mut g Gen) bitor_reg(a Register, b Register) {
g.write8(0x48 + if int(a) >= int(Register.r8) { 1 } else { 0 } +
if int(b) >= int(Register.r8) { 4 } else { 0 })
g.write8(0x09)
g.write8(0xc0 + int(a) % 8 + int(b) % 8 * 8)
}
fn (mut g Gen) bitxor_reg(a Register, b Register) {
g.write8(0x48 + if int(a) >= int(Register.r8) { 1 } else { 0 } +
if int(b) >= int(Register.r8) { 4 } else { 0 })
g.write8(0x31)
g.write8(0xc0 + int(a) % 8 + int(b) % 8 * 8)
}
fn (mut g Gen) shl_reg(a Register, b Register) {
if b != .rcx {
g.mov_reg(.rcx, b)
}
g.write8(if int(a) >= int(Register.r8) { 0x49 } else { 0x48 })
g.write8(0xd3)
g.write8(0xe0 + int(a) % 8)
g.println('shl $a, $b')
}
fn (mut g Gen) sar_reg(a Register, b Register) {
if b != .rcx {
g.mov_reg(.rcx, b)
}
g.write8(if int(a) > 7 { 0x49 } else { 0x48 })
g.write8(0xd3)
g.write8(0xf8 + int(a) % 8)
g.println('sar $a, $b')
}
fn (mut g Gen) shr_reg(a Register, b Register) {
if b != .rcx {
g.mov_reg(.rcx, b)
}
g.write8(if int(a) > 7 { 0x49 } else { 0x48 })
g.write8(0xd3)
g.write8(0xe8 + int(a) % 8)
g.println('shr $a, $b')
}
fn (mut g Gen) leave() {
g.println('; label 0: return')
if g.defer_stmts.len != 0 {
@ -1332,39 +1383,25 @@ fn (mut g Gen) mod_reg(a Register, b Register) {
}
fn (mut g Gen) sub_reg(a Register, b Register) {
if a == .rax && b == .rbx {
g.write8(0x48)
if int(a) <= int(Register.r15) && int(b) <= int(Register.r15) {
g.write8(0x48 + if int(a) >= int(Register.r8) { 1 } else { 0 } +
if int(b) >= int(Register.r8) { 4 } else { 0 })
g.write8(0x29)
g.write8(0xd8)
} else if a == .rdx && b == .rax {
g.write8(0x48)
g.write8(0x29)
g.write8(0xc2)
} else if a == .rdi && b == .rax {
g.write8(0x48)
g.write8(0x29)
g.write8(0xc7)
g.write8(0xc0 + int(a) % 8 + int(b) % 8 * 8)
} else {
panic('unhandled add $a, $b')
g.n_error('unhandled sub $a, $b')
}
g.println('sub $a, $b')
}
fn (mut g Gen) add_reg(a Register, b Register) {
if a == .rax && b == .rbx {
g.write8(0x48)
if int(a) <= int(Register.r15) && int(b) <= int(Register.r15) {
g.write8(0x48 + if int(a) >= int(Register.r8) { 1 } else { 0 } +
if int(b) >= int(Register.r8) { 4 } else { 0 })
g.write8(0x01)
g.write8(0xd8)
} else if a == .rax && b == .rdi {
g.write8(0x48)
g.write8(0x01)
g.write8(0xf8)
} else if a == .rax && b == .rax {
g.write8(0x48)
g.write8(0x01)
g.write8(0xc0)
g.write8(0xc0 + int(a) % 8 + int(b) % 8 * 8)
} else {
panic('unhandled add $a, $b')
g.n_error('unhandled add $a, $b')
}
g.println('add $a, $b')
}
@ -1741,6 +1778,7 @@ fn (mut g Gen) cset_op(op token.Kind) {
}
fn (mut g Gen) infix_expr(node ast.InfixExpr) {
/*
if node.left is ast.Ident && node.right is ast.Ident {
left := node.left as ast.Ident
right := node.right as ast.Ident
@ -1756,33 +1794,109 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
}
return
}
}
g.expr(node.left)
mut label := 0
g.push(.rax)
}*/
if node.op in [.logical_or, .and] {
label = g.labels.new_label()
g.expr(node.left)
label := g.labels.new_label()
g.cmp_zero(.rax)
jump_addr := g.cjmp(if node.op == .logical_or { .jne } else { .je })
g.labels.patches << LabelPatch{
id: label
pos: jump_addr
}
}
g.expr(node.right)
g.pop(.rdx)
// left: rdx, right: rax
match node.op {
.logical_or, .and {
g.labels.addrs[label] = g.pos()
g.expr(node.right)
g.labels.addrs[label] = g.pos()
return
} else {
g.expr(node.right)
// optimize for ast.Ident
match node.left {
ast.Ident {
g.mov_reg(match node.op {
.left_shift, .right_shift, .unsigned_right_shift, .div, .mod { .rcx }
else { .rdx }
}, .rax)
g.mov_var_to_reg(.rax, node.left as ast.Ident)
}
else {
g.push(.rax)
g.expr(node.left)
g.pop(match node.op {
.left_shift, .right_shift, .unsigned_right_shift, .div, .mod { .rcx }
else { .rdx }
})
}
}
.eq, .ne, .gt, .lt, .ge, .le {
g.cmp_reg(.rdx, .rax)
g.mov64(.rax, 0)
g.cset_op(node.op)
if node.left_type !in ast.integer_type_idxs && node.left_type != ast.bool_type_idx {
g.n_error('unsupported type for `$node.op`: $node.left_type')
}
else {
g.n_error('`$node.op` expression is not supported right now')
// left: rax, right: rdx
match node.op {
.eq, .ne, .gt, .lt, .ge, .le {
g.cmp_reg(.rax, .rdx)
g.mov64(.rax, 0)
g.cset_op(node.op)
}
.plus {
g.add_reg(.rax, .rdx)
}
.minus {
g.sub_reg(.rax, .rdx)
}
.mul {
g.write32(0xc2af0f48)
g.println('imul rax, rdx')
}
.div {
if node.left_type in ast.unsigned_integer_type_idxs {
g.write8(0xba)
g.write32(0)
g.println('mov edx, 0')
g.write([u8(0x48), 0xf7, 0xf1])
g.println('div rcx')
} else {
g.write16(0x9948)
g.println('cqo')
g.write([u8(0x48), 0xf7, 0xf9])
g.println('idiv rcx')
}
}
.mod {
if node.left_type in ast.unsigned_integer_type_idxs {
g.write8(0xba)
g.write32(0)
g.println('mov edx, 0')
g.write([u8(0x48), 0xf7, 0xf1])
g.println('div rcx')
} else {
g.write16(0x9948)
g.println('cqo')
g.write([u8(0x48), 0xf7, 0xf9])
g.println('idiv rcx')
}
g.mov_reg(.rax, .rdx)
}
.amp {
g.bitand_reg(.rax, .rdx)
}
.pipe {
g.bitor_reg(.rax, .rdx)
}
.xor {
g.bitxor_reg(.rax, .rdx)
}
.left_shift {
g.shl_reg(.rax, .rcx)
}
.right_shift {
g.sar_reg(.rax, .rcx)
}
.unsigned_right_shift {
g.shr_reg(.rax, .rcx)
}
else {
g.n_error('`$node.op` expression is not supported right now')
}
}
}
}

View File

@ -44,17 +44,39 @@ fn test_add() {
y := 3
sum := x + y
product := x * y
// diff := y - x
diff := y - x
div := y / x
mod := y % x
bitand := x & y
bitor := x | y
bitxor := x ^ y
lshift := x << x
rshift := 12 >> x
print_number(x)
print_number(y)
print_number(sum)
print_number(product)
// XXX fails on linux-amd64 but works on macos-amd64
// print_number(diff)
print_number(diff)
print_number(div)
print_number(mod)
print_number(bitand)
print_number(bitor)
print_number(bitxor)
print_number(lshift)
print_number(rshift)
}
fn test_multiple() {
a := 3
b := 5
c := 2
result := (a * ((a & b) + c) << (b ^ a)) | a - b % (b / c)
println(result)
}
fn main() {
println('start')
test_add()
test_multiple()
println('end')
}

View File

@ -4,5 +4,14 @@ test_add()
3
5
6
1
1
1
2
3
1
8
3
578
end