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