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