mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
C++: Add ability to dump local dataflow info in IR dumps
This change adds a new module, `PrintIRLocalFlow.qll`, which can be imported into any query that uses both `PrintIR.qll` and the IR dataflow library. The IR dump printed by `PrintIR.qll` will be annotated with information about how each operand and instruction participates in dataflow.
For each operand and instruction, the following propeties are displayed:
- `flow`: Which local operands/instructions have flow to this node, and which local operands/instruction this node has flow to.
- `source`: `true` if this node is a source
- `sink`: `true` if this node is a sink
- `barrier`: Lists which kinds of barrier this node is. Can be zero or more of `full`, `in`, `out`, and `guard`. If the node is a guard barrier, the IR of the guarding instruction is also printed.
We already had a way to print additional properties for instructions and blocks, but not for operands. I added support for operand properties to `IRPropertyProvider`. These are now printed in a curly-brace-enclosed list immediately after the corresponding operand.
When printing flow, instructions are identified by their result ID (e.g., `m128`). Operands are identified by both the result ID of their instruction and their kind (e.g., `r145.left`). For flow from an operand to its use instruction, it just prints `result` at the operand, and prints only the operand kind on the instruction.
Example output:
```
# 344| m344_34(vector<int, allocator<int>>) = Chi : total:m344_20{flow:def->@, @->result}, partial:m344_33{flow:def->@, @->result}
# 344| flow = total->@, partial->@, +m344_33->@, @->+r347_3, @->v347_7.side_effect, @->m347_9.total, @->m344_20.1
```
The `+` annotations indicate when the flow came from `isAdditionalFlowStep()`, rather than built-in local flow.
This commit is contained in:
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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() }
|
||||
|
||||
/**
|
||||
@@ -477,6 +484,10 @@ 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.
|
||||
*/
|
||||
|
||||
@@ -50,6 +50,32 @@ 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
|
||||
@@ -190,7 +216,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()) + " = " +
|
||||
@@ -210,6 +236,20 @@ 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) {
|
||||
|
||||
@@ -40,7 +40,19 @@ abstract class OperandTag extends TOperandTag {
|
||||
/**
|
||||
* Gets a label that will appear before the operand when the IR is printed.
|
||||
*/
|
||||
string getLabel() { result = "" }
|
||||
final string getLabel() {
|
||||
if alwaysPrintLabel() then result = getId() + ":" else result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an identifier that uniquely identifies this operand within its instruction.
|
||||
*/
|
||||
abstract string getId();
|
||||
|
||||
/**
|
||||
* Holds if the operand should always be prefixed with its label in the dump of its instruction.
|
||||
*/
|
||||
predicate alwaysPrintLabel() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,7 +81,9 @@ class AddressOperandTag extends RegisterOperandTag, TAddressOperand {
|
||||
|
||||
final override int getSortOrder() { result = 0 }
|
||||
|
||||
final override string getLabel() { result = "&:" }
|
||||
final override predicate alwaysPrintLabel() { any() }
|
||||
|
||||
final override string getId() { result = "&" }
|
||||
}
|
||||
|
||||
AddressOperandTag addressOperand() { result = TAddressOperand() }
|
||||
@@ -82,6 +96,8 @@ class BufferSizeOperandTag extends RegisterOperandTag, TBufferSizeOperand {
|
||||
final override string toString() { result = "BufferSize" }
|
||||
|
||||
final override int getSortOrder() { result = 1 }
|
||||
|
||||
final override string getId() { result = "size" }
|
||||
}
|
||||
|
||||
BufferSizeOperandTag bufferSizeOperand() { result = TBufferSizeOperand() }
|
||||
@@ -93,6 +109,8 @@ class SideEffectOperandTag extends TypedOperandTag, TSideEffectOperand {
|
||||
final override string toString() { result = "SideEffect" }
|
||||
|
||||
final override int getSortOrder() { result = 2 }
|
||||
|
||||
final override string getId() { result = "side_effect" }
|
||||
}
|
||||
|
||||
SideEffectOperandTag sideEffectOperand() { result = TSideEffectOperand() }
|
||||
@@ -105,6 +123,8 @@ class LoadOperandTag extends TypedOperandTag, TLoadOperand {
|
||||
final override string toString() { result = "Load" }
|
||||
|
||||
final override int getSortOrder() { result = 3 }
|
||||
|
||||
final override string getId() { result = "load" }
|
||||
}
|
||||
|
||||
LoadOperandTag loadOperand() { result = TLoadOperand() }
|
||||
@@ -116,6 +136,8 @@ class StoreValueOperandTag extends RegisterOperandTag, TStoreValueOperand {
|
||||
final override string toString() { result = "StoreValue" }
|
||||
|
||||
final override int getSortOrder() { result = 4 }
|
||||
|
||||
final override string getId() { result = "store" }
|
||||
}
|
||||
|
||||
StoreValueOperandTag storeValueOperand() { result = TStoreValueOperand() }
|
||||
@@ -127,6 +149,8 @@ class UnaryOperandTag extends RegisterOperandTag, TUnaryOperand {
|
||||
final override string toString() { result = "Unary" }
|
||||
|
||||
final override int getSortOrder() { result = 5 }
|
||||
|
||||
final override string getId() { result = "unary" }
|
||||
}
|
||||
|
||||
UnaryOperandTag unaryOperand() { result = TUnaryOperand() }
|
||||
@@ -138,6 +162,8 @@ class LeftOperandTag extends RegisterOperandTag, TLeftOperand {
|
||||
final override string toString() { result = "Left" }
|
||||
|
||||
final override int getSortOrder() { result = 6 }
|
||||
|
||||
final override string getId() { result = "left" }
|
||||
}
|
||||
|
||||
LeftOperandTag leftOperand() { result = TLeftOperand() }
|
||||
@@ -149,6 +175,8 @@ class RightOperandTag extends RegisterOperandTag, TRightOperand {
|
||||
final override string toString() { result = "Right" }
|
||||
|
||||
final override int getSortOrder() { result = 7 }
|
||||
|
||||
final override string getId() { result = "right" }
|
||||
}
|
||||
|
||||
RightOperandTag rightOperand() { result = TRightOperand() }
|
||||
@@ -160,6 +188,8 @@ class ConditionOperandTag extends RegisterOperandTag, TConditionOperand {
|
||||
final override string toString() { result = "Condition" }
|
||||
|
||||
final override int getSortOrder() { result = 8 }
|
||||
|
||||
final override string getId() { result = "cond" }
|
||||
}
|
||||
|
||||
ConditionOperandTag conditionOperand() { result = TConditionOperand() }
|
||||
@@ -172,7 +202,9 @@ class CallTargetOperandTag extends RegisterOperandTag, TCallTargetOperand {
|
||||
|
||||
final override int getSortOrder() { result = 10 }
|
||||
|
||||
final override string getLabel() { result = "func:" }
|
||||
final override predicate alwaysPrintLabel() { any() }
|
||||
|
||||
final override string getId() { result = "func" }
|
||||
}
|
||||
|
||||
CallTargetOperandTag callTargetOperand() { result = TCallTargetOperand() }
|
||||
@@ -195,7 +227,9 @@ class ThisArgumentOperandTag extends ArgumentOperandTag, TThisArgumentOperand {
|
||||
|
||||
final override int getSortOrder() { result = 11 }
|
||||
|
||||
final override string getLabel() { result = "this:" }
|
||||
final override predicate alwaysPrintLabel() { any() }
|
||||
|
||||
final override string getId() { result = "this" }
|
||||
}
|
||||
|
||||
ThisArgumentOperandTag thisArgumentOperand() { result = TThisArgumentOperand() }
|
||||
@@ -212,9 +246,11 @@ class PositionalArgumentOperandTag extends ArgumentOperandTag, TPositionalArgume
|
||||
|
||||
final override int getSortOrder() { result = 12 + argIndex }
|
||||
|
||||
final override string getLabel() { result = argIndex.toString() + ":" }
|
||||
final override predicate alwaysPrintLabel() { any() }
|
||||
|
||||
final int getArgIndex() { result = argIndex }
|
||||
|
||||
final override string getId() { result = argIndex.toString() }
|
||||
}
|
||||
|
||||
PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) {
|
||||
@@ -228,7 +264,9 @@ class ChiTotalOperandTag extends ChiOperandTag, TChiTotalOperand {
|
||||
|
||||
final override int getSortOrder() { result = 13 }
|
||||
|
||||
final override string getLabel() { result = "total:" }
|
||||
final override predicate alwaysPrintLabel() { any() }
|
||||
|
||||
final override string getId() { result = "total" }
|
||||
}
|
||||
|
||||
ChiTotalOperandTag chiTotalOperand() { result = TChiTotalOperand() }
|
||||
@@ -238,7 +276,9 @@ class ChiPartialOperandTag extends ChiOperandTag, TChiPartialOperand {
|
||||
|
||||
final override int getSortOrder() { result = 14 }
|
||||
|
||||
final override string getLabel() { result = "partial:" }
|
||||
final override predicate alwaysPrintLabel() { any() }
|
||||
|
||||
final override string getId() { result = "partial" }
|
||||
}
|
||||
|
||||
ChiPartialOperandTag chiPartialOperand() { result = TChiPartialOperand() }
|
||||
@@ -252,7 +292,9 @@ class AsmOperandTag extends RegisterOperandTag, TAsmOperand {
|
||||
|
||||
final override int getSortOrder() { result = 15 + index }
|
||||
|
||||
final override string getLabel() { result = index.toString() + ":" }
|
||||
final override predicate alwaysPrintLabel() { any() }
|
||||
|
||||
final override string getId() { result = index.toString() }
|
||||
}
|
||||
|
||||
AsmOperandTag asmOperand(int index) { result = TAsmOperand(index) }
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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() }
|
||||
|
||||
/**
|
||||
@@ -477,6 +484,10 @@ 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.
|
||||
*/
|
||||
|
||||
@@ -50,6 +50,32 @@ 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
|
||||
@@ -190,7 +216,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()) + " = " +
|
||||
@@ -210,6 +236,20 @@ 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) {
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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() }
|
||||
|
||||
/**
|
||||
@@ -477,6 +484,10 @@ 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.
|
||||
*/
|
||||
|
||||
@@ -50,6 +50,32 @@ 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
|
||||
@@ -190,7 +216,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()) + " = " +
|
||||
@@ -210,6 +236,20 @@ 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) {
|
||||
|
||||
@@ -40,7 +40,19 @@ abstract class OperandTag extends TOperandTag {
|
||||
/**
|
||||
* Gets a label that will appear before the operand when the IR is printed.
|
||||
*/
|
||||
string getLabel() { result = "" }
|
||||
final string getLabel() {
|
||||
if alwaysPrintLabel() then result = getId() + ":" else result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an identifier that uniquely identifies this operand within its instruction.
|
||||
*/
|
||||
abstract string getId();
|
||||
|
||||
/**
|
||||
* Holds if the operand should always be prefixed with its label in the dump of its instruction.
|
||||
*/
|
||||
predicate alwaysPrintLabel() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,7 +81,9 @@ class AddressOperandTag extends RegisterOperandTag, TAddressOperand {
|
||||
|
||||
final override int getSortOrder() { result = 0 }
|
||||
|
||||
final override string getLabel() { result = "&:" }
|
||||
final override predicate alwaysPrintLabel() { any() }
|
||||
|
||||
final override string getId() { result = "&" }
|
||||
}
|
||||
|
||||
AddressOperandTag addressOperand() { result = TAddressOperand() }
|
||||
@@ -82,6 +96,8 @@ class BufferSizeOperandTag extends RegisterOperandTag, TBufferSizeOperand {
|
||||
final override string toString() { result = "BufferSize" }
|
||||
|
||||
final override int getSortOrder() { result = 1 }
|
||||
|
||||
final override string getId() { result = "size" }
|
||||
}
|
||||
|
||||
BufferSizeOperandTag bufferSizeOperand() { result = TBufferSizeOperand() }
|
||||
@@ -93,6 +109,8 @@ class SideEffectOperandTag extends TypedOperandTag, TSideEffectOperand {
|
||||
final override string toString() { result = "SideEffect" }
|
||||
|
||||
final override int getSortOrder() { result = 2 }
|
||||
|
||||
final override string getId() { result = "side_effect" }
|
||||
}
|
||||
|
||||
SideEffectOperandTag sideEffectOperand() { result = TSideEffectOperand() }
|
||||
@@ -105,6 +123,8 @@ class LoadOperandTag extends TypedOperandTag, TLoadOperand {
|
||||
final override string toString() { result = "Load" }
|
||||
|
||||
final override int getSortOrder() { result = 3 }
|
||||
|
||||
final override string getId() { result = "load" }
|
||||
}
|
||||
|
||||
LoadOperandTag loadOperand() { result = TLoadOperand() }
|
||||
@@ -116,6 +136,8 @@ class StoreValueOperandTag extends RegisterOperandTag, TStoreValueOperand {
|
||||
final override string toString() { result = "StoreValue" }
|
||||
|
||||
final override int getSortOrder() { result = 4 }
|
||||
|
||||
final override string getId() { result = "store" }
|
||||
}
|
||||
|
||||
StoreValueOperandTag storeValueOperand() { result = TStoreValueOperand() }
|
||||
@@ -127,6 +149,8 @@ class UnaryOperandTag extends RegisterOperandTag, TUnaryOperand {
|
||||
final override string toString() { result = "Unary" }
|
||||
|
||||
final override int getSortOrder() { result = 5 }
|
||||
|
||||
final override string getId() { result = "unary" }
|
||||
}
|
||||
|
||||
UnaryOperandTag unaryOperand() { result = TUnaryOperand() }
|
||||
@@ -138,6 +162,8 @@ class LeftOperandTag extends RegisterOperandTag, TLeftOperand {
|
||||
final override string toString() { result = "Left" }
|
||||
|
||||
final override int getSortOrder() { result = 6 }
|
||||
|
||||
final override string getId() { result = "left" }
|
||||
}
|
||||
|
||||
LeftOperandTag leftOperand() { result = TLeftOperand() }
|
||||
@@ -149,6 +175,8 @@ class RightOperandTag extends RegisterOperandTag, TRightOperand {
|
||||
final override string toString() { result = "Right" }
|
||||
|
||||
final override int getSortOrder() { result = 7 }
|
||||
|
||||
final override string getId() { result = "right" }
|
||||
}
|
||||
|
||||
RightOperandTag rightOperand() { result = TRightOperand() }
|
||||
@@ -160,6 +188,8 @@ class ConditionOperandTag extends RegisterOperandTag, TConditionOperand {
|
||||
final override string toString() { result = "Condition" }
|
||||
|
||||
final override int getSortOrder() { result = 8 }
|
||||
|
||||
final override string getId() { result = "cond" }
|
||||
}
|
||||
|
||||
ConditionOperandTag conditionOperand() { result = TConditionOperand() }
|
||||
@@ -172,7 +202,9 @@ class CallTargetOperandTag extends RegisterOperandTag, TCallTargetOperand {
|
||||
|
||||
final override int getSortOrder() { result = 10 }
|
||||
|
||||
final override string getLabel() { result = "func:" }
|
||||
final override predicate alwaysPrintLabel() { any() }
|
||||
|
||||
final override string getId() { result = "func" }
|
||||
}
|
||||
|
||||
CallTargetOperandTag callTargetOperand() { result = TCallTargetOperand() }
|
||||
@@ -195,7 +227,9 @@ class ThisArgumentOperandTag extends ArgumentOperandTag, TThisArgumentOperand {
|
||||
|
||||
final override int getSortOrder() { result = 11 }
|
||||
|
||||
final override string getLabel() { result = "this:" }
|
||||
final override predicate alwaysPrintLabel() { any() }
|
||||
|
||||
final override string getId() { result = "this" }
|
||||
}
|
||||
|
||||
ThisArgumentOperandTag thisArgumentOperand() { result = TThisArgumentOperand() }
|
||||
@@ -212,9 +246,11 @@ class PositionalArgumentOperandTag extends ArgumentOperandTag, TPositionalArgume
|
||||
|
||||
final override int getSortOrder() { result = 12 + argIndex }
|
||||
|
||||
final override string getLabel() { result = argIndex.toString() + ":" }
|
||||
final override predicate alwaysPrintLabel() { any() }
|
||||
|
||||
final int getArgIndex() { result = argIndex }
|
||||
|
||||
final override string getId() { result = argIndex.toString() }
|
||||
}
|
||||
|
||||
PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) {
|
||||
@@ -228,7 +264,9 @@ class ChiTotalOperandTag extends ChiOperandTag, TChiTotalOperand {
|
||||
|
||||
final override int getSortOrder() { result = 13 }
|
||||
|
||||
final override string getLabel() { result = "total:" }
|
||||
final override predicate alwaysPrintLabel() { any() }
|
||||
|
||||
final override string getId() { result = "total" }
|
||||
}
|
||||
|
||||
ChiTotalOperandTag chiTotalOperand() { result = TChiTotalOperand() }
|
||||
@@ -238,7 +276,9 @@ class ChiPartialOperandTag extends ChiOperandTag, TChiPartialOperand {
|
||||
|
||||
final override int getSortOrder() { result = 14 }
|
||||
|
||||
final override string getLabel() { result = "partial:" }
|
||||
final override predicate alwaysPrintLabel() { any() }
|
||||
|
||||
final override string getId() { result = "partial" }
|
||||
}
|
||||
|
||||
ChiPartialOperandTag chiPartialOperand() { result = TChiPartialOperand() }
|
||||
@@ -252,7 +292,9 @@ class AsmOperandTag extends RegisterOperandTag, TAsmOperand {
|
||||
|
||||
final override int getSortOrder() { result = 15 + index }
|
||||
|
||||
final override string getLabel() { result = index.toString() + ":" }
|
||||
final override predicate alwaysPrintLabel() { any() }
|
||||
|
||||
final override string getId() { result = index.toString() }
|
||||
}
|
||||
|
||||
AsmOperandTag asmOperand(int index) { result = TAsmOperand(index) }
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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() }
|
||||
|
||||
/**
|
||||
@@ -477,6 +484,10 @@ 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.
|
||||
*/
|
||||
|
||||
@@ -50,6 +50,32 @@ 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
|
||||
@@ -190,7 +216,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()) + " = " +
|
||||
@@ -210,6 +236,20 @@ 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) {
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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() }
|
||||
|
||||
/**
|
||||
@@ -477,6 +484,10 @@ 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.
|
||||
*/
|
||||
|
||||
@@ -50,6 +50,32 @@ 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
|
||||
@@ -190,7 +216,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()) + " = " +
|
||||
@@ -210,6 +236,20 @@ 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) {
|
||||
|
||||
Reference in New Issue
Block a user