lib/std/arch/rv64/printer.rad 14.2 KiB 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
            }
309
            write(out, " "); write(out, regNameR(instruction.rd)); write(out, ", ");
310
            if instruction.format.operation <> 2 {
311
                write(out, regNameR(instruction.rs2));
312
                write(out, ", ");
313
            }
314
            write(out, "0("); write(out, regNameR(instruction.rs1)); write(out, ")");
315
        },
316
        case decode::Instr::Fence { predecessor, successor } => {
317
            write(out, "fence "); fenceMask(out, predecessor); write(out, ", "); fenceMask(out, successor);
318
        },
319
        case decode::Instr::FenceI => write(out, "fence.i"),
320
        case decode::Instr::Ecall  => write(out, "ecall"),
321
        case decode::Instr::Ebreak => write(out, "ebreak"),
322
        case decode::Instr::Unknown { bits } => {
323
            write(out, "unknown");
324
            writeParens(out, formatU32(a, bits));
325
        },
326
    }
327
}
328
329
/// Print code with labels to the given output.
330
export unsafe fn printCodeTo(out: &mut sexpr::Output, pkgName: *[u8], code: *[u32], funcs: *[types::FuncAddr], arena: &mut alloc::Arena) {
331
    // Package header.
332
    write(out, "# package `");
333
    write(out, pkgName);
334
    write(out, "`\n\n");
335
336
    for instr, i in code {
337
        if let name = findFunc(funcs, i) {
338
            write(out, "\n# ");
339
            write(out, name);
340
            write(out, "\n\n");
341
        }
342
        printInstr(out, arena, instr);
343
        write(out, "\n");
344
    }
345
}
346
347
/// Find function at given instruction index.
348
fn findFunc(funcs: *[types::FuncAddr], index: u32) -> ?*[u8] {
349
    for i in 0..funcs.len {
350
        if funcs[i].index == index {
351
            return funcs[i].name;
352
        }
353
    }
354
    return nil;
355
}
356
357
/// Print a memory-ordering mask in canonical order.
358
unsafe fn fenceMask(out: &mut sexpr::Output, mask: u32) {
359
    if mask == 0 {
360
        write(out, "0");
361
        return;
362
    }
363
    if (mask & 8) <> 0 {
364
        write(out, "i");
365
    }
366
    if (mask & 4) <> 0 {
367
        write(out, "o");
368
    }
369
    if (mask & 2) <> 0 {
370
        write(out, "r");
371
    }
372
    if (mask & 1) <> 0 {
373
        write(out, "w");
374
    }
375
}