Skip to content

Commit dffde8f

Browse files
authored
Merge pull request github#12532 from MathiasVP/local-flow-for-getAdditionalFlowIntoCallNodeTerm
C++: Use local flow instead of GVN in `getAdditionalFlowIntoCallNodeTerm`
2 parents 11932a5 + 08419b7 commit dffde8f

File tree

1 file changed

+93
-37
lines changed

1 file changed

+93
-37
lines changed

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

Lines changed: 93 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,58 @@ private import DataFlowDispatch
55
private import DataFlowImplConsistency
66
private import semmle.code.cpp.ir.internal.IRCppLanguage
77
private import SsaInternals as Ssa
8-
private import DataFlowImplCommon
9-
private import semmle.code.cpp.ir.ValueNumbering
8+
private import DataFlowImplCommon as DataFlowImplCommon
109

1110
cached
1211
private module Cached {
1312
cached
14-
newtype TIRDataFlowNode0 =
15-
TInstructionNode0(Instruction i) {
16-
not Ssa::ignoreInstruction(i) and
17-
not exists(Operand op |
18-
not Ssa::ignoreOperand(op) and i = Ssa::getIRRepresentationOfOperand(op)
19-
) and
20-
// We exclude `void`-typed instructions because they cannot contain data.
21-
// However, if the instruction is a glvalue, and their type is `void`, then the result
22-
// type of the instruction is really `void*`, and thus we still want to have a dataflow
23-
// node for it.
24-
(not i.getResultType() instanceof VoidType or i.isGLValue())
25-
} or
26-
TMultipleUseOperandNode0(Operand op) {
27-
not Ssa::ignoreOperand(op) and not exists(Ssa::getIRRepresentationOfOperand(op))
28-
} or
29-
TSingleUseOperandNode0(Operand op) {
30-
not Ssa::ignoreOperand(op) and exists(Ssa::getIRRepresentationOfOperand(op))
31-
}
32-
}
33-
34-
private import Cached
13+
module Nodes0 {
14+
cached
15+
newtype TIRDataFlowNode0 =
16+
TInstructionNode0(Instruction i) {
17+
not Ssa::ignoreInstruction(i) and
18+
not exists(Operand op |
19+
not Ssa::ignoreOperand(op) and i = Ssa::getIRRepresentationOfOperand(op)
20+
) and
21+
// We exclude `void`-typed instructions because they cannot contain data.
22+
// However, if the instruction is a glvalue, and their type is `void`, then the result
23+
// type of the instruction is really `void*`, and thus we still want to have a dataflow
24+
// node for it.
25+
(not i.getResultType() instanceof VoidType or i.isGLValue())
26+
} or
27+
TMultipleUseOperandNode0(Operand op) {
28+
not Ssa::ignoreOperand(op) and not exists(Ssa::getIRRepresentationOfOperand(op))
29+
} or
30+
TSingleUseOperandNode0(Operand op) {
31+
not Ssa::ignoreOperand(op) and exists(Ssa::getIRRepresentationOfOperand(op))
32+
}
33+
}
34+
35+
/**
36+
* Gets an additional term that is added to the `join` and `branch` computations to reflect
37+
* an additional forward or backwards branching factor that is not taken into account
38+
* when calculating the (virtual) dispatch cost.
39+
*
40+
* Argument `arg` is part of a path from a source to a sink, and `p` is the target parameter.
41+
*/
42+
pragma[nomagic]
43+
cached
44+
int getAdditionalFlowIntoCallNodeTerm(ArgumentNode arg, ParameterNode p) {
45+
DataFlowImplCommon::forceCachingInSameStage() and
46+
exists(
47+
ParameterNode switchee, SwitchInstruction switch, ConditionOperand op, DataFlowCall call
48+
|
49+
DataFlowImplCommon::viableParamArg(call, p, arg) and
50+
DataFlowImplCommon::viableParamArg(call, switchee, _) and
51+
switch.getExpressionOperand() = op and
52+
getAdditionalFlowIntoCallNodeTermStep+(switchee, operandNode(op)) and
53+
result = countNumberOfBranchesUsingParameter(switch, p)
54+
)
55+
}
56+
}
57+
58+
import Cached
59+
private import Nodes0
3560

