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