From 939e9245db3b1aca813a98efaa9832f46b8be100 Mon Sep 17 00:00:00 2001 From: lemon Date: Fri, 26 Aug 2022 13:07:15 +0900 Subject: [PATCH] native: support integer infix arithmetics (#15536) --- vlib/v/gen/native/amd64.v | 202 ++++++++++++++++----- vlib/v/gen/native/tests/expressions.vv | 28 ++- vlib/v/gen/native/tests/expressions.vv.out | 9 + 3 files changed, 192 insertions(+), 47 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 83002d443..7df355516 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -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) - 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) + 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(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) - 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) + 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(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() - } - .eq, .ne, .gt, .lt, .ge, .le { - g.cmp_reg(.rdx, .rax) - g.mov64(.rax, 0) - g.cset_op(node.op) - } - else { - g.n_error('`$node.op` expression is not supported right now') + 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 } + }) + } + } + 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') + } + // 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') + } } } } diff --git a/vlib/v/gen/native/tests/expressions.vv b/vlib/v/gen/native/tests/expressions.vv index 6d367605b..b1555f909 100644 --- a/vlib/v/gen/native/tests/expressions.vv +++ b/vlib/v/gen/native/tests/expressions.vv @@ -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') } diff --git a/vlib/v/gen/native/tests/expressions.vv.out b/vlib/v/gen/native/tests/expressions.vv.out index 2232a584e..d31fa5c76 100644 --- a/vlib/v/gen/native/tests/expressions.vv.out +++ b/vlib/v/gen/native/tests/expressions.vv.out @@ -4,5 +4,14 @@ test_add() 3 5 6 +1 +1 +1 +2 +3 +1 +8 +3 +578 end -- 2.30.2