|
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