Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 152 additions & 0 deletions cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRLocalFlow.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
private import cpp
// The `ValueNumbering` library has to be imported right after `cpp` to ensure
// that the cached IR gets the same checksum here as it does in queries that use
// `ValueNumbering` without `DataFlow`.
private import semmle.code.cpp.ir.ValueNumbering
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil

/**
* Gets a short ID for an IR dataflow node.
* - For `Instruction`s, this is just the result ID of the instruction (e.g. `m128`).
* - For `Operand`s, this is the label of the operand, prefixed with the result ID of the
* instruction and a dot (e.g. `m128.left`).
* - For `Variable`s, this is the qualified name of the variable.
*/
private string nodeId(DataFlow::Node node, int order1, int order2) {
exists(Instruction instruction | instruction = node.asInstruction() |
result = instruction.getResultId() and
order1 = instruction.getBlock().getDisplayIndex() and
order2 = instruction.getDisplayIndexInBlock()
)
or
exists(Operand operand, Instruction instruction |
operand = node.asOperand() and
instruction = operand.getUse()
|
result = instruction.getResultId() + "." + operand.getDumpId() and
order1 = instruction.getBlock().getDisplayIndex() and
order2 = instruction.getDisplayIndexInBlock()
)
or
result = "var(" + node.asVariable().getQualifiedName() + ")" and
order1 = 1000000 and
order2 = 0
}

/**
* Gets the local dataflow from other nodes in the same function to this node.
*/
private string getFromFlow(DataFlow::Node useNode, int order1, int order2) {
exists(DataFlow::Node defNode, string prefix |
(
simpleLocalFlowStep(defNode, useNode) and prefix = ""
or
any(DataFlow::Configuration cfg).isAdditionalFlowStep(defNode, useNode) and
defNode.getEnclosingCallable() = useNode.getEnclosingCallable() and
prefix = "+"
) and
if defNode.asInstruction() = useNode.asOperand().getAnyDef()
then
// Shorthand for flow from the def of this operand.
result = prefix + "def" and
order1 = -1 and
order2 = 0
else
if defNode.asOperand().getUse() = useNode.asInstruction()
then
// Shorthand for flow from an operand of this instruction
result = prefix + defNode.asOperand().getDumpId() and
order1 = -1 and
order2 = defNode.asOperand().getDumpSortOrder()
else result = prefix + nodeId(defNode, order1, order2)
)
}

/**
* Gets the local dataflow from this node to other nodes in the same function.
*/
private string getToFlow(DataFlow::Node defNode, int order1, int order2) {
exists(DataFlow::Node useNode, string prefix |
(
simpleLocalFlowStep(defNode, useNode) and prefix = ""
or
any(DataFlow::Configuration cfg).isAdditionalFlowStep(defNode, useNode) and
defNode.getEnclosingCallable() = useNode.getEnclosingCallable() and
prefix = "+"
) and
if useNode.asInstruction() = defNode.asOperand().getUse()
then
// Shorthand for flow to this operand's instruction.
result = prefix + "result" and
order1 = -1 and
order2 = 0
else result = prefix + nodeId(useNode, order1, order2)
)
}

/**
* Gets the properties of the dataflow node `node`.
*/
private string getNodeProperty(DataFlow::Node node, string key) {
// List dataflow into and out of this node. Flow into this node is printed as `src->@`, and flow
// out of this node is printed as `@->dest`.
key = "flow" and
result =
strictconcat(string flow, boolean to, int order1, int order2 |
flow = getFromFlow(node, order1, order2) + "->@" and to = false
or
flow = "@->" + getToFlow(node, order1, order2) and to = true
|
flow, ", " order by to, order1, order2, flow
)
or
// Is this node a dataflow sink?
key = "sink" and
any(DataFlow::Configuration cfg).isSink(node) and
result = "true"
or
// Is this node a dataflow source?
key = "source" and
any(DataFlow::Configuration cfg).isSource(node) and
result = "true"
or
// Is this node a dataflow barrier, and if so, what kind?
key = "barrier" and
result =
strictconcat(string kind |
any(DataFlow::Configuration cfg).isBarrier(node) and kind = "full"
or
any(DataFlow::Configuration cfg).isBarrierIn(node) and kind = "in"
or
any(DataFlow::Configuration cfg).isBarrierOut(node) and kind = "out"
or
exists(DataFlow::BarrierGuard guard |
any(DataFlow::Configuration cfg).isBarrierGuard(guard) and
node = guard.getAGuardedNode() and
kind = "guard(" + guard.getResultId() + ")"
)
|
kind, ", "
)
}

