From 500b48788e6e71f9f847c533651d14dd0f847617 Mon Sep 17 00:00:00 2001 From: crthpl <56052645+crthpl@users.noreply.github.com> Date: Wed, 23 Jun 2021 04:20:07 -0700 Subject: [PATCH] parser, cgen: fix basic asm registers, fix numbered labels in addressing, support indirect branching (#10545) --- cmd/tools/vast/vast.v | 2 +- vlib/v/ast/ast.v | 12 +++++------ vlib/v/fmt/fmt.v | 10 +++++++-- vlib/v/gen/c/cgen.v | 31 ++++++++++----------------- vlib/v/parser/parser.v | 48 +++++++++++++----------------------------- 5 files changed, 41 insertions(+), 62 deletions(-) diff --git a/cmd/tools/vast/vast.v b/cmd/tools/vast/vast.v index 94dcad1ec6..8b8b43387c 100644 --- a/cmd/tools/vast/vast.v +++ b/cmd/tools/vast/vast.v @@ -1775,7 +1775,7 @@ fn (t Tree) asm_stmt(node ast.AsmStmt) &Node { mut obj := new_object() obj.add('ast_type', t.string_node('AsmStmt')) obj.add('arch', t.enum_node(node.arch)) - obj.add('is_top_level', t.bool_node(node.is_top_level)) + obj.add('is_basic', t.bool_node(node.is_basic)) obj.add('is_volatile', t.bool_node(node.is_volatile)) obj.add('is_goto', t.bool_node(node.is_goto)) obj.add('scope', t.scope(node.scope)) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 5e4c8a19a4..e966650aae 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -1106,12 +1106,12 @@ pub mut: pub struct AsmStmt { pub: - arch pref.Arch - is_top_level bool - is_volatile bool - is_goto bool - clobbered []AsmClobbered - pos token.Position + arch pref.Arch + is_basic bool + is_volatile bool + is_goto bool + clobbered []AsmClobbered + pos token.Position pub mut: templates []AsmTemplate scope &Scope diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 0b8b6500df..aab5bd73fa 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -730,7 +730,7 @@ fn (mut f Fmt) asm_stmt(stmt ast.AsmStmt) { } f.indent-- f.writeln('}') - if stmt.is_top_level { + if f.indent == 0 { f.writeln('') } } @@ -801,7 +801,13 @@ fn (mut f Fmt) asm_arg(arg ast.AsmArg) { f.write(']') } ast.AsmDisp { - f.write(arg.val) + if arg.val.len >= 2 && arg.val[arg.val.len - 1] in [`b`, `f`] + && arg.val[..arg.val.len - 1].bytes().all(it.is_digit()) { + f.write(arg.val[arg.val.len - 1].ascii_str()) + f.write(arg.val[..arg.val.len - 1]) + } else { + f.write(arg.val) + } } } } diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index a4f2f7a8b5..fc75a1846c 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1955,6 +1955,11 @@ fn (mut g Gen) gen_asm_stmt(stmt ast.AsmStmt) { } for i, arg in template.args { + if stmt.arch == .amd64 && (template.name == 'call' || template.name[0] == `j`) + && arg is ast.AsmRegister { + g.write('*') // indirect branching + } + g.asm_arg(arg, stmt) if i + 1 < template.args.len { g.write(', ') @@ -1966,6 +1971,7 @@ fn (mut g Gen) gen_asm_stmt(stmt ast.AsmStmt) { } g.writeln('"') } + if stmt.output.len != 0 || stmt.input.len != 0 || stmt.clobbered.len != 0 || stmt.is_goto { g.write(': ') } @@ -2007,7 +2013,7 @@ fn (mut g Gen) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt) { ast.AsmAlias { name := arg.name if name in stmt.local_labels || name in stmt.global_labels - || name in g.file.global_labels || stmt.is_top_level + || name in g.file.global_labels || stmt.is_basic || (name !in stmt.input.map(it.alias) && name !in stmt.output.map(it.alias)) { asm_formatted_name := if name in stmt.global_labels { '%l[$name]' } else { name } g.write(asm_formatted_name) @@ -2025,8 +2031,8 @@ fn (mut g Gen) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt) { g.write('\$$arg.val.str()') } ast.AsmRegister { - if !stmt.is_top_level { - g.write('%') // escape percent in extended assembly + if !stmt.is_basic { + g.write('%') // escape percent with percent in extended assembly } g.write('%$arg.name') } @@ -2093,25 +2099,10 @@ fn (mut g Gen) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt) { } } ast.AsmDisp { - if arg.val.len >= 2 && arg.val[0] in [`b`, `f`] { - mut is_digit := true - for c in arg.val[1..] { - if !c.is_digit() { - is_digit = false - break - } - } - if is_digit { - g.write(arg.val[1..] + rune(arg.val[0]).str()) - } else { - g.write(arg.val) - } - } else { - g.write(arg.val) - } + g.write(arg.val) } string { - g.write('$arg') + g.write(arg) } } } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 0d241fae33..e7b35aed94 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -931,27 +931,7 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt { } match p.tok.kind { .name { - if p.tok.kind == .name && p.tok.lit.len >= 2 - && (p.tok.lit.starts_with('b') || p.tok.lit.starts_with('f')) { - mut is_digit := true - for c in p.tok.lit[1..] { - if !c.is_digit() { - is_digit = false - break - } - } - if is_digit { - args << ast.AsmDisp{ - val: p.tok.lit - pos: p.tok.position() - } - p.check(.name) - } else { - args << p.reg_or_alias() - } - } else { - args << p.reg_or_alias() - } + args << p.reg_or_alias() } .number { number_lit := p.parse_number_literal() @@ -962,9 +942,7 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt { } } ast.IntegerLiteral { - if (is_directive || number_lit.val.ends_with('b') - || number_lit.val.ends_with('f')) - && !number_lit.val.starts_with('0x') { + if is_directive { args << ast.AsmDisp{ val: number_lit.val pos: number_lit.pos @@ -1099,7 +1077,7 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt { input: input clobbered: clobbered pos: pos.extend(p.tok.position()) - is_top_level: is_top_level + is_basic: is_top_level || output.len + input.len + clobbered.len == 0 scope: scope global_labels: global_labels local_labels: local_labels @@ -1107,18 +1085,21 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt { } fn (mut p Parser) reg_or_alias() ast.AsmArg { - if p.tok.lit in p.scope.objects { - x := p.scope.objects[p.tok.lit] + p.check(.name) + if p.prev_tok.lit in p.scope.objects { + x := p.scope.objects[p.prev_tok.lit] if x is ast.AsmRegister { - b := x - p.check(.name) - return b + return ast.AsmArg(x as ast.AsmRegister) } else { - verror('parser bug: non-register ast.ScopeObject found in scope') + verror('non-register ast.ScopeObject found in scope') return ast.AsmDisp{} // should not be reached } + } else if p.prev_tok.len >= 2 && p.prev_tok.lit[0] in [`b`, `f`] + && p.prev_tok.lit[1..].bytes().all(it.is_digit()) { + return ast.AsmDisp{ + val: p.prev_tok.lit[1..] + p.prev_tok.lit[0].ascii_str() + } } else { - p.check(.name) return ast.AsmAlias{ name: p.prev_tok.lit pos: p.prev_tok.position() @@ -1215,11 +1196,12 @@ fn (mut p Parser) reg_or_alias() ast.AsmArg { // pos: pos.extend(p.prev_tok.position()) // } // } + fn (mut p Parser) asm_addressing() ast.AsmAddressing { pos := p.tok.position() p.check(.lsbr) unknown_addressing_mode := 'unknown addressing mode. supported ones are [displacement], [base], [base + displacement], [index ∗ scale + displacement], [base + index ∗ scale + displacement], [base + index + displacement], [rip + displacement]' - // this mess used to look much cleaner before the removal of peek_tok3, see above + // this mess used to look much cleaner before the removal of peek_tok2/3, see above code for cleaner version if p.peek_tok.kind == .rsbr { // [displacement] or [base] if p.tok.kind == .name { base := p.reg_or_alias()