Skip to content

Commit 2b720b3

Browse files
committed
C++: Fix join order in reachesWithoutAssignment
The negation in this predicate did not get pulled into an `#antijoin_rhs` predicate but got materialized as part of each iteration, which meant that the temporary `ControlFlowNode` column did not get projected away. The tuple counts looked like this on kamailio/kamailio (iteration 20): 5724 ~13% {3} r9 = JOIN r8 WITH BasicBlocks::Cached::bb_successor_cached#ff@staged_ext AS R ON FIRST 2 OUTPUT r8.<2>, r8.<3>, r8.<1> 5724 ~12% {3} r10 = JOIN r8 WITH BasicBlocks::Cached::bb_successor_cached#ff@staged_ext AS R ON FIRST 2 OUTPUT r8.<3>, r8.<2>, r8.<1> 124717061 ~11% {4} r11 = JOIN r10 WITH project#FlowVar::FlowVar_internal::assignmentLikeOperation#ffff_10#join_rhs AS R ON FIRST 1 OUTPUT R.<1>, r10.<2>, r10.<1>, r10.<0> 66 ~0% {3} r12 = JOIN r11 WITH project#BasicBlocks::Cached::basic_block_member AS R ON FIRST 2 OUTPUT r11.<2>, r11.<3>, r11.<1> 66 {3} r13 = MATERIALIZE r12 AS antijoin_rhs 5658 ~14% {3} r14 = r9 AND NOT r13(r9.<0>, r9.<1>, r9.<2>) After manually pulling out the join inside the negation, the time per iteration drops from ~30 to <1s. The pipeline above is replaced with 892394 ~0% {4} r6 = r5 AND NOT FlowVar::FlowVar_internal::assignsToVar#fb AS R(r5.<3>, r5.<2>) 892394 ~0% {4} r7 = SCAN r6 OUTPUT r6.<1>, r6.<3>, r6.<0>, r6.<2> 5658 ~11% {3} r8 = JOIN r7 WITH BasicBlocks::Cached::bb_successor_cached#ff@staged_ext AS R ON FIRST 2 OUTPUT r7.<2>, r7.<1>, r7.<3>
1 parent c9e22ab commit 2b720b3

File tree

1 file changed

+8
-2
lines changed
  • cpp/ql/src/semmle/code/cpp/dataflow/internal

1 file changed

+8
-2
lines changed

cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ module FlowVar_internal {
427427
/**
428428
* Gets a variable that is assigned in this loop and read outside the loop.
429429
*/
430-
private Variable getARelevantVariable() {
430+
Variable getARelevantVariable() {
431431
result = this.getAVariableAssignedInLoop() and
432432
exists(VariableAccess va |
433433
va.getTarget() = result and
@@ -472,10 +472,16 @@ module FlowVar_internal {
472472
reachesWithoutAssignment(bb.getAPredecessor(), v) and
473473
this.bbInLoop(bb)
474474
) and
475-
not assignmentLikeOperation(bb.getANode(), v, _, _)
475+
not assignsToVar(bb, v)
476476
}
477477
}
478478

479+
pragma[noinline]
480+
private predicate assignsToVar(BasicBlock bb, Variable v) {
481+
assignmentLikeOperation(bb.getANode(), v, _, _) and
482+
exists(AlwaysTrueUponEntryLoop loop | v = loop.getARelevantVariable())
483+
}
484+
479485
/**
480486
* Holds if `loop` always assigns to `v` before leaving through an edge
481487
* from `bbInside` in its condition to `bbOutside` outside the loop. Also,

0 commit comments

Comments
 (0)