From 6576d876fc1a1ce41aca65c68f2dfed500731d4e Mon Sep 17 00:00:00 2001 From: crthpl <56052645+crthpl@users.noreply.github.com> Date: Fri, 11 Jun 2021 01:03:39 -0700 Subject: [PATCH] cgen: support a `[_naked]` fn attribute (#10418) --- vlib/v/checker/checker.v | 2 +- vlib/v/gen/c/fn.v | 6 +++++- vlib/v/parser/fn.v | 3 ++- vlib/v/parser/parser.v | 2 +- vlib/v/tests/assembly/naked_attr_test.amd64.v | 14 ++++++++++++++ vlib/v/tests/assembly/naked_attr_test.i386.v | 14 ++++++++++++++ 6 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 vlib/v/tests/assembly/naked_attr_test.amd64.v create mode 100644 vlib/v/tests/assembly/naked_attr_test.i386.v diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 56047d34f2..b99943f6c9 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -7260,7 +7260,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { && (node.is_method || node.name !in ['panic', 'exit']) { if c.inside_anon_fn { c.error('missing return at the end of an anonymous function', node.pos) - } else { + } else if !node.attrs.contains('_naked') { c.error('missing return at end of function `$node.name`', node.pos) } } diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 32402c2a17..4ec39a6469 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -332,7 +332,8 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) { } else { g.defer_stmts = [] } - if node.return_type != ast.void_type && node.stmts.len > 0 && node.stmts.last() !is ast.Return { + if node.return_type != ast.void_type && node.stmts.len > 0 && node.stmts.last() !is ast.Return + && !node.attrs.contains('_naked') { default_expr := g.type_default(node.return_type) // TODO: perf? if default_expr == '{0}' { @@ -1354,6 +1355,9 @@ fn (mut g Gen) write_fn_attrs(attrs []ast.Attr) string { // repeated invocations of the function with the same argument values. g.write('__attribute__((const)) ') } + '_naked' { + g.write('__attribute__((naked)) ') + } 'windows_stdcall' { // windows attributes (msvc/mingw) // prefixed by windows to indicate they're for advanced users only and not really supported by V. diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 7c099849a4..a26a026356 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -342,7 +342,8 @@ fn (mut p Parser) fn_decl() ast.FnDecl { short_fn_name := name is_main := short_fn_name == 'main' && p.mod == 'main' mut is_test := (short_fn_name.starts_with('test_') || short_fn_name.starts_with('testsuite_')) - && (p.file_base.ends_with('_test.v') || p.file_base.ends_with('_test.vv')) + && (p.file_base.ends_with('_test.v') + || p.file_base.all_before_last('.v').all_before_last('.').ends_with('_test')) // Register if is_method { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 1529bddef9..71924d601a 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -900,7 +900,7 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt { p.check(.name) } // dots are part of instructions for some riscv extensions - if arch in [.rv32, .rv64] { + if arch in [.rv32, .rv64, .amd64] { for p.tok.kind == .dot { name += '.' p.next() diff --git a/vlib/v/tests/assembly/naked_attr_test.amd64.v b/vlib/v/tests/assembly/naked_attr_test.amd64.v new file mode 100644 index 0000000000..a2b3296675 --- /dev/null +++ b/vlib/v/tests/assembly/naked_attr_test.amd64.v @@ -0,0 +1,14 @@ +[_naked] +fn naked_fn() { + asm amd64 { + push rbp + mov rbp, rsp + mov rsp, rbp + pop rbp + ret + } +} + +fn test_naked_attr() { + naked_fn() +} diff --git a/vlib/v/tests/assembly/naked_attr_test.i386.v b/vlib/v/tests/assembly/naked_attr_test.i386.v new file mode 100644 index 0000000000..34fa41e1c7 --- /dev/null +++ b/vlib/v/tests/assembly/naked_attr_test.i386.v @@ -0,0 +1,14 @@ +[_naked] +fn naked_fn() { + asm i386 { + push ebp + mov ebp, esp + mov esp, ebp + pop ebp + ret + } +} + +fn test_naked_attr() { + naked_fn() +}