compiler/
kernel/
lib/
examples/
std/
arch/
rv64/
asm/
image/
shared/
asm.rad
24.0 KiB
atomicTests.rad
4.9 KiB
atomics.rad
3.4 KiB
bounds.rad
8.5 KiB
decode.rad
15.2 KiB
emit.rad
30.1 KiB
encode.rad
22.0 KiB
image.rad
4.4 KiB
isel.rad
49.1 KiB
printer.rad
14.1 KiB
shared.rad
15.6 KiB
tests.rad
17.2 KiB
rv64.rad
16.0 KiB
char/
collections/
lang/
sys/
arch.rad
68 B
char.rad
855 B
collections.rad
39 B
fmt.rad
8.3 KiB
intrinsics.rad
467 B
io.rad
1.7 KiB
lang.rad
276 B
mem.rad
2.3 KiB
sys.rad
179 B
testing.rad
2.4 KiB
tests.rad
15.7 KiB
vec.rad
3.2 KiB
std.rad
281 B
scripts/
seed/
sublime/
test/
vim/
.gitignore
336 B
.gitsigners
112 B
CONTRIBUTING
2.1 KiB
LICENSE
1.1 KiB
Makefile
10.2 KiB
README
2.5 KiB
STYLE
2.5 KiB
std.lib
1.5 KiB
std.lib.test
551 B
lib/std/arch/rv64/printer.rad
raw
| 1 | //! RV64 instruction printer. |
| 2 | //! |
| 3 | //! Prints 32-bit instructions in assembly text format. |
| 4 | |
| 5 | use std::fmt; |
| 6 | use std::mem; |
| 7 | use std::lang::alloc; |
| 8 | use std::lang::gen; |
| 9 | use std::lang::sexpr; |
| 10 | use std::lang::gen::types; |
| 11 | |
| 12 | use super::decode; |
| 13 | use super::atomics; |
| 14 | use super::emit; |
| 15 | |
| 16 | ///////////////////// |
| 17 | // Register Names // |
| 18 | ///////////////////// |
| 19 | |
| 20 | /// ABI register names. |
| 21 | constant REG_NAMES: [*[u8]; 32] = [ |
| 22 | "%zero", "%ra", "%sp", "%gp", "%tp", "%t0", "%t1", "%t2", |
| 23 | "%fp", "%s1", "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", |
| 24 | "%a6", "%a7", "%s2", "%s3", "%s4", "%s5", "%s6", "%s7", |
| 25 | "%s8", "%s9", "%s10", "%s11", "%t3", "%t4", "%t5", "%t6" |
| 26 | ]; |
| 27 | |
| 28 | /// Get register name from number. |
| 29 | fn regName(n: u8) -> *[u8] { |
| 30 | return "?" if n >= 32 else REG_NAMES[n as u32]; |
| 31 | } |
| 32 | |
| 33 | /// Get register name from Reg. |
| 34 | fn regNameR(r: gen::Reg) -> *[u8] { |
| 35 | return regName(*r); |
| 36 | } |
| 37 | |
| 38 | /////////////////////// |
| 39 | // Output Helpers // |
| 40 | /////////////////////// |
| 41 | |
| 42 | /// Write a string to output. |
| 43 | unsafe fn write(out: &mut sexpr::Output, s: &[u8]) { |
| 44 | sexpr::write(out, s); |
| 45 | } |
| 46 | |
| 47 | /// Format `i32` into arena. |
| 48 | unsafe fn formatI32(a: &mut alloc::Arena, val: i32) -> *[u8] { |
| 49 | let mut digits: [u8; 12] = undefined; |
| 50 | let start = fmt::formatI32(val, &mut digits[..]); |
| 51 | let slice = try! alloc::allocSlice(a, 1, 1, digits.len - start) as *mut [u8]; |
| 52 | try! mem::copy(slice, &digits[start..]); |
| 53 | |
| 54 | return slice; |
| 55 | } |
| 56 | |
| 57 | /// Format `u32` into arena. |
| 58 | unsafe fn formatU32(a: &mut alloc::Arena, val: u32) -> *[u8] { |
| 59 | let mut digits: [u8; 10] = undefined; |
| 60 | let start = fmt::formatU32(val, &mut digits[..]); |
| 61 | let slice = try! alloc::allocSlice(a, 1, 1, digits.len - start) as *mut [u8]; |
| 62 | try! mem::copy(slice, &digits[start..]); |
| 63 | |
| 64 | return slice; |
| 65 | } |
| 66 | |
| 67 | /////////////////////////////// |
| 68 | // Instruction Printing // |
| 69 | /////////////////////////////// |
| 70 | |
| 71 | /// Mnemonic column width for alignment. |
| 72 | constant MNEMONIC_WIDTH: u32 = 8; |
| 73 | |
| 74 | /// Write text wrapped in parentheses. |
| 75 | unsafe fn writeParens(out: &mut sexpr::Output, s: &[u8]) { |
| 76 | write(out, "("); |
| 77 | write(out, s); |
| 78 | write(out, ")"); |
| 79 | } |
| 80 | |
| 81 | /// Write strings separated by ", ". |
| 82 | unsafe fn writeDelim(out: &mut sexpr::Output, parts: &[*[u8]]) { |
| 83 | for part, i in parts { |
| 84 | if i > 0 { |
| 85 | write(out, ", "); |
| 86 | } |
| 87 | write(out, part); |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | /// Write mnemonic with padding for alignment. |
| 92 | unsafe fn writeMnem(out: &mut sexpr::Output, m: *[u8]) { |
| 93 | write(out, m); |
| 94 | let mut i = m.len; |
| 95 | while i < MNEMONIC_WIDTH { |
| 96 | write(out, " "); |
| 97 | set i += 1; |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | //////////////////////////////// |
| 102 | // Instruction Format Helpers // |
| 103 | //////////////////////////////// |
| 104 | |
| 105 | /// R-type: `op rd, rs1, rs2`. |
| 106 | unsafe fn fmtR(out: &mut sexpr::Output, m: *[u8], rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) { |
| 107 | writeMnem(out, m); |
| 108 | writeDelim(out, &[regNameR(rd), regNameR(rs1), regNameR(rs2)]); |
| 109 | } |
| 110 | |
| 111 | /// I-type: `op rd, rs1, imm`. |
| 112 | unsafe fn fmtI(out: &mut sexpr::Output, a: &mut alloc::Arena, m: *[u8], rd: gen::Reg, rs1: gen::Reg, imm: i32) { |
| 113 | writeMnem(out, m); |
| 114 | writeDelim(out, &[regNameR(rd), regNameR(rs1), formatI32(a, imm)]); |
| 115 | } |
| 116 | |
| 117 | /// 2-reg: `op rd, rs`. |
| 118 | unsafe fn fmt2R(out: &mut sexpr::Output, m: *[u8], rd: gen::Reg, rs: gen::Reg) { |
| 119 | writeMnem(out, m); |
| 120 | writeDelim(out, &[regNameR(rd), regNameR(rs)]); |
| 121 | } |
| 122 | |
| 123 | /// reg + imm: `op rd, imm`. |
| 124 | unsafe fn fmtRI(out: &mut sexpr::Output, a: &mut alloc::Arena, m: *[u8], rd: gen::Reg, imm: i32) { |
| 125 | writeMnem(out, m); |
| 126 | writeDelim(out, &[regNameR(rd), formatI32(a, imm)]); |
| 127 | } |
| 128 | |
| 129 | /// imm only: `op imm`. |
| 130 | unsafe fn fmtImm(out: &mut sexpr::Output, a: &mut alloc::Arena, m: *[u8], imm: i32) { |
| 131 | writeMnem(out, m); |
| 132 | write(out, formatI32(a, imm)); |
| 133 | } |
| 134 | |
| 135 | /// 1-reg: `op rs`. |
| 136 | unsafe fn fmt1R(out: &mut sexpr::Output, m: *[u8], rs: gen::Reg) { |
| 137 | writeMnem(out, m); |
| 138 | write(out, regNameR(rs)); |
| 139 | } |
| 140 | |
| 141 | /// Load: `op rd, imm(rs1)`. |
| 142 | unsafe fn fmtLoad(out: &mut sexpr::Output, a: &mut alloc::Arena, m: *[u8], rd: gen::Reg, rs1: gen::Reg, imm: i32) { |
| 143 | writeMnem(out, m); |
| 144 | writeDelim(out, &[regNameR(rd), formatI32(a, imm)]); |
| 145 | writeParens(out, regNameR(rs1)); |
| 146 | } |
| 147 | |
| 148 | /// Store: `op rs2, imm(rs1)`. |
| 149 | unsafe fn fmtStore(out: &mut sexpr::Output, a: &mut alloc::Arena, m: *[u8], rs2: gen::Reg, rs1: gen::Reg, imm: i32) { |
| 150 | writeMnem(out, m); |
| 151 | writeDelim(out, &[regNameR(rs2), formatI32(a, imm)]); |
| 152 | writeParens(out, regNameR(rs1)); |
| 153 | } |
| 154 | |
| 155 | /// Branch: `op rs1, rs2, imm`. |
| 156 | unsafe fn fmtB(out: &mut sexpr::Output, a: &mut alloc::Arena, m: *[u8], rs1: gen::Reg, rs2: gen::Reg, imm: i32) { |
| 157 | writeMnem(out, m); |
| 158 | writeDelim(out, &[regNameR(rs1), regNameR(rs2), formatI32(a, imm)]); |
| 159 | } |
| 160 | |
| 161 | /// Branch zero: `op rs1, imm`. |
| 162 | unsafe fn fmtBz(out: &mut sexpr::Output, a: &mut alloc::Arena, m: *[u8], rs1: gen::Reg, imm: i32) { |
| 163 | writeMnem(out, m); |
| 164 | writeDelim(out, &[regNameR(rs1), formatI32(a, imm)]); |
| 165 | } |
| 166 | |
| 167 | /// Print a single instruction to output buffer. |
| 168 | export unsafe fn printInstr(out: &mut sexpr::Output, a: &mut alloc::Arena, instr: u32) { |
| 169 | let decoded = decode::decode(instr); |
| 170 | |
| 171 | match decoded { |
| 172 | case decode::Instr::Lui { rd, imm } => fmtRI(out, a, "lui", rd, imm), |
| 173 | case decode::Instr::Auipc { rd, imm } => fmtRI(out, a, "auipc", rd, imm), |
| 174 | case decode::Instr::Jal { rd, imm } => { |
| 175 | if *rd == 0 { |
| 176 | fmtImm(out, a, "j", imm); |
| 177 | } else { |
| 178 | fmtRI(out, a, "jal", rd, imm); |
| 179 | } |
| 180 | }, |
| 181 | case decode::Instr::Jalr { rd, rs1, imm } => { |
| 182 | if *rd == 0 and *rs1 == 1 and imm == 0 { |
| 183 | write(out, "ret"); |
| 184 | } else if *rd == 0 and imm == 0 { |
| 185 | fmt1R(out, "jr", rs1); |
| 186 | } else { |
| 187 | fmtI(out, a, "jalr", rd, rs1, imm); |
| 188 | } |
| 189 | }, |
| 190 | case decode::Instr::Beq { rs1, rs2, imm } => { |
| 191 | if *rs2 == 0 { |
| 192 | fmtBz(out, a, "beqz", rs1, imm); |
| 193 | } else { |
| 194 | fmtB(out, a, "beq", rs1, rs2, imm); |
| 195 | } |
| 196 | }, |
| 197 | case decode::Instr::Bne { rs1, rs2, imm } => { |
| 198 | if *rs2 == 0 { |
| 199 | fmtBz(out, a, "bnez", rs1, imm); |
| 200 | } else { |
| 201 | fmtB(out, a, "bne", rs1, rs2, imm); |
| 202 | } |
| 203 | }, |
| 204 | case decode::Instr::Blt { rs1, rs2, imm } => fmtB(out, a, "blt", rs1, rs2, imm), |
| 205 | case decode::Instr::Bge { rs1, rs2, imm } => fmtB(out, a, "bge", rs1, rs2, imm), |
| 206 | case decode::Instr::Bltu { rs1, rs2, imm } => fmtB(out, a, "bltu", rs1, rs2, imm), |
| 207 | case decode::Instr::Bgeu { rs1, rs2, imm } => fmtB(out, a, "bgeu", rs1, rs2, imm), |
| 208 | case decode::Instr::Lb { rd, rs1, imm } => fmtLoad(out, a, "lb", rd, rs1, imm), |
| 209 | case decode::Instr::Lh { rd, rs1, imm } => fmtLoad(out, a, "lh", rd, rs1, imm), |
| 210 | case decode::Instr::Lw { rd, rs1, imm } => fmtLoad(out, a, "lw", rd, rs1, imm), |
| 211 | case decode::Instr::Ld { rd, rs1, imm } => fmtLoad(out, a, "ld", rd, rs1, imm), |
| 212 | case decode::Instr::Lbu { rd, rs1, imm } => fmtLoad(out, a, "lbu", rd, rs1, imm), |
| 213 | case decode::Instr::Lhu { rd, rs1, imm } => fmtLoad(out, a, "lhu", rd, rs1, imm), |
| 214 | case decode::Instr::Lwu { rd, rs1, imm } => fmtLoad(out, a, "lwu", rd, rs1, imm), |
| 215 | case decode::Instr::Sb { rs2, rs1, imm } => fmtStore(out, a, "sb", rs2, rs1, imm), |
| 216 | case decode::Instr::Sh { rs2, rs1, imm } => fmtStore(out, a, "sh", rs2, rs1, imm), |
| 217 | case decode::Instr::Sw { rs2, rs1, imm } => fmtStore(out, a, "sw", rs2, rs1, imm), |
| 218 | case decode::Instr::Sd { rs2, rs1, imm } => fmtStore(out, a, "sd", rs2, rs1, imm), |
| 219 | case decode::Instr::Addi { rd, rs1, imm } => { |
| 220 | if *rd == 0 and *rs1 == 0 and imm == 0 { |
| 221 | write(out, "nop"); |
| 222 | } else if imm == 0 { |
| 223 | fmt2R(out, "mv", rd, rs1); |
| 224 | } else if *rs1 == 0 { |
| 225 | fmtRI(out, a, "li", rd, imm); |
| 226 | } else { |
| 227 | fmtI(out, a, "addi", rd, rs1, imm); |
| 228 | } |
| 229 | }, |
| 230 | case decode::Instr::Slti { rd, rs1, imm } => fmtI(out, a, "slti", rd, rs1, imm), |
| 231 | case decode::Instr::Sltiu { rd, rs1, imm } => { |
| 232 | if imm == 1 { |
| 233 | fmt2R(out, "seqz", rd, rs1); |
| 234 | } else { |
| 235 | fmtI(out, a, "sltiu", rd, rs1, imm); |
| 236 | } |
| 237 | }, |
| 238 | case decode::Instr::Xori { rd, rs1, imm } => { |
| 239 | if imm == -1 { |
| 240 | fmt2R(out, "not", rd, rs1); |
| 241 | } else { |
| 242 | fmtI(out, a, "xori", rd, rs1, imm); |
| 243 | } |
| 244 | }, |
| 245 | case decode::Instr::Ori { rd, rs1, imm } => fmtI(out, a, "ori", rd, rs1, imm), |
| 246 | case decode::Instr::Andi { rd, rs1, imm } => fmtI(out, a, "andi", rd, rs1, imm), |
| 247 | case decode::Instr::Slli { rd, rs1, shamt } => fmtI(out, a, "slli", rd, rs1, shamt), |
| 248 | case decode::Instr::Srli { rd, rs1, shamt } => fmtI(out, a, "srli", rd, rs1, shamt), |
| 249 | case decode::Instr::Srai { rd, rs1, shamt } => fmtI(out, a, "srai", rd, rs1, shamt), |
| 250 | case decode::Instr::Add { rd, rs1, rs2 } => fmtR(out, "add", rd, rs1, rs2), |
| 251 | case decode::Instr::Sub { rd, rs1, rs2 } => { |
| 252 | if *rs1 == 0 { |
| 253 | fmt2R(out, "neg", rd, rs2); |
| 254 | } else { |
| 255 | fmtR(out, "sub", rd, rs1, rs2); |
| 256 | } |
| 257 | }, |
| 258 | case decode::Instr::Sll { rd, rs1, rs2 } => fmtR(out, "sll", rd, rs1, rs2), |
| 259 | case decode::Instr::Slt { rd, rs1, rs2 } => fmtR(out, "slt", rd, rs1, rs2), |
| 260 | case decode::Instr::Sltu { rd, rs1, rs2 } => { |
| 261 | if *rs1 == 0 { |
| 262 | fmt2R(out, "snez", rd, rs2); |
| 263 | } else { |
| 264 | fmtR(out, "sltu", rd, rs1, rs2); |
| 265 | } |
| 266 | }, |
| 267 | case decode::Instr::Xor { rd, rs1, rs2 } => fmtR(out, "xor", rd, rs1, rs2), |
| 268 | case decode::Instr::Srl { rd, rs1, rs2 } => fmtR(out, "srl", rd, rs1, rs2), |
| 269 | case decode::Instr::Sra { rd, rs1, rs2 } => fmtR(out, "sra", rd, rs1, rs2), |
| 270 | case decode::Instr::Or { rd, rs1, rs2 } => fmtR(out, "or", rd, rs1, rs2), |
| 271 | case decode::Instr::And { rd, rs1, rs2 } => fmtR(out, "and", rd, rs1, rs2), |
| 272 | case decode::Instr::Mul { rd, rs1, rs2 } => fmtR(out, "mul", rd, rs1, rs2), |
| 273 | case decode::Instr::Mulh { rd, rs1, rs2 } => fmtR(out, "mulh", rd, rs1, rs2), |
| 274 | case decode::Instr::Mulhsu { rd, rs1, rs2 } => fmtR(out, "mulhsu", rd, rs1, rs2), |
| 275 | case decode::Instr::Mulhu { rd, rs1, rs2 } => fmtR(out, "mulhu", rd, rs1, rs2), |
| 276 | case decode::Instr::Div { rd, rs1, rs2 } => fmtR(out, "div", rd, rs1, rs2), |
| 277 | case decode::Instr::Divu { rd, rs1, rs2 } => fmtR(out, "divu", rd, rs1, rs2), |
| 278 | case decode::Instr::Rem { rd, rs1, rs2 } => fmtR(out, "rem", rd, rs1, rs2), |
| 279 | case decode::Instr::Remu { rd, rs1, rs2 } => fmtR(out, "remu", rd, rs1, rs2), |
| 280 | case decode::Instr::Addiw { rd, rs1, imm } => { |
| 281 | if imm == 0 { |
| 282 | fmt2R(out, "sext.w", rd, rs1); |
| 283 | } else { |
| 284 | fmtI(out, a, "addiw", rd, rs1, imm); |
| 285 | } |
| 286 | }, |
| 287 | case decode::Instr::Slliw { rd, rs1, shamt } => fmtI(out, a, "slliw", rd, rs1, shamt), |
| 288 | case decode::Instr::Srliw { rd, rs1, shamt } => fmtI(out, a, "srliw", rd, rs1, shamt), |
| 289 | case decode::Instr::Sraiw { rd, rs1, shamt } => fmtI(out, a, "sraiw", rd, rs1, shamt), |
| 290 | case decode::Instr::Addw { rd, rs1, rs2 } => fmtR(out, "addw", rd, rs1, rs2), |
| 291 | case decode::Instr::Subw { rd, rs1, rs2 } => fmtR(out, "subw", rd, rs1, rs2), |
| 292 | case decode::Instr::Sllw { rd, rs1, rs2 } => fmtR(out, "sllw", rd, rs1, rs2), |
| 293 | case decode::Instr::Srlw { rd, rs1, rs2 } => fmtR(out, "srlw", rd, rs1, rs2), |
| 294 | case decode::Instr::Sraw { rd, rs1, rs2 } => fmtR(out, "sraw", rd, rs1, rs2), |
| 295 | case decode::Instr::Mulw { rd, rs1, rs2 } => fmtR(out, "mulw", rd, rs1, rs2), |
| 296 | case decode::Instr::Divw { rd, rs1, rs2 } => fmtR(out, "divw", rd, rs1, rs2), |
| 297 | case decode::Instr::Divuw { rd, rs1, rs2 } => fmtR(out, "divuw", rd, rs1, rs2), |
| 298 | case decode::Instr::Remw { rd, rs1, rs2 } => fmtR(out, "remw", rd, rs1, rs2), |
| 299 | case decode::Instr::Remuw { rd, rs1, rs2 } => fmtR(out, "remuw", rd, rs1, rs2), |
| 300 | case decode::Instr::Atomic(instruction) => { |
| 301 | let stem = atomics::name(instruction.format.operation) else panic "invalid atomic operation"; |
| 302 | write(out, stem); |
| 303 | write(out, ".w" if instruction.format.width == 2 else ".d"); |
| 304 | match instruction.format.order { |
| 305 | case 1 => write(out, ".rl"), case 2 => write(out, ".aq"), case 3 => write(out, ".aqrl"), |
| 306 | else => {}, |
| 307 | } |
| 308 | write(out, " "); write(out, regNameR(instruction.rd)); write(out, ", "); |
| 309 | if instruction.format.operation <> 2 { write(out, regNameR(instruction.rs2)); write(out, ", "); } |
| 310 | write(out, "0("); write(out, regNameR(instruction.rs1)); write(out, ")"); |
| 311 | }, |
| 312 | case decode::Instr::Fence { predecessor, successor } => { |
| 313 | write(out, "fence "); fenceMask(out, predecessor); write(out, ", "); fenceMask(out, successor); |
| 314 | }, |
| 315 | case decode::Instr::FenceI => write(out, "fence.i"), |
| 316 | case decode::Instr::Ecall => write(out, "ecall"), |
| 317 | case decode::Instr::Ebreak => write(out, "ebreak"), |
| 318 | case decode::Instr::Unknown { bits } => { |
| 319 | write(out, "unknown"); |
| 320 | writeParens(out, formatU32(a, bits)); |
| 321 | }, |
| 322 | } |
| 323 | } |
| 324 | |
| 325 | /// Print code with labels to the given output. |
| 326 | export unsafe fn printCodeTo(out: &mut sexpr::Output, pkgName: *[u8], code: *[u32], funcs: *[types::FuncAddr], arena: &mut alloc::Arena) { |
| 327 | // Package header. |
| 328 | write(out, "# package `"); |
| 329 | write(out, pkgName); |
| 330 | write(out, "`\n\n"); |
| 331 | |
| 332 | for instr, i in code { |
| 333 | if let name = findFunc(funcs, i) { |
| 334 | write(out, "\n# "); |
| 335 | write(out, name); |
| 336 | write(out, "\n\n"); |
| 337 | } |
| 338 | printInstr(out, arena, instr); |
| 339 | write(out, "\n"); |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | /// Find function at given instruction index. |
| 344 | fn findFunc(funcs: *[types::FuncAddr], index: u32) -> ?*[u8] { |
| 345 | for i in 0..funcs.len { |
| 346 | if funcs[i].index == index { |
| 347 | return funcs[i].name; |
| 348 | } |
| 349 | } |
| 350 | return nil; |
| 351 | } |
| 352 | |
| 353 | /// Print a memory-ordering mask in canonical order. |
| 354 | unsafe fn fenceMask(out: &mut sexpr::Output, mask: u32) { |
| 355 | if mask == 0 { write(out, "0"); return; } |
| 356 | if (mask & 8) <> 0 { write(out, "i"); } |
| 357 | if (mask & 4) <> 0 { write(out, "o"); } |
| 358 | if (mask & 2) <> 0 { write(out, "r"); } |
| 359 | if (mask & 1) <> 0 { write(out, "w"); } |
| 360 | } |