|
1 | 1 | import csharp |
2 | 2 |
|
3 | 3 | /** |
4 | | - * INTERNAL: Do not use. |
5 | | - * |
6 | 4 | * Provides a simple SSA implementation for local scope variables. |
7 | 5 | */ |
8 | 6 | module BaseSsa { |
9 | | - private import ControlFlow |
10 | | - private import AssignableDefinitions |
| 7 | + import basessa.SsaImplSpecific |
| 8 | + private import basessa.SsaImplCommon as SsaImpl |
11 | 9 |
|
12 | | - pragma[noinline] |
13 | | - Callable getAnAssigningCallable(LocalScopeVariable v) { |
14 | | - result = any(AssignableDefinition def | def.getTarget() = v).getEnclosingCallable() |
15 | | - } |
16 | | - |
17 | | - private class SimpleLocalScopeVariable extends LocalScopeVariable { |
18 | | - SimpleLocalScopeVariable() { not getAnAssigningCallable(this) != getAnAssigningCallable(this) } |
19 | | - } |
20 | | - |
21 | | - /** |
22 | | - * Holds if the `i`th node of basic block `bb` is assignable definition `def`, |
23 | | - * targeting local scope variable `v`. |
24 | | - */ |
25 | | - private predicate defAt(BasicBlock bb, int i, AssignableDefinition def, SimpleLocalScopeVariable v) { |
26 | | - bb.getNode(i) = def.getAControlFlowNode() and |
27 | | - v = def.getTarget() and |
28 | | - // In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x` |
29 | | - not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def | |
30 | | - second.getAssignment() = first.getAssignment() and |
31 | | - second.getEvaluationOrder() > first.getEvaluationOrder() and |
32 | | - second.getTarget() = v |
33 | | - ) |
34 | | - } |
| 10 | + class Definition extends SsaImpl::Definition { |
| 11 | + final AssignableRead getARead() { |
| 12 | + exists(BasicBlock bb, int i | |
| 13 | + SsaImpl::ssaDefReachesRead(_, this, bb, i) and |
| 14 | + result.getAControlFlowNode() = bb.getNode(i) |
| 15 | + ) |
| 16 | + } |
35 | 17 |
|
36 | | - /** |
37 | | - * Holds if basic block `bb` would need to start with a phi node for local scope |
38 | | - * variable `v` in an SSA representation. |
39 | | - */ |
40 | | - private predicate needsPhiNode(BasicBlock bb, SimpleLocalScopeVariable v) { |
41 | | - exists(BasicBlock def | def.inDominanceFrontier(bb) | |
42 | | - defAt(def, _, _, v) or |
43 | | - needsPhiNode(def, v) |
44 | | - ) |
45 | | - } |
| 18 | + final AssignableDefinition getDefinition() { |
| 19 | + exists(BasicBlock bb, int i, SourceVariable v | |
| 20 | + this.definesAt(v, bb, i) and |
| 21 | + definitionAt(result, bb, i, v) |
| 22 | + ) |
| 23 | + } |
46 | 24 |
|
47 | | - private newtype SsaRefKind = |
48 | | - SsaRead() or |
49 | | - SsaDef() |
| 25 | + private Definition getAPhiInputOrPriorDefinition() { |
| 26 | + result = this.(PhiNode).getAnInput() or |
| 27 | + SsaImpl::uncertainWriteDefinitionInput(this, result) |
| 28 | + } |
50 | 29 |
|
51 | | - /** |
52 | | - * Holds if the `i`th node of basic block `bb` is a reference to `v`, |
53 | | - * either a read (when `k` is `SsaRead()`) or a write including phi nodes |
54 | | - * (when `k` is `SsaDef()`). |
55 | | - */ |
56 | | - private predicate ssaRef(BasicBlock bb, int i, SimpleLocalScopeVariable v, SsaRefKind k) { |
57 | | - bb.getNode(i).getElement() = v.getAnAccess().(VariableRead) and |
58 | | - k = SsaRead() |
59 | | - or |
60 | | - defAt(bb, i, _, v) and |
61 | | - k = SsaDef() |
62 | | - or |
63 | | - needsPhiNode(bb, v) and |
64 | | - i = -1 and |
65 | | - k = SsaDef() |
66 | | - } |
| 30 | + final Definition getAnUltimateDefinition() { |
| 31 | + result = this.getAPhiInputOrPriorDefinition*() and |
| 32 | + not result instanceof PhiNode |
| 33 | + } |
67 | 34 |
|
68 | | - /** |
69 | | - * Gets the (1-based) rank of the reference to `v` at the `i`th node of basic |
70 | | - * block `bb`, which has the given reference kind `k`. |
71 | | - */ |
72 | | - private int ssaRefRank(BasicBlock bb, int i, SimpleLocalScopeVariable v, SsaRefKind k) { |
73 | | - i = rank[result](int j | ssaRef(bb, j, v, _)) and |
74 | | - ssaRef(bb, i, v, k) |
| 35 | + Location getLocation() { result = this.getDefinition().getLocation() } |
75 | 36 | } |
76 | 37 |
|
77 | | - /** |
78 | | - * Holds if definition `def` of local scope variable `v` inside basic block |
79 | | - * `bb` reaches the reference at rank `rnk`, without passing through another |
80 | | - * definition of `v`, including phi nodes. |
81 | | - */ |
82 | | - private predicate defReachesRank( |
83 | | - BasicBlock bb, AssignableDefinition def, SimpleLocalScopeVariable v, int rnk |
84 | | - ) { |
85 | | - exists(int i | rnk = ssaRefRank(bb, i, v, SsaDef()) | defAt(bb, i, def, v)) |
86 | | - or |
87 | | - defReachesRank(bb, def, v, rnk - 1) and |
88 | | - rnk = ssaRefRank(bb, _, v, SsaRead()) |
89 | | - } |
90 | | - |
91 | | - /** |
92 | | - * Holds if definition `def` of local scope variable `v` reaches the end of |
93 | | - * basic block `bb` without passing through another definition of `v`, including |
94 | | - * phi nodes. |
95 | | - */ |
96 | | - private predicate reachesEndOf(AssignableDefinition def, SimpleLocalScopeVariable v, BasicBlock bb) { |
97 | | - exists(int rnk | |
98 | | - defReachesRank(bb, def, v, rnk) and |
99 | | - rnk = max(ssaRefRank(bb, _, v, _)) |
100 | | - ) |
101 | | - or |
102 | | - exists(BasicBlock mid | |
103 | | - reachesEndOf(def, v, mid) and |
104 | | - not exists(ssaRefRank(bb, _, v, SsaDef())) and |
105 | | - bb = mid.getASuccessor() |
106 | | - ) |
107 | | - } |
| 38 | + class PhiNode extends SsaImpl::PhiNode, Definition { |
| 39 | + override Location getLocation() { result = this.getBasicBlock().getLocation() } |
108 | 40 |
|
109 | | - /** |
110 | | - * Gets a read of the SSA definition for variable `v` at definition `def`. That is, |
111 | | - * a read that is guaranteed to read the value assigned at definition `def`. |
112 | | - */ |
113 | | - cached |
114 | | - AssignableRead getARead(AssignableDefinition def, SimpleLocalScopeVariable v) { |
115 | | - exists(BasicBlock bb, int i, int rnk | |
116 | | - result.getAControlFlowNode() = bb.getNode(i) and |
117 | | - rnk = ssaRefRank(bb, i, v, SsaRead()) |
118 | | - | |
119 | | - defReachesRank(bb, def, v, rnk) |
120 | | - or |
121 | | - reachesEndOf(def, v, bb.getAPredecessor()) and |
122 | | - not ssaRefRank(bb, _, v, SsaDef()) < rnk |
123 | | - ) |
| 41 | + final Definition getAnInput() { SsaImpl::phiHasInputFromBlock(this, result, _) } |
124 | 42 | } |
125 | 43 | } |
0 commit comments