Skip to content

Commit efb6f47

Browse files
authored
Merge pull request #891 from github/michaelrfairhurst/compatible-types-performance-fix-alt
Michaelrfairhurst/compatible types performance fix alt
2 parents 0edeb8f + 7e0ff96 commit efb6f47

9 files changed

+346
-115
lines changed

c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql

+10-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ import codingstandards.c.cert
1919
import codingstandards.cpp.types.Compatible
2020
import ExternalIdentifiers
2121

22+
predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) {
23+
not f1 = f2 and
24+
f1.getDeclaration() = f2.getDeclaration() and
25+
f1.getName() = f2.getName()
26+
}
27+
2228
from ExternalIdentifiers d, FunctionDeclarationEntry f1, FunctionDeclarationEntry f2
2329
where
2430
not isExcluded(f1, Declarations2Package::incompatibleFunctionDeclarationsQuery()) and
@@ -29,10 +35,12 @@ where
2935
f1.getName() = f2.getName() and
3036
(
3137
//return type check
32-
not FunctionDeclarationTypeEquivalence<TypesCompatibleConfig>::equalReturnTypes(f1, f2)
38+
not FunctionDeclarationTypeEquivalence<TypesCompatibleConfig, interestedInFunctions/2>::equalReturnTypes(f1,
39+
f2)
3340
or
3441
//parameter type check
35-
not FunctionDeclarationTypeEquivalence<TypesCompatibleConfig>::equalParameterTypes(f1, f2)
42+
not FunctionDeclarationTypeEquivalence<TypesCompatibleConfig, interestedInFunctions/2>::equalParameterTypes(f1,
43+
f2)
3644
) and
3745
// Apply ordering on start line, trying to avoid the optimiser applying this join too early
3846
// in the pipeline

c/misra/src/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.ql

+8-12
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,14 @@ import codingstandards.cpp.types.LvalueConversion
2020
import codingstandards.cpp.types.SimpleAssignment
2121

2222
predicate typesCompatible(Type t1, Type t2) {
23-
TypeEquivalence<TypesCompatibleConfig, TypeFromGeneric>::equalTypes(t1, t2)
23+
TypeEquivalence<TypesCompatibleConfig, relevantTypes/2>::equalTypes(t1, t2)
2424
}
2525

