Skip to content

Commit 8c9c316

Browse files
author
Robert Marsh
committed
C++: performance and termination fixes
1 parent 567eee1 commit 8c9c316

File tree

6 files changed

+127
-53
lines changed

6 files changed

+127
-53
lines changed

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ private predicate uniqueValueNumber(Instruction instr, FunctionIR funcIR) {
216216
/**
217217
* Gets the value number assigned to `instr`, if any. Returns at most one result.
218218
*/
219-
ValueNumber valueNumber(Instruction instr) {
219+
cached ValueNumber valueNumber(Instruction instr) {
220220
result = nonUniqueValueNumber(instr) or
221221
exists(FunctionIR funcIR |
222222
uniqueValueNumber(instr, funcIR) and

cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ private newtype TBound =
1010
(
1111
i.getResultType() instanceof IntegralType or
1212
i.getResultType() instanceof PointerType
13-
)
13+
) and
14+
not vn.getAnInstruction() instanceof ConstantInstruction
1415
|
1516
i instanceof PhiInstruction
1617
or

cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll

Lines changed: 61 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ class CondReason extends Reason, TCondReason {
197197
* Holds if a cast from `fromtyp` to `totyp` can be ignored for the purpose of
198198
* range analysis.
199199
*/
200+
pragma[inline]
200201
private predicate safeCast(IntegralType fromtyp, IntegralType totyp) {
201202
fromtyp.getSize() < totyp.getSize() and
202203
(
@@ -256,7 +257,7 @@ private class NarrowingCastInstruction extends ConvertInstruction {
256257
* - `upper = true` : `i <= op + delta`
257258
* - `upper = false` : `i >= op + delta`
258259
*/
259-
private predicate boundFlowStep(Instruction i, Operand op, int delta, boolean upper) {
260+
private predicate boundFlowStep(Instruction i, NonPhiOperand op, int delta, boolean upper) {
260261
valueFlowStep(i, op, delta) and
261262
(upper = true or upper = false)
262263
or
@@ -425,12 +426,27 @@ private predicate boundedPhiOperand(
425426
)
426427
}
427428

429+
/** Holds if `v != e + delta` at `pos`. */
430+
private predicate unequalFlowStep(
431+
Operand op1, Operand op2, int delta, Reason reason
432+
) {
433+
exists(IRGuardCondition guard, boolean testIsTrue |
434+
guard = eqFlowCond(valueNumberOfOperand(op1), op2, delta, false, testIsTrue) and
435+
guard.controls(op1.getInstruction().getBlock(), testIsTrue) and
436+
reason = TCondReason(guard)
437+
)
438+
}
439+
428440
/**
429441
* Holds if `op != b + delta` at `pos`.
430442
*/
431443
private predicate unequalOperand(Operand op, Bound b, int delta, Reason reason) {
432-
// TODO: implement this
433-
none()
444+
exists(Operand op2, int d1, int d2 |
445+
unequalFlowStep(op, op2, delta, reason) and
446+
boundedNonPhiOperand(op2, b, d2, true, _, _, _) and
447+
boundedNonPhiOperand(op2, b, d2, true, _, _, _) and
448+
delta = d1 + d2
449+
)
434450
}
435451

436452
private predicate boundedPhiCandValidForEdge(
@@ -544,50 +560,47 @@ private predicate boundedCastExpr(
544560
private predicate boundedInstruction(
545561
Instruction i, Bound b, int delta, boolean upper, boolean fromBackEdge, int origdelta, Reason reason
546562
) {
547-
i instanceof PhiInstruction and
548-
forex(PhiOperand op | op = i.getAnOperand() |
549-
boundedPhiCandValidForEdge(i, b, delta, upper, fromBackEdge, origdelta, reason, op)
550-
)
551-
or
552-
i = b.getInstruction(delta) and
553-
(upper = true or upper = false) and
554-
fromBackEdge = false and
555-
origdelta = delta and
556-
reason = TNoReason()
557-
or
558-
exists(Operand mid, int d1, int d2 |
559-
boundFlowStep(i, mid, d1, upper) and
560-
boundedNonPhiOperand(mid, b, d2, upper, fromBackEdge, origdelta, reason) and
561-
delta = d1 + d2 and
562-
not exists(getValue(getConstantValue(i)))
563-
)
564-
or
565-
exists(Operand mid, int factor, int d |
566-
boundFlowStepMul(i, mid, factor) and
567-
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
568-
b instanceof ZeroBound and
569-
delta = d*factor and
570-
not exists(getValue(getConstantValue(i)))
571-
)
572-
or
573-
exists(Operand mid, int factor, int d |
574-
boundFlowStepDiv(i, mid, factor) and
575-
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
576-
d >= 0 and
577-
b instanceof ZeroBound and
578-
delta = d / factor and
579-
not exists(getValue(getConstantValue(i)))
580-
)
581-
or
582-
exists(NarrowingCastInstruction cast |
583-
cast = i and
584-
safeNarrowingCast(cast, upper.booleanNot()) and
585-
boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason)
563+
isReducibleCFG(i.getFunction()) and
564+
(
565+
i instanceof PhiInstruction and
566+
forex(PhiOperand op | op = i.getAnOperand() |
567+
boundedPhiCandValidForEdge(i, b, delta, upper, fromBackEdge, origdelta, reason, op)
568+
)
569+
or
570+
i = b.getInstruction(delta) and
571+
(upper = true or upper = false) and
572+
fromBackEdge = false and
573+
origdelta = delta and
574+
reason = TNoReason()
575+
or
576+
exists(Operand mid, int d1, int d2 |
577+
boundFlowStep(i, mid, d1, upper) and
578+
boundedNonPhiOperand(mid, b, d2, upper, fromBackEdge, origdelta, reason) and
579+
delta = d1 + d2 and
580+
not exists(getValue(getConstantValue(i)))
581+
)
582+
or
583+
exists(Operand mid, int factor, int d |
584+
boundFlowStepMul(i, mid, factor) and
585+
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
586+
b instanceof ZeroBound and
587+
delta = d*factor and
588+
not exists(getValue(getConstantValue(i)))
589+
)
590+
or
591+
exists(Operand mid, int factor, int d |
592+
boundFlowStepDiv(i, mid, factor) and
593+
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
594+
d >= 0 and
595+
b instanceof ZeroBound and
596+
delta = d / factor and
597+
not exists(getValue(getConstantValue(i)))
598+
)
599+
or
600+
exists(NarrowingCastInstruction cast |
601+
cast = i and
602+
safeNarrowingCast(cast, upper.booleanNot()) and
603+
boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason)
604+
)
586605
)
587606
}
588-
589-
predicate backEdge(PhiInstruction phi, PhiOperand op) {
590-
phi.getAnOperand() = op and
591-
phi.getBlock().dominates(op.getPredecessorBlock())
592-
// TODO: identify backedges during IR construction
593-
}

cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeUtils.qll

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,25 @@ predicate valueFlowStep(Instruction i, Operand op, int delta) {
6262
-getValue(getConstantValue(x.getDefinitionInstruction()))
6363
)
6464
}
65+
66+
predicate isReducibleCFG(Function f) {
67+
not exists(LabelStmt l, GotoStmt goto |
68+
goto.getTarget() = l and
69+
l.getLocation().isBefore(goto.getLocation()) and
70+
l.getEnclosingFunction() = f
71+
) and
72+
not exists(LabelStmt ls, Loop l |
73+
ls.getParent*() = l and
74+
l.getEnclosingFunction() = f
75+
) and
76+
not exists(SwitchCase cs |
77+
cs.getSwitchStmt().getStmt() != cs.getParentStmt() and
78+
cs.getEnclosingFunction() = f
79+
)
80+
}
81+
82+
predicate backEdge(PhiInstruction phi, PhiOperand op) {
83+
phi.getAnOperand() = op and
84+
phi.getBlock().dominates(op.getPredecessorBlock())
85+
// TODO: identify backedges during IR construction
86+
}

cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
| test.cpp:97:10:97:10 | Load: x | file://:0:0:0:0 | 0 | 1 | false | CompareLT: ... < ... | test.cpp:94:7:94:11 | test.cpp:94:7:94:11 |
3636
| test.cpp:100:10:100:10 | Load: x | file://:0:0:0:0 | 0 | 1 | true | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 |
3737
| test.cpp:102:10:102:10 | Load: x | file://:0:0:0:0 | 0 | 2 | false | CompareLE: ... <= ... | test.cpp:99:7:99:12 | test.cpp:99:7:99:12 |
38-
| test.cpp:106:5:106:10 | Phi: test10 | test.cpp:113:3:113:6 | Phi: call to sink | -1 | true | CompareLT: ... < ... | test.cpp:114:18:114:22 | test.cpp:114:18:114:22 |
39-
| test.cpp:106:5:106:10 | Phi: test10 | test.cpp:114:18:114:18 | Phi: i | 0 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
40-
| test.cpp:106:5:106:10 | Phi: test10 | test.cpp:114:18:114:18 | Phi: i | 0 | true | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
38+
| test.cpp:107:5:107:10 | Phi: test10 | test.cpp:114:3:114:6 | Phi: call to sink | -1 | true | CompareLT: ... < ... | test.cpp:115:18:115:22 | test.cpp:115:18:115:22 |
39+
| test.cpp:140:10:140:10 | Store: i | file://:0:0:0:0 | 0 | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
40+
| test.cpp:140:10:140:10 | Store: i | test.cpp:135:16:135:16 | InitializeParameter: x | 0 | false | CompareLT: ... < ... | test.cpp:139:11:139:15 | test.cpp:139:11:139:15 |
41+
| test.cpp:140:10:140:10 | Store: i | test.cpp:138:5:138:5 | Phi: i | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
42+
| test.cpp:140:10:140:10 | Store: i | test.cpp:138:5:138:5 | Phi: i | 1 | true | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
43+
| test.cpp:149:10:149:10 | Store: i | file://:0:0:0:0 | 0 | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
44+
| test.cpp:149:10:149:10 | Store: i | test.cpp:147:5:147:5 | Phi: i | 1 | false | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |
45+
| test.cpp:149:10:149:10 | Store: i | test.cpp:147:5:147:5 | Phi: i | 1 | true | NoReason | file://:0:0:0:0 | file://:0:0:0:0 |

cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/test.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ void test9(int x) {
103103
}
104104
}
105105

106+
// Phi nodes as bounds
106107
int test10(int y, int z, bool use_y) {
107108
int x;
108109
if(use_y) {
@@ -115,3 +116,35 @@ int test10(int y, int z, bool use_y) {
115116
return i;
116117
}
117118
}
119+
120+
// Irreducible CFGs
121+
int test11(int y, int x) {
122+
int i = 0;
123+
if (x < y) {
124+
x = y;
125+
} else {
126+
goto inLoop;
127+
}
128+
for(i = 0; i < x; i++) {
129+
inLoop:
130+
sink(i);
131+
}
132+
}
133+
134+
// do-while
135+
int test12(int x) {
136+
int i = 0;
137+
do {
138+
i++;
139+
} while(i < x);
140+
return i;
141+
}
142+
143+
// do while false
144+
int test13(int x) {
145+
int i = 0;
146+
do {
147+
i++;
148+
} while(false);
149+
return i;
150+
}

0 commit comments

Comments
 (0)