Skip to content

Commit d34e731

Browse files
committed
C++: Add a small QLDoc novel above the IPA type for 'TIRDataFlowNode'.
1 parent d624259 commit d34e731

File tree

1 file changed

+39
-0
lines changed

1 file changed

+39
-0
lines changed

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,45 @@ private import SsaInternals as Ssa
1515

1616
cached
1717
private module Cached {
18+
/**
19+
* The IR dataflow graph consists of the following nodes:
20+
* - `InstructionNode`, which represents an `Instruction` in the graph.
21+
* - `OperandNode`, which represents an `Operand` in the graph.
22+
* - `VariableNode`, which is used to model global variables.
23+
* - Two kinds of `StoreNode`s:
24+
* 1. `StoreNodeInstr`, which represents the value of an address computed by an `Instruction` that
25+
* has been updated by a write operation.
26+
* 2. `StoreNodeOperand`, which represents the value of an address in an `ArgumentOperand` after a
27+
* function call that may have changed the value.
28+
* - `ReadNode`, which represents the result of reading a field of an object.
29+
* - `SsaPhiNode`, which represents phi nodes as computed by the shared SSA library.
30+
*
31+
* The following section describes how flow is generally transferred between these nodes:
32+
* - Flow between `InstructionNode`s and `OperandNode`s follow the def-use information as computed by
33+
* the IR. Because the IR compute must-alias information for memory operands, we only follow def-use
34+
* flow for register operands.
35+
* - Flow can enter a `StoreNode` in two ways (both done in `StoreNode.flowInto`):
36+
* 1. Flow is transferred from a `StoreValueOperand` to a `StoreNodeInstr`. Flow will then proceed
37+
* along the chain of addresses computed by `StoreNodeInstr.getInner` to identify field writes
38+
* and call `storeStep` accordingly (i.e., for an expression like `a.b.c = x`, we visit `c`, then
39+
* `b`, then `a`).
40+
* 2. Flow is transfered from a `WriteSideEffectInstruction` to a `StoreNodeOperand` after flow
41+
* returns to a caller. Flow will then proceed to the defining instruction of the operand (because
42+
* the `StoreNodeInstr` computed by `StoreNodeOperand.getInner()` is the `StoreNode` containing
43+
* the defining instruction), and then along the chain computed by `StoreNodeInstr.getInner` like
44+
* above.
45+
* In both cases, flow leaves a `StoreNode` once the entire chain has been traversed, and the shared
46+
* SSA library is used to find the next use of the variable at the end of the chain.
47+
* - Flow can enter a `ReadNode` through an `OperandNode` that represents an address of some variable.
48+
* Flow will then proceed along the chain of addresses computed by `ReadNode.getOuter` (i.e., for an
49+
* expression like `use(a.b.c)` we visit `a`, then `b`, then `c`) and call `readStep` accordingly.
50+
* Once the entire chain has been traversed, flow is transferred to the load instruction that reads
51+
* the final address of the chain.
52+
* - Flow can enter a `SsaPhiNode` from an `InstructionNode`, a `StoreNode` or another `SsaPhiNode`
53+
* (in `toPhiNode`), depending on which node provided the previous definition of the underlying
54+
* variable. Flow leaves a `SsaPhiNode` (in `fromPhiNode`) by using the shared SSA library to
55+
* determine the next use of the variable.
56+
*/
1857
cached
1958
newtype TIRDataFlowNode =
2059
TInstructionNode(Instruction i) or

0 commit comments

Comments
 (0)