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