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()
|
mut obj := new_object()
|
||||||
obj.add('ast_type', t.string_node('AsmStmt'))
|
obj.add('ast_type', t.string_node('AsmStmt'))
|
||||||
obj.add('arch', t.enum_node(node.arch))
|
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_volatile', t.bool_node(node.is_volatile))
|
||||||
obj.add('is_goto', t.bool_node(node.is_goto))
|
obj.add('is_goto', t.bool_node(node.is_goto))
|
||||||
obj.add('scope', t.scope(node.scope))
|
obj.add('scope', t.scope(node.scope))
|
||||||
|
|
|
@ -1106,12 +1106,12 @@ pub mut:
|
||||||
|
|
||||||
pub struct AsmStmt {
|
pub struct AsmStmt {
|
||||||
pub:
|
pub:
|
||||||
arch pref.Arch
|
arch pref.Arch
|
||||||
is_top_level bool
|
is_basic bool
|
||||||
is_volatile bool
|
is_volatile bool
|
||||||
is_goto bool
|
is_goto bool
|
||||||
clobbered []AsmClobbered
|
clobbered []AsmClobbered
|
||||||
pos token.Position
|
pos token.Position
|
||||||
pub mut:
|
pub mut:
|
||||||
templates []AsmTemplate
|
templates []AsmTemplate
|
||||||
scope &Scope
|
scope &Scope
|
||||||
|
|
|
@ -730,7 +730,7 @@ fn (mut f Fmt) asm_stmt(stmt ast.AsmStmt) {
|
||||||
}
|
}
|
||||||
f.indent--
|
f.indent--
|
||||||
f.writeln('}')
|
f.writeln('}')
|
||||||
if stmt.is_top_level {
|
if f.indent == 0 {
|
||||||
f.writeln('')
|
f.writeln('')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -801,7 +801,13 @@ fn (mut f Fmt) asm_arg(arg ast.AsmArg) {
|
||||||
f.write(']')
|
f.write(']')
|
||||||
}
|
}
|
||||||
ast.AsmDisp {
|
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 {
|
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)
|
g.asm_arg(arg, stmt)
|
||||||
if i + 1 < template.args.len {
|
if i + 1 < template.args.len {
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
|
@ -1966,6 +1971,7 @@ fn (mut g Gen) gen_asm_stmt(stmt ast.AsmStmt) {
|
||||||
}
|
}
|
||||||
g.writeln('"')
|
g.writeln('"')
|
||||||
}
|
}
|
||||||
|
|
||||||
if stmt.output.len != 0 || stmt.input.len != 0 || stmt.clobbered.len != 0 || stmt.is_goto {
|
if stmt.output.len != 0 || stmt.input.len != 0 || stmt.clobbered.len != 0 || stmt.is_goto {
|
||||||
g.write(': ')
|
g.write(': ')
|
||||||
}
|
}
|
||||||
|
@ -2007,7 +2013,7 @@ fn (mut g Gen) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt) {
|
||||||
ast.AsmAlias {
|
ast.AsmAlias {
|
||||||
name := arg.name
|
name := arg.name
|
||||||
if name in stmt.local_labels || name in stmt.global_labels
|
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)) {
|
|| (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 }
|
asm_formatted_name := if name in stmt.global_labels { '%l[$name]' } else { name }
|
||||||
g.write(asm_formatted_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()')
|
g.write('\$$arg.val.str()')
|
||||||
}
|
}
|
||||||
ast.AsmRegister {
|
ast.AsmRegister {
|
||||||
if !stmt.is_top_level {
|
if !stmt.is_basic {
|
||||||
g.write('%') // escape percent in extended assembly
|
g.write('%') // escape percent with percent in extended assembly
|
||||||
}
|
}
|
||||||
g.write('%$arg.name')
|
g.write('%$arg.name')
|
||||||
}
|
}
|
||||||
|
@ -2093,25 +2099,10 @@ fn (mut g Gen) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.AsmDisp {
|
ast.AsmDisp {
|
||||||
if arg.val.len >= 2 && arg.val[0] in [`b`, `f`] {
|
g.write(arg.val)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
string {
|
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 {
|
match p.tok.kind {
|
||||||
.name {
|
.name {
|
||||||
if p.tok.kind == .name && p.tok.lit.len >= 2
|
args << p.reg_or_alias()
|
||||||
&& (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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.number {
|
.number {
|
||||||
number_lit := p.parse_number_literal()
|
number_lit := p.parse_number_literal()
|
||||||
|
@ -962,9 +942,7 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.IntegerLiteral {
|
ast.IntegerLiteral {
|
||||||
if (is_directive || number_lit.val.ends_with('b')
|
if is_directive {
|
||||||
|| number_lit.val.ends_with('f'))
|
|
||||||
&& !number_lit.val.starts_with('0x') {
|
|
||||||
args << ast.AsmDisp{
|
args << ast.AsmDisp{
|
||||||
val: number_lit.val
|
val: number_lit.val
|
||||||
pos: number_lit.pos
|
pos: number_lit.pos
|
||||||
|
@ -1099,7 +1077,7 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
|
||||||
input: input
|
input: input
|
||||||
clobbered: clobbered
|
clobbered: clobbered
|
||||||
pos: pos.extend(p.tok.position())
|
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
|
scope: scope
|
||||||
global_labels: global_labels
|
global_labels: global_labels
|
||||||
local_labels: local_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 {
|
fn (mut p Parser) reg_or_alias() ast.AsmArg {
|
||||||
if p.tok.lit in p.scope.objects {
|
p.check(.name)
|
||||||
x := p.scope.objects[p.tok.lit]
|
if p.prev_tok.lit in p.scope.objects {
|
||||||
|
x := p.scope.objects[p.prev_tok.lit]
|
||||||
if x is ast.AsmRegister {
|
if x is ast.AsmRegister {
|
||||||
b := x
|
return ast.AsmArg(x as ast.AsmRegister)
|
||||||
p.check(.name)
|
|
||||||
return b
|
|
||||||
} else {
|
} 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
|
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 {
|
} else {
|
||||||
p.check(.name)
|
|
||||||
return ast.AsmAlias{
|
return ast.AsmAlias{
|
||||||
name: p.prev_tok.lit
|
name: p.prev_tok.lit
|
||||||
pos: p.prev_tok.position()
|
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())
|
// pos: pos.extend(p.prev_tok.position())
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
fn (mut p Parser) asm_addressing() ast.AsmAddressing {
|
fn (mut p Parser) asm_addressing() ast.AsmAddressing {
|
||||||
pos := p.tok.position()
|
pos := p.tok.position()
|
||||||
p.check(.lsbr)
|
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]'
|
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.peek_tok.kind == .rsbr { // [displacement] or [base]
|
||||||
if p.tok.kind == .name {
|
if p.tok.kind == .name {
|
||||||
base := p.reg_or_alias()
|
base := p.reg_or_alias()
|
||||||
|
|
Loading…
Reference in New Issue