compiler: Borrow assembler string storage by lexical region
411cc85d65bd108f7f72d8ffd43b9fc318c24ba89f5049b06c078a7ec55933f3
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); |