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