Skip to content

Commit 5dc3789

Browse files
authored
Merge pull request github#13266 from MathiasVP/modernize-print-ir-local-flow
C++: Modernize `PrintIR` for local dataflow
2 parents 9591645 + 4b92a2a commit 5dc3789

File tree

14 files changed

+222
-150
lines changed

14 files changed

+222
-150
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* Print the dataflow local store steps in IR dumps.
3+
*/
4+
5+
private import cpp
6+
private import semmle.code.cpp.ir.IR
7+
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
8+
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
9+
private import PrintIRUtilities
10+
11+
/** A property provider for local IR dataflow store steps. */
12+
class FieldFlowPropertyProvider extends IRPropertyProvider {
13+
override string getOperandProperty(Operand operand, string key) {
14+
exists(PostFieldUpdateNode pfun, Content content |
15+
key = "store " + content.toString() and
16+
operand = pfun.getPreUpdateNode().(IndirectOperand).getOperand() and
17+
result =
18+
strictconcat(string element, Node node |
19+
storeStep(node, content, pfun) and
20+
element = nodeId(node, _, _)
21+
|
22+
element, ", "
23+
)
24+
)
25+
or
26+
exists(Node node2, Content content |
27+
key = "read " + content.toString() and
28+
operand = node2.(IndirectOperand).getOperand() and
29+
result =
30+
strictconcat(string element, Node node1 |
31+
readStep(node1, content, node2) and
32+
element = nodeId(node1, _, _)
33+
|
34+
element, ", "
35+
)
36+
)
37+
}
38+
}
Lines changed: 21 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,136 +1,66 @@
11
private import cpp
2-
// The `ValueNumbering` library has to be imported right after `cpp` to ensure
3-
// that the cached IR gets the same checksum here as it does in queries that use
4-
// `ValueNumbering` without `DataFlow`.
5-
private import semmle.code.cpp.ir.ValueNumbering
62
private import semmle.code.cpp.ir.IR
7-
private import semmle.code.cpp.ir.dataflow.DataFlow
83
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
4+
private import SsaInternals as Ssa
95
private import PrintIRUtilities
106

