| 1 | // Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved. |
| 2 | // Use of this source code is governed by an MIT license |
| 3 | // that can be found in the LICENSE file. |
| 4 | module fmt |
| 5 | |
| 6 | import v.ast |
| 7 | |
| 8 | fn (mut f Fmt) asm_stmt(stmt ast.AsmStmt) { |
| 9 | f.write('asm ') |
| 10 | if stmt.is_volatile { |
| 11 | f.write('volatile ') |
| 12 | } else if stmt.is_goto { |
| 13 | f.write('goto ') |
| 14 | } |
| 15 | lit_arch := if stmt.arch == .wasm32 { |
| 16 | 'wasm' |
| 17 | } else { |
| 18 | stmt.arch.str() |
| 19 | } |
| 20 | f.writeln('${lit_arch} {') |
| 21 | f.indent++ |
| 22 | |
| 23 | f.asm_templates(stmt.templates) |
| 24 | |
| 25 | if stmt.output.len != 0 || stmt.input.len != 0 || stmt.clobbered.len != 0 { |
| 26 | f.write('; ') |
| 27 | } |
| 28 | f.asm_ios(stmt.output) |
| 29 | |
| 30 | if stmt.input.len != 0 || stmt.clobbered.len != 0 { |
| 31 | f.write('; ') |
| 32 | } |
| 33 | f.asm_ios(stmt.input) |
| 34 | |
| 35 | if stmt.clobbered.len != 0 { |
| 36 | f.write('; ') |
| 37 | } |
| 38 | f.asm_clobbered(stmt.clobbered) |
| 39 | |
| 40 | f.indent-- |
| 41 | f.writeln('}') |
| 42 | if f.indent == 0 { |
| 43 | f.writeln('') |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | fn (mut f Fmt) asm_arg(arg ast.AsmArg) { |
| 48 | match arg { |
| 49 | ast.AsmRegister { |
| 50 | f.asm_reg(arg) |
| 51 | } |
| 52 | ast.AsmAlias { |
| 53 | f.write('${arg.name}') |
| 54 | } |
| 55 | ast.IntegerLiteral, ast.FloatLiteral, ast.CharLiteral { |
| 56 | f.write(arg.val) |
| 57 | } |
| 58 | ast.BoolLiteral { |
| 59 | f.write(arg.val.str()) |
| 60 | } |
| 61 | string { |
| 62 | f.string_literal(ast.StringLiteral{ val: arg }) |
| 63 | } |
| 64 | ast.AsmAddressing { |
| 65 | if arg.segment != '' { |
| 66 | f.write(arg.segment) |
| 67 | f.write(':') |
| 68 | } |
| 69 | f.write('[') |
| 70 | base := arg.base |
| 71 | index := arg.index |
| 72 | displacement := arg.displacement |
| 73 | scale := arg.scale |
| 74 | match arg.mode { |
| 75 | .base { |
| 76 | f.asm_arg(base) |
| 77 | } |
| 78 | .displacement { |
| 79 | f.asm_arg(displacement) |
| 80 | } |
| 81 | .base_plus_displacement { |
| 82 | f.asm_arg(base) |
| 83 | f.write(' + ') |
| 84 | f.asm_arg(displacement) |
| 85 | } |
| 86 | .index_times_scale_plus_displacement { |
| 87 | f.asm_arg(index) |
| 88 | f.write(' * ${scale} + ') |
| 89 | f.asm_arg(displacement) |
| 90 | } |
| 91 | .base_plus_index_plus_displacement { |
| 92 | f.asm_arg(base) |
| 93 | f.write(' + ') |
| 94 | f.asm_arg(index) |
| 95 | f.write(' + ') |
| 96 | f.asm_arg(displacement) |
| 97 | } |
| 98 | .base_plus_index_times_scale_plus_displacement { |
| 99 | f.asm_arg(base) |
| 100 | f.write(' + ') |
| 101 | f.asm_arg(index) |
| 102 | f.write(' * ${scale} + ') |
| 103 | f.asm_arg(displacement) |
| 104 | } |
| 105 | .rip_plus_displacement { |
| 106 | f.asm_arg(base) |
| 107 | f.write(' + ') |
| 108 | f.asm_arg(displacement) |
| 109 | } |
| 110 | .invalid { |
| 111 | panic('fmt: invalid addressing mode') |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | f.write(']') |
| 116 | } |
| 117 | ast.AsmDisp { |
| 118 | if arg.val.len >= 2 && arg.val[arg.val.len - 1] in [`b`, `f`] |
| 119 | && arg.val[..arg.val.len - 1].bytes().all(it.is_digit()) { |
| 120 | f.write(arg.val[arg.val.len - 1].ascii_str()) |
| 121 | f.write(arg.val[..arg.val.len - 1]) |
| 122 | } else { |
| 123 | f.write(arg.val) |
| 124 | } |
| 125 | } |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | fn (mut f Fmt) asm_reg(reg ast.AsmRegister) { |
| 130 | f.write(reg.name) |
| 131 | } |
| 132 | |
| 133 | fn (mut f Fmt) asm_templates(templates []ast.AsmTemplate) { |
| 134 | for template in templates { |
| 135 | if template.is_directive { |
| 136 | f.write('.') |
| 137 | } |
| 138 | f.write('${template.name}') |
| 139 | if template.is_label { |
| 140 | f.write(':') |
| 141 | } else if template.args.len > 0 { |
| 142 | f.write(' ') |
| 143 | } |
| 144 | for i, arg in template.args { |
| 145 | f.asm_arg(arg) |
| 146 | if i + 1 < template.args.len { |
| 147 | f.write(', ') |
| 148 | } |
| 149 | } |
| 150 | if template.comments.len == 0 { |
| 151 | f.writeln('') |
| 152 | } else { |
| 153 | f.comments(template.comments) |
| 154 | } |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | fn (mut f Fmt) asm_clobbered(clobbered []ast.AsmClobbered) { |
| 159 | for i, clob in clobbered { |
| 160 | if i != 0 { |
| 161 | f.write(' ') |
| 162 | } |
| 163 | f.write(clob.reg.name) |
| 164 | |
| 165 | if clob.comments.len == 0 { |
| 166 | f.writeln('') |
| 167 | } else { |
| 168 | f.comments(clob.comments) |
| 169 | } |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | fn (mut f Fmt) asm_ios(ios []ast.AsmIO) { |
| 174 | for i, io in ios { |
| 175 | if i != 0 { |
| 176 | f.write(' ') |
| 177 | } |
| 178 | |
| 179 | f.write('${io.constraint} (${io.expr})') |
| 180 | mut as_block := true |
| 181 | if io.expr is ast.Ident { |
| 182 | if io.expr.name == io.alias { |
| 183 | as_block = false |
| 184 | } |
| 185 | } |
| 186 | if as_block && io.alias != '' { |
| 187 | f.write(' as ${io.alias}') |
| 188 | } |
| 189 | if io.comments.len == 0 { |
| 190 | f.writeln('') |
| 191 | } else { |
| 192 | f.comments(io.comments) |
| 193 | } |
| 194 | } |
| 195 | } |
| 196 | |