@@ -5,33 +5,58 @@ private import DataFlowDispatch
55private import DataFlowImplConsistency
66private import semmle.code.cpp.ir.internal.IRCppLanguage
77private import SsaInternals as Ssa
8- private import DataFlowImplCommon
9- private import semmle.code.cpp.ir.ValueNumbering
8+ private import DataFlowImplCommon as DataFlowImplCommon
109
1110cached
1211private 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
3661class 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`. */
919975pragma [ nomagic]
920976private 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