Skip to content

Commit 6b2fd17

Browse files
committed
C++: IR: faster definitionReachesRank
On Wireshark with 6GB RAM, I've observed `definitionReachesRank` to be the slowest predicate in the IR. It seems that the implementation was slow because the optimizer failed to eliminate the common `reachesRank - 1` subexpression. This led to context being pushed into the `not`, which got implemented as `MATERIALIZE`. That wouldn't normally be a disaster, but this is one of the largest predicates in the IR SSA construction, and iteration 2 was very slow. Before: (1505s) Starting to evaluate predicate SSAConstruction::DefUse::definitionReachesRank#ffff#cur_delta/4[1]@93f592 (iteration 1) (1535s) Tuple counts for SSAConstruction::DefUse::definitionReachesRank#ffff#cur_delta: 130670697 ~0% {4} r1 = SCAN project#SSAConstruction::DefUse::hasDefinitionAtRank#fffff AS I OUTPUT I.<0>, I.<1>, I.<2>, (I.<2> + 1) 130670697 ~6% {5} r2 = JOIN r1 WITH SSAConstruction::DefUse::exitRank#fff AS R ON FIRST 2 OUTPUT r1.<0>, r1.<1>, r1.<2>, r1.<3>, R.<2> 130670697 ~6% {5} r3 = SELECT r2 ON r2.<3> <= r2.<4> 130670697 ~0% {4} r4 = SCAN r3 OUTPUT r3.<0>, r3.<1>, r3.<2>, r3.<3> return r4 (1535s) - SSAConstruction::DefUse::definitionReachesRank#ffff_delta has 130670697 rows (order for disjuncts: delta=<standard>). (1535s) Starting to evaluate predicate SSAConstruction::DefUse::definitionReachesRank#ffff#cur_delta/4[2]@866c14 (iteration 2) (1626s) Tuple counts for SSAConstruction::DefUse::definitionReachesRank#ffff#cur_delta: 261341394 ~107% {4} r1 = JOIN SSAConstruction::DefUse::definitionReachesRank#ffff#prev_delta AS L WITH SSAConstruction::DefUse::definitionReachesRank#ffff#join_rhs AS R ON FIRST 3 OUTPUT R.<0>, R.<1>, R.<2>, (1 + L.<3>) 261341394 ~107% {4} r2 = r1 AND NOT SSAConstruction::DefUse::definitionReachesRank#ffff#prev AS R(r1.<0>, r1.<1>, r1.<2>, r1.<3>) 130670697 ~0% {5} r3 = SCAN r2 OUTPUT r2.<0>, r2.<1>, (r2.<3> - 1), r2.<2>, r2.<3> 106034590 ~1% {4} r4 = JOIN r3 WITH project#SSAConstruction::DefUse::hasDefinitionAtRank#fffff AS R ON FIRST 3 OUTPUT r3.<0>, r3.<1>, r3.<3>, r3.<4> 106034590 {4} r5 = MATERIALIZE r4 AS antijoin_rhs 24636107 ~3% {4} r6 = r2 AND NOT r5(r2.<0>, r2.<1>, r2.<2>, r2.<3>) 24636107 ~0% {5} r7 = JOIN r6 WITH SSAConstruction::DefUse::exitRank#fff AS R ON FIRST 2 OUTPUT r6.<0>, r6.<1>, r6.<2>, r6.<3>, R.<2> 2749441 ~0% {5} r8 = SELECT r7 ON r7.<3> <= r7.<4> 2749441 ~4% {4} r9 = SCAN r8 OUTPUT r8.<0>, r8.<1>, r8.<2>, r8.<3> return r9 (1626s) - SSAConstruction::DefUse::definitionReachesRank#ffff_delta has 2749441 rows (order for disjuncts: delta=<standard>). After: (12s) Tuple counts for SSAConstruction::DefUse::definitionReachesRank#ffff#cur_delta: 130670697 ~0% {4} r1 = SCAN project#SSAConstruction::DefUse::hasDefinitionAtRank#fffff AS I OUTPUT I.<0>, I.<1>, I.<2>, (I.<2> + 1) return r1 (12s) - SSAConstruction::DefUse::definitionReachesRank#ffff_delta has 130670697 rows (order for disjuncts: delta=<standard>). (12s) Starting to evaluate predicate SSAConstruction::DefUse::definitionReachesRank#ffff#cur_delta/4[2]@fff64c (iteration 2) (34s) Tuple counts for SSAConstruction::DefUse::definitionReachesRank#ffff#cur_delta: 108784031 ~0% {4} r1 = SSAConstruction::DefUse::definitionReachesRank#ffff#prev_delta AS L AND NOT SSAConstruction::DefUse::exitRank#fff AS R(L.<0>, L.<1>, L.<3>) 2749441 ~5% {4} r2 = r1 AND NOT project#SSAConstruction::DefUse::hasDefinitionAtRank#fffff AS R(r1.<0>, r1.<1>, r1.<3>) 2749441 ~4% {4} r3 = SCAN r2 OUTPUT r2.<0>, r2.<1>, r2.<2>, (r2.<3> + 1) 2749441 ~4% {4} r4 = r3 AND NOT SSAConstruction::DefUse::definitionReachesRank#ffff#prev AS R(r3.<0>, r3.<1>, r3.<2>, r3.<3>) return r4 (34s) - SSAConstruction::DefUse::definitionReachesRank#ffff_delta has 2749441 rows (order for disjuncts: delta=<standard>). Note that the row counts are exactly the same before and after.
1 parent 88c74b2 commit 6b2fd17

