Skip to content

Commit 1c971d3

Browse files
committed
HashCons: Further performance improvements
The key insight here is that `HC_FieldCons` and `HC_Array` are functionally determined by the things that arise in another recursive call. Lifting them to their own predicate, therefore, reduces nonlinearity and constrains the join order in a way that cannot be asymptotically bad -- and, indeed, makes quite a big difference in practice.
1 parent eca3190 commit 1c971d3

File tree

1 file changed

+27
-18
lines changed

1 file changed

+27
-18
lines changed

cpp/ql/src/semmle/code/cpp/valuenumbering/HashCons.qll

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,18 @@ private predicate mk_AlignofExpr(HashCons child, AlignofExprOperator e) {
729729
child = hashCons(e.getAChild())
730730
}
731731

732+
/**
733+
* Gets the hash cons of field initializer expressions [0..i), where i > 0, for
734+
* the class aggregate literal `cal` of type `c`, where `head` is the hash cons
735+
* of the i'th initializer expression.
736+
*/
737+
HC_Fields aggInitExprsUpTo(ClassAggregateLiteral cal, Class c, int i) {
738+
exists(Field f, HashCons head, HC_Fields tail |
739+
result = HC_FieldCons(c, i - 1, f, head, tail) and
740+
mk_FieldCons(c, i - 1, f, head, tail, cal)
741+
)
742+
}
743+
732744
private predicate mk_FieldCons(
733745
Class c, int i, Field f, HashCons hc, HC_Fields hcf, ClassAggregateLiteral cal
734746
) {
@@ -738,12 +750,8 @@ private predicate mk_FieldCons(
738750
e = cal.getFieldExpr(f).getFullyConverted() and
739751
f.getInitializationOrder() = i and
740752
(
741-
exists(HashCons head, Field f2, HC_Fields tail |
742-
hc = hashCons(e) and
743-
hcf = HC_FieldCons(c, i - 1, f2, head, tail) and
744-
f2.getInitializationOrder() = i - 1 and
745-
mk_FieldCons(c, i - 1, f2, head, tail, cal)
746-
)
753+
hc = hashCons(e) and
754+
hcf = aggInitExprsUpTo(cal, c, i)
747755
or
748756
hc = hashCons(e) and
749757
i = 0 and
@@ -766,14 +774,7 @@ private predicate mk_ClassAggregateLiteral(Class c, HC_Fields hcf, ClassAggregat
766774
analyzableClassAggregateLiteral(cal) and
767775
c = cal.getUnspecifiedType() and
768776
(
769-
exists(HC_Fields tail, Expr e, Field f, int numChildren, HashCons eCons |
770-
f.getInitializationOrder() = cal.getNumChild() - 1 and
771-
e = cal.getFieldExpr(f).getFullyConverted() and
772-
eCons = hashCons(e) and
773-
numChildren = cal.getNumChild() and
774-
hcf = HC_FieldCons(c, numChildren - 1, f, eCons, tail) and
775-
mk_FieldCons(c, numChildren - 1, f, eCons, tail, cal)
776-
)
777+
hcf = aggInitExprsUpTo(cal, c, cal.getNumChild())
777778
or
778779
cal.getNumChild() = 0 and
779780
hcf = HC_EmptyFields(c)
@@ -785,15 +786,23 @@ private predicate analyzableArrayAggregateLiteral(ArrayAggregateLiteral aal) {
785786
strictcount(aal.getUnspecifiedType()) = 1
786787
}
787788

789+
/**
790+
* Gets the hash cons of array elements in [0..i), where i > 0, for
791+
* the array aggregate literal `aal` of type `t`.
792+
*/
793+
private HC_Array arrayElemsUpTo(ArrayAggregateLiteral aal, Type t, int i) {
794+
exists(HC_Array tail, HashCons head |
795+
result = HC_ArrayCons(t, i - 1, head, tail) and
796+
mk_ArrayCons(t, i - 1, head, tail, aal)
797+
)
798+
}
799+
788800
private predicate mk_ArrayCons(Type t, int i, HashCons hc, HC_Array hca, ArrayAggregateLiteral aal) {
789801
analyzableArrayAggregateLiteral(aal) and
790802
t = aal.getUnspecifiedType() and
791803
hc = hashCons(aal.getChild(i)) and
792804
(
793-
exists(HC_Array tail, HashCons head |
794-
hca = HC_ArrayCons(t, i - 1, head, tail) and
795-
mk_ArrayCons(t, i - 1, head, tail, aal)
796-
)
805+
hca = arrayElemsUpTo(aal, t, i)
797806
or
798807
i = 0 and
799808
hca = HC_EmptyArray(t)

0 commit comments

Comments
 (0)