lib/std/lang/gen/regalloc/flow.rad 4.1 KiB raw
1
//! Owned control-flow topology for dataflow analysis.
2
3
use std::graph;
4
use std::lang::alloc;
5
use std::lang::il::published;
6
7
/// Zero-state owner for authority over one flow topology.
8
export record Permission {}
9
10
/// Stable block identity and private successor storage.
11
export opaque record Block: 'storage + 'permission + Copy {
12
    /// Graph capability identity.
13
    token: graph::Node 'storage,
14
    /// Block position in the function's dataflow tables.
15
    index: u32,
16
    /// Successors published when construction is complete.
17
    links: &'storage cell 'permission &'storage [Block 'storage 'permission],
18
}
19
20
/// Immutable topology whose storage belongs to the analysis session.
21
export opaque record Flow: 'storage + 'permission + Copy {
22
    /// Shared authority for every block in the topology.
23
    frozen: graph::Frozen 'storage,
24
    /// Stable block handles in function order.
25
    blocks: &'storage [Block 'storage 'permission],
26
}
27
28
/// Copy published successor topology into session-owned graph storage.
29
export fn snapshot 'input 'storage 'permission (
30
    blocks: &[published::Block 'input],
31
    storage: &Session 'storage,
32
    permission: &'permission mut Permission,
33
) -> Flow 'storage 'permission throws (alloc::AllocError) {
34
    let mut builder = try graph::new(storage);
35
    let none: [Block 'storage 'permission; 0] = [];
36
    let empty: &'storage [Block 'storage 'permission] = try storage.copy(&none[..]);
37
    if blocks.len == 0 {
38
        return Flow 'storage 'permission {
39
            frozen: try! graph::freeze(builder),
40
            blocks: empty,
41
        };
42
    }
43
    let first = try reserve(&mut builder, 0, empty, storage, permission);
44
    let entries = try storage.fill(first, blocks.len);
45
    for i in 1..blocks.len {
46
        set entries[i] = try reserve(&mut builder, i, empty, storage, permission);
47
    }
48
    for block, i in blocks {
49
        let instructions = block.instructions;
50
        let mut links = empty;
51
        if instructions.len > 0 {
52
            let targets = published::successors(&instructions[instructions.len - 1]);
53
            if targets.len > 0 {
54
                let successors = try storage.fill(entries[targets[0]], targets.len);
55
                for j in 1..targets.len {
56
                    set successors[j] = entries[targets[j]];
57
                }
58
                set links = &successors[..];
59
            }
60
        }
61
        try! define(&mut builder, entries[i], links, permission);
62
    }
63
    return Flow 'storage 'permission {
64
        frozen: try! graph::freeze(builder),
65
        blocks: &entries[..],
66
    };
67
}
68
69
/// Reserve a block before its outgoing links are known.
70
fn reserve 'storage 'permission (
71
    builder: &mut graph::Builder 'storage,
72
    index: u32,
73
    empty: &'storage [Block 'storage 'permission],
74
    storage: &Session 'storage,
75
    permission: &'permission mut Permission,
76
) -> Block 'storage 'permission throws (alloc::AllocError) {
77
    let links = try storage.new(empty);
78
    let token = try graph::reserve(builder, storage);
79
    return Block 'storage 'permission {
80
        token,
81
        index,
82
        links: &cell 'permission *links,
83
    };
84
}
85
86
/// Complete a block after all successors have been checked.
87
fn define 'storage 'permission (
88
    builder: &mut graph::Builder 'storage,
89
    block: Block 'storage 'permission,
90
    links: &'storage [Block 'storage 'permission],
91
    permission: &'permission mut Permission,
92
) throws (graph::Error) {
93
    try graph::check(builder, block.token);
94
    for successor in links {
95
        try graph::check(builder, successor.token);
96
    }
97
    set *block.links = links;
98
    try graph::complete(builder, block.token);
99
}
100
101
/// Borrow the successors of a published block.
102
export fn successors 'storage 'permission (
103
    flow: &Flow 'storage 'permission,
104
    index: u32,
105
    permission: &'permission mut Permission,
106
) -> &'storage [Block 'storage 'permission] {
107
    let block = flow.blocks[index];
108
    try! graph::checkFrozen(&flow.frozen, block.token);
109
    let authority: 'loan = &*permission, links = &*block.links in {
110
        return *links;
111
    }
112
}
113
114
/// Return the dataflow table position retained by a block identity.
115
export fn index 'storage 'permission (block: Block 'storage 'permission) -> u32 {
116
    return block.index;
117
}