3661
class Node0Impl extends TIRDataFlowNode0 {
3762
/**
@@ -898,23 +923,54 @@ IRBlock getBasicBlock(Node node) {
898923
}
899924

900925
/**
901-
* Gets an additional term that is added to the `join` and `branch` computations to reflect
902-
* an additional forward or backwards branching factor that is not taken into account
903-
* when calculating the (virtual) dispatch cost.
904-
*
905-
* Argument `arg` is part of a path from a source to a sink, and `p` is the target parameter.
926+
* A local flow relation that includes both local steps, read steps and
927+
* argument-to-return flow through summarized functions.
906928
*/
907-
pragma[nomagic]
908-
int getAdditionalFlowIntoCallNodeTerm(ArgumentNode arg, ParameterNode p) {
909-
exists(ParameterNode switchee, SwitchInstruction switch, ConditionOperand op, DataFlowCall call |
910-
viableParamArg(call, p, arg) and
911-
viableParamArg(call, switchee, _) and
912-
switch.getExpressionOperand() = op and
913-
valueNumber(switchee.asInstruction()).getAUse() = op and
914-
result = countNumberOfBranchesUsingParameter(switch, p)
929+
private predicate localFlowStepWithSummaries(Node node1, Node node2) {
930+
localFlowStep(node1, node2)
931+
or
932+
readStep(node1, _, node2)
933+
or
934+
DataFlowImplCommon::argumentValueFlowsThrough(node1, _, node2)
935+
}
936+
937+
/** Holds if `node` flows to a node that is used in a `SwitchInstruction`. */
938+
private predicate localStepsToSwitch(Node node) {
939+
node.asOperand() = any(SwitchInstruction switch).getExpressionOperand()
940+
or
941+
exists(Node succ |
942+
localStepsToSwitch(succ) and
943+
localFlowStepWithSummaries(node, succ)
915944
)
916945
}
917946

947+
/**
948+
* Holds if `node` is part of a path from a `ParameterNode` to an operand
949+
* of a `SwitchInstruction`.
950+
*/
951+
private predicate localStepsFromParameterToSwitch(Node node) {
952+
localStepsToSwitch(node) and
953+
(
954+
node instanceof ParameterNode
955+
or
956+
exists(Node prev |
957+
localStepsFromParameterToSwitch(prev) and
958+
localFlowStepWithSummaries(prev, node)
959+
)
960+
)
961+
}
962+
963+
/**
964+
* The local flow relation `localFlowStepWithSummaries` pruned to only
965+
* include steps that are part of a path from a `ParameterNode` to an
966+
* operand of a `SwitchInstruction`.
967+
*/
968+
private predicate getAdditionalFlowIntoCallNodeTermStep(Node node1, Node node2) {
969+
localStepsFromParameterToSwitch(node1) and
970+
localStepsFromParameterToSwitch(node2) and
971+
localFlowStepWithSummaries(node1, node2)
972+
}
973+
918974
/** Gets the `IRVariable` associated with the parameter node `p`. */
919975
pragma[nomagic]
920976
private IRVariable getIRVariableForParameterNode(ParameterNode p) {
@@ -943,7 +999,7 @@ private EdgeKind caseOrDefaultEdge() {
943999
/**
9441000
* Gets the number of switch branches that that read from (or write to) the parameter `p`.
9451001
*/
946-
int countNumberOfBranchesUsingParameter(SwitchInstruction switch, ParameterNode p) {
1002+
private int countNumberOfBranchesUsingParameter(SwitchInstruction switch, ParameterNode p) {
9471003
exists(Ssa::SourceVariable sv |
9481004
parameterNodeHasSourceVariable(p, sv) and
9491005
// Count the number of cases that use the parameter. We do this by finding the phi node

0 commit comments

Comments
 (0)