parser, cgen: fix basic asm registers, fix numbered labels in addressing, support indirect branching (#10545)

pull/10552/head
crthpl 2021-06-23 04:20:07 -07:00 committed by GitHub
parent 69227b8be7
commit 500b48788e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 41 additions and 62 deletions

View File

@ -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))

View File

@ -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

View File

@ -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)
}
}
}
}

View File

@ -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)
}
}
}

View File

@ -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()