parser, cgen: fix basic asm registers, fix numbered labels in addressing, support indirect branching (#10545)
parent
69227b8be7
commit
500b48788e
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue