Skip to content

Commit 2515026

Browse files
committed
C#: Compute phi inputs in pre-SSA library
Logic is copied directly from the ordinary SSA library.
1 parent 33111b6 commit 2515026

File tree

3 files changed

+149
-20
lines changed

3 files changed

+149
-20
lines changed

csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll

Lines changed: 107 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2516,8 +2516,12 @@ module ControlFlow {
25162516
result = strictcount(getAnElement())
25172517
}
25182518

2519+
predicate immediatelyDominates(PreBasicBlock bb) {
2520+
bbIDominates(this, bb)
2521+
}
2522+
25192523
predicate strictlyDominates(PreBasicBlock bb) {
2520-
bbIDominates+(this, bb)
2524+
this.immediatelyDominates+(bb)
25212525
}
25222526

25232527
predicate dominates(PreBasicBlock bb) {
@@ -2584,8 +2588,6 @@ module ControlFlow {
25842588
}
25852589
}
25862590

2587-
private newtype SsaRefKind = SsaRead() or SsaDef()
2588-
25892591
class Definition extends TPreSsaDef {
25902592
string toString() {
25912593
exists(AssignableDefinition def |
@@ -2626,12 +2628,25 @@ module ControlFlow {
26262628
)
26272629
}
26282630

2631+
PreBasicBlock getBasicBlock() {
2632+
this = TExplicitPreSsaDef(result, _, _, _) or
2633+
this = TPhiPreSsaDef(result, _)
2634+
}
2635+
26292636
AssignableDefinition getDefinition() {
26302637
this = TExplicitPreSsaDef(_, _, result, _)
26312638
}
2639+
2640+
Definition getAPhiInput() {
2641+
exists(PreBasicBlock bb, PreBasicBlock phiPred, SimpleLocalScopeVariable v |
2642+
this = TPhiPreSsaDef(bb, v) |
2643+
bb.getAPredecessor() = phiPred and
2644+
ssaDefReachesEndOfBlock(phiPred, result, v)
2645+
)
2646+
}
26322647
}
26332648

2634-
predicate assignableDefAt(PreBasicBlocks::PreBasicBlock bb, int i, AssignableDefinition def, SimpleLocalScopeVariable v) {
2649+
private predicate assignableDefAt(PreBasicBlocks::PreBasicBlock bb, int i, AssignableDefinition def, SimpleLocalScopeVariable v) {
26352650
bb.getElement(i) = def.getExpr() and
26362651
v = def.getTarget() and
26372652
// In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x`
@@ -2650,16 +2665,82 @@ module ControlFlow {
26502665
)
26512666
}
26522667

2668+
private predicate readAt(PreBasicBlock bb, int i, LocalScopeVariableRead read, SimpleLocalScopeVariable v) {
2669+
read = bb.getElement(i) and
2670+
read.getTarget() = v
2671+
}
2672+
2673+
pragma[noinline]
2674+
private predicate exitBlock(PreBasicBlock bb, Callable c) {
2675+
exists(succExit(bb.getLastElement(), _)) and
2676+
c = bb.getEnclosingCallable()
2677+
}
2678+
2679+
private predicate outRefExitRead(PreBasicBlock bb, int i, SimpleLocalScopeVariable v) {
2680+
exitBlock(bb, v.getCallable()) and
2681+
i = bb.length() + 1 and
2682+
(v.isRef() or v.(Parameter).isOut())
2683+
}
2684+
2685+
private newtype RefKind =
2686+
Read()
2687+
or
2688+
Write(boolean certain) { certain = true or certain = false }
2689+
2690+
private predicate ref(PreBasicBlock bb, int i, SimpleLocalScopeVariable v, RefKind k) {
2691+
(readAt(bb, i, _, v) or outRefExitRead(bb, i, v)) and
2692+
k = Read()
2693+
or
2694+
exists(AssignableDefinition def, boolean certain |
2695+
assignableDefAt(bb, i, def, v) |
2696+
if def.getTargetAccess().isRefArgument() then certain = false else certain = true and
2697+
k = Write(certain)
2698+
)
2699+
}
2700+
2701+
private int refRank(PreBasicBlock bb, int i, SimpleLocalScopeVariable v, RefKind k) {
2702+
i = rank[result](int j | ref(bb, j, v, _)) and
2703+
ref(bb, i, v, k)
2704+
}
2705+
2706+
private int firstReadOrCertainWrite(PreBasicBlock bb, SimpleLocalScopeVariable v) {
2707+
result = min(int r, RefKind k |
2708+
r = refRank(bb, _, v, k) and
2709+
k != Write(false)
2710+
|
2711+
r
2712+
)
2713+
}
2714+
2715+
predicate liveAtEntry(PreBasicBlock bb, SimpleLocalScopeVariable v) {
2716+
refRank(bb, _, v, Read()) = firstReadOrCertainWrite(bb, v)
2717+
or
2718+
not exists(firstReadOrCertainWrite(bb, v)) and
2719+
liveAtExit(bb, v)
2720+
}
2721+
2722+
private predicate liveAtExit(PreBasicBlock bb, SimpleLocalScopeVariable v) {
2723+
liveAtEntry(bb.getASuccessor(), v)
2724+
}
2725+
2726+
predicate assignableDefAtLive(PreBasicBlocks::PreBasicBlock bb, int i, AssignableDefinition def, SimpleLocalScopeVariable v) {
2727+
assignableDefAt(bb, i, def, v) and
2728+
exists(int rnk |
2729+
rnk = refRank(bb, i, v, Write(_)) |
2730+
rnk + 1 = refRank(bb, _, v, Read())
2731+
or
2732+
rnk = max(refRank(bb, _, v, _)) and
2733+
liveAtExit(bb, v)
2734+
)
2735+
}
2736+
26532737
predicate defAt(PreBasicBlock bb, int i, Definition def, SimpleLocalScopeVariable v) {
26542738
def = TExplicitPreSsaDef(bb, i, _, v)
26552739
or
26562740
def = TPhiPreSsaDef(bb, v) and i = -1
26572741
}
26582742

2659-
private predicate readAt(PreBasicBlock bb, int i, LocalScopeVariableRead read, SimpleLocalScopeVariable v) {
2660-
read = bb.getElement(i) and
2661-
read.getTarget() = v
2662-
}
2743+
private newtype SsaRefKind = SsaRead() or SsaDef()
26632744

26642745
private predicate ssaRef(PreBasicBlock bb, int i, SimpleLocalScopeVariable v, SsaRefKind k) {
26652746
readAt(bb, i, _, v) and
@@ -2756,6 +2837,22 @@ module ControlFlow {
27562837
readAt(bb2, i2, read2, v)
27572838
)
27582839
}
2840+
2841+
predicate ssaDefReachesEndOfBlock(PreBasicBlock bb, Definition def, SimpleLocalScopeVariable v) {
2842+
liveAtExit(bb, v) and
2843+
(
2844+
exists(int last |
2845+
last = max(ssaRefRank(bb, _, v, _)) |
2846+
defReachesRank(bb, def, v, last)
2847+
)
2848+
or
2849+
exists(PreBasicBlock idom |
2850+
idom.immediatelyDominates(bb) |
2851+
ssaDefReachesEndOfBlock(idom, def, v) and
2852+
not exists(ssaRefRank(bb, _, v, SsaDef()))
2853+
)
2854+
)
2855+
}
27592856
}
27602857

27612858
/**
@@ -3847,10 +3944,11 @@ module ControlFlow {
38473944
newtype TPreSsaDef =
38483945
TExplicitPreSsaDef(PreBasicBlocks::PreBasicBlock bb, int i, AssignableDefinition def, LocalScopeVariable v) {
38493946
Guards::Internal::CachedWithCFG::forceCachingInSameStage() and
3850-
PreSsa::assignableDefAt(bb, i, def, v)
3947+
PreSsa::assignableDefAtLive(bb, i, def, v)
38513948
}
38523949
or
38533950
TPhiPreSsaDef(PreBasicBlocks::PreBasicBlock bb, LocalScopeVariable v) {
3951+
PreSsa::liveAtEntry(bb, v) and
38543952
exists(PreBasicBlocks::PreBasicBlock def |
38553953
def.inDominanceFrontier(bb) |
38563954
PreSsa::defAt(def, _, _, v)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
defReadInconsistency
2+
readReadInconsistency
3+
phiInconsistency
Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import csharp
22
import ControlFlow::Internal
33

4-
predicate defReadInconsistency(AssignableRead ar, Expr e, boolean b) {
4+
query
5+
predicate defReadInconsistency(AssignableRead ar, Expr e, PreSsa::SimpleLocalScopeVariable v, boolean b) {
56
exists(AssignableDefinition def |
67
e = def.getExpr() |
78
b = true and
89
exists(PreSsa::Definition ssaDef |
10+
ssaDef.getVariable() = v |
911
PreSsa::firstReadSameVar(ssaDef, ar) and
1012
ssaDef.getDefinition() = def and
1113
not exists(Ssa::ExplicitDefinition edef |
@@ -18,7 +20,7 @@ predicate defReadInconsistency(AssignableRead ar, Expr e, boolean b) {
1820
exists(Ssa::ExplicitDefinition edef |
1921
edef.getADefinition() = def and
2022
edef.getAFirstRead() = ar and
21-
def.getTarget() instanceof PreSsa::SimpleLocalScopeVariable and
23+
def.getTarget() = v and
2224
not exists(PreSsa::Definition ssaDef |
2325
PreSsa::firstReadSameVar(ssaDef, ar) and
2426
ssaDef.getDefinition() = def
@@ -27,22 +29,48 @@ predicate defReadInconsistency(AssignableRead ar, Expr e, boolean b) {
2729
)
2830
}
2931

30-
predicate readReadInconsistency(LocalScopeVariableRead read1, LocalScopeVariableRead read2, boolean b) {
32+
query
33+
predicate readReadInconsistency(LocalScopeVariableRead read1, LocalScopeVariableRead read2, PreSsa::SimpleLocalScopeVariable v, boolean b) {
3134
b = true and
35+
v = read1.getTarget() and
3236
PreSsa::adjacentReadPairSameVar(read1, read2) and
3337
not Ssa::Internal::adjacentReadPairSameVar(read1, read2)
3438
or
3539
b = false and
40+
v = read1.getTarget() and
3641
Ssa::Internal::adjacentReadPairSameVar(read1, read2) and
3742
read1.getTarget() instanceof PreSsa::SimpleLocalScopeVariable and
3843
not PreSsa::adjacentReadPairSameVar(read1, read2)
3944
}
4045

41-
from Element e1, Element e2, boolean b, string s
42-
where
43-
defReadInconsistency(e1, e2, b) and
44-
s = "def-read inconsistency (" + b + ")"
45-
or
46-
readReadInconsistency(e1, e2, b) and
47-
s = "read-read inconsistency (" + b + ")"
48-
select e1, e2, s
46+
query
47+
predicate phiInconsistency(ControlFlowElement cfe, Expr e, PreSsa::SimpleLocalScopeVariable v, boolean b) {
48+
exists(AssignableDefinition adef |
49+
e = adef.getExpr() |
50+
b = true and
51+
exists(PreSsa::Definition def |
52+
v = def.getVariable() |
53+
adef = def.getAPhiInput+().getDefinition() and
54+
cfe = def.getBasicBlock().getFirstElement() and
55+
not exists(Ssa::PhiNode phi, ControlFlow::BasicBlock bb, Ssa::ExplicitDefinition edef |
56+
edef = phi.getAnUltimateDefinition() |
57+
edef.getADefinition() = adef and
58+
phi.definesAt(bb, _) and
59+
cfe = bb.getFirstNode().getElement()
60+
)
61+
)
62+
or
63+
b = false and
64+
exists(Ssa::PhiNode phi, ControlFlow::BasicBlock bb, Ssa::ExplicitDefinition edef |
65+
v = phi.getSourceVariable().getAssignable() |
66+
edef = phi.getAnUltimateDefinition() and
67+
edef.getADefinition() = adef and
68+
phi.definesAt(bb, _) and
69+
cfe = bb.getFirstNode().getElement() and
70+
not exists(PreSsa::Definition def |
71+
adef = def.getAPhiInput+().getDefinition() and
72+
cfe = def.getBasicBlock().getFirstElement()
73+
)
74+
)
75+
)
76+
}

0 commit comments

Comments
 (0)