File tree

3 files changed

+33
-30
lines changed

3 files changed

+33
-30
lines changed

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -665,17 +665,18 @@ module DefUse {
665665
private predicate definitionReachesRank(
666666
Alias::MemoryLocation useLocation, OldBlock block, int defRank, int reachesRank
667667
) {
668+
// The def always reaches the next use, even if there is also a def on the
669+
// use instruction.
668670
hasDefinitionAtRank(useLocation, _, block, defRank, _) and
669-
reachesRank <= exitRank(useLocation, block) and // Without this, the predicate would be infinite.
670-
(
671-
// The def always reaches the next use, even if there is also a def on the
672-
// use instruction.
673-
reachesRank = defRank + 1
674-
or
675-
// If the def reached the previous rank, it also reaches the current rank,
676-
// unless there was another def at the previous rank.
677-
definitionReachesRank(useLocation, block, defRank, reachesRank - 1) and
678-
not hasDefinitionAtRank(useLocation, _, block, reachesRank - 1, _)
671+
reachesRank = defRank + 1
672+
or
673+
// If the def reached the previous rank, it also reaches the current rank,
674+
// unless there was another def at the previous rank.
675+
exists(int prevRank |
676+
reachesRank = prevRank + 1 and
677+
definitionReachesRank(useLocation, block, defRank, prevRank) and
678+
not prevRank = exitRank(useLocation, block) and
679+
not hasDefinitionAtRank(useLocation, _, block, prevRank, _)
679680
)
680681
}
681682

cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -665,17 +665,18 @@ module DefUse {
665665
private predicate definitionReachesRank(
666666
Alias::MemoryLocation useLocation, OldBlock block, int defRank, int reachesRank
667667
) {
668+
// The def always reaches the next use, even if there is also a def on the
669+
// use instruction.
668670
hasDefinitionAtRank(useLocation, _, block, defRank, _) and
669-
reachesRank <= exitRank(useLocation, block) and // Without this, the predicate would be infinite.
670-
(
671-
// The def always reaches the next use, even if there is also a def on the
672-
// use instruction.
673-
reachesRank = defRank + 1
674-
or
675-
// If the def reached the previous rank, it also reaches the current rank,
676-
// unless there was another def at the previous rank.
677-
definitionReachesRank(useLocation, block, defRank, reachesRank - 1) and
678-
not hasDefinitionAtRank(useLocation, _, block, reachesRank - 1, _)
671+
reachesRank = defRank + 1
672+
or
673+
// If the def reached the previous rank, it also reaches the current rank,
674+
// unless there was another def at the previous rank.
675+
exists(int prevRank |
676+
reachesRank = prevRank + 1 and
677+
definitionReachesRank(useLocation, block, defRank, prevRank) and
678+
not prevRank = exitRank(useLocation, block) and
679+
not hasDefinitionAtRank(useLocation, _, block, prevRank, _)
679680
)
680681
}
681682

csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -665,17 +665,18 @@ module DefUse {
665665
private predicate definitionReachesRank(
666666
Alias::MemoryLocation useLocation, OldBlock block, int defRank, int reachesRank
667667
) {
668+
// The def always reaches the next use, even if there is also a def on the
669+
// use instruction.
668670
hasDefinitionAtRank(useLocation, _, block, defRank, _) and
669-
reachesRank <= exitRank(useLocation, block) and // Without this, the predicate would be infinite.
670-
(
671-
// The def always reaches the next use, even if there is also a def on the
672-
// use instruction.
673-
reachesRank = defRank + 1
674-
or
675-
// If the def reached the previous rank, it also reaches the current rank,
676-
// unless there was another def at the previous rank.
677-
definitionReachesRank(useLocation, block, defRank, reachesRank - 1) and
678-
not hasDefinitionAtRank(useLocation, _, block, reachesRank - 1, _)
671+
reachesRank = defRank + 1
672+
or
673+
// If the def reached the previous rank, it also reaches the current rank,
674+
// unless there was another def at the previous rank.
675+
exists(int prevRank |
676+
reachesRank = prevRank + 1 and
677+
definitionReachesRank(useLocation, block, defRank, prevRank) and
678+
not prevRank = exitRank(useLocation, block) and
679+
not hasDefinitionAtRank(useLocation, _, block, prevRank, _)
679680
)
680681
}
681682

0 commit comments

Comments
 (0)