/**
* Property provider for local IR dataflow.
*/
class LocalFlowPropertyProvider extends IRPropertyProvider {
override string getOperandProperty(Operand operand, string key) {
exists(DataFlow::Node node |
operand = node.asOperand() and
result = getNodeProperty(node, key)
)
}

override string getInstructionProperty(Instruction instruction, string key) {
exists(DataFlow::Node node |
instruction = node.asInstruction() and
result = getNodeProperty(node, key)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,9 @@ class IRPropertyProvider extends TIRPropertyProvider {
* Gets the value of the property named `key` for the specified block.
*/
string getBlockProperty(IRBlock block, string key) { none() }

/**
* Gets the value of the property named `key` for the specified operand.
*/
string getOperandProperty(Operand operand, string key) { none() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ class Operand extends TOperand {
*/
string getDumpLabel() { result = "" }

/**
* Gets a string that uniquely identifies this operand on its use instruction.
*/
string getDumpId() { result = "" }

/**
* Gets a string describing this operand, suitable for display in IR dumps. This consists of the
* result ID of the instruction consumed by the operand, plus a label identifying the operand
Expand Down Expand Up @@ -280,6 +285,8 @@ class NonPhiOperand extends Operand {

final override string getDumpLabel() { result = tag.getLabel() }

final override string getDumpId() { result = tag.getId() }

final override int getDumpSortOrder() { result = tag.getSortOrder() }

/**
Expand Down Expand Up @@ -477,6 +484,8 @@ class PhiInputOperand extends MemoryOperand, PhiOperandBase {
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
}

final override string getDumpId() { result = getPredecessorBlock().getDisplayIndex().toString() }

/**
* Gets the predecessor block from which this value comes.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,37 @@ private string getAdditionalBlockProperty(IRBlock block, string key) {
exists(IRPropertyProvider provider | result = provider.getBlockProperty(block, key))
}

/**
* Gets the properties of an operand from any active property providers.
*/
private string getAdditionalOperandProperty(Operand operand, string key) {
exists(IRPropertyProvider provider | result = provider.getOperandProperty(operand, key))
}

/**
* Gets a string listing the properties of the operand and their corresponding values. If the
* operand has no properties, this predicate has no result.
*/
private string getOperandPropertyListString(Operand operand) {
result =
strictconcat(string key, string value |
value = getAdditionalOperandProperty(operand, key)
|
key + ":" + value, ", "
)
}

/**
* Gets a string listing the properties of the operand and their corresponding values. The list is
* surrounded by curly braces. If the operand has no properties, this predicate returns an empty
* string.
*/
private string getOperandPropertyString(Operand operand) {
result = "{" + getOperandPropertyListString(operand) + "}"
or
not exists(getOperandPropertyListString(operand)) and result = ""
}

private newtype TPrintableIRNode =
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
Expand Down Expand Up @@ -190,7 +221,7 @@ private class PrintableInstruction extends PrintableIRNode, TPrintableInstructio
|
resultString = instr.getResultString() and
operationString = instr.getOperationString() and
operandsString = instr.getOperandsString() and
operandsString = getOperandsString() and
columnWidths(block, resultWidth, operationWidth) and
result =
resultString + getPaddingString(resultWidth - resultString.length()) + " = " +
Expand All @@ -210,6 +241,22 @@ private class PrintableInstruction extends PrintableIRNode, TPrintableInstructio
result = PrintableIRNode.super.getProperty(key) or
result = getAdditionalInstructionProperty(instr, key)
}

/**
* Gets the string representation of the operand list. This is the same as
* `Instruction::getOperandsString()`, except that each operand is annotated with any properties
* provided by active `IRPropertyProvider` instances.
*/
private string getOperandsString() {
result =
concat(Operand operand |
operand = instr.getAnOperand()
|
operand.getDumpString() + getOperandPropertyString(operand), ", "
order by
operand.getDumpSortOrder()
)
}
}

private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {
Expand Down
Loading