lib/std/arch/rv64/asm/parser.rad 32.5 KiB raw
1
//! Assembler parser pass.
2
use std::mem;
3
use std::fmt;
4
use std::lang::alloc;
5
use std::lang::strings;
6
use std::lang::parser;
7
use std::lang::gen;
8
use std::collections::dict;
9
use std::arch::rv64::encode;
10
use std::arch::rv64;
11
12
use super::emit;
13
use super::scanner;
14
15
/// Parsed memory operand with base register and signed byte offset.
16
record MemOperand: Copy {
17
    /// Base register inside the memory operand parentheses.
18
    base: gen::Reg,
19
    /// Signed byte offset preceding the base register.
20
    offset: i32,
21
}
22
23
/// Parse assembler source into the supplied assembler state.
24
export fn parseProgram(a: *mut super::Assembler) throws (super::Error) {
25
    advance(a);
26
27
    while a.scan.current.kind <> scanner::TokenKind::Eof {
28
        try parseItem(a);
29
    }
30
}
31
32
/// Align `value` upward to `alignment`, returning nil on u32 overflow.
33
fn checkedAlignUp(value: u32, alignment: u32) -> ?u32 {
34
    let padding = alignment - 1;
35
    if value > parser::U32_MAX - padding {
36
        return nil;
37
    }
38
    return mem::alignUp(value, alignment);
39
}
40
41
/// Advance the parser by one token, preserving the previous token.
42
fn advance(a: *mut super::Assembler) {
43
    set a.scan.previous = a.scan.current;
44
    set a.scan.current = scanner::next(&mut a.scan);
45
}
46
47
/// Consume the current token when it has `kind`.
48
fn consume(a: *mut super::Assembler, kind: scanner::TokenKind) -> bool {
49
    if a.scan.current.kind == kind {
50
        advance(a);
51
        return true;
52
    }
53
    return false;
54
}
55
56
/// Create an error at the current token.
57
fn fail(a: *super::Assembler, message: *[u8]) -> super::Error {
58
    return super::Error::Invalid { offset: a.scan.current.offset, message };
59
}
60
61
/// Create an error at `tok`.
62
fn failOnToken(tok: scanner::Token, message: *[u8]) -> super::Error {
63
    return super::Error::Invalid { offset: tok.offset, message };
64
}
65
66
/// Require that a data directive appears while assembling the data section.
67
fn expectDataSection(a: *super::Assembler, tok: scanner::Token) throws (super::Error) {
68
    if a.section <> super::Section::Data {
69
        throw failOnToken(tok, "data directive is only valid in the data section");
70
    }
71
}
72
73
/// Consume `kind` or throw `message` at the current token.
74
fn expect(a: *mut super::Assembler, kind: scanner::TokenKind, message: *[u8]) throws (super::Error) {
75
    if not consume(a, kind) {
76
        throw fail(a, message);
77
    }
78
}
79
80
/// Consume `kind` and return the consumed token.
81
fn expectToken(a: *mut super::Assembler, kind: scanner::TokenKind, message: *[u8]) -> scanner::Token throws (super::Error) {
82
    try expect(a, kind, message);
83
    return a.scan.previous;
84
}
85
86
/// Require that the current item has reached its semicolon terminator.
87
fn expectTerminator(a: *super::Assembler, message: *[u8]) throws (super::Error) {
88
    if a.scan.current.kind <> scanner::TokenKind::Semicolon {
89
        throw fail(a, message);
90
    }
91
}
92
93
/// Require that `value` fits in i32.
94
fn expectI32Value(a: *super::Assembler, value: i64, message: *[u8]) -> i32 throws (super::Error) {
95
    if value < -super::I32_MIN_MAGNITUDE or value > super::I32_MAX_VALUE {
96
        throw fail(a, message);
97
    }
98
    return value as i32;
99
}
100
101
/// Require that `value` fits in a signed 12-bit immediate field.
102
fn expectSmallImmValue(a: *super::Assembler, value: i64) -> i32 throws (super::Error) {
103
    if not encode::isSmallImm64(value) {
104
        throw fail(a, "immediate out of range");
105
    }
106
    return value as i32;
107
}
108
109
/// Define a label at the current text or data offset.
110
fn defineSymbol(a: *mut super::Assembler, name: *[u8], tok: scanner::Token) throws (super::Error) {
111
    if dict::get(&a.symbolMap, name) <> nil {
112
        throw failOnToken(tok, "duplicate label");
113
    }
114
    emit::defineSymbol(a, name);
115
}
116
117
/// Emit a parsed integer data value after applying source-level range checks.
118
fn emitDataValue(a: *mut super::Assembler, value: i64, width: super::DataWidth) throws (super::Error) {
119
    match width {
120
        case super::DataWidth::Word =>
121
            try emit::emitDataValue(a, (try expectI32Value(a, value, "word literal out of range")) as i64, width),
122
        case super::DataWidth::Dword =>
123
            try emit::emitDataValue(a, value, width),
124
    }
125
}
126
127
/// Parse a possibly scoped name from one or more `::`-separated segments.
128
fn parseScopedName(
129
    a: *mut super::Assembler,
130
    kind: scanner::TokenKind,
131
    message: *[u8],
132
    trimPrefix: u32
133
) -> *[u8] throws (super::Error) {
134
    let first = try expectToken(a, kind, message);
135
    let start = first.offset + trimPrefix;
136
    let mut end = first.offset + first.source.len;
137
138
    while consume(a, scanner::TokenKind::ColonColon) {
139
        let segment = try expectToken(a, scanner::TokenKind::Ident, "expected identifier after `::`");
140
        set end = segment.offset + segment.source.len;
141
    }
142
    return strings::intern(a.scan.pool, &a.scan.source[start..end]);
143
}
144
145
/// Parse a bare symbol name.
146
fn parseSymbolName(a: *mut super::Assembler) -> *[u8] throws (super::Error) {
147
    return try parseScopedName(a, scanner::TokenKind::Ident, "expected symbol name", 0);
148
}
149
150
/// Return `true` when [`tok`] is any label token form.
151
fn isLabel(tok: scanner::TokenKind) -> bool {
152
    return tok == scanner::TokenKind::Label or tok == scanner::TokenKind::QuotedLabel;
153
}
154
155
/// Parse the contents of a quoted label token, decoding escapes as needed.
156
fn parseQuotedLabelName(a: *mut super::Assembler) -> *[u8] throws (super::Error) {
157
    let tok = try expectToken(a, scanner::TokenKind::QuotedLabel, "expected label name");
158
    let rawStart = super::LABEL_SIGIL_LEN + super::QUOTE_DELIM_LEN;
159
    let raw = &tok.source[rawStart..tok.source.len - super::QUOTE_DELIM_LEN];
160
    let storage = try alloc::allocSlice(a.arena, 1, 1, raw.len) catch {
161
        panic "asm: out of memory allocating quoted label";
162
    } as *mut [u8];
163
    let len = fmt::unescapeString(raw, storage);
164
165
    return strings::intern(a.scan.pool, &storage[..len]);
166
}
167
168
/// Parse a label reference or definition name.
169
fn parseLabelName(a: *mut super::Assembler) -> *[u8] throws (super::Error) {
170
    if a.scan.current.kind == scanner::TokenKind::QuotedLabel {
171
        return try parseQuotedLabelName(a);
172
    }
173
    return try parseScopedName(a, scanner::TokenKind::Label, "expected label name", super::LABEL_SIGIL_LEN);
174
}
175
176
/// Parse a directive name without its leading `.`.
177
fn parseDirectiveName(a: *mut super::Assembler) -> *[u8] throws (super::Error) {
178
    let name = try expectToken(a, scanner::TokenKind::Directive, "expected directive name");
179
    return &name.source[super::DIRECTIVE_SIGIL_LEN..];
180
}
181
182
/// Parse one top-level assembler item.
183
fn parseItem(a: *mut super::Assembler) throws (super::Error) {
184
    match a.scan.current.kind {
185
        case scanner::TokenKind::Ident => {
186
            let tok = a.scan.current;
187
            let name = try parseSymbolName(a);
188
            try parseInstruction(a, name, tok);
189
            try expect(a, scanner::TokenKind::Semicolon, "expected `;` after instruction");
190
        }
191
        case scanner::TokenKind::Number => {
192
            let tok = a.scan.current;
193
            advance(a);
194
            throw failOnToken(tok, "unexpected number at top level");
195
        }
196
        case scanner::TokenKind::Label, scanner::TokenKind::QuotedLabel => {
197
            let tok = a.scan.current;
198
            let name = try parseLabelName(a);
199
            try defineSymbol(a, name, tok);
200
        }
201
        case scanner::TokenKind::Directive => {
202
            let tok = a.scan.current;
203
            let name = try parseDirectiveName(a);
204
            try parseDirective(a, name, tok);
205
            try expect(a, scanner::TokenKind::Semicolon, "expected `;` after directive");
206
        }
207
        else => throw fail(a, "expected label, instruction, or directive"),
208
    }
209
}
210
211
/// Find `name` in a sorted descriptor table.
212
fn findSortedNameIndex(name: *[u8], len: u32, getName: fn(u32) -> *[u8]) -> ?u32 {
213
    let mut left: u32 = 0;
214
    let mut right: u32 = len;
215
216
    while left < right {
217
        let mid = left + ((right - left) / 2);
218
        let cmp = mem::cmp(name, getName(mid));
219
220
        match cmp {
221
            case -1 => set right = mid,
222
            case  1 => set left = mid + 1,
223
            else => return mid,
224
        }
225
    }
226
    return nil;
227
}
228
229
/// Adapter used by [`findSortedNameIndex`] to read an instruction mnemonic.
230
fn instructionNameAt(index: u32) -> *[u8] {
231
    return super::INSTRUCTIONS[index].name;
232
}
233
234
/// Adapter used by [`findSortedNameIndex`] to read a directive name.
235
fn directiveNameAt(index: u32) -> *[u8] {
236
    return super::DIRECTIVES[index].name;
237
}
238
239
/// Adapter used by [`findSortedNameIndex`] to read a register name.
240
fn registerNameAt(index: u32) -> *[u8] {
241
    return super::REGISTERS[index].name;
242
}
243
244
/// Adapter used by [`findSortedNameIndex`] to read a CSR name.
245
fn csrNameAt(index: u32) -> *[u8] {
246
    return super::CSRS[index].name;
247
}
248
249
/// Look up the operand parser and encoder for an instruction mnemonic.
250
fn lookupInstruction(name: *[u8]) -> ?super::InstructionEncoder {
251
    let index = findSortedNameIndex(name, super::INSTRUCTIONS.len, instructionNameAt) else {
252
        return nil;
253
    };
254
    return super::INSTRUCTIONS[index].encoder;
255
}
256
257
/// Classify a directive name.
258
fn classifyDirective(name: *[u8]) -> ?super::DirectiveKind {
259
    let index = findSortedNameIndex(name, super::DIRECTIVES.len, directiveNameAt) else {
260
        return nil;
261
    };
262
    return super::DIRECTIVES[index].kind;
263
}
264
265
/// Look up a percent-prefixed register name after the `%` has been removed.
266
fn lookupRegister(name: *[u8]) -> ?gen::Reg {
267
    let index = findSortedNameIndex(name, super::REGISTERS.len, registerNameAt) else {
268
        return nil;
269
    };
270
    return super::REGISTERS[index].reg;
271
}
272
273
/// Look up a CSR name.
274
fn lookupCsr(name: *[u8]) -> ?u32 {
275
    let index = findSortedNameIndex(name, super::CSRS.len, csrNameAt) else {
276
        return nil;
277
    };
278
    return super::CSRS[index].csr;
279
}
280
281
/// Parse an instruction after its mnemonic has already been consumed.
282
fn parseInstruction(a: *mut super::Assembler, name: *[u8], tok: scanner::Token) throws (super::Error) {
283
    if a.section <> super::Section::Text {
284
        throw failOnToken(tok, "instructions are only valid in the text section");
285
    }
286
    let form = lookupInstruction(name) else {
287
        throw failOnToken(tok, "unknown instruction");
288
    };
289
    match form {
290
        case super::InstructionEncoder::NoOperand { enc } => {
291
            if a.scan.current.kind <> scanner::TokenKind::Semicolon {
292
                throw fail(a, "unexpected operand");
293
            }
294
            try emit::emitText(a, enc());
295
            return;
296
        }
297
        case super::InstructionEncoder::Fence => return try parseFence(a, tok),
298
        case super::InstructionEncoder::Li => return try parseLi(a),
299
        case super::InstructionEncoder::La => return try parseLa(a),
300
        case super::InstructionEncoder::RR { enc } => return try parseRR(a, enc),
301
        case super::InstructionEncoder::RRR { enc } => return try parseRRR(a, enc),
302
        case super::InstructionEncoder::RRI { enc } => return try parseRRI(a, enc),
303
        case super::InstructionEncoder::Shift { enc } =>
304
            return try parseShift(a, enc, super::SHIFT_LIMIT, "shift amount out of range"),
305
        case super::InstructionEncoder::WordShift { enc } =>
306
            return try parseShift(a, enc, super::WORD_SHIFT_LIMIT, "word shift amount out of range"),
307
        case super::InstructionEncoder::Load { enc } => return try parseLoad(a, enc),
308
        case super::InstructionEncoder::Store { enc } => return try parseStore(a, enc),
309
        case super::InstructionEncoder::Atomic { funct5 } => return try parseAtomic(a, tok, funct5),
310
        case super::InstructionEncoder::Branch { op } => return try parseBranch(a, op),
311
        case super::InstructionEncoder::BranchZero { op } => return try parseBranchZero(a, op),
312
        case super::InstructionEncoder::Jal => return try parseJal(a),
313
        case super::InstructionEncoder::Jump { rd } => return try parseJ(a, rd),
314
        case super::InstructionEncoder::RdCsr { enc } => return try parseRdCsr(a, enc),
315
        case super::InstructionEncoder::CsrRs1 { enc } => return try parseCsrRs1(a, enc),
316
        case super::InstructionEncoder::Csrrw => return try parseCsrrw(a),
317
        case super::InstructionEncoder::Csrsi => return try parseCsrsi(a),
318
        case super::InstructionEncoder::Upper { enc } => return try parseUpper(a, enc),
319
    }
320
}
321
322
/// Parse a full memory/I/O fence or the adjacent `.i` instruction-cache suffix.
323
fn parseFence(a: *mut super::Assembler, mnemonic: scanner::Token) throws (super::Error) {
324
    let mut instruction = encode::fence();
325
    if a.scan.current.kind == scanner::TokenKind::Directive {
326
        if a.scan.current.offset <> mnemonic.offset + mnemonic.source.len
327
            or not mem::eq(a.scan.current.source, ".i") {
328
            throw fail(a, "expected adjacent .i fence suffix");
329
        }
330
        advance(a);
331
        set instruction = encode::fenceI();
332
    }
333
    try expectTerminator(a, "unexpected fence operand");
334
    try emit::emitText(a, instruction);
335
}
336
337
/// Parse the `li` pseudo-instruction.
338
fn parseLi(a: *mut super::Assembler) throws (super::Error) {
339
    let rd = try parseRegister(a);
340
    let value = try parseValue(a);
341
    if encode::isSmallImm64(value) {
342
        try emit::emitText(a, encode::addi(rd, rv64::ZERO, value as i32));
343
        return;
344
    }
345
    let imm = try expectI32Value(a, value, "li immediate out of range");
346
    let split = rv64::emit::splitImm(imm);
347
348
    try emit::emitText(a, encode::lui(rd, split.hi));
349
    try emit::emitText(a, encode::addi(rd, rd, split.lo));
350
}
351
352
/// Parse the `la` pseudo-instruction.
353
fn parseLa(a: *mut super::Assembler) throws (super::Error) {
354
    let rd = try parseRegister(a);
355
    let target = try parseLabelName(a);
356
    let index = a.text.len;
357
358
    try emit::recordTextFixup(a, target, super::FixupInfo::Addr { rd, index }, 2);
359
}
360
361
/// Parse a CSR read-like instruction with destination register then CSR.
362
fn parseRdCsr(a: *mut super::Assembler, enc: fn(gen::Reg, u32) -> u32) throws (super::Error) {
363
    let rd = try parseRegister(a);
364
    let csr = try parseCsr(a);
365
366
    try emit::emitText(a, enc(rd, csr));
367
}
368
369
/// Parse a CSR write-like instruction with CSR then source register.
370
fn parseCsrRs1(a: *mut super::Assembler, enc: fn(u32, gen::Reg) -> u32) throws (super::Error) {
371
    let csr = try parseCsr(a);
372
    let rs1 = try parseRegister(a);
373
374
    try emit::emitText(a, enc(csr, rs1));
375
}
376
377
/// Parse `csrrw`.
378
fn parseCsrrw(a: *mut super::Assembler) throws (super::Error) {
379
    let rd = try parseRegister(a);
380
    let csr = try parseCsr(a);
381
    let rs1 = try parseRegister(a);
382
383
    try emit::emitText(a, encode::csrrw(rd, csr, rs1));
384
}
385
386
/// Parse a CSR immediate instruction.
387
fn parseCsrsi(a: *mut super::Assembler) throws (super::Error) {
388
    let csr = try parseCsr(a);
389
    let imm = try parseValue(a);
390
    if imm < 0 or imm >= super::CSR_IMM_LIMIT {
391
        throw fail(a, "CSR immediate out of range");
392
    }
393
    try emit::emitText(a, encode::csrsi(csr, imm as u32));
394
}
395
396
/// Parse a two-register instruction.
397
fn parseRR(a: *mut super::Assembler, enc: fn(gen::Reg, gen::Reg) -> u32) throws (super::Error) {
398
    let rd = try parseRegister(a);
399
    let rs = try parseRegister(a);
400
401
    try emit::emitText(a, enc(rd, rs));
402
}
403
404
/// Parse a three-register instruction.
405
fn parseRRR(a: *mut super::Assembler, enc: fn(gen::Reg, gen::Reg, gen::Reg) -> u32) throws (super::Error) {
406
    let rd = try parseRegister(a);
407
    let rs1 = try parseRegister(a);
408
    let rs2 = try parseRegister(a);
409
410
    try emit::emitText(a, enc(rd, rs1, rs2));
411
}
412
413
/// Parse a register-register-immediate instruction.
414
fn parseRRI(a: *mut super::Assembler, enc: fn(gen::Reg, gen::Reg, i32) -> u32) throws (super::Error) {
415
    let rd = try parseRegister(a);
416
    let rs1 = try parseRegister(a);
417
    let imm = try parseSmallImm(a);
418
419
    try emit::emitText(a, enc(rd, rs1, imm));
420
}
421
422
/// Parse a shift-immediate instruction and enforce its RV64 shift bound.
423
fn parseShift(
424
    a: *mut super::Assembler,
425
    enc: fn(gen::Reg, gen::Reg, i32) -> u32,
426
    limit: i32,
427
    message: *[u8]
428
) throws (super::Error) {
429
    let rd = try parseRegister(a);
430
    let rs1 = try parseRegister(a);
431
    let shamt64 = try parseValue(a);
432
433
    if shamt64 < 0 {
434
        throw fail(a, "shift amount must be non-negative");
435
    }
436
    if shamt64 >= limit as i64 {
437
        throw fail(a, message);
438
    }
439
    let shamt = shamt64 as i32;
440
441
    try emit::emitText(a, enc(rd, rs1, shamt));
442
}
443
444
/// Parse a load instruction with a memory operand.
445
fn parseLoad(a: *mut super::Assembler, enc: fn(gen::Reg, gen::Reg, i32) -> u32) throws (super::Error) {
446
    let rd = try parseRegister(a);
447
    let memop = try parseMemory(a);
448
449
    try emit::emitText(a, enc(rd, memop.base, memop.offset));
450
}
451
452
/// Parse a store instruction with a memory operand.
453
fn parseStore(a: *mut super::Assembler, enc: fn(gen::Reg, gen::Reg, i32) -> u32) throws (super::Error) {
454
    let rs2 = try parseRegister(a);
455
    let memop = try parseMemory(a);
456
457
    try emit::emitText(a, enc(rs2, memop.base, memop.offset));
458
}
459
460
/// Parse the adjacent width/order suffixes and zero-offset RV64A operands.
461
fn parseAtomic(a: *mut super::Assembler, tok: scanner::Token, funct5: u32) throws (super::Error) {
462
    let widthToken = try expectToken(a, scanner::TokenKind::Directive, "expected atomic width suffix");
463
    if widthToken.offset <> tok.offset + tok.source.len {
464
        throw failOnToken(widthToken, "atomic width must adjoin mnemonic");
465
    }
466
    let mut width: u32 = encode::F3_WORD;
467
    if mem::eq(widthToken.source, ".d") {
468
        set width = encode::F3_DWORD;
469
    } else if not mem::eq(widthToken.source, ".w") {
470
        throw failOnToken(widthToken, "expected `.w` or `.d` atomic width");
471
    }
472
    let mut ordering: u32 = 0;
473
    if a.scan.current.kind == scanner::TokenKind::Directive {
474
        let orderToken = a.scan.current;
475
        if orderToken.offset <> widthToken.offset + widthToken.source.len {
476
            throw failOnToken(orderToken, "atomic ordering must adjoin width");
477
        }
478
        if mem::eq(orderToken.source, ".aq") {
479
            set ordering = 2;
480
        } else if mem::eq(orderToken.source, ".rl") {
481
            set ordering = 1;
482
        } else if mem::eq(orderToken.source, ".aqrl") {
483
            set ordering = 3;
484
        } else {
485
            throw failOnToken(orderToken, "expected `.aq`, `.rl`, or `.aqrl` atomic ordering");
486
        }
487
        advance(a);
488
    }
489
    let rd = try parseRegister(a);
490
    // LR reserves rs2 = x0 and has no source register operand.
491
    let mut rs2 = rv64::ZERO;
492
    if funct5 <> encode::F5_LR {
493
        set rs2 = try parseRegister(a);
494
    }
495
    let memop = try parseMemory(a);
496
    if memop.offset <> 0 {
497
        throw fail(a, "atomic memory offset must be zero");
498
    }
499
    try expectTerminator(a, "unexpected atomic operand");
500
    try emit::emitText(a, encode::atomic(rd, memop.base, rs2, funct5, width, ordering));
501
}
502
503
/// Parse a two-register branch instruction.
504
fn parseBranch(a: *mut super::Assembler, op: super::BranchOp) throws (super::Error) {
505
    let rs1 = try parseRegister(a);
506
    let rs2 = try parseRegister(a);
507
508
    try parseBranchLabel(a, op, rs1, rs2);
509
}
510
511
/// Parse an optional label operand.
512
fn parseOptionalLabel(a: *mut super::Assembler) -> ?*[u8] throws (super::Error) {
513
    if not isLabel(a.scan.current.kind) {
514
        return nil;
515
    }
516
    return try parseLabelName(a);
517
}
518
519
/// Parse a branch target as either a label fixup or immediate offset.
520
fn parseBranchLabel(a: *mut super::Assembler, op: super::BranchOp, rs1: gen::Reg, rs2: gen::Reg) throws (super::Error) {
521
    let index = a.text.len;
522
    if let target = try parseOptionalLabel(a) {
523
        try emit::recordTextFixup(a, target, super::FixupInfo::Branch { op, rs1, rs2, index }, 1);
524
        return;
525
    }
526
    let imm = try parseBranchImm(a);
527
    try emit::emitText(a, emit::encodeBranch(op, rs1, rs2, imm));
528
}
529
530
/// Parse a branch-to-zero pseudo-instruction.
531
fn parseBranchZero(a: *mut super::Assembler, op: super::BranchOp) throws (super::Error) {
532
    let rs = try parseRegister(a);
533
    try parseBranchLabel(a, op, rs, rv64::ZERO);
534
}
535
536
/// Parse `jal` with an explicit destination register.
537
fn parseJal(a: *mut super::Assembler) throws (super::Error) {
538
    let rd = try parseRegister(a);
539
    try parseJ(a, rd);
540
}
541
542
/// Parse a jump target for `jal` or a jump pseudo-instruction.
543
fn parseJ(a: *mut super::Assembler, rd: gen::Reg) throws (super::Error) {
544
    let index = a.text.len;
545
    if let target = try parseOptionalLabel(a) {
546
        try emit::recordTextFixup(a, target, super::FixupInfo::Jal { rd, index }, 1);
547
        return;
548
    }
549
    let imm = try parseJumpImm(a);
550
    try emit::emitText(a, encode::jal(rd, imm));
551
}
552
553
/// Parse an upper-immediate instruction.
554
fn parseUpper(a: *mut super::Assembler, enc: fn(gen::Reg, i32) -> u32) throws (super::Error) {
555
    let rd = try parseRegister(a);
556
    let imm64 = try parseValue(a);
557
    if imm64 < 0 or imm64 > super::UPPER_IMM_MAX_VALUE {
558
        throw fail(a, "upper immediate out of range");
559
    }
560
    try emit::emitText(a, enc(rd, imm64 as i32));
561
}
562
563
/// Parse a directive after its name has already been consumed.
564
fn parseDirective(a: *mut super::Assembler, name: *[u8], tok: scanner::Token) throws (super::Error) {
565
    let directive = classifyDirective(name) else {
566
        throw failOnToken(tok, "unknown directive");
567
    };
568
    match directive {
569
        case super::DirectiveKind::Text => {
570
            try expectTerminator(a, "unexpected operand");
571
            set a.section = super::Section::Text;
572
            return;
573
        }
574
        case super::DirectiveKind::Data => {
575
            try expectTerminator(a, "unexpected operand");
576
            set a.section = super::Section::Data;
577
            return;
578
        }
579
        case super::DirectiveKind::Align =>
580
            return try parseAlignDirective(a),
581
        case super::DirectiveKind::Ascii => {
582
            try expectDataSection(a, tok);
583
            return try parseStringDirective(a);
584
        }
585
        case super::DirectiveKind::Byte => {
586
            try expectDataSection(a, tok);
587
            return try parseByteDirective(a);
588
        }
589
        case super::DirectiveKind::Constant =>
590
            return try parseConstantDirective(a),
591
        case super::DirectiveKind::Dword => {
592
            try expectDataSection(a, tok);
593
            return try parseIntDirective(a, super::DataWidth::Dword);
594
        }
595
        case super::DirectiveKind::Export =>
596
            return try parseExportDirective(a),
597
        case super::DirectiveKind::Space => {
598
            try expectDataSection(a, tok);
599
            return try parseSpaceDirective(a);
600
        }
601
        case super::DirectiveKind::Word => {
602
            try expectDataSection(a, tok);
603
            return try parseIntDirective(a, super::DataWidth::Word);
604
        }
605
    }
606
}
607
608
/// Parse a `.constant` directive.
609
fn parseConstantDirective(a: *mut super::Assembler) throws (super::Error) {
610
    let name = try parseSymbolName(a);
611
    let value = try expectI32Value(a, try parseExpr(a), "constant out of range");
612
613
    dict::insert(&mut a.constMap, name, value);
614
}
615
616
/// Parse a `.export` directive.
617
fn parseExportDirective(a: *mut super::Assembler) throws (super::Error) {
618
    let name = try parseLabelName(a);
619
    dict::insert(&mut a.exportMap, name, 1);
620
    if let idx = dict::get(&a.symbolMap, name) {
621
        set a.symbols[idx as u32].isExported = true;
622
    }
623
}
624
625
/// Parse a `.space` directive.
626
fn parseSpaceDirective(a: *mut super::Assembler) throws (super::Error) {
627
    let count = try parseValue(a);
628
    if count < 0 {
629
        throw fail(a, "space size must be non-negative");
630
    }
631
    // The data section grows on demand; only reject sizes that cannot be
632
    // represented as a section offset.
633
    if count > super::U32_MAX_VALUE - a.data.len as i64 {
634
        throw super::Error::DataOverflow;
635
    }
636
    for _ in 0..count as u32 {
637
        try emit::emitByte(a, 0);
638
    }
639
}
640
641
/// Parse an `.align` directive for the current section.
642
fn parseAlignDirective(a: *mut super::Assembler) throws (super::Error) {
643
    let amount64 = try parseValue(a);
644
    if amount64 <= 0 {
645
        throw fail(a, "alignment must be positive");
646
    }
647
    if amount64 > super::U32_MAX_VALUE {
648
        throw fail(a, "alignment out of range");
649
    }
650
    let amount = amount64 as u32;
651
    if (amount & (amount - 1)) <> 0 {
652
        throw fail(a, "alignment must be a power of two");
653
    }
654
    match a.section {
655
        case super::Section::Text => {
656
            if amount % rv64::INSTR_SIZE as u32 <> 0 {
657
                throw fail(a, "text alignment must be a multiple of 4");
658
            }
659
            let bytes = a.text.len * rv64::INSTR_SIZE as u32;
660
            let aligned = checkedAlignUp(bytes, amount) else {
661
                throw super::Error::TextOverflow;
662
            };
663
            let words = (aligned - bytes) / rv64::INSTR_SIZE as u32;
664
            try emit::emitTextPadding(a, words);
665
        }
666
        case super::Section::Data => {
667
            let aligned = checkedAlignUp(a.data.len, amount) else {
668
                throw super::Error::DataOverflow;
669
            };
670
            for _ in a.data.len..aligned {
671
                try emit::emitByte(a, 0);
672
            }
673
        }
674
    }
675
}
676
677
/// Parse a `.byte` directive.
678
fn parseByteDirective(a: *mut super::Assembler) throws (super::Error) {
679
    loop {
680
        if a.scan.current.kind == scanner::TokenKind::Char {
681
            let ch = parseCharLiteral(a.scan.current) else {
682
                throw fail(a, "invalid char literal");
683
            };
684
            try emit::emitByte(a, ch);
685
            advance(a);
686
        } else {
687
            let value = try parseValue(a);
688
            if value < 0 or value > super::U8_MAX_VALUE {
689
                throw fail(a, "byte literal out of range");
690
            }
691
            try emit::emitByte(a, value as u8);
692
        }
693
        if not consume(a, scanner::TokenKind::Comma) {
694
            return;
695
        }
696
    }
697
}
698
699
/// Parse a fixed-width integer data directive.
700
fn parseIntDirective(a: *mut super::Assembler, width: super::DataWidth) throws (super::Error) {
701
    loop {
702
        if isLabel(a.scan.current.kind) {
703
            let target = try parseLabelName(a);
704
            try emit::recordDataFixup(a, target, width);
705
        } else if a.scan.current.kind == scanner::TokenKind::Char {
706
            let ch = parseCharLiteral(a.scan.current) else {
707
                throw fail(a, "invalid char literal");
708
            };
709
            advance(a);
710
            try emitDataValue(a, ch as i64, width);
711
        } else {
712
            try emitDataValue(a, try parseValue(a), width);
713
        }
714
        if not consume(a, scanner::TokenKind::Comma) {
715
            return;
716
        }
717
    }
718
}
719
720
/// Parse a `.ascii` string literal list.
721
fn parseStringDirective(a: *mut super::Assembler) throws (super::Error) {
722
    loop {
723
        let literal = try expectToken(a, scanner::TokenKind::String, "expected string literal");
724
        try emit::emitDecodedString(a, literal.source);
725
        if not consume(a, scanner::TokenKind::Comma) {
726
            return;
727
        }
728
    }
729
}
730
731
/// Parse and resolve a register operand.
732
fn parseRegister(a: *mut super::Assembler) -> gen::Reg throws (super::Error) {
733
    let tok = try expectToken(a, scanner::TokenKind::Register, "expected register");
734
    let reg = lookupRegister(&tok.source[1..]) else {
735
        throw super::Error::Invalid { offset: tok.offset, message: "unknown register" };
736
    };
737
    return reg;
738
}
739
740
/// Parse a simple signed immediate or constant value.
741
fn parseValue(a: *mut super::Assembler) -> i64 throws (super::Error) {
742
    if consume(a, scanner::TokenKind::Minus) {
743
        return -(try parseValuePrimary(a));
744
    }
745
    return try parseValuePrimary(a);
746
}
747
748
/// Parse the primary form used by simple immediate values.
749
fn parseValuePrimary(a: *mut super::Assembler) -> i64 throws (super::Error) {
750
    if a.scan.current.kind == scanner::TokenKind::Number {
751
        return try parseInteger(a);
752
    }
753
    if a.scan.current.kind == scanner::TokenKind::Ident {
754
        return try parseConstantValue(a);
755
    }
756
    throw fail(a, "expected number or constant");
757
}
758
759
/// Parse an additive constant expression.
760
fn parseExpr(a: *mut super::Assembler) -> i64 throws (super::Error) {
761
    let mut value = try parseExprMul(a);
762
763
    while a.scan.current.kind == scanner::TokenKind::Plus or a.scan.current.kind == scanner::TokenKind::Minus {
764
        let op = a.scan.current.kind;
765
        advance(a);
766
767
        let rhs = try parseExprMul(a);
768
        if op == scanner::TokenKind::Plus {
769
            set value += rhs;
770
        } else {
771
            set value -= rhs;
772
        }
773
    }
774
    return value;
775
}
776
777
/// Parse multiplicative expression operators.
778
fn parseExprMul(a: *mut super::Assembler) -> i64 throws (super::Error) {
779
    let mut value = try parseExprUnary(a);
780
781
    while a.scan.current.kind == scanner::TokenKind::Star or a.scan.current.kind == scanner::TokenKind::Slash {
782
        let op = a.scan.current.kind;
783
        advance(a);
784
785
        let rhs = try parseExprUnary(a);
786
        if op == scanner::TokenKind::Star {
787
            set value *= rhs;
788
        } else {
789
            if rhs == 0 {
790
                throw fail(a, "division by zero");
791
            }
792
            set value /= rhs;
793
        }
794
    }
795
    return value;
796
}
797
798
/// Parse unary expression operators.
799
fn parseExprUnary(a: *mut super::Assembler) -> i64 throws (super::Error) {
800
    if consume(a, scanner::TokenKind::Minus) {
801
        return -(try parseExprUnary(a));
802
    }
803
    if consume(a, scanner::TokenKind::Plus) {
804
        return try parseExprUnary(a);
805
    }
806
    return try parseExprPrimary(a);
807
}
808
809
/// Parse expression atoms.
810
fn parseExprPrimary(a: *mut super::Assembler) -> i64 throws (super::Error) {
811
    if consume(a, scanner::TokenKind::LParen) {
812
        let value = try parseExpr(a);
813
        try expect(a, scanner::TokenKind::RParen, "expected `)`");
814
        return value;
815
    }
816
    if a.scan.current.kind == scanner::TokenKind::Number {
817
        return try parseInteger(a);
818
    }
819
    if a.scan.current.kind == scanner::TokenKind::Ident {
820
        return try parseConstantValue(a);
821
    }
822
    throw fail(a, "expected expression");
823
}
824
825
/// Parse and resolve a named assembler constant.
826
fn parseConstantValue(a: *mut super::Assembler) -> i64 throws (super::Error) {
827
    let name = try parseSymbolName(a);
828
    let value = dict::get(&a.constMap, name) else {
829
        throw super::Error::Invalid { offset: a.scan.previous.offset, message: "undefined constant" };
830
    };
831
    return value as i64;
832
}
833
834
/// Parse and resolve a CSR operand.
835
fn parseCsr(a: *mut super::Assembler) -> u32 throws (super::Error) {
836
    let name = try parseSymbolName(a);
837
    let csr = lookupCsr(name) else {
838
        throw super::Error::Invalid { offset: a.scan.previous.offset, message: "unknown CSR" };
839
    };
840
    return csr;
841
}
842
843
/// Parse an offset(base) memory operand.
844
fn parseMemory(a: *mut super::Assembler) -> MemOperand throws (super::Error) {
845
    let mut offset: i32 = 0;
846
    if a.scan.current.kind <> scanner::TokenKind::LParen {
847
        set offset = try expectSmallImmValue(a, try parseValue(a));
848
    }
849
    try expect(a, scanner::TokenKind::LParen, "expected `(`");
850
    let base = try parseRegister(a);
851
    try expect(a, scanner::TokenKind::RParen, "expected `)`");
852
853
    return MemOperand { base, offset };
854
}
855
856
/// Parse an immediate value that fits in a signed 12-bit field.
857
fn parseSmallImm(a: *mut super::Assembler) -> i32 throws (super::Error) {
858
    return try expectSmallImmValue(a, try parseValue(a));
859
}
860
861
/// Parse and validate a branch immediate.
862
fn parseBranchImm(a: *mut super::Assembler) -> i32 throws (super::Error) {
863
    let value = try expectI32Value(a, try parseValue(a), "branch immediate out of range");
864
    if not encode::isBranchImm(value) {
865
        throw fail(a, "branch immediate out of range");
866
    }
867
    return value;
868
}
869
870
/// Parse and validate a jump immediate.
871
fn parseJumpImm(a: *mut super::Assembler) -> i32 throws (super::Error) {
872
    let value = try expectI32Value(a, try parseValue(a), "jump immediate out of range");
873
    if not encode::isJumpImm(value) {
874
        throw fail(a, "jump immediate out of range");
875
    }
876
    return value;
877
}
878
879
/// Parse an integer token as an i64.
880
fn parseInteger(a: *mut super::Assembler) -> i64 throws (super::Error) {
881
    let tok = try expectToken(a, scanner::TokenKind::Number, "expected number");
882
    let value = parseIntegerText(tok.source) else {
883
        throw failOnToken(tok, "invalid integer literal");
884
    };
885
    return value;
886
}
887
888
/// Parse integer literal text as an i64.
889
fn parseIntegerText(text: *[u8]) -> ?i64 {
890
    if text.len == 0 {
891
        return nil;
892
    }
893
    let negative = text[0] == '-';
894
    let magnitudeText = &text[1..] if negative or text[0] == '+' else text;
895
    let literal = try fmt::parseInt(magnitudeText) catch {
896
        return nil;
897
    };
898
    if negative {
899
        if literal.magnitude > parser::I64_MIN_MAGNITUDE {
900
            return nil;
901
        }
902
        if literal.magnitude == parser::I64_MIN_MAGNITUDE {
903
            return parser::I64_MIN;
904
        }
905
        return -(literal.magnitude as i64);
906
    }
907
    if literal.magnitude > parser::I64_MAX_MAGNITUDE {
908
        return nil;
909
    }
910
    return literal.magnitude as i64;
911
}
912
913
/// Parse a character literal token as one byte.
914
fn parseCharLiteral(tok: scanner::Token) -> ?u8 {
915
    return try fmt::parseChar(tok.source) catch {
916
        return nil;
917
    };
918
}