compiler/
kernel/
lib/
examples/
std/
arch/
char/
collections/
lang/
alloc/
ast/
gen/
bitset/
regalloc/
bitset.rad
4.6 KiB
data.rad
8.5 KiB
labels.rad
2.4 KiB
regalloc.rad
2.4 KiB
types.rad
594 B
il/
module/
parser/
resolver/
scanner/
alloc.rad
7.1 KiB
ast.rad
26.7 KiB
gen.rad
513 B
il.rad
19.5 KiB
lower.rad
308.1 KiB
module.rad
14.9 KiB
package.rad
1.3 KiB
parser.rad
89.5 KiB
resolver.rad
439.6 KiB
scanner.rad
18.0 KiB
sexpr.rad
6.4 KiB
strings.rad
2.2 KiB
types.rad
1.6 KiB
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
9.2 KiB
README
2.5 KiB
STYLE
2.5 KiB
std.lib
1.5 KiB
std.lib.test
662 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 | } |