26-
class TypeFromGeneric extends Type {
27-
TypeFromGeneric() {
28-
exists(C11GenericExpr g |
29-
(
30-
this = g.getAssociationType(_) or
31-
this = g.getControllingExpr().getFullyConverted().getType()
32-
)
33-
)
34-
}
26+
predicate relevantTypes(Type a, Type b) {
27+
exists(C11GenericExpr g |
28+
a = g.getAnAssociationType() and
29+
b = getLvalueConverted(g.getControllingExpr().getFullyConverted().getType())
30+
)
3531
}
3632

3733
predicate missesOnPointerConversion(Type provided, Type expected) {
@@ -40,11 +36,11 @@ predicate missesOnPointerConversion(Type provided, Type expected) {
4036
// But 6.5.16.1 simple assignment constraints would have been satisfied:
4137
(
4238
// Check as if the controlling expr is assigned to the expected type:
43-
SimpleAssignment<TypeFromGeneric>::satisfiesSimplePointerAssignment(expected, provided)
39+
SimpleAssignment<relevantTypes/2>::satisfiesSimplePointerAssignment(expected, provided)
4440
or
4541
// Since developers typically rely on the compiler to catch const/non-const assignment
4642
// errors, don't assume a const-to-non-const generic selection miss was intentional.
47-
SimpleAssignment<TypeFromGeneric>::satisfiesSimplePointerAssignment(provided, expected)
43+
SimpleAssignment<relevantTypes/2>::satisfiesSimplePointerAssignment(provided, expected)
4844
)
4945
}
5046

c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql

+9-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ import cpp
1616
import codingstandards.c.misra
1717
import codingstandards.cpp.types.Compatible
1818

19+
predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) {
20+
not f1 = f2 and
21+
f1.getDeclaration() = f2.getDeclaration()
22+
}
23+
1924
from FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, string case, string pluralDo
2025
where
2126
not isExcluded(f1, Declarations4Package::declarationsOfAFunctionSameNameAndTypeQuery()) and
@@ -24,12 +29,14 @@ where
2429
f1.getDeclaration() = f2.getDeclaration() and
2530
//return type check
2631
(
27-
not FunctionDeclarationTypeEquivalence<TypeNamesMatchConfig>::equalReturnTypes(f1, f2) and
32+
not FunctionDeclarationTypeEquivalence<TypeNamesMatchConfig, interestedInFunctions/2>::equalReturnTypes(f1,
33+
f2) and
2834
case = "return type" and
2935
pluralDo = "does"
3036
or
3137
//parameter type check
32-
not FunctionDeclarationTypeEquivalence<TypeNamesMatchConfig>::equalParameterTypes(f1, f2) and
38+
not FunctionDeclarationTypeEquivalence<TypeNamesMatchConfig, interestedInFunctions/2>::equalParameterTypes(f1,
39+
f2) and
3340
case = "parameter types" and
3441
pluralDo = "do"
3542
or

c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql

+9-10
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,6 @@ import cpp
1616
import codingstandards.c.misra
1717
import codingstandards.cpp.types.Compatible
1818

19-
class RelevantType extends Type {
20-
RelevantType() {
21-
exists(VariableDeclarationEntry decl |
22-
(relevantPair(decl, _) or relevantPair(_, decl)) and
23-
decl.getType() = this
24-
)
25-
}
26-
}
27-
2819
predicate relevantPair(VariableDeclarationEntry decl1, VariableDeclarationEntry decl2) {
2920
not decl1 = decl2 and
3021
not decl1.getVariable().getDeclaringType().isAnonymous() and
@@ -43,12 +34,20 @@ predicate relevantPair(VariableDeclarationEntry decl1, VariableDeclarationEntry
4334
)
4435
}
4536

37+
predicate relevantTypes(Type a, Type b) {
38+
exists(VariableDeclarationEntry varA, VariableDeclarationEntry varB |
39+
a = varA.getType() and
40+
b = varB.getType() and
41+
relevantPair(varA, varB)
42+
)
43+
}
44+
4645
from VariableDeclarationEntry decl1, VariableDeclarationEntry decl2
4746
where
4847
not isExcluded(decl1, Declarations4Package::declarationsOfAnObjectSameNameAndTypeQuery()) and
4948
not isExcluded(decl2, Declarations4Package::declarationsOfAnObjectSameNameAndTypeQuery()) and
5049
relevantPair(decl1, decl2) and
51-
not TypeEquivalence<TypeNamesMatchConfig, RelevantType>::equalTypes(decl1.getType(),
50+
not TypeEquivalence<TypeNamesMatchConfig, relevantTypes/2>::equalTypes(decl1.getType(),
5251
decl2.getType())
5352
select decl1,
5453
"The object $@ of type " + decl1.getType().toString() +

c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql

+15-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,17 @@ import codingstandards.c.misra
1919
import codingstandards.cpp.Identifiers
2020
import codingstandards.cpp.types.Compatible
2121

22+
predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) {
23+
f1.getDeclaration() instanceof ExternalIdentifiers and
24+
f1.isDefinition() and
25+
f1.getDeclaration() = f2.getDeclaration() and
26+
// This condition should always hold, but removing it affects join order performance.
27+
f1.getName() = f2.getName() and
28+
not f2.isDefinition() and
29+
not f1.isFromTemplateInstantiation(_) and
30+
not f2.isFromTemplateInstantiation(_)
31+
}
32+
2233
from FunctionDeclarationEntry f1
2334
where
2435
not isExcluded(f1, Declarations4Package::compatibleDeclarationFunctionDefinedQuery()) and
@@ -38,10 +49,12 @@ where
3849
f2.getDeclaration() = f1.getDeclaration() and
3950
(
4051
//return types differ
41-
not FunctionDeclarationTypeEquivalence<TypesCompatibleConfig>::equalReturnTypes(f1, f2)
52+
not FunctionDeclarationTypeEquivalence<TypesCompatibleConfig, interestedInFunctions/2>::equalReturnTypes(f1,
53+
f2)
4254
or
4355
//parameter types differ
44-
not FunctionDeclarationTypeEquivalence<TypesCompatibleConfig>::equalParameterTypes(f1, f2)
56+
not FunctionDeclarationTypeEquivalence<TypesCompatibleConfig, interestedInFunctions/2>::equalParameterTypes(f1,
57+
f2)
4558
or
4659
//parameter names differ
4760
parameterNamesUnmatched(f1, f2)

c/misra/src/rules/RULE-8-4/CompatibleDeclarationObjectDefined.ql

+8-8
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ import codingstandards.c.misra
1919
import codingstandards.cpp.Identifiers
2020
import codingstandards.cpp.types.Compatible
2121

22-
class RelevantType extends Type {
23-
RelevantType() {
24-
exists(VariableDeclarationEntry decl |
25-
count(VariableDeclarationEntry others | others.getDeclaration() = decl.getDeclaration()) > 1 and
26-
decl.getType() = this
27-
)
28-
}
22+
predicate relevantTypes(Type a, Type b) {
23+
exists(VariableDeclarationEntry varA, VariableDeclarationEntry varB |
24+
not varA = varB and
25+
varA.getDeclaration() = varB.getDeclaration() and
26+
a = varA.getType() and
27+
b = varB.getType()
28+
)
2929
}
3030

3131
from VariableDeclarationEntry decl1
@@ -37,7 +37,7 @@ where
3737
not exists(VariableDeclarationEntry decl2 |
3838
not decl2.isDefinition() and
3939
decl1.getDeclaration() = decl2.getDeclaration() and
40-
TypeEquivalence<TypesCompatibleConfig, RelevantType>::equalTypes(decl1.getType(),
40+
TypeEquivalence<TypesCompatibleConfig, relevantTypes/2>::equalTypes(decl1.getType(),
4141
decl2.getType())
4242
)
4343
select decl1, "No separate compatible declaration found for this definition."
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
- `RULE-8-3`, `RULE-8-4`, `DCL40-C`, `RULE-23-5`: `DeclarationsOfAFunctionSameNameAndType.ql`, `DeclarationsOfAnObjectSameNameAndType.ql`, `CompatibleDeclarationOfFunctionDefined.ql`, `CompatibleDeclarationObjectDefined.ql`, `IncompatibleFunctionDeclarations.ql`, `DangerousDefaultSelectionForPointerInGeneric.ql`:
2+
- Added pragmas to alter join order on function parameter equivalence (names and types).
3+
- Refactored expression which the optimizer was confused by, and compiled into a cartesian product.
4+
- Altered the module `Compatible.qll` to compute equality in two stages. Firstly, all pairs of possible type comparisons (including recursive comparisons) are found, then those pairwise comparisons are evaluated in a second stage. This greatly reduces the number of comparisons and greatly improves performance.
5+
- `RULE-23-5`: `DangerousDefaultSelectionForPointerInGeneric.ql`:
6+
- Altered the module `SimpleAssignment.qll` in accordance with the changes to `Compatible.qll`.

0 commit comments

Comments
 (0)