compiler/
lib/
examples/
std/
arch/
collections/
lang/
alloc/
ast/
gen/
bitset/
regalloc/
bitset.rad
5.6 KiB
data.rad
5.1 KiB
labels.rad
2.3 KiB
regalloc.rad
2.3 KiB
types.rad
576 B
il/
module/
parser/
resolver/
scanner/
alloc.rad
4.2 KiB
ast.rad
22.4 KiB
gen.rad
489 B
il.rad
15.1 KiB
lower.rad
259.5 KiB
module.rad
13.4 KiB
package.rad
1.2 KiB
parser.rad
78.5 KiB
resolver.rad
244.3 KiB
scanner.rad
18.1 KiB
sexpr.rad
6.3 KiB
strings.rad
2.2 KiB
sys/
arch.rad
65 B
collections.rad
36 B
fmt.rad
3.8 KiB
intrinsics.rad
399 B
io.rad
1.2 KiB
lang.rad
222 B
mem.rad
2.1 KiB
sys.rad
167 B
testing.rad
2.3 KiB
tests.rad
11.6 KiB
vec.rad
3.1 KiB
std.rad
231 B
scripts/
seed/
test/
vim/
.gitignore
353 B
.gitsigners
112 B
LICENSE
1.1 KiB
Makefile
3.0 KiB
README
2.5 KiB
std.lib
1.0 KiB
std.lib.test
252 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 | pub const MAX_BLOCKS_PER_FN: u32 = 4096; |
| 9 | /// Maximum number of functions. |
| 10 | pub const MAX_FUNCS: u32 = 8192; |
| 11 | /// Size of the function hash table. Must be a power of two. |
| 12 | pub const FUNC_TABLE_SIZE: u32 = MAX_FUNCS * 2; |
| 13 | |
| 14 | /// Label tracking for code emission. |
| 15 | pub 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 | pub 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 | pub fn resetBlocks(l: *mut Labels) { |
| 36 | l.blockCount = 0; |
| 37 | } |
| 38 | |
| 39 | /// Record a block's code offset by its index. O(1). |
| 40 | pub fn recordBlock(l: *mut Labels, blockIdx: u32, offset: i32) { |
| 41 | assert blockIdx < l.blockOffsets.len, "recordBlock: block index out of range"; |
| 42 | l.blockOffsets[blockIdx] = offset; |
| 43 | l.blockCount += 1; |
| 44 | } |
| 45 | |
| 46 | /// Look up a block's byte offset by index. O(1). |
| 47 | pub 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 | pub 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 | pub 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 | pub 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 | } |