Merge pull request #879 from rdmarsh2/rdmarsh/cpp/ir-guards-edges

C++: Add edge-based predicates to IRGuards
This commit is contained in:
Jonas Jensen
2019-02-19 16:54:52 +01:00
committed by GitHub
3 changed files with 36 additions and 15 deletions

View File

@@ -239,9 +239,10 @@ private class GuardConditionFromIR extends GuardCondition {
* IRGuardConditions. * IRGuardConditions.
*/ */
class IRGuardCondition extends Instruction { class IRGuardCondition extends Instruction {
ConditionalBranchInstruction branch;
IRGuardCondition() { IRGuardCondition() {
is_condition(this) branch = get_branch_for_condition(this)
} }
/** /**
@@ -280,6 +281,16 @@ class IRGuardCondition extends Instruction {
ne.controls(controlled, testIsTrue.booleanNot())) ne.controls(controlled, testIsTrue.booleanNot()))
} }
predicate controlsEdge(IRBlock pred, IRBlock succ, boolean testIsTrue) {
pred.getASuccessor() = succ and
controls(pred, testIsTrue)
or
hasBranchEdge(succ, testIsTrue) and
branch.getCondition() = this and
branch.getBlock() = pred
}
/** /**
* Holds if `branch` jumps directly to `succ` when this condition is `testIsTrue`. * Holds if `branch` jumps directly to `succ` when this condition is `testIsTrue`.
* *
@@ -295,7 +306,7 @@ class IRGuardCondition extends Instruction {
* return x; * return x;
* ``` * ```
*/ */
predicate hasBranchEdge(ConditionalBranchInstruction branch, IRBlock succ, boolean testIsTrue) { private predicate hasBranchEdge(IRBlock succ, boolean testIsTrue) {
branch.getCondition() = this and branch.getCondition() = this and
( (
testIsTrue = true and testIsTrue = true and
@@ -319,6 +330,14 @@ class IRGuardCondition extends Instruction {
) )
} }
/** Holds if (determined by this guard) `left < right + k` must be `isLessThan` on the edge from
* `pred` to `succ`. If `isLessThan = false` then this implies `left >= right + k`. */
cached predicate ensuresLtEdge(Operand left, Operand right, int k, IRBlock pred, IRBlock succ, boolean isLessThan) {
exists(boolean testIsTrue |
compares_lt(this, left, right, k, isLessThan, testIsTrue) and this.controlsEdge(pred, succ, testIsTrue)
)
}
/** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */ /** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */
cached predicate comparesEq(Operand left, Operand right, int k, boolean areEqual, boolean testIsTrue) { cached predicate comparesEq(Operand left, Operand right, int k, boolean areEqual, boolean testIsTrue) {
compares_eq(this, left, right, k, areEqual, testIsTrue) compares_eq(this, left, right, k, areEqual, testIsTrue)
@@ -331,6 +350,13 @@ class IRGuardCondition extends Instruction {
compares_eq(this, left, right, k, areEqual, testIsTrue) and this.controls(block, testIsTrue) compares_eq(this, left, right, k, areEqual, testIsTrue) and this.controls(block, testIsTrue)
) )
} }
/** Holds if (determined by this guard) `left == right + k` must be `areEqual` on the edge from
* `pred` to `succ`. If `areEqual = false` then this implies `left != right + k`. */
cached predicate ensuresEqEdge(Operand left, Operand right, int k, IRBlock pred, IRBlock succ, boolean areEqual) {
exists(boolean testIsTrue |
compares_eq(this, left, right, k, areEqual, testIsTrue) and this.controlsEdge(pred, succ, testIsTrue)
)
}
/** /**
* Holds if this condition controls `block`, meaning that `block` is only * Holds if this condition controls `block`, meaning that `block` is only
@@ -340,9 +366,9 @@ class IRGuardCondition extends Instruction {
*/ */
private predicate controlsBlock(IRBlock controlled, boolean testIsTrue) { private predicate controlsBlock(IRBlock controlled, boolean testIsTrue) {
not isUnreachedBlock(controlled) and not isUnreachedBlock(controlled) and
exists(IRBlock thisblock exists(IRBlock branchBlock
| thisblock.getAnInstruction() = this | branchBlock.getAnInstruction() = branch
| exists(IRBlock succ, ConditionalBranchInstruction branch | exists(IRBlock succ
| testIsTrue = true and succ.getFirstInstruction() = branch.getTrueSuccessor() | testIsTrue = true and succ.getFirstInstruction() = branch.getTrueSuccessor()
or or
testIsTrue = false and succ.getFirstInstruction() = branch.getFalseSuccessor() testIsTrue = false and succ.getFirstInstruction() = branch.getFalseSuccessor()
@@ -350,16 +376,16 @@ class IRGuardCondition extends Instruction {
succ.dominates(controlled) and succ.dominates(controlled) and
forall(IRBlock pred forall(IRBlock pred
| pred.getASuccessor() = succ | pred.getASuccessor() = succ
| pred = thisblock or succ.dominates(pred) or not pred.isReachableFromFunctionEntry()))) | pred = branchBlock or succ.dominates(pred) or not pred.isReachableFromFunctionEntry())))
} }
} }
private predicate is_condition(Instruction guard) { private ConditionalBranchInstruction get_branch_for_condition(Instruction guard) {
exists(ConditionalBranchInstruction branch| exists(ConditionalBranchInstruction branch|
branch.getCondition() = guard branch.getCondition() = guard
) )
or or
exists(LogicalNotInstruction cond | is_condition(cond) and cond.getUnary() = guard) exists(LogicalNotInstruction cond | result = get_branch_for_condition(cond) and cond.getUnary() = guard)
} }
/** /**

View File

@@ -386,11 +386,7 @@ private predicate boundFlowStepPhi(
or or
exists(IRGuardCondition guard, boolean testIsTrue | exists(IRGuardCondition guard, boolean testIsTrue |
guard = boundFlowCond(valueNumberOfOperand(op2), op1, delta, upper, testIsTrue) and guard = boundFlowCond(valueNumberOfOperand(op2), op1, delta, upper, testIsTrue) and
( guard.controlsEdge(op2.getPredecessorBlock(), op2.getUseInstruction().getBlock(), testIsTrue) and
guard.hasBranchEdge(op2.getPredecessorBlock().getLastInstruction(), op2.getUseInstruction().getBlock(), testIsTrue)
or
guard.controls(op2.getPredecessorBlock(), testIsTrue)
) and
reason = TCondReason(guard) reason = TCondReason(guard)
) )
} }

View File

@@ -151,4 +151,3 @@ void test5(int x) {
void test6(int x, int y) { void test6(int x, int y) {
return x && y; return x && y;
} }