compiler/
lib/
examples/
std/
arch/
char/
collections/
lang/
alloc/
ast/
gen/
bitset/
regalloc/
bitset.rad
6.1 KiB
data.rad
8.6 KiB
labels.rad
2.4 KiB
regalloc.rad
2.3 KiB
types.rad
594 B
il/
module/
parser/
resolver/
scanner/
alloc.rad
5.3 KiB
ast.rad
23.6 KiB
gen.rad
513 B
il.rad
15.5 KiB
lower.rad
277.2 KiB
module.rad
13.5 KiB
package.rad
1.3 KiB
parser.rad
79.6 KiB
resolver.rad
332.7 KiB
scanner.rad
17.6 KiB
sexpr.rad
6.4 KiB
strings.rad
2.2 KiB
types.rad
286 B
sys/
arch.rad
68 B
char.rad
855 B
collections.rad
39 B
fmt.rad
8.3 KiB
intrinsics.rad
467 B
io.rad
1.7 KiB
lang.rad
276 B
mem.rad
2.3 KiB
sys.rad
179 B
testing.rad
2.4 KiB
tests.rad
15.7 KiB
vec.rad
3.2 KiB
std.rad
281 B
scripts/
seed/
sublime/
test/
vim/
.gitignore
336 B
.gitsigners
112 B
CONTRIBUTING
2.1 KiB
LICENSE
1.1 KiB
Makefile
4.1 KiB
README
2.5 KiB
STYLE
2.6 KiB
std.lib
1.2 KiB
std.lib.test
347 B
lib/std/lang/gen/labels.rad
raw
| 1 | //! Label tracking and branch resolution. |
| 2 | //! |
| 3 | //! Provides target-independent block/label tracking for branch resolution. |
| 4 | |
| 5 | use std::collections::dict; |
| 6 | |
| 7 | /// Maximum number of blocks per function. |
| 8 | export constant MAX_BLOCKS_PER_FN: u32 = 4096; |
| 9 | /// Maximum number of functions. |
| 10 | export constant MAX_FUNCS: u32 = 8192; |
| 11 | /// Size of the function hash table. Must be a power of two. |
| 12 | export constant FUNC_TABLE_SIZE: u32 = MAX_FUNCS * 2; |
| 13 | |
| 14 | /// Label tracking for code emission. |
| 15 | export record Labels { |
| 16 | /// Block offsets indexed by block index. |
| 17 | /// Per-function, reset each function. |
| 18 | blockOffsets: *mut [i32], |
| 19 | /// Number of blocks recorded in current function. |
| 20 | blockCount: u32, |
| 21 | /// Function name to byte offset mapping. |
| 22 | funcs: dict::Dict, |
| 23 | } |
| 24 | |
| 25 | /// Create a new labels tracker with caller-provided storage. |
| 26 | export fn init(blockOffsets: *mut [i32], funcEntries: *mut [dict::Entry]) -> Labels { |
| 27 | return Labels { |
| 28 | blockOffsets, |
| 29 | blockCount: 0, |
| 30 | funcs: dict::init(funcEntries), |
| 31 | }; |
| 32 | } |
| 33 | |
| 34 | /// Reset block count for a new function. |
| 35 | export fn resetBlocks(l: &mut Labels) { |
| 36 | set l.blockCount = 0; |
| 37 | } |
| 38 | |
| 39 | /// Record a block's code offset by its index. O(1). |
| 40 | export fn recordBlock(l: &mut Labels, blockIdx: u32, offset: i32) { |
| 41 | assert blockIdx < l.blockOffsets.len, "recordBlock: block index out of range"; |
| 42 | set l.blockOffsets[blockIdx] = offset; |
| 43 | set l.blockCount += 1; |
| 44 | } |
| 45 | |
| 46 | /// Look up a block's byte offset by index. O(1). |
| 47 | export fn blockOffset(l: &Labels, blockIdx: u32) -> i32 { |
| 48 | assert blockIdx < l.blockCount, "blockOffset: block not recorded"; |
| 49 | return l.blockOffsets[blockIdx]; |
| 50 | } |
| 51 | |
| 52 | /// Look up a function's byte offset by name. |
| 53 | export fn funcOffset(l: &Labels, name: *[u8]) -> i32 { |
| 54 | if let offset = dict::get(&l.funcs, name) { |
| 55 | return offset; |
| 56 | } |
| 57 | panic "funcOffset: unknown function"; |
| 58 | } |
| 59 | |
| 60 | /// Compute branch offset to a block given source instruction index. |
| 61 | export fn branchToBlock(l: &Labels, srcIndex: u32, blockIdx: u32, instrSize: i32) -> i32 { |
| 62 | let targetOffset = blockOffset(l, blockIdx); |
| 63 | let srcOffset = srcIndex as i32 * instrSize; |
| 64 | |
| 65 | return targetOffset - srcOffset; |
| 66 | } |
| 67 | |
| 68 | /// Compute branch offset to a function given source instruction index. |
| 69 | export fn branchToFunc(l: &Labels, srcIndex: u32, name: *[u8], instrSize: i32) -> i32 { |
| 70 | let targetOffset = funcOffset(l, name); |
| 71 | let srcOffset = srcIndex as i32 * instrSize; |
| 72 | |
| 73 | return targetOffset - srcOffset; |
| 74 | } |