From 3c85a03b8aec965ce60e5846a9601a1f747de62d Mon Sep 17 00:00:00 2001 From: pancake Date: Tue, 24 Aug 2021 14:30:41 +0200 Subject: [PATCH] v.gen.native: initial support for the asm statement in the native backend (#11292) --- vlib/v/gen/native/amd64.v | 109 +++++++++++++++++++++++++++++ vlib/v/gen/native/arm64.v | 4 ++ vlib/v/gen/native/gen.v | 3 + vlib/v/gen/native/tests/asm.vv | 10 +++ vlib/v/gen/native/tests/asm.vv.out | 1 + 5 files changed, 127 insertions(+) create mode 100644 vlib/v/gen/native/tests/asm.vv create mode 100644 vlib/v/gen/native/tests/asm.vv.out diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index dbfab0564c..2dea254dfd 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -37,6 +37,7 @@ enum Register { const ( fn_arg_registers = [Register.rdi, .rsi, .rdx, .rcx, .r8, .r9] + amd64_cpuregs = ['eax', 'ecx', 'edx', 'ebx', 'esp', 'ebp', 'esi', 'edi'] ) fn (mut g Gen) dec(reg Register) { @@ -53,6 +54,11 @@ fn (mut g Gen) dec(reg Register) { g.println('dec $reg') } +[inline] +fn byt(n int, s int) byte { + return byte((n >> (s * 8)) & 0xff) +} + fn (mut g Gen) inc(reg Register) { g.write16(0xff49) match reg { @@ -1038,6 +1044,109 @@ fn (mut g Gen) trap() { g.println('trap') } +fn (mut g Gen) gen_asm_stmt(asm_node ast.AsmStmt) { + if g.pref.arch == .arm64 { + g.gen_asm_stmt_arm64(asm_node) + } else { + g.gen_asm_stmt_amd64(asm_node) + } +} + +fn (mut g Gen) gen_asm_stmt_amd64(asm_node ast.AsmStmt) { + // inline assembly using vasm + g.println('// asm inline') + mut reg := 0 + mut imm := 0 + mut regname := '' + // dump(asm_node) + for t in asm_node.templates { + mut line := t.name + mut comma := false + for a in t.args { + if comma { + line += ', ' + } else { + comma = true + } + match a { + ast.AsmRegister { + regname = a.name + reg = native.amd64_cpuregs.index(regname) + line += a.typ.str() + } + ast.IntegerLiteral { + line += a.val + imm = a.val.int() + } + ast.BoolLiteral { + line += a.val.str() + imm = if a.val { 1 } else { 0 } + } + /* + ast.AsmAddressing { + } + ast.AsmAlias { + } + ast.AsmDisp { + } + ast.CharLiteral { + } + ast.FloatLiteral { + } + */ + string { + // XXX + g.v_error('no strings allowed in this context', asm_node.pos) + } + else { + g.v_error('unsupported instruction argument argument', asm_node.pos) + } + } + } + g.println(': $line') + match t.name { + 'nop' { + g.write8(byte(0x90)) + } + 'syscall' { + g.write8(byte(0x0f)) + g.write8(byte(0x05)) + } + 'ret' { + g.write8(byte(0xc3)) + } + 'int3' { + g.write8(byte(0xcc)) + g.write8(byte(imm)) + } + 'sti' { + g.write8(byte(0xfb)) + } + 'cli' { + g.write8(byte(0xfa)) + } + 'int' { + g.write8(byte(0xcd)) + g.write8(byte(imm)) + } + 'cpuid' { + g.write8(byte(0x0f)) + g.write8(byte(0xa2)) + } + 'mov' { + g.write8(byte(0xb8 + reg)) + g.write8(byt(imm, 0)) + g.write8(byt(imm, 1)) + g.write8(byt(imm, 2)) + g.write8(byt(imm, 3)) + } + else { + g.v_error('unsupported instruction $t.name', asm_node.pos) + } + } + } +} + fn (mut g Gen) gen_assert(assert_node ast.AssertStmt) { mut cjmp_addr := 0 mut ine := ast.InfixExpr{} diff --git a/vlib/v/gen/native/arm64.v b/vlib/v/gen/native/arm64.v index 46b8ffe6a6..22336c92a1 100644 --- a/vlib/v/gen/native/arm64.v +++ b/vlib/v/gen/native/arm64.v @@ -197,3 +197,7 @@ pub fn (mut g Gen) gen_arm64_exit(expr ast.Expr) { g.mov_arm(.x0, 0) g.svc() } + +fn (mut g Gen) gen_asm_stmt_arm64(asm_node ast.AsmStmt) { + g.v_error('The asm statement for arm64 not yet implemented', asm_node.pos) +} diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index 1bf19fd667..c8bb5c3c48 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -380,6 +380,9 @@ fn (mut g Gen) stmt(node ast.Stmt) { g.pop(.rbp) g.ret() } + ast.AsmStmt { + g.gen_asm_stmt(node) + } ast.AssertStmt { g.gen_assert(node) } diff --git a/vlib/v/gen/native/tests/asm.vv b/vlib/v/gen/native/tests/asm.vv new file mode 100644 index 0000000000..1c08411ccc --- /dev/null +++ b/vlib/v/gen/native/tests/asm.vv @@ -0,0 +1,10 @@ +fn asm_test() { + asm amd64 { + nop + } + println('inline works') +} + +fn main() { + asm_test() +} diff --git a/vlib/v/gen/native/tests/asm.vv.out b/vlib/v/gen/native/tests/asm.vv.out new file mode 100644 index 0000000000..9e07c4d433 --- /dev/null +++ b/vlib/v/gen/native/tests/asm.vv.out @@ -0,0 +1 @@ +inline works