compiler: Borrow assembler string storage by lexical region

411cc85d65bd108f7f72d8ffd43b9fc318c24ba89f5049b06c078a7ec55933f3
Alexis Sellier committed ago 1 parent eee99ebe
lib/std/arch/rv64/asm.rad +41 -39
454 454
    /// Fixup payload.
455 455
    info: FixupInfo,
456 456
}
457 457
458 458
/// Parser and emission state.
459 -
export record Assembler {
459 +
export record Assembler: 'parse {
460 460
    /// Allocation arena for temporary assembler state.
461 461
    arena: *unsafe mut alloc::Arena,
462 -
    /// Intern pool for identifier-shaped token text. It must remain valid while parsing.
463 -
    pool: *unsafe mut strings::Pool,
462 +
    /// Intern pool borrowed for the current parse.
463 +
    pool: &'parse mut strings::Pool,
464 464
    /// Assembler lexical scanner.
465 465
    scan: scanner::Scanner,
466 466
    /// Output text buffer.
467 467
    text: *mut [u32],
468 468
    /// Number of emitted text words.
500 500
    sourceKind: scanner::SourceKind,
501 501
    source: *[u8],
502 502
    textBuf: *mut [u32],
503 503
    dataBuf: *mut [u8],
504 504
    arena: &mut alloc::Arena,
505 -
    pool: *unsafe mut strings::Pool,
505 +
    pool: &mut strings::Pool,
506 506
    dataBase: u32
507 507
) -> Program throws (Error) {
508 508
    let slotCap = tokenCapacity(sourceKind, source, pool);
509 509
    let tableCap = nextPowerOfTwo(slotCap * TABLE_CAPACITY_SCALE);
510 510
516 516
    let exportEntries = try! alloc::allocSlice(arena, @sizeOf(dict::Entry), @alignOf(dict::Entry), tableCap);
517 517
518 518
    let symbolBuf = symbols as *mut [Symbol];
519 519
    let fixupBuf = fixups as *mut [Fixup];
520 520
    let externalBuf = externalFixups as *mut [Fixup];
521 -
    let mut a = Assembler {
522 -
        arena: arena as *unsafe mut alloc::Arena,
523 -
        pool,
524 -
        scan: scanner::scanner(sourceKind, source),
525 -
        text: textBuf,
526 -
        textLen: 0,
527 -
        data: dataBuf,
528 -
        dataLen: 0,
529 -
        section: Section::Text,
530 -
        symbols: symbolBuf,
531 -
        symbolsLen: 0,
532 -
        symbolMap: dict::init(entries as *mut [dict::Entry]),
533 -
        constMap: dict::init(constEntries as *mut [dict::Entry]),
534 -
        exportMap: dict::init(exportEntries as *mut [dict::Entry]),
535 -
        fixups: fixupBuf,
536 -
        fixupsLen: 0,
537 -
        externalFixups: externalBuf,
538 -
        externalFixupsLen: 0,
539 -
        dataBase,
540 -
    };
541 -
    // Parse assembly source and emit instructions.
542 -
    try parser::parseProgram(&mut a);
543 -
    // Resolve fixups and finalize program.
544 -
    try emit::finishProgram(&mut a);
521 +
    let poolRef: 'parse = &mut *pool in {
522 +
        let mut a = Assembler 'parse {
523 +
            arena: arena as *unsafe mut alloc::Arena,
524 +
            pool: poolRef,
525 +
            scan: scanner::scanner(sourceKind, source),
526 +
            text: textBuf,
527 +
            textLen: 0,
528 +
            data: dataBuf,
529 +
            dataLen: 0,
530 +
            section: Section::Text,
531 +
            symbols: symbolBuf,
532 +
            symbolsLen: 0,
533 +
            symbolMap: dict::init(entries as *mut [dict::Entry]),
534 +
            constMap: dict::init(constEntries as *mut [dict::Entry]),
535 +
            exportMap: dict::init(exportEntries as *mut [dict::Entry]),
536 +
            fixups: fixupBuf,
537 +
            fixupsLen: 0,
538 +
            externalFixups: externalBuf,
539 +
            externalFixupsLen: 0,
540 +
            dataBase,
541 +
        };
542 +
        // Parse assembly source and emit instructions.
543 +
        try parser::parseProgram(&mut a);
544 +
        // Resolve fixups and finalize program.
545 +
        try emit::finishProgram(&mut a);
545 546
546 -
    let case Assembler {
547 -
        text, textLen, data, dataLen, symbols: definedSymbols, symbolsLen,
548 -
        externalFixups: pendingFixups, externalFixupsLen, ..
549 -
    } = a
550 -
        else panic "expected assembler state";
551 -
    return Program {
552 -
        text: &text[..textLen],
553 -
        data: &data[..dataLen],
554 -
        symbols: &definedSymbols[..symbolsLen],
555 -
        externalFixups: &pendingFixups[..externalFixupsLen],
556 -
    };
547 +
        let case Assembler 'parse {
548 +
            text, textLen, data, dataLen, symbols: definedSymbols, symbolsLen,
549 +
            externalFixups: pendingFixups, externalFixupsLen, ..
550 +
        } = a
551 +
            else panic "expected assembler state";
552 +
        return Program {
553 +
            text: &text[..textLen],
554 +
            data: &data[..dataLen],
555 +
            symbols: &definedSymbols[..symbolsLen],
556 +
            externalFixups: &pendingFixups[..externalFixupsLen],
557 +
        };
558 +
    }
