v/vlib/v/fmt/asm.v

190 lines
3.6 KiB
V

// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module fmt
import v.ast
fn (mut f Fmt) asm_stmt(stmt ast.AsmStmt) {
f.write('asm ')
if stmt.is_volatile {
f.write('volatile ')
} else if stmt.is_goto {
f.write('goto ')
}
f.writeln('$stmt.arch {')
f.indent++
f.asm_templates(stmt.templates)
if stmt.output.len != 0 || stmt.input.len != 0 || stmt.clobbered.len != 0 {
f.write('; ')
}
f.asm_ios(stmt.output)
if stmt.input.len != 0 || stmt.clobbered.len != 0 {
f.write('; ')
}
f.asm_ios(stmt.input)
if stmt.clobbered.len != 0 {
f.write('; ')
}
f.asm_clobbered(stmt.clobbered)
f.indent--
f.writeln('}')
if f.indent == 0 {
f.writeln('')
}
}
fn (mut f Fmt) asm_arg(arg ast.AsmArg) {
match arg {
ast.AsmRegister {
f.asm_reg(arg)
}
ast.AsmAlias {
f.write('$arg.name')
}
ast.IntegerLiteral, ast.FloatLiteral, ast.CharLiteral {
f.write(arg.val)
}
ast.BoolLiteral {
f.write(arg.val.str())
}
string {
f.write(arg)
}
ast.AsmAddressing {
if arg.segment != '' {
f.write(arg.segment)
f.write(':')
}
f.write('[')
base := arg.base
index := arg.index
displacement := arg.displacement
scale := arg.scale
match arg.mode {
.base {
f.asm_arg(base)
}
.displacement {
f.asm_arg(displacement)
}
.base_plus_displacement {
f.asm_arg(base)
f.write(' + ')
f.asm_arg(displacement)
}
.index_times_scale_plus_displacement {
f.asm_arg(index)
f.write(' * $scale + ')
f.asm_arg(displacement)
}
.base_plus_index_plus_displacement {
f.asm_arg(base)
f.write(' + ')
f.asm_arg(index)
f.write(' + ')
f.asm_arg(displacement)
}
.base_plus_index_times_scale_plus_displacement {
f.asm_arg(base)
f.write(' + ')
f.asm_arg(index)
f.write(' * $scale + ')
f.asm_arg(displacement)
}
.rip_plus_displacement {
f.asm_arg(base)
f.write(' + ')
f.asm_arg(displacement)
}
.invalid {
panic('fmt: invalid addressing mode')
}
}
f.write(']')
}
ast.AsmDisp {
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)
}
}
}
}
fn (mut f Fmt) asm_reg(reg ast.AsmRegister) {
f.write(reg.name)
}
fn (mut f Fmt) asm_templates(templates []ast.AsmTemplate) {
for template in templates {
if template.is_directive {
f.write('.')
}
f.write('$template.name')
if template.is_label {
f.write(':')
} else if template.args.len > 0 {
f.write(' ')
}
for i, arg in template.args {
f.asm_arg(arg)
if i + 1 < template.args.len {
f.write(', ')
}
}
if template.comments.len == 0 {
f.writeln('')
} else {
f.comments(template.comments, inline: false)
}
}
}
fn (mut f Fmt) asm_clobbered(clobbered []ast.AsmClobbered) {
for i, clob in clobbered {
if i != 0 {
f.write(' ')
}
f.write(clob.reg.name)
if clob.comments.len == 0 {
f.writeln('')
} else {
f.comments(clob.comments, inline: false)
}
}
}
fn (mut f Fmt) asm_ios(ios []ast.AsmIO) {
for i, io in ios {
if i != 0 {
f.write(' ')
}
f.write('$io.constraint ($io.expr)')
mut as_block := true
if io.expr is ast.Ident {
if io.expr.name == io.alias {
as_block = false
}
}
if as_block && io.alias != '' {
f.write(' as $io.alias')
}
if io.comments.len == 0 {
f.writeln('')
} else {
f.comments(io.comments, inline: false)
}
}
}