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