557 559
}
558 560
559 561
/// Bound symbol and fixup counts by lexical tokens, including one spare slot.
560 562
fn tokenCapacity(kind: scanner::SourceKind, source: *[u8], pool: &mut strings::Pool) -> u32 {
561 563
    let mut scan = scanner::scanner(kind, source);
lib/std/arch/rv64/asm/emit.rad +15 -15
6 6
7 7
use std::collections::dict;
8 8
use std::lang::gen;
9 9
10 10
/// Define a symbol at the current text or data offset.
11 -
export fn defineSymbol(a: &mut super::Assembler, name: *[u8]) {
11 +
export fn defineSymbol 'parse (a: &mut super::Assembler 'parse, name: *[u8]) {
12 12
    let idx = a.symbolsLen;
13 13
    let offset: i32 = a.dataLen as i32
14 14
        if a.section == super::Section::Data
15 15
        else a.textLen as i32 * rv64::INSTR_SIZE;
16 16
24 24
    set a.symbolsLen += 1;
25 25
    dict::insert(&mut a.symbolMap, name, idx as i32);
26 26
}
27 27
28 28
/// Append one encoded instruction word to the text section.
29 -
export fn emitText(a: &mut super::Assembler, word: u32) throws (super::Error) {
29 +
export fn emitText 'parse (a: &mut super::Assembler 'parse, word: u32) throws (super::Error) {
30 30
    if a.textLen >= a.text.len {
31 31
        throw super::Error::TextOverflow;
32 32
    }
33 33
    set a.text[a.textLen] = word;
34 34
    set a.textLen += 1;
35 35
}
36 36
37 37
/// Append `words` no-op instructions to the text section.
38 -
export fn emitTextPadding(a: &mut super::Assembler, words: u32) throws (super::Error) {
38 +
export fn emitTextPadding 'parse (a: &mut super::Assembler 'parse, words: u32) throws (super::Error) {
39 39
    for _ in 0..words {
40 40
        try emitText(a, encode::nop());
41 41
    }
42 42
}
43 43
44 44
/// Append one byte to the data section.
45 -
export fn emitByte(a: &mut super::Assembler, byte: u8) throws (super::Error) {
45 +
export fn emitByte 'parse (a: &mut super::Assembler 'parse, byte: u8) throws (super::Error) {
46 46
    if a.dataLen >= a.data.len {
47 47
        throw super::Error::DataOverflow;
48 48
    }
49 49
    set a.data[a.dataLen] = byte;
50 50
    set a.dataLen += 1;
51 51
}
52 52
53 53
/// Emit a little-endian integer with `bytes` bytes.
54 -
fn emitDataInt(a: &mut super::Assembler, bits: u64, bytes: u32) throws (super::Error) {
54 +
fn emitDataInt 'parse (a: &mut super::Assembler 'parse, bits: u64, bytes: u32) throws (super::Error) {
55 55
    for i in 0..bytes {
56 56
        try emitByte(a, ((bits >> ((i as u64) * super::BITS_PER_BYTE)) & super::BYTE_MASK) as u8);
57 57
    }
58 58
}
59 59
60 60
/// Patch a little-endian integer with `bytes` bytes.
61 -
fn patchDataInt(a: &mut super::Assembler, offset: u32, bits: u64, bytes: u32) {
61 +
fn patchDataInt 'parse (a: &mut super::Assembler 'parse, offset: u32, bits: u64, bytes: u32) {
62 62
    for i in 0..bytes {
63 63
        set a.data[offset + i] = ((bits >> ((i as u64) * super::BITS_PER_BYTE)) & super::BYTE_MASK) as u8;
64 64
    }
65 65
}
66 66
67 67
/// Emit an integer data directive value.
68 -
export fn emitDataValue(a: &mut super::Assembler, value: i64, width: super::DataWidth) throws (super::Error) {
68 +
export fn emitDataValue 'parse (a: &mut super::Assembler 'parse, value: i64, width: super::DataWidth) throws (super::Error) {
69 69
    match width {
70 70
        case super::DataWidth::Word => try emitDataInt(a, value as u64, rv64::WORD_SIZE as u32),
71 71
        case super::DataWidth::Dword => try emitDataInt(a, value as u64, rv64::DWORD_SIZE as u32),
72 72
    }
73 73
}
74 74
75 75
/// Record a data-section symbol fixup and reserve its bytes.
76 -
export fn recordDataFixup(a: &mut super::Assembler, target: *[u8], width: super::DataWidth) throws (super::Error) {
76 +
export fn recordDataFixup 'parse (a: &mut super::Assembler 'parse, target: *[u8], width: super::DataWidth) throws (super::Error) {
77 77
    let offset = a.dataLen;
78 78
    match width {
79 79
        case super::DataWidth::Word => {
80 80
            recordFixup(a, target, super::FixupInfo::Word { offset });
81 81
            try emitDataInt(a, 0, rv64::WORD_SIZE as u32);
86 86
        }
87 87
    }
88 88
}
89 89
90 90
/// Record a pending symbol fixup.
91 -
fn recordFixup(a: &mut super::Assembler, symbol: *[u8], info: super::FixupInfo) {
91 +
fn recordFixup 'parse (a: &mut super::Assembler 'parse, symbol: *[u8], info: super::FixupInfo) {
92 92
    assert a.fixupsLen < a.fixups.len, "recordFixup: fixup buffer full";
93 93
    set a.fixups[a.fixupsLen] = super::Fixup { symbol, info };
94 94
    set a.fixupsLen += 1;
95 95
}
96 96
97 97
/// Record a text fixup that must be resolved after all program text is known.
98 -
fn recordExternalFixup(a: &mut super::Assembler, fixup: super::Fixup) {
98 +
fn recordExternalFixup 'parse (a: &mut super::Assembler 'parse, fixup: super::Fixup) {
99 99
    assert a.externalFixupsLen < a.externalFixups.len, "recordExternalFixup: fixup buffer full";
100 100
    set a.externalFixups[a.externalFixupsLen] = fixup;
101 101
    set a.externalFixupsLen += 1;
102 102
}
103 103
104 104
/// Record a text-section symbol fixup and reserve its instruction words.
105 -
export fn recordTextFixup(a: &mut super::Assembler, symbol: *[u8], info: super::FixupInfo, words: u32) throws (super::Error) {
105 +
export fn recordTextFixup 'parse (a: &mut super::Assembler 'parse, symbol: *[u8], info: super::FixupInfo, words: u32) throws (super::Error) {
106 106
    recordFixup(a, symbol, info);
107 107
    try emitTextPadding(a, words);
108 108
}
109 109
110 110
/// Find a previously defined symbol by name.
111 -
fn findSymbol(a: &super::Assembler, name: *[u8]) -> ?super::Symbol {
111 +
fn findSymbol 'parse (a: &super::Assembler 'parse, name: *[u8]) -> ?super::Symbol {
112 112
    let idx = dict::get(&a.symbolMap, name)
113 113
        else return nil;
114 114
    return a.symbols[idx as u32];
115 115
}
116 116
117 117
/// Return the final address for a data symbol.
118 -
fn dataSymbolAddr(a: &super::Assembler, symbol: super::Symbol) -> i32 throws (super::Error) {
118 +
fn dataSymbolAddr 'parse (a: &super::Assembler 'parse, symbol: super::Symbol) -> i32 throws (super::Error) {
119 119
    if symbol.section <> super::Section::Data {
120 120
        throw super::Error::Invalid { offset: 0, message: "data address target must be in data section" };
121 121
    }
122 122
    return symbol.offset + (a.dataBase as i32);
123 123
}
124 124
125 125
/// Resolve final symbol references and patch all delayed output.
126 -
export fn finishProgram(a: &mut super::Assembler) throws (super::Error) {
126 +
export fn finishProgram 'parse (a: &mut super::Assembler 'parse) throws (super::Error) {
127 127
    for i in 0..a.fixupsLen {
128 128
        let fixup = a.fixups[i];
129 129
        let symbol = findSymbol(a, fixup.symbol) else {
130 130
            match fixup.info {
131 131
                case super::FixupInfo::Jal { .. }, super::FixupInfo::Addr { .. } => {
198 198
        case super::BranchOp::Bgt  => return encode::bgt(rs1, rs2, imm),
199 199
    }
200 200
}
201 201
202 202
/// Decode string literal escapes and emit the resulting data bytes.
203 -
export fn emitDecodedString(a: &mut super::Assembler, literal: *[u8]) throws (super::Error) {
203 +
export fn emitDecodedString 'parse (a: &mut super::Assembler 'parse, literal: *[u8]) throws (super::Error) {
204 204
    let raw = &literal[super::QUOTE_DELIM_LEN..literal.len - super::QUOTE_DELIM_LEN];
205 205
    let mut i: u32 = 0;
206 206
207 207
    while i < raw.len {
208 208
        if raw[i] == '\\' and i + 1 < raw.len {
lib/std/arch/rv64/asm/parser.rad +64 -64
20 20
    /// Signed byte offset preceding the base register.
21 21
    offset: i32,
22 22
}
23 23
24 24
/// Parse assembler source into the supplied assembler state.
25 -
export unsafe fn parseProgram(a: &mut super::Assembler) throws (super::Error) {
25 +
export unsafe fn parseProgram 'parse (a: &mut super::Assembler 'parse) throws (super::Error) {
26 26
    advance(a);
27 27
28 28
    while a.scan.current.kind <> scanner::TokenKind::Eof {
29 29
        try parseItem(a);
30 30
    }
38 38
    }
39 39
    return mem::alignUp(value, alignment);
40 40
}
41 41
42 42
/// Advance the parser by one token, preserving the previous token.
43 -
unsafe fn advance(a: &mut super::Assembler) {
43 +
fn advance 'parse (a: &mut super::Assembler 'parse) {
44 44
    set a.scan.previous = a.scan.current;
45 45
    set a.scan.current = scanner::next(&mut a.scan, a.pool);
46 46
}
47 47
48 48
/// Consume the current token when it has `kind`.
49 -
unsafe fn consume(a: &mut super::Assembler, kind: scanner::TokenKind) -> bool {
49 +
fn consume 'parse (a: &mut super::Assembler 'parse, kind: scanner::TokenKind) -> bool {
50 50
    if a.scan.current.kind == kind {
51 51
        advance(a);
52 52
        return true;
53 53
    }
54 54
    return false;
55 55
}
56 56
57 57
/// Create an error at the current token.
58 -
fn fail(a: &super::Assembler, message: *[u8]) -> super::Error {
58 +
fn fail 'parse (a: &super::Assembler 'parse, message: *[u8]) -> super::Error {
59 59
    return super::Error::Invalid { offset: a.scan.current.offset, message };
60 60
}
61 61
62 62
/// Create an error at `tok`.
63 63
fn failOnToken(tok: scanner::Token, message: *[u8]) -> super::Error {
64 64
    return super::Error::Invalid { offset: tok.offset, message };
65 65
}
66 66
67 67
/// Require that a data directive appears while assembling the data section.
68 -
fn expectDataSection(a: &super::Assembler, tok: scanner::Token) throws (super::Error) {
68 +
fn expectDataSection 'parse (a: &super::Assembler 'parse, tok: scanner::Token) throws (super::Error) {
69 69
    if a.section <> super::Section::Data {
70 70
        throw failOnToken(tok, "data directive is only valid in the data section");
71 71
    }
72 72
}
73 73
74 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) {
75 +
fn expect 'parse (a: &mut super::Assembler 'parse, kind: scanner::TokenKind, message: *[u8]) throws (super::Error) {
76 76
    if not consume(a, kind) {
77 77
        throw fail(a, message);
78 78
    }
79 79
}
80 80
81 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) {
82 +
fn expectToken 'parse (a: &mut super::Assembler 'parse, kind: scanner::TokenKind, message: *[u8]) -> scanner::Token throws (super::Error) {
83 83
    try expect(a, kind, message);
84 84
    return a.scan.previous;
85 85
}
86 86
87 87
/// Require that the current item has reached its semicolon terminator.
88 -
fn expectTerminator(a: &super::Assembler, message: *[u8]) throws (super::Error) {
88 +
fn expectTerminator 'parse (a: &super::Assembler 'parse, message: *[u8]) throws (super::Error) {
89 89
    if a.scan.current.kind <> scanner::TokenKind::Semicolon {
90 90
        throw fail(a, message);
91 91
    }
92 92
}
93 93
94 94
/// Require that `value` fits in i32.
95 -
fn expectI32Value(a: &super::Assembler, value: i64, message: *[u8]) -> i32 throws (super::Error) {
95 +
fn expectI32Value 'parse (a: &super::Assembler 'parse, value: i64, message: *[u8]) -> i32 throws (super::Error) {
96 96
    if value < -super::I32_MIN_MAGNITUDE or value > super::I32_MAX_VALUE {
97 97
        throw fail(a, message);
98 98
    }
99 99
    return value as i32;
100 100
}
101 101
102 102
/// Require that `value` fits in a signed 12-bit immediate field.
103 -
fn expectSmallImmValue(a: &super::Assembler, value: i64) -> i32 throws (super::Error) {
103 +
fn expectSmallImmValue 'parse (a: &super::Assembler 'parse, value: i64) -> i32 throws (super::Error) {
104 104
    if not encode::isSmallImm64(value) {
105 105
        throw fail(a, "immediate out of range");
106 106
    }
107 107
    return value as i32;
108 108
}
109 109
110 110
/// Define a label at the current text or data offset.
111 -
fn defineSymbol(a: &mut super::Assembler, name: *[u8], tok: scanner::Token) throws (super::Error) {
111 +
fn defineSymbol 'parse (a: &mut super::Assembler 'parse, name: *[u8], tok: scanner::Token) throws (super::Error) {
112 112
    if dict::get(&a.symbolMap, name) <> nil {
113 113
        throw failOnToken(tok, "duplicate label");
114 114
    }
115 115
    emit::defineSymbol(a, name);
116 116
}
117 117
118 118
/// Emit a parsed integer data value after applying source-level range checks.
119 -
fn emitDataValue(a: &mut super::Assembler, value: i64, width: super::DataWidth) throws (super::Error) {
119 +
fn emitDataValue 'parse (a: &mut super::Assembler 'parse, value: i64, width: super::DataWidth) throws (super::Error) {
120 120
    match width {
121 121
        case super::DataWidth::Word =>
122 122
            try emit::emitDataValue(a, (try expectI32Value(a, value, "word literal out of range")) as i64, width),
123 123
        case super::DataWidth::Dword =>
124 124
            try emit::emitDataValue(a, value, width),
125 125
    }
126 126
}
127 127
128 128
/// Parse a possibly scoped name from one or more `::`-separated segments.
129 -
unsafe fn parseScopedName(
130 -
    a: &mut super::Assembler,
129 +
fn parseScopedName 'parse (
130 +
    a: &mut super::Assembler 'parse,
131 131
    kind: scanner::TokenKind,
132 132
    message: *[u8],
133 133
    trimPrefix: u32
134 134
) -> *[u8] throws (super::Error) {
135 135
    let first = try expectToken(a, kind, message);
143 143
    let source = &a.scan.source[start..end];
144 144
    return strings::intern(a.pool, source);
145 145
}
146 146
147 147
/// Parse a bare symbol name.
148 -
unsafe fn parseSymbolName(a: &mut super::Assembler) -> *[u8] throws (super::Error) {
148 +
fn parseSymbolName 'parse (a: &mut super::Assembler 'parse) -> *[u8] throws (super::Error) {
149 149
    return try parseScopedName(a, scanner::TokenKind::Ident, "expected symbol name", 0);
150 150
}
151 151
152 152
/// Return `true` when [`tok`] is any label token form.
153 153
fn isLabel(tok: scanner::TokenKind) -> bool {
154 154
    return tok == scanner::TokenKind::Label or tok == scanner::TokenKind::QuotedLabel;
155 155
}
156 156
157 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) {
158 +
unsafe fn parseQuotedLabelName 'parse (a: &mut super::Assembler 'parse) -> *[u8] throws (super::Error) {
159 159
    let tok = try expectToken(a, scanner::TokenKind::QuotedLabel, "expected label name");
160 160
    let rawStart = super::LABEL_SIGIL_LEN + super::QUOTE_DELIM_LEN;
161 161
    let raw = &tok.source[rawStart..tok.source.len - super::QUOTE_DELIM_LEN];
162 162
    let storage = try alloc::allocSlice(a.arena, 1, 1, raw.len) catch {
163 163
        panic "asm: out of memory allocating quoted label";
166 166
167 167
    return strings::intern(a.pool, &storage[..len]);
168 168
}
169 169
170 170
/// Parse a label reference or definition name.
171 -
unsafe fn parseLabelName(a: &mut super::Assembler) -> *[u8] throws (super::Error) {
171 +
unsafe fn parseLabelName 'parse (a: &mut super::Assembler 'parse) -> *[u8] throws (super::Error) {
172 172
    if a.scan.current.kind == scanner::TokenKind::QuotedLabel {
173 173
        return try parseQuotedLabelName(a);
174 174
    }
175 175
    return try parseScopedName(a, scanner::TokenKind::Label, "expected label name", super::LABEL_SIGIL_LEN);
176 176
}
177 177
178 178
/// Parse a directive name without its leading `.`.
179 -
unsafe fn parseDirectiveName(a: &mut super::Assembler) -> *[u8] throws (super::Error) {
179 +
fn parseDirectiveName 'parse (a: &mut super::Assembler 'parse) -> *[u8] throws (super::Error) {
180 180
    let name = try expectToken(a, scanner::TokenKind::Directive, "expected directive name");
181 181
    return &name.source[super::DIRECTIVE_SIGIL_LEN..];
182 182
}
183 183
184 184
/// Parse one top-level assembler item.
185 -
unsafe fn parseItem(a: &mut super::Assembler) throws (super::Error) {
185 +
unsafe fn parseItem 'parse (a: &mut super::Assembler 'parse) throws (super::Error) {
186 186
    match a.scan.current.kind {
187 187
        case scanner::TokenKind::Ident => {
188 188
            let tok = a.scan.current;
189 189
            let name = try parseSymbolName(a);
190 190
            try parseInstruction(a, name, tok);
279 279
    };
280 280
    return super::CSRS[index].csr;
281 281
}
282 282
283 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) {
284 +
unsafe fn parseInstruction 'parse (a: &mut super::Assembler 'parse, name: *[u8], tok: scanner::Token) throws (super::Error) {
285 285
    if a.section <> super::Section::Text {
286 286
        throw failOnToken(tok, "instructions are only valid in the text section");
287 287
    }
288 288
    if let format = atomics::parse(name) {
289 289
        let rd = try parseRegister(a);
332 332
        case super::InstructionEncoder::Upper { enc } => return try parseUpper(a, enc),
333 333
    }
334 334
}
335 335
336 336
/// Parse the `li` pseudo-instruction.
337 -
unsafe fn parseLi(a: &mut super::Assembler) throws (super::Error) {
337 +
fn parseLi 'parse (a: &mut super::Assembler 'parse) throws (super::Error) {
338 338
    let rd = try parseRegister(a);
339 339
    let value = try parseValue(a);
340 340
    if encode::isSmallImm64(value) {
341 341
        try emit::emitText(a, encode::addi(rd, rv64::ZERO, value as i32));
342 342
        return;
347 347
    try emit::emitText(a, encode::lui(rd, split.hi));
348 348
    try emit::emitText(a, encode::addi(rd, rd, split.lo));
349 349
}
350 350
351 351
/// Parse the `la` pseudo-instruction.
352 -
unsafe fn parseLa(a: &mut super::Assembler) throws (super::Error) {
352 +
unsafe fn parseLa 'parse (a: &mut super::Assembler 'parse) throws (super::Error) {
353 353
    let rd = try parseRegister(a);
354 354
    let target = try parseLabelName(a);
355 355
    let index = a.textLen;
356 356
357 357
    try emit::recordTextFixup(a, target, super::FixupInfo::Addr { rd, index }, 2);
358 358
}
359 359
360 360
/// Parse a CSR read-like instruction with destination register then CSR.
361 -
unsafe fn parseRdCsr(a: &mut super::Assembler, enc: fn(gen::Reg, u32) -> u32) throws (super::Error) {
361 +
fn parseRdCsr 'parse (a: &mut super::Assembler 'parse, enc: fn(gen::Reg, u32) -> u32) throws (super::Error) {
362 362
    let rd = try parseRegister(a);
363 363
    let csr = try parseCsr(a);
364 364
365 365
    try emit::emitText(a, enc(rd, csr));
366 366
}
367 367
368 368
/// Parse a CSR write-like instruction with CSR then source register.
369 -
unsafe fn parseCsrRs1(a: &mut super::Assembler, enc: fn(u32, gen::Reg) -> u32) throws (super::Error) {
369 +
fn parseCsrRs1 'parse (a: &mut super::Assembler 'parse, enc: fn(u32, gen::Reg) -> u32) throws (super::Error) {
370 370
    let csr = try parseCsr(a);
371 371
    let rs1 = try parseRegister(a);
372 372
373 373
    try emit::emitText(a, enc(csr, rs1));
374 374
}
375 375
376 376
/// Parse `csrrw`.
377 -
unsafe fn parseCsrrw(a: &mut super::Assembler) throws (super::Error) {
377 +
fn parseCsrrw 'parse (a: &mut super::Assembler 'parse) throws (super::Error) {
378 378
    let rd = try parseRegister(a);
379 379
    let csr = try parseCsr(a);
380 380
    let rs1 = try parseRegister(a);
381 381
382 382
    try emit::emitText(a, encode::csrrw(rd, csr, rs1));
383 383
}
384 384
385 385
/// Parse a CSR immediate instruction.
386 -
unsafe fn parseCsrsi(a: &mut super::Assembler) throws (super::Error) {
386 +
fn parseCsrsi 'parse (a: &mut super::Assembler 'parse) throws (super::Error) {
387 387
    let csr = try parseCsr(a);
388 388
    let imm = try parseValue(a);
389 389
    if imm < 0 or imm >= super::CSR_IMM_LIMIT {
390 390
        throw fail(a, "CSR immediate out of range");
391 391
    }
392 392
    try emit::emitText(a, encode::csrsi(csr, imm as u32));
393 393
}
394 394
395 395
/// Parse a two-register instruction.
396 -
unsafe fn parseRR(a: &mut super::Assembler, enc: fn(gen::Reg, gen::Reg) -> u32) throws (super::Error) {
396 +
fn parseRR 'parse (a: &mut super::Assembler 'parse, enc: fn(gen::Reg, gen::Reg) -> u32) throws (super::Error) {
397 397
    let rd = try parseRegister(a);
398 398
    let rs = try parseRegister(a);
399 399
400 400
    try emit::emitText(a, enc(rd, rs));
401 401
}
402 402
403 403
/// Parse a three-register instruction.
404 -
unsafe fn parseRRR(a: &mut super::Assembler, enc: fn(gen::Reg, gen::Reg, gen::Reg) -> u32) throws (super::Error) {
404 +
fn parseRRR 'parse (a: &mut super::Assembler 'parse, enc: fn(gen::Reg, gen::Reg, gen::Reg) -> u32) throws (super::Error) {
405 405
    let rd = try parseRegister(a);
406 406
    let rs1 = try parseRegister(a);
407 407
    let rs2 = try parseRegister(a);
408 408
409 409
    try emit::emitText(a, enc(rd, rs1, rs2));
410 410
}
411 411
412 412
/// Parse a register-register-immediate instruction.
413 -
unsafe fn parseRRI(a: &mut super::Assembler, enc: fn(gen::Reg, gen::Reg, i32) -> u32) throws (super::Error) {
413 +
fn parseRRI 'parse (a: &mut super::Assembler 'parse, enc: fn(gen::Reg, gen::Reg, i32) -> u32) throws (super::Error) {
414 414
    let rd = try parseRegister(a);
415 415
    let rs1 = try parseRegister(a);
416 416
    let imm = try parseSmallImm(a);
417 417
418 418
    try emit::emitText(a, enc(rd, rs1, imm));
419 419
}
420 420
421 421
/// Parse a shift-immediate instruction and enforce its RV64 shift bound.
422 -
unsafe fn parseShift(
423 -
    a: &mut super::Assembler,
422 +
fn parseShift 'parse (
423 +
    a: &mut super::Assembler 'parse,
424 424
    enc: fn(gen::Reg, gen::Reg, i32) -> u32,
425 425
    limit: i32,
426 426
    message: *[u8]
427 427
) throws (super::Error) {
428 428
    let rd = try parseRegister(a);
439 439
440 440
    try emit::emitText(a, enc(rd, rs1, shamt));
441 441
}
442 442
443 443
/// Parse a load instruction with a memory operand.
444 -
unsafe fn parseLoad(a: &mut super::Assembler, enc: fn(gen::Reg, gen::Reg, i32) -> u32) throws (super::Error) {
444 +
fn parseLoad 'parse (a: &mut super::Assembler 'parse, enc: fn(gen::Reg, gen::Reg, i32) -> u32) throws (super::Error) {
445 445
    let rd = try parseRegister(a);
446 446
    let memop = try parseMemory(a);
447 447
448 448
    try emit::emitText(a, enc(rd, memop.base, memop.offset));
449 449
}
450 450
451 451
/// Parse a store instruction with a memory operand.
452 -
unsafe fn parseStore(a: &mut super::Assembler, enc: fn(gen::Reg, gen::Reg, i32) -> u32) throws (super::Error) {
452 +
fn parseStore 'parse (a: &mut super::Assembler 'parse, enc: fn(gen::Reg, gen::Reg, i32) -> u32) throws (super::Error) {
453 453
    let rs2 = try parseRegister(a);
454 454
    let memop = try parseMemory(a);
455 455
456 456
    try emit::emitText(a, enc(rs2, memop.base, memop.offset));
457 457
}
458 458
459 459
/// Parse a two-register branch instruction.
460 -
unsafe fn parseBranch(a: &mut super::Assembler, op: super::BranchOp) throws (super::Error) {
460 +
unsafe fn parseBranch 'parse (a: &mut super::Assembler 'parse, op: super::BranchOp) throws (super::Error) {
461 461
    let rs1 = try parseRegister(a);
462 462
    let rs2 = try parseRegister(a);
463 463
464 464
    try parseBranchLabel(a, op, rs1, rs2);
465 465
}
466 466
467 467
/// Parse an optional label operand.
468 -
unsafe fn parseOptionalLabel(a: &mut super::Assembler) -> ?*[u8] throws (super::Error) {
468 +
unsafe fn parseOptionalLabel 'parse (a: &mut super::Assembler 'parse) -> ?*[u8] throws (super::Error) {
469 469
    if not isLabel(a.scan.current.kind) {
470 470
        return nil;
471 471
    }
472 472
    return try parseLabelName(a);
473 473
}
474 474
475 475
/// Parse a branch target as either a label fixup or immediate offset.
476 -
unsafe fn parseBranchLabel(a: &mut super::Assembler, op: super::BranchOp, rs1: gen::Reg, rs2: gen::Reg) throws (super::Error) {
476 +
unsafe fn parseBranchLabel 'parse (a: &mut super::Assembler 'parse, op: super::BranchOp, rs1: gen::Reg, rs2: gen::Reg) throws (super::Error) {
477 477
    let index = a.textLen;
478 478
    if let target = try parseOptionalLabel(a) {
479 479
        try emit::recordTextFixup(a, target, super::FixupInfo::Branch { op, rs1, rs2, index }, 1);
480 480
        return;
481 481
    }
482 482
    let imm = try parseBranchImm(a);
483 483
    try emit::emitText(a, emit::encodeBranch(op, rs1, rs2, imm));
484 484
}
485 485
486 486
/// Parse a branch-to-zero pseudo-instruction.
487 -
unsafe fn parseBranchZero(a: &mut super::Assembler, op: super::BranchOp) throws (super::Error) {
487 +
unsafe fn parseBranchZero 'parse (a: &mut super::Assembler 'parse, op: super::BranchOp) throws (super::Error) {
488 488
    let rs = try parseRegister(a);
489 489
    try parseBranchLabel(a, op, rs, rv64::ZERO);
490 490
}
491 491
492 492
/// Parse `jal` with an explicit destination register.
493 -
unsafe fn parseJal(a: &mut super::Assembler) throws (super::Error) {
493 +
unsafe fn parseJal 'parse (a: &mut super::Assembler 'parse) throws (super::Error) {
494 494
    let rd = try parseRegister(a);
495 495
    try parseJ(a, rd);
496 496
}
497 497
498 498
/// Parse a jump target for `jal` or a jump pseudo-instruction.
499 -
unsafe fn parseJ(a: &mut super::Assembler, rd: gen::Reg) throws (super::Error) {
499 +
unsafe fn parseJ 'parse (a: &mut super::Assembler 'parse, rd: gen::Reg) throws (super::Error) {
500 500
    let index = a.textLen;
501 501
    if let target = try parseOptionalLabel(a) {
502 502
        try emit::recordTextFixup(a, target, super::FixupInfo::Jal { rd, index }, 1);
503 503
        return;
504 504
    }
505 505
    let imm = try parseJumpImm(a);
506 506
    try emit::emitText(a, encode::jal(rd, imm));
507 507
}
508 508
509 509
/// Parse an upper-immediate instruction.
510 -
unsafe fn parseUpper(a: &mut super::Assembler, enc: fn(gen::Reg, i32) -> u32) throws (super::Error) {
510 +
fn parseUpper 'parse (a: &mut super::Assembler 'parse, enc: fn(gen::Reg, i32) -> u32) throws (super::Error) {
511 511
    let rd = try parseRegister(a);
512 512
    let imm64 = try parseValue(a);
513 513
    if imm64 < 0 or imm64 > super::UPPER_IMM_MAX_VALUE {
514 514
        throw fail(a, "upper immediate out of range");
515 515
    }
516 516
    try emit::emitText(a, enc(rd, imm64 as i32));
517 517
}
518 518
519 519
/// Parse a directive after its name has already been consumed.
520 -
unsafe fn parseDirective(a: &mut super::Assembler, name: *[u8], tok: scanner::Token) throws (super::Error) {
520 +
unsafe fn parseDirective 'parse (a: &mut super::Assembler 'parse, name: *[u8], tok: scanner::Token) throws (super::Error) {
521 521
    let directive = classifyDirective(name) else {
522 522
        throw failOnToken(tok, "unknown directive");
523 523
    };
524 524
    match directive {
525 525
        case super::DirectiveKind::Text => {
560 560
        }
561 561
    }
562 562
}
563 563
564 564
/// Parse a `.constant` directive.
565 -
unsafe fn parseConstantDirective(a: &mut super::Assembler) throws (super::Error) {
565 +
fn parseConstantDirective 'parse (a: &mut super::Assembler 'parse) throws (super::Error) {
566 566
    let name = try parseSymbolName(a);
567 567
    let value = try expectI32Value(a, try parseExpr(a), "constant out of range");
568 568
569 569
    dict::insert(&mut a.constMap, name, value);
570 570
}
571 571
572 572
/// Parse a `.export` directive.
573 -
unsafe fn parseExportDirective(a: &mut super::Assembler) throws (super::Error) {
573 +
unsafe fn parseExportDirective 'parse (a: &mut super::Assembler 'parse) throws (super::Error) {
574 574
    let name = try parseLabelName(a);
575 575
    dict::insert(&mut a.exportMap, name, 1);
576 576
    if let idx = dict::get(&a.symbolMap, name) {
577 577
        set a.symbols[idx as u32].isExported = true;
578 578
    }
579 579
}
580 580
581 581
/// Parse a `.space` directive.
582 -
unsafe fn parseSpaceDirective(a: &mut super::Assembler) throws (super::Error) {
582 +
fn parseSpaceDirective 'parse (a: &mut super::Assembler 'parse) throws (super::Error) {
583 583
    let count = try parseValue(a);
584 584
    if count < 0 {
585 585
        throw fail(a, "space size must be non-negative");
586 586
    }
587 587
    // The data section grows on demand; only reject sizes that cannot be
593 593
        try emit::emitByte(a, 0);
594 594
    }
595 595
}
596 596
597 597
/// Parse an `.align` directive for the current section.
598 -
unsafe fn parseAlignDirective(a: &mut super::Assembler) throws (super::Error) {
598 +
fn parseAlignDirective 'parse (a: &mut super::Assembler 'parse) throws (super::Error) {
599 599
    let amount64 = try parseValue(a);
600 600
    if amount64 <= 0 {
601 601
        throw fail(a, "alignment must be positive");
602 602
    }
603 603
    if amount64 > super::U32_MAX_VALUE {
629 629
        }
630 630
    }
631 631
}
632 632
633 633
/// Parse a `.byte` directive.
634 -
unsafe fn parseByteDirective(a: &mut super::Assembler) throws (super::Error) {
634 +
fn parseByteDirective 'parse (a: &mut super::Assembler 'parse) throws (super::Error) {
635 635
    loop {
636 636
        if a.scan.current.kind == scanner::TokenKind::Char {
637 637
            let ch = parseCharLiteral(a.scan.current) else {
638 638
                throw fail(a, "invalid char literal");
639 639
            };
651 651
        }
652 652
    }
653 653
}
654 654
655 655
/// Parse a fixed-width integer data directive.
656 -
unsafe fn parseIntDirective(a: &mut super::Assembler, width: super::DataWidth) throws (super::Error) {
656 +
unsafe fn parseIntDirective 'parse (a: &mut super::Assembler 'parse, width: super::DataWidth) throws (super::Error) {
657 657
    loop {
658 658
        if isLabel(a.scan.current.kind) {
659 659
            let target = try parseLabelName(a);
660 660
            try emit::recordDataFixup(a, target, width);
661 661
        } else if a.scan.current.kind == scanner::TokenKind::Char {
672 672
        }
673 673
    }
674 674
}
675 675
676 676
/// Parse a `.ascii` string literal list.
677 -
unsafe fn parseStringDirective(a: &mut super::Assembler) throws (super::Error) {
677 +
fn parseStringDirective 'parse (a: &mut super::Assembler 'parse) throws (super::Error) {
678 678
    loop {
679 679
        let literal = try expectToken(a, scanner::TokenKind::String, "expected string literal");
680 680
        try emit::emitDecodedString(a, literal.source);
681 681
        if not consume(a, scanner::TokenKind::Comma) {
682 682
            return;
683 683
        }
684 684
    }
685 685
}
686 686
687 687
/// Parse and resolve a register operand.
688 -
unsafe fn parseRegister(a: &mut super::Assembler) -> gen::Reg throws (super::Error) {
688 +
fn parseRegister 'parse (a: &mut super::Assembler 'parse) -> gen::Reg throws (super::Error) {
689 689
    let tok = try expectToken(a, scanner::TokenKind::Register, "expected register");
690 690
    let reg = lookupRegister(&tok.source[1..]) else {
691 691
        throw super::Error::Invalid { offset: tok.offset, message: "unknown register" };
692 692
    };
693 693
    return reg;
694 694
}
695 695
696 696
/// Parse a simple signed immediate or constant value.
697 -
unsafe fn parseValue(a: &mut super::Assembler) -> i64 throws (super::Error) {
697 +
fn parseValue 'parse (a: &mut super::Assembler 'parse) -> i64 throws (super::Error) {
698 698
    if consume(a, scanner::TokenKind::Minus) {
699 699
        return -(try parseValuePrimary(a));
700 700
    }
701 701
    return try parseValuePrimary(a);
702 702
}
703 703
704 704
/// Parse the primary form used by simple immediate values.
705 -
unsafe fn parseValuePrimary(a: &mut super::Assembler) -> i64 throws (super::Error) {
705 +
fn parseValuePrimary 'parse (a: &mut super::Assembler 'parse) -> i64 throws (super::Error) {
706 706
    if a.scan.current.kind == scanner::TokenKind::Number {
707 707
        return try parseInteger(a);
708 708
    }
709 709
    if a.scan.current.kind == scanner::TokenKind::Ident {
710 710
        return try parseConstantValue(a);
711 711
    }
712 712
    throw fail(a, "expected number or constant");
713 713
}
714 714
715 715
/// Parse an additive constant expression.
716 -
unsafe fn parseExpr(a: &mut super::Assembler) -> i64 throws (super::Error) {
716 +
fn parseExpr 'parse (a: &mut super::Assembler 'parse) -> i64 throws (super::Error) {
717 717
    let mut value = try parseExprMul(a);
718 718
719 719
    while a.scan.current.kind == scanner::TokenKind::Plus or a.scan.current.kind == scanner::TokenKind::Minus {
720 720
        let op = a.scan.current.kind;
721 721
        advance(a);
729 729
    }
730 730
    return value;
731 731
}
732 732
733 733
/// Parse multiplicative expression operators.
734 -
unsafe fn parseExprMul(a: &mut super::Assembler) -> i64 throws (super::Error) {
734 +
fn parseExprMul 'parse (a: &mut super::Assembler 'parse) -> i64 throws (super::Error) {
735 735
    let mut value = try parseExprUnary(a);
736 736
737 737
    while a.scan.current.kind == scanner::TokenKind::Star or a.scan.current.kind == scanner::TokenKind::Slash {
738 738
        let op = a.scan.current.kind;
739 739
        advance(a);
750 750
    }
751 751
    return value;
752 752
}
753 753
754 754
/// Parse unary expression operators.
755 -
unsafe fn parseExprUnary(a: &mut super::Assembler) -> i64 throws (super::Error) {
755 +
fn parseExprUnary 'parse (a: &mut super::Assembler 'parse) -> i64 throws (super::Error) {
756 756
    if consume(a, scanner::TokenKind::Minus) {
757 757
        return -(try parseExprUnary(a));
758 758
    }
759 759
    if consume(a, scanner::TokenKind::Plus) {
760 760
        return try parseExprUnary(a);
761 761
    }
762 762
    return try parseExprPrimary(a);
763 763
}
764 764
765 765
/// Parse expression atoms.
766 -
unsafe fn parseExprPrimary(a: &mut super::Assembler) -> i64 throws (super::Error) {
766 +
fn parseExprPrimary 'parse (a: &mut super::Assembler 'parse) -> i64 throws (super::Error) {
767 767
    if consume(a, scanner::TokenKind::LParen) {
768 768
        let value = try parseExpr(a);
769 769
        try expect(a, scanner::TokenKind::RParen, "expected `)`");
770 770
        return value;
771 771
    }
777 777
    }
778 778
    throw fail(a, "expected expression");
779 779
}
780 780
781 781
/// Parse and resolve a named assembler constant.
782 -
unsafe fn parseConstantValue(a: &mut super::Assembler) -> i64 throws (super::Error) {
782 +
fn parseConstantValue 'parse (a: &mut super::Assembler 'parse) -> i64 throws (super::Error) {
783 783
    let name = try parseSymbolName(a);
784 784
    let value = dict::get(&a.constMap, name) else {
785 785
        throw super::Error::Invalid { offset: a.scan.previous.offset, message: "undefined constant" };
786 786
    };
787 787
    return value as i64;
788 788
}
789 789
790 790
/// Parse and resolve a CSR operand.
791 -
unsafe fn parseCsr(a: &mut super::Assembler) -> u32 throws (super::Error) {
791 +
fn parseCsr 'parse (a: &mut super::Assembler 'parse) -> u32 throws (super::Error) {
792 792
    let name = try parseSymbolName(a);
793 793
    let csr = lookupCsr(name) else {
794 794
        throw super::Error::Invalid { offset: a.scan.previous.offset, message: "unknown CSR" };
795 795
    };
796 796
    return csr;
797 797
}
798 798
799 799
/// Parse an offset(base) memory operand.
800 -
unsafe fn parseMemory(a: &mut super::Assembler) -> MemOperand throws (super::Error) {
800 +
fn parseMemory 'parse (a: &mut super::Assembler 'parse) -> MemOperand throws (super::Error) {
801 801
    let mut offset: i32 = 0;
802 802
    if a.scan.current.kind <> scanner::TokenKind::LParen {
803 803
        set offset = try expectSmallImmValue(a, try parseValue(a));
804 804
    }
805 805
    try expect(a, scanner::TokenKind::LParen, "expected `(`");
808 808
809 809
    return MemOperand { base, offset };
810 810
}
811 811
812 812
/// Parse an immediate value that fits in a signed 12-bit field.
813 -
unsafe fn parseSmallImm(a: &mut super::Assembler) -> i32 throws (super::Error) {
813 +
fn parseSmallImm 'parse (a: &mut super::Assembler 'parse) -> i32 throws (super::Error) {
814 814
    return try expectSmallImmValue(a, try parseValue(a));
815 815
}
816 816
817 817
/// Parse and validate a branch immediate.
818 -
unsafe fn parseBranchImm(a: &mut super::Assembler) -> i32 throws (super::Error) {
818 +
fn parseBranchImm 'parse (a: &mut super::Assembler 'parse) -> i32 throws (super::Error) {
819 819
    let value = try expectI32Value(a, try parseValue(a), "branch immediate out of range");
820 820
    if not encode::isBranchImm(value) {
821 821
        throw fail(a, "branch immediate out of range");
822 822
    }
823 823
    return value;
824 824
}
825 825
826 826
/// Parse and validate a jump immediate.
827 -
unsafe fn parseJumpImm(a: &mut super::Assembler) -> i32 throws (super::Error) {
827 +
fn parseJumpImm 'parse (a: &mut super::Assembler 'parse) -> i32 throws (super::Error) {
828 828
    let value = try expectI32Value(a, try parseValue(a), "jump immediate out of range");
829 829
    if not encode::isJumpImm(value) {
830 830
        throw fail(a, "jump immediate out of range");
831 831
    }
832 832
    return value;
833 833
}
834 834
835 835
/// Parse an integer token as an i64.
836 -
unsafe fn parseInteger(a: &mut super::Assembler) -> i64 throws (super::Error) {
836 +
fn parseInteger 'parse (a: &mut super::Assembler 'parse) -> i64 throws (super::Error) {
837 837
    let tok = try expectToken(a, scanner::TokenKind::Number, "expected number");
838 838
    let value = parseIntegerText(tok.source) else {
839 839
        throw failOnToken(tok, "invalid integer literal");
840 840
    };
841 841
    return value;
872 872
        return nil;
873 873
    };
874 874
}
875 875
876 876
/// Parse an access-class mask without duplicate fields.
877 -
unsafe fn parseFenceMask(a: &mut super::Assembler) -> u32 throws (super::Error) {
877 +
fn parseFenceMask 'parse (a: &mut super::Assembler 'parse) -> u32 throws (super::Error) {
878 878
    if a.scan.current.kind == scanner::TokenKind::Number {
879 879
        let value = try parseValue(a);
880 880
        if value <> 0 {
881 881
            throw fail(a, "numeric fence mask must be zero");
882 882
        }
906 906
    }
907 907
    return mask;
908 908
}
909 909
910 910
/// Parse a full memory fence or a pair of explicit access-class masks.
911 -
unsafe fn parseFence(a: &mut super::Assembler) throws (super::Error) {
911 +
fn parseFence 'parse (a: &mut super::Assembler 'parse) throws (super::Error) {
912 912
    if a.scan.current.kind == scanner::TokenKind::Semicolon {
913 913
        try emit::emitText(a, encode::fence());
914 914
        return;
915 915
    }
916 916
    let predecessor = try parseFenceMask(a);