Skip to content

Commit bed6620

Browse files
committed
C#: Use shared SSA implementation for BaseSsa
1 parent b0ee508 commit bed6620

File tree

7 files changed

+714
-115
lines changed

7 files changed

+714
-115
lines changed

config/identical-files.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@
428428
],
429429
"SSA C#": [
430430
"csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll",
431-
"csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll"
431+
"csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll",
432+
"csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll"
432433
]
433434
}
Lines changed: 27 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,43 @@
11
import csharp
22

33
/**
4-
* INTERNAL: Do not use.
5-
*
64
* Provides a simple SSA implementation for local scope variables.
75
*/
86
module BaseSsa {
9-
private import ControlFlow
10-
private import AssignableDefinitions
7+
import basessa.SsaImplSpecific
8+
private import basessa.SsaImplCommon as SsaImpl
119

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+
}
3517

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+
}
4624

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+
}
5029

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+
}
6734

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() }
7536
}
7637

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() }
10840

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, _) }
12442
}
12543
}

csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ module Steps {
1616
* Gets a read that is guaranteed to read the value assigned at definition `def`.
1717
*/
1818
private AssignableRead getARead(AssignableDefinition def) {
19-
result = BaseSsa::getARead(def, _)
19+
exists(BaseSsa::Definition ssaDef |
20+
ssaDef.getDefinition() = def and
21+
result = ssaDef.getARead()
22+
)
2023
or
2124
exists(LocalScopeVariable v | def.getTarget() = v |
2225
result = v.getAnAccess() and

0 commit comments

Comments
 (0)