117
/**
128
* Gets the local dataflow from other nodes in the same function to this node.
139
*/
14-
private string getFromFlow(DataFlow::Node useNode, int order1, int order2) {
15-
exists(DataFlow::Node defNode, string prefix |
16-
(
17-
simpleLocalFlowStep(defNode, useNode) and prefix = ""
18-
or
19-
any(DataFlow::Configuration cfg).isAdditionalFlowStep(defNode, useNode) and
20-
defNode.getEnclosingCallable() = useNode.getEnclosingCallable() and
21-
prefix = "+"
22-
) and
23-
if defNode.asInstruction() = useNode.asOperand().getAnyDef()
24-
then
25-
// Shorthand for flow from the def of this operand.
26-
result = prefix + "def" and
27-
order1 = -1 and
28-
order2 = 0
29-
else
30-
if defNode.asOperand().getUse() = useNode.asInstruction()
31-
then
32-
// Shorthand for flow from an operand of this instruction
33-
result = prefix + defNode.asOperand().getDumpId() and
34-
order1 = -1 and
35-
order2 = defNode.asOperand().getDumpSortOrder()
36-
else result = prefix + nodeId(defNode, order1, order2)
10+
private string getFromFlow(Node node2, int order1, int order2) {
11+
exists(Node node1 |
12+
simpleLocalFlowStep(node1, node2) and
13+
result = nodeId(node1, order1, order2)
3714
)
3815
}
3916

4017
/**
4118
* Gets the local dataflow from this node to other nodes in the same function.
4219
*/
43-
private string getToFlow(DataFlow::Node defNode, int order1, int order2) {
44-
exists(DataFlow::Node useNode, string prefix |
45-
(
46-
simpleLocalFlowStep(defNode, useNode) and prefix = ""
47-
or
48-
any(DataFlow::Configuration cfg).isAdditionalFlowStep(defNode, useNode) and
49-
defNode.getEnclosingCallable() = useNode.getEnclosingCallable() and
50-
prefix = "+"
51-
) and
52-
if useNode.asInstruction() = defNode.asOperand().getUse()
53-
then
54-
// Shorthand for flow to this operand's instruction.
55-
result = prefix + "result" and
56-
order1 = -1 and
57-
order2 = 0
58-
else result = prefix + nodeId(useNode, order1, order2)
20+
private string getToFlow(Node node1, int order1, int order2) {
21+
exists(Node node2 |
22+
simpleLocalFlowStep(node1, node2) and
23+
result = nodeId(node2, order1, order2)
5924
)
6025
}
6126

6227
/**
6328
* Gets the properties of the dataflow node `node`.
6429
*/
65-
private string getNodeProperty(DataFlow::Node node, string key) {
30+
private string getNodeProperty(Node node, string key) {
6631
// List dataflow into and out of this node. Flow into this node is printed as `src->@`, and flow
6732
// out of this node is printed as `@->dest`.
6833
key = "flow" and
6934
result =
7035
strictconcat(string flow, boolean to, int order1, int order2 |
71-
flow = getFromFlow(node, order1, order2) + "->@" and to = false
36+
flow = getFromFlow(node, order1, order2) + "->" + starsForNode(node) + "@" and to = false
7237
or
73-
flow = "@->" + getToFlow(node, order1, order2) and to = true
38+
flow = starsForNode(node) + "@->" + getToFlow(node, order1, order2) and to = true
7439
|
7540
flow, ", " order by to, order1, order2, flow
7641
)
77-
or
78-
// Is this node a dataflow sink?
79-
key = "sink" and
80-
any(DataFlow::Configuration cfg).isSink(node) and
81-
result = "true"
82-
or
83-
// Is this node a dataflow source?
84-
key = "source" and
85-
any(DataFlow::Configuration cfg).isSource(node) and
86-
result = "true"
87-
or
88-
// Is this node a dataflow barrier, and if so, what kind?
89-
key = "barrier" and
90-
result =
91-
strictconcat(string kind |
92-
any(DataFlow::Configuration cfg).isBarrier(node) and kind = "full"
93-
or
94-
any(DataFlow::Configuration cfg).isBarrierIn(node) and kind = "in"
95-
or
96-
any(DataFlow::Configuration cfg).isBarrierOut(node) and kind = "out"
97-
|
98-
kind, ", "
99-
)
100-
// or
101-
// // Is there partial flow from a source to this node?
102-
// // This property will only be emitted if partial flow is enabled by overriding
103-
// // `DataFlow::Configuration::explorationLimit()`.
104-
// key = "pflow" and
105-
// result =
106-
// strictconcat(DataFlow::PartialPathNode sourceNode, DataFlow::PartialPathNode destNode, int dist,
107-
// int order1, int order2 |
108-
// any(DataFlow::Configuration cfg).hasPartialFlow(sourceNode, destNode, dist) and
109-
// destNode.getNode() = node and
110-
// // Only print flow from a source in the same function.
111-
// sourceNode.getNode().getEnclosingCallable() = node.getEnclosingCallable()
112-
// |
113-
// nodeId(sourceNode.getNode(), order1, order2) + "+" + dist.toString(), ", "
114-
// order by
115-
// order1, order2, dist desc
116-
// )
11742
}
11843

11944
/**
12045
* Property provider for local IR dataflow.
12146
*/
12247
class LocalFlowPropertyProvider extends IRPropertyProvider {
12348
override string getOperandProperty(Operand operand, string key) {
124-
exists(DataFlow::Node node |
125-
operand = node.asOperand() and
49+
exists(Node node |
50+
operand = [node.asOperand(), node.(RawIndirectOperand).getOperand()] and
12651
result = getNodeProperty(node, key)
12752
)
12853
}
12954

13055
override string getInstructionProperty(Instruction instruction, string key) {
131-
exists(DataFlow::Node node |
132-
instruction = node.asInstruction() and
56+
exists(Node node |
57+
instruction = [node.asInstruction(), node.(RawIndirectInstruction).getInstruction()]
58+
|
13359
result = getNodeProperty(node, key)
13460
)
13561
}
62+
63+
override predicate shouldPrintOperand(Operand operand) { not Ssa::ignoreOperand(operand) }
64+
65+
override predicate shouldPrintInstruction(Instruction instr) { not Ssa::ignoreInstruction(instr) }
13666
}

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

Lines changed: 0 additions & 33 deletions
This file was deleted.

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

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,59 @@
33
*/
44

55
private import cpp
6-
// The `ValueNumbering` library has to be imported right after `cpp` to ensure
7-
// that the cached IR gets the same checksum here as it does in queries that use
8-
// `ValueNumbering` without `DataFlow`.
9-
private import semmle.code.cpp.ir.ValueNumbering
106
private import semmle.code.cpp.ir.IR
11-
private import semmle.code.cpp.ir.dataflow.DataFlow
7+
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
8+
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
9+
10+
private string stars(int k) {
11+
k =
12+
[0 .. max([
13+
any(RawIndirectInstruction n).getIndirectionIndex(),
14+
any(RawIndirectOperand n).getIndirectionIndex()
15+
]
16+
)] and
17+
(if k = 0 then result = "" else result = "*" + stars(k - 1))
18+
}
19+
20+
string starsForNode(Node node) {
21+
result = stars(node.(IndirectInstruction).getIndirectionIndex())
22+
or
23+
result = stars(node.(IndirectOperand).getIndirectionIndex())
24+
or
25+
not node instanceof IndirectInstruction and
26+
not node instanceof IndirectOperand and
27+
result = ""
28+
}
29+
30+
private Instruction getInstruction(Node n, string stars) {
31+
result = [n.asInstruction(), n.(RawIndirectInstruction).getInstruction()] and
32+
stars = starsForNode(n)
33+
}
34+
35+
private Operand getOperand(Node n, string stars) {
36+
result = [n.asOperand(), n.(RawIndirectOperand).getOperand()] and
37+
stars = starsForNode(n)
38+
}
1239

1340
/**
1441
* Gets a short ID for an IR dataflow node.
1542
* - For `Instruction`s, this is just the result ID of the instruction (e.g. `m128`).
1643
* - For `Operand`s, this is the label of the operand, prefixed with the result ID of the
1744
* instruction and a dot (e.g. `m128.left`).
18-
* - For `Variable`s, this is the qualified name of the variable.
1945
*/
20-
string nodeId(DataFlow::Node node, int order1, int order2) {
21-
exists(Instruction instruction | instruction = node.asInstruction() |
22-
result = instruction.getResultId() and
46+
string nodeId(Node node, int order1, int order2) {
47+
exists(Instruction instruction, string stars | instruction = getInstruction(node, stars) |
48+
result = stars + instruction.getResultId() and
2349
order1 = instruction.getBlock().getDisplayIndex() and
2450
order2 = instruction.getDisplayIndexInBlock()
2551
)
2652
or
27-
exists(Operand operand, Instruction instruction |
28-
operand = node.asOperand() and
53+
exists(Operand operand, Instruction instruction, string stars |
54+
operand = getOperand(node, stars) and
2955
instruction = operand.getUse()
3056
|
31-
result = instruction.getResultId() + "." + operand.getDumpId() and
57+
result = stars + instruction.getResultId() + "." + operand.getDumpId() and
3258
order1 = instruction.getBlock().getDisplayIndex() and
3359
order2 = instruction.getDisplayIndexInBlock()
3460
)
35-
or
36-
result = "var(" + node.asVariable().getQualifiedName() + ")" and
37-
order1 = 1000000 and
38-
order2 = 0
3961
}

cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,16 @@ class IRPropertyProvider extends TIRPropertyProvider {
7777
* Gets the value of the property named `key` for the specified operand.
7878
*/
7979
string getOperandProperty(Operand operand, string key) { none() }
80+
81+
/**
82+
* Holds if the instruction `instr` should be included when printing
83+
* the IR instructions.
84+
*/
85+
predicate shouldPrintInstruction(Instruction instr) { any() }
86+
87+
/**
88+
* Holds if the operand `operand` should be included when printing the an
89+
* instruction's operand list.
90+
*/
91+
predicate shouldPrintOperand(Operand operand) { any() }
8092
}

cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ private predicate shouldPrintFunction(Language::Declaration decl) {
4242
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
4343
}
4444

45+
private predicate shouldPrintInstruction(Instruction i) {
46+
exists(IRPropertyProvider provider | provider.shouldPrintInstruction(i))
47+
}
48+
49+
private predicate shouldPrintOperand(Operand operand) {
50+
exists(IRPropertyProvider provider | provider.shouldPrintOperand(operand))
51+
}
52+
4553
private string getAdditionalInstructionProperty(Instruction instr, string key) {
4654
exists(IRPropertyProvider provider | result = provider.getInstructionProperty(instr, key))
4755
}
@@ -84,7 +92,9 @@ private string getOperandPropertyString(Operand operand) {
8492
private newtype TPrintableIRNode =
8593
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
8694
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
87-
TPrintableInstruction(Instruction instr) { shouldPrintFunction(instr.getEnclosingFunction()) }
95+
TPrintableInstruction(Instruction instr) {
96+
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
97+
}
8898

8999
/**
90100
* A node to be emitted in the IR graph.
@@ -252,7 +262,8 @@ private class PrintableInstruction extends PrintableIRNode, TPrintableInstructio
252262
private string getOperandsString() {
253263
result =
254264
concat(Operand operand |
255-
operand = instr.getAnOperand()
265+
operand = instr.getAnOperand() and
266+
shouldPrintOperand(operand)
256267
|
257268
operand.getDumpString() + getOperandPropertyString(operand), ", "
258269
order by

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IR.qll

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,16 @@ class IRPropertyProvider extends TIRPropertyProvider {
7777
* Gets the value of the property named `key` for the specified operand.
7878
*/
7979
string getOperandProperty(Operand operand, string key) { none() }
80+
81+
/**
82+
* Holds if the instruction `instr` should be included when printing
83+
* the IR instructions.
84+
*/
85+
predicate shouldPrintInstruction(Instruction instr) { any() }
86+
87+
/**
88+
* Holds if the operand `operand` should be included when printing the an
89+
* instruction's operand list.
90+
*/
91+
predicate shouldPrintOperand(Operand operand) { any() }
8092
}

0 commit comments

Comments
 (0)