C++: performance and termination fixes

This commit is contained in:
Robert Marsh 2018-12-14 14:59:25 -08:00
Родитель 567eee1114
Коммит 8c9c316e1b
6 изменённых файлов: 127 добавлений и 53 удалений

Просмотреть файл

@ -216,7 +216,7 @@ private predicate uniqueValueNumber(Instruction instr, FunctionIR funcIR) {
/** /**
* Gets the value number assigned to `instr`, if any. Returns at most one result. * Gets the value number assigned to `instr`, if any. Returns at most one result.
*/ */
ValueNumber valueNumber(Instruction instr) { cached ValueNumber valueNumber(Instruction instr) {
result = nonUniqueValueNumber(instr) or result = nonUniqueValueNumber(instr) or
exists(FunctionIR funcIR | exists(FunctionIR funcIR |
uniqueValueNumber(instr, funcIR) and uniqueValueNumber(instr, funcIR) and

Просмотреть файл

@ -10,7 +10,8 @@ private newtype TBound =
( (
i.getResultType() instanceof IntegralType or i.getResultType() instanceof IntegralType or
i.getResultType() instanceof PointerType i.getResultType() instanceof PointerType
) ) and
not vn.getAnInstruction() instanceof ConstantInstruction
| |
i instanceof PhiInstruction i instanceof PhiInstruction
or or

Просмотреть файл

@ -197,6 +197,7 @@ class CondReason extends Reason, TCondReason {
* Holds if a cast from `fromtyp` to `totyp` can be ignored for the purpose of * Holds if a cast from `fromtyp` to `totyp` can be ignored for the purpose of
* range analysis. * range analysis.
*/ */
pragma[inline]
private predicate safeCast(IntegralType fromtyp, IntegralType totyp) { private predicate safeCast(IntegralType fromtyp, IntegralType totyp) {
fromtyp.getSize() < totyp.getSize() and fromtyp.getSize() < totyp.getSize() and
( (
@ -256,7 +257,7 @@ private class NarrowingCastInstruction extends ConvertInstruction {
* - `upper = true` : `i <= op + delta` * - `upper = true` : `i <= op + delta`
* - `upper = false` : `i >= op + delta` * - `upper = false` : `i >= op + delta`
*/ */
private predicate boundFlowStep(Instruction i, Operand op, int delta, boolean upper) { private predicate boundFlowStep(Instruction i, NonPhiOperand op, int delta, boolean upper) {
valueFlowStep(i, op, delta) and valueFlowStep(i, op, delta) and
(upper = true or upper = false) (upper = true or upper = false)
or or
@ -425,12 +426,27 @@ private predicate boundedPhiOperand(
) )
} }
/** Holds if `v != e + delta` at `pos`. */
private predicate unequalFlowStep(
Operand op1, Operand op2, int delta, Reason reason
) {
exists(IRGuardCondition guard, boolean testIsTrue |
guard = eqFlowCond(valueNumberOfOperand(op1), op2, delta, false, testIsTrue) and
guard.controls(op1.getInstruction().getBlock(), testIsTrue) and
reason = TCondReason(guard)
)
}
/** /**
* Holds if `op != b + delta` at `pos`. * Holds if `op != b + delta` at `pos`.
*/ */
private predicate unequalOperand(Operand op, Bound b, int delta, Reason reason) { private predicate unequalOperand(Operand op, Bound b, int delta, Reason reason) {
// TODO: implement this exists(Operand op2, int d1, int d2 |
none() unequalFlowStep(op, op2, delta, reason) and
boundedNonPhiOperand(op2, b, d2, true, _, _, _) and
boundedNonPhiOperand(op2, b, d2, true, _, _, _) and
delta = d1 + d2
)
} }
private predicate boundedPhiCandValidForEdge( private predicate boundedPhiCandValidForEdge(
@ -544,50 +560,47 @@ private predicate boundedCastExpr(
private predicate boundedInstruction( private predicate boundedInstruction(
Instruction i, Bound b, int delta, boolean upper, boolean fromBackEdge, int origdelta, Reason reason Instruction i, Bound b, int delta, boolean upper, boolean fromBackEdge, int origdelta, Reason reason
) { ) {
i instanceof PhiInstruction and isReducibleCFG(i.getFunction()) and
forex(PhiOperand op | op = i.getAnOperand() | (
boundedPhiCandValidForEdge(i, b, delta, upper, fromBackEdge, origdelta, reason, op) i instanceof PhiInstruction and
) forex(PhiOperand op | op = i.getAnOperand() |
or boundedPhiCandValidForEdge(i, b, delta, upper, fromBackEdge, origdelta, reason, op)
i = b.getInstruction(delta) and )
(upper = true or upper = false) and or
fromBackEdge = false and i = b.getInstruction(delta) and
origdelta = delta and (upper = true or upper = false) and
reason = TNoReason() fromBackEdge = false and
or origdelta = delta and
exists(Operand mid, int d1, int d2 | reason = TNoReason()
boundFlowStep(i, mid, d1, upper) and or
boundedNonPhiOperand(mid, b, d2, upper, fromBackEdge, origdelta, reason) and exists(Operand mid, int d1, int d2 |
delta = d1 + d2 and boundFlowStep(i, mid, d1, upper) and
not exists(getValue(getConstantValue(i))) boundedNonPhiOperand(mid, b, d2, upper, fromBackEdge, origdelta, reason) and
) delta = d1 + d2 and
or not exists(getValue(getConstantValue(i)))
exists(Operand mid, int factor, int d | )
boundFlowStepMul(i, mid, factor) and or
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and exists(Operand mid, int factor, int d |
b instanceof ZeroBound and boundFlowStepMul(i, mid, factor) and
delta = d*factor and boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
not exists(getValue(getConstantValue(i))) b instanceof ZeroBound and
) delta = d*factor and
or not exists(getValue(getConstantValue(i)))
exists(Operand mid, int factor, int d | )
boundFlowStepDiv(i, mid, factor) and or
boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and exists(Operand mid, int factor, int d |
d >= 0 and boundFlowStepDiv(i, mid, factor) and
b instanceof ZeroBound and boundedNonPhiOperand(mid, b, d, upper, fromBackEdge, origdelta, reason) and
delta = d / factor and d >= 0 and
not exists(getValue(getConstantValue(i))) b instanceof ZeroBound and
) delta = d / factor and
or not exists(getValue(getConstantValue(i)))
exists(NarrowingCastInstruction cast | )
cast = i and or
safeNarrowingCast(cast, upper.booleanNot()) and exists(NarrowingCastInstruction cast |
boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason) cast = i and
safeNarrowingCast(cast, upper.booleanNot()) and
boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason)
)
) )
} }
predicate backEdge(PhiInstruction phi, PhiOperand op) {
phi.getAnOperand() = op and
phi.getBlock().dominates(op.getPredecessorBlock())
// TODO: identify backedges during IR construction
}

Просмотреть файл

@ -62,3 +62,25 @@ predicate valueFlowStep(Instruction i, Operand op, int delta) {
-getValue(getConstantValue(x.getDefinitionInstruction())) -getValue(getConstantValue(x.getDefinitionInstruction()))
) )
} }
predicate isReducibleCFG(Function f) {
not exists(LabelStmt l, GotoStmt goto |
goto.getTarget() = l and
l.getLocation().isBefore(goto.getLocation()) and
l.getEnclosingFunction() = f
) and
not exists(LabelStmt ls, Loop l |
ls.getParent*() = l and
l.getEnclosingFunction() = f
) and
not exists(SwitchCase cs |
cs.getSwitchStmt().getStmt() != cs.getParentStmt() and
cs.getEnclosingFunction() = f
)
}
predicate backEdge(PhiInstruction phi, PhiOperand op) {
phi.getAnOperand() = op and
phi.getBlock().dominates(op.getPredecessorBlock())
// TODO: identify backedges during IR construction
}

Просмотреть файл

@ -35,6 +35,11 @@
| 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 | | 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 |
| 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 | | 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 |
| 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 | | 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 |
| 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 | | 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 |
| 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 | | 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 |
| 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 | | 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |

Просмотреть файл

@ -103,6 +103,7 @@ void test9(int x) {
} }
} }
// Phi nodes as bounds
int test10(int y, int z, bool use_y) { int test10(int y, int z, bool use_y) {
int x; int x;
if(use_y) { if(use_y) {
@ -115,3 +116,35 @@ int test10(int y, int z, bool use_y) {
return i; return i;
} }
} }
// Irreducible CFGs
int test11(int y, int x) {
int i = 0;
if (x < y) {
x = y;
} else {
goto inLoop;
}
for(i = 0; i < x; i++) {
inLoop:
sink(i);
}
}
// do-while
int test12(int x) {
int i = 0;
do {
i++;
} while(i < x);
return i;
}
// do while false
int test13(int x) {
int i = 0;
do {
i++;
} while(false);
return i;
}