mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
C++: Make IR dump and AST dump tests use the official graph query format
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
* @name Print AST
|
* @name Print AST
|
||||||
* @description Outputs a representation of the Abstract Syntax Tree.
|
* @description Outputs a representation of the Abstract Syntax Tree.
|
||||||
* @id cpp/print-ast
|
* @id cpp/print-ast
|
||||||
|
* @kind graph
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
|
|||||||
@@ -2,11 +2,18 @@ import cpp
|
|||||||
|
|
||||||
private newtype TPrintASTConfiguration = MkPrintASTConfiguration()
|
private newtype TPrintASTConfiguration = MkPrintASTConfiguration()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The query can extend this class to control which functions are printed.
|
||||||
|
*/
|
||||||
class PrintASTConfiguration extends TPrintASTConfiguration {
|
class PrintASTConfiguration extends TPrintASTConfiguration {
|
||||||
string toString() {
|
string toString() {
|
||||||
result = "PrintASTConfiguration"
|
result = "PrintASTConfiguration"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the AST for `func` should be printed. By default, holds for all
|
||||||
|
* functions.
|
||||||
|
*/
|
||||||
predicate shouldPrintFunction(Function func) {
|
predicate shouldPrintFunction(Function func) {
|
||||||
any()
|
any()
|
||||||
}
|
}
|
||||||
@@ -18,165 +25,500 @@ private predicate shouldPrintFunction(Function func) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private Locatable getAChild(Locatable parent) {
|
bindingset[s]
|
||||||
result = getChild(parent, _)
|
private string escapeString(string s) {
|
||||||
|
result = s.replaceAll("\\", "\\\\").replaceAll("\n", "\\n").replaceAll("\r", "\\r").replaceAll("\t", "\\t")
|
||||||
}
|
}
|
||||||
|
|
||||||
private Function getEnclosingFunction(Locatable ast) {
|
/**
|
||||||
getAChild*(result) = ast
|
* Due to extractor issues with ODR violations, a given AST may wind up with
|
||||||
|
* multiple locations. This predicate returns a single location - the one whose
|
||||||
|
* string representation comes first in lexicographical order.
|
||||||
|
*/
|
||||||
|
private Location getRepresentativeLocation(Locatable ast) {
|
||||||
|
result = rank[1](Location loc | loc = ast.getLocation() | loc order by loc.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getEntryPointIndex(Function func) {
|
/**
|
||||||
if func instanceof Constructor then
|
* Most nodes are just a wrapper around `Locatable`, but we do synthesize new
|
||||||
result = count(func.(Constructor).getAnInitializer())
|
* nodes for things like parameter lists and constructor init lists.
|
||||||
else
|
*/
|
||||||
result = 0
|
private newtype TPrintASTNode =
|
||||||
|
TASTNode(Locatable ast) or
|
||||||
|
TParametersNode(Function func) or
|
||||||
|
TConstructorInitializersNode(Constructor ctor) {
|
||||||
|
ctor.hasEntryPoint()
|
||||||
|
} or
|
||||||
|
TDestructorDestructionsNode(Destructor dtor) {
|
||||||
|
dtor.hasEntryPoint()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node in the output tree.
|
||||||
|
*/
|
||||||
|
class PrintASTNode extends TPrintASTNode {
|
||||||
|
abstract string toString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the child node at index `childIndex`. Child indices must be unique,
|
||||||
|
* but need not be contiguous (but see `getChildByRank`).
|
||||||
|
*/
|
||||||
|
abstract PrintASTNode getChild(int childIndex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this node should be printed in the output. By default, all nodes
|
||||||
|
* within a function are printed, but the query can override
|
||||||
|
* `PrintASTConfiguration.shouldPrintFunction` to filter the output.
|
||||||
|
*/
|
||||||
|
final predicate shouldPrint() {
|
||||||
|
shouldPrintFunction(getEnclosingFunction())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the children of this node.
|
||||||
|
*/
|
||||||
|
final PrintASTNode getAChild() {
|
||||||
|
result = getChild(_)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the parent of this node, if any.
|
||||||
|
*/
|
||||||
|
final PrintASTNode getParent() {
|
||||||
|
result.getAChild() = this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the location of this node in the source code.
|
||||||
|
*/
|
||||||
|
abstract Location getLocation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of the property of this node, where the name of the property
|
||||||
|
* is `key`.
|
||||||
|
*/
|
||||||
|
string getProperty(string key) {
|
||||||
|
key = "semmle.label" and
|
||||||
|
result = toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the label for the edge from this node to the specified child. By
|
||||||
|
* default, this is just the index of the child, but subclasses can override
|
||||||
|
* this.
|
||||||
|
*/
|
||||||
|
string getChildEdgeLabel(int childIndex) {
|
||||||
|
exists(getChild(childIndex)) and
|
||||||
|
result = childIndex.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the `Function` that contains this node.
|
||||||
|
*/
|
||||||
|
private Function getEnclosingFunction() {
|
||||||
|
result = getParent*().(FunctionNode).getFunction()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Locatable getChild(Locatable parent, int childIndex) {
|
/**
|
||||||
exists(Function func, Stmt entryPoint |
|
* A node representing an AST node.
|
||||||
parent = func and
|
*/
|
||||||
result = entryPoint and
|
abstract class ASTNode extends PrintASTNode, TASTNode {
|
||||||
entryPoint = func.getEntryPoint() and
|
Locatable ast;
|
||||||
childIndex = getEntryPointIndex(func)
|
|
||||||
) or
|
ASTNode() {
|
||||||
exists(Function func, Expr childExpr |
|
this = TASTNode(ast)
|
||||||
parent = func and
|
}
|
||||||
result = childExpr and
|
|
||||||
|
override string toString() {
|
||||||
|
result = ast.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override final Location getLocation() {
|
||||||
|
result = getRepresentativeLocation(ast)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the AST represented by this node.
|
||||||
|
*/
|
||||||
|
final Locatable getAST() {
|
||||||
|
result = ast
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node representing an `Expr`.
|
||||||
|
*/
|
||||||
|
class ExprNode extends ASTNode {
|
||||||
|
Expr expr;
|
||||||
|
|
||||||
|
ExprNode() {
|
||||||
|
expr = ast
|
||||||
|
}
|
||||||
|
|
||||||
|
override ASTNode getChild(int childIndex) {
|
||||||
|
result.getAST() = expr.getChild(childIndex).getFullyConverted()
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getProperty(string key) {
|
||||||
|
result = super.getProperty(key) or
|
||||||
(
|
(
|
||||||
childExpr = func.(Constructor).getInitializer(childIndex) or
|
key = "Value" and
|
||||||
childExpr = func.(Destructor).getDestruction(childIndex - 1)
|
result = getValue()
|
||||||
)
|
) or
|
||||||
) or
|
|
||||||
exists(Stmt parentStmt |
|
|
||||||
parentStmt = parent and
|
|
||||||
(
|
(
|
||||||
parentStmt.getChild(childIndex).(Expr).getFullyConverted() = result or
|
key = "Type" and
|
||||||
parentStmt.getChild(childIndex).(Stmt) = result
|
result = expr.getType().toString()
|
||||||
|
) or
|
||||||
|
(
|
||||||
|
key = "ValueCategory" and
|
||||||
|
result = expr.getValueCategoryString()
|
||||||
)
|
)
|
||||||
) or
|
}
|
||||||
exists(Expr parentExpr, Expr childExpr |
|
|
||||||
parent = parentExpr and
|
string getValue() {
|
||||||
result = childExpr and
|
result = expr.getValue()
|
||||||
childExpr = parentExpr.getChild(childIndex).getFullyConverted()
|
}
|
||||||
) or
|
|
||||||
exists(Conversion parentConv, Expr childExpr |
|
|
||||||
parent = parentConv and
|
|
||||||
result = childExpr and
|
|
||||||
childExpr = parentConv.getExpr() and
|
|
||||||
childIndex = 0
|
|
||||||
) or
|
|
||||||
exists(DeclStmt declStmt, DeclarationEntry childEntry |
|
|
||||||
parent = declStmt and
|
|
||||||
result = childEntry and
|
|
||||||
childEntry = declStmt.getDeclarationEntry(childIndex)
|
|
||||||
) or
|
|
||||||
exists(VariableDeclarationEntry declEntry, Initializer init |
|
|
||||||
parent = declEntry and
|
|
||||||
result = init and
|
|
||||||
init = declEntry.getVariable().getInitializer() and
|
|
||||||
childIndex = 0
|
|
||||||
) or
|
|
||||||
exists(Initializer init, Expr expr |
|
|
||||||
parent = init and
|
|
||||||
result = expr and
|
|
||||||
expr = init.getExpr().getFullyConverted() and
|
|
||||||
childIndex = 0
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string getTypeString(Locatable ast) {
|
/**
|
||||||
if ast instanceof Expr then (
|
* A node representing a `StringLiteral`.
|
||||||
exists(Expr expr |
|
*/
|
||||||
expr = ast and
|
class StringLiteralNode extends ExprNode {
|
||||||
result = expr.getValueCategoryString() + ": " + expr.getType().toString()
|
StringLiteralNode() {
|
||||||
|
expr instanceof StringLiteral
|
||||||
|
}
|
||||||
|
|
||||||
|
override string toString() {
|
||||||
|
result = escapeString(expr.getValue())
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getValue() {
|
||||||
|
result = "\"" + escapeString(expr.getValue()) + "\""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node representing a `Conversion`.
|
||||||
|
*/
|
||||||
|
class ConversionNode extends ExprNode {
|
||||||
|
Conversion conv;
|
||||||
|
|
||||||
|
ConversionNode() {
|
||||||
|
conv = expr
|
||||||
|
}
|
||||||
|
|
||||||
|
override ASTNode getChild(int childIndex) {
|
||||||
|
childIndex = 0 and
|
||||||
|
result.getAST() = conv.getExpr()
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getChildEdgeLabel(int childIndex) {
|
||||||
|
childIndex = 0 and result = "expr"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node representing a `Cast`.
|
||||||
|
*/
|
||||||
|
class CastNode extends ConversionNode {
|
||||||
|
Cast cast;
|
||||||
|
|
||||||
|
CastNode() {
|
||||||
|
cast = conv
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getProperty(string key) {
|
||||||
|
result = super.getProperty(key) or
|
||||||
|
(
|
||||||
|
key = "Conversion" and
|
||||||
|
result = cast.getSemanticConversionString()
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
else if ast instanceof DeclarationEntry then (
|
|
||||||
result = ast.(DeclarationEntry).getType().toString()
|
|
||||||
)
|
|
||||||
else (
|
|
||||||
result = ""
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string getExtraInfoString(Locatable ast) {
|
/**
|
||||||
if ast instanceof Cast then (
|
* A node representing a `DeclarationEntry`.
|
||||||
result = ast.(Cast).getSemanticConversionString()
|
*/
|
||||||
)
|
class DeclarationEntryNode extends ASTNode {
|
||||||
else (
|
DeclarationEntry entry;
|
||||||
result = ""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private string getValueString(Locatable ast) {
|
DeclarationEntryNode() {
|
||||||
if exists(ast.(Expr).getValue()) then
|
entry = ast
|
||||||
result = "=" + ast.(Expr).getValue()
|
}
|
||||||
else
|
|
||||||
result = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
private Locatable getChildByRank(Locatable parent, int rankIndex) {
|
override PrintASTNode getChild(int childIndex) {
|
||||||
result = rank[rankIndex + 1](Locatable child, int id |
|
none()
|
||||||
child = getChild(parent, id) |
|
}
|
||||||
child order by id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
language[monotonicAggregates]
|
override string getProperty(string key) {
|
||||||
private int getDescendantCount(Locatable ast) {
|
result = super.getProperty(key) or
|
||||||
result = 1 + sum(Locatable child |
|
(
|
||||||
child = getChildByRank(ast, _) |
|
key = "Type" and
|
||||||
getDescendantCount(child)
|
result = entry.getType().toString()
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private Locatable getParent(Locatable ast) {
|
|
||||||
ast = getAChild(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getUniqueId(Locatable ast) {
|
|
||||||
shouldPrintFunction(getEnclosingFunction(ast)) and
|
|
||||||
if not exists(getParent(ast)) then
|
|
||||||
result = 0
|
|
||||||
else
|
|
||||||
exists(Locatable parent |
|
|
||||||
parent = getParent(ast) and
|
|
||||||
if ast = getChildByRank(parent, 0) then
|
|
||||||
result = 1 + getUniqueId(parent)
|
|
||||||
else
|
|
||||||
exists(int childIndex, Locatable previousChild |
|
|
||||||
ast = getChildByRank(parent, childIndex) and
|
|
||||||
previousChild = getChildByRank(parent, childIndex - 1) and
|
|
||||||
result = getUniqueId(previousChild) +
|
|
||||||
getDescendantCount(previousChild)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
query predicate printAST(string functionLocation,
|
/**
|
||||||
string function, int nodeId, int parentId, int childIndex, string ast,
|
* A node representing a `VariableDeclarationEntry`.
|
||||||
string extra, string value, string type, string astLocation) {
|
*/
|
||||||
exists(Function func, Locatable astNode |
|
class VariableDeclarationEntryNode extends DeclarationEntryNode {
|
||||||
shouldPrintFunction(func) and
|
VariableDeclarationEntry varEntry;
|
||||||
func = getEnclosingFunction(astNode) and
|
|
||||||
nodeId = getUniqueId(astNode) and
|
VariableDeclarationEntryNode() {
|
||||||
if nodeId = 0 then (
|
varEntry = entry
|
||||||
parentId = -1 and
|
}
|
||||||
childIndex = 0
|
|
||||||
)
|
override ASTNode getChild(int childIndex) {
|
||||||
else (
|
childIndex = 0 and
|
||||||
exists(Locatable parent |
|
result.getAST() = varEntry.getVariable().getInitializer()
|
||||||
astNode = getChild(parent, childIndex) and
|
}
|
||||||
parentId = getUniqueId(parent)
|
|
||||||
|
override string getChildEdgeLabel(int childIndex) {
|
||||||
|
childIndex = 0 and result = "init"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node representing a `Stmt`.
|
||||||
|
*/
|
||||||
|
class StmtNode extends ASTNode {
|
||||||
|
Stmt stmt;
|
||||||
|
|
||||||
|
StmtNode() {
|
||||||
|
stmt = ast
|
||||||
|
}
|
||||||
|
|
||||||
|
override ASTNode getChild(int childIndex) {
|
||||||
|
exists(Locatable child |
|
||||||
|
child = stmt.getChild(childIndex) and
|
||||||
|
(
|
||||||
|
result.getAST() = child.(Expr).getFullyConverted() or
|
||||||
|
result.getAST() = child.(Stmt)
|
||||||
)
|
)
|
||||||
) and
|
)
|
||||||
functionLocation = func.getLocation().toString() and
|
}
|
||||||
function = func.getFullSignature() and
|
}
|
||||||
ast = astNode.toString() and
|
|
||||||
extra = getExtraInfoString(astNode) and
|
/**
|
||||||
value = getValueString(astNode) and
|
* A node representing a `DeclStmt`.
|
||||||
type = getTypeString(astNode) and
|
*/
|
||||||
astLocation = astNode.getLocation().toString()
|
class DeclStmtNode extends StmtNode {
|
||||||
)
|
DeclStmt declStmt;
|
||||||
|
|
||||||
|
DeclStmtNode() {
|
||||||
|
declStmt = stmt
|
||||||
|
}
|
||||||
|
|
||||||
|
override ASTNode getChild(int childIndex) {
|
||||||
|
result.getAST() = declStmt.getDeclarationEntry(childIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node representing a `Parameter`.
|
||||||
|
*/
|
||||||
|
class ParameterNode extends ASTNode {
|
||||||
|
Parameter param;
|
||||||
|
|
||||||
|
ParameterNode() {
|
||||||
|
param = ast
|
||||||
|
}
|
||||||
|
|
||||||
|
override final PrintASTNode getChild(int childIndex) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
override final string getProperty(string key) {
|
||||||
|
result = super.getProperty(key) or
|
||||||
|
(
|
||||||
|
key = "Type" and
|
||||||
|
result = param.getType().toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node representing an `Initializer`.
|
||||||
|
*/
|
||||||
|
class InitializerNode extends ASTNode {
|
||||||
|
Initializer init;
|
||||||
|
|
||||||
|
InitializerNode() {
|
||||||
|
init = ast
|
||||||
|
}
|
||||||
|
|
||||||
|
override ASTNode getChild(int childIndex) {
|
||||||
|
childIndex = 0 and
|
||||||
|
result.getAST() = init.getExpr().getFullyConverted()
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getChildEdgeLabel(int childIndex) {
|
||||||
|
childIndex = 0 and
|
||||||
|
result = "expr"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node representing the parameters of a `Function`.
|
||||||
|
*/
|
||||||
|
class ParametersNode extends PrintASTNode, TParametersNode {
|
||||||
|
Function func;
|
||||||
|
|
||||||
|
ParametersNode() {
|
||||||
|
this = TParametersNode(func)
|
||||||
|
}
|
||||||
|
|
||||||
|
override final string toString() {
|
||||||
|
result = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
override final Location getLocation() {
|
||||||
|
result = getRepresentativeLocation(func)
|
||||||
|
}
|
||||||
|
|
||||||
|
override ASTNode getChild(int childIndex) {
|
||||||
|
result.getAST() = func.getParameter(childIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
final Function getFunction() {
|
||||||
|
result = func
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node representing the initializer list of a `Constructor`.
|
||||||
|
*/
|
||||||
|
class ConstructorInitializersNode extends PrintASTNode, TConstructorInitializersNode {
|
||||||
|
Constructor ctor;
|
||||||
|
|
||||||
|
ConstructorInitializersNode() {
|
||||||
|
this = TConstructorInitializersNode(ctor)
|
||||||
|
}
|
||||||
|
|
||||||
|
override final string toString() {
|
||||||
|
result = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
override final Location getLocation() {
|
||||||
|
result = getRepresentativeLocation(ctor)
|
||||||
|
}
|
||||||
|
|
||||||
|
override final ASTNode getChild(int childIndex) {
|
||||||
|
result.getAST() = ctor.getInitializer(childIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
final Constructor getConstructor() {
|
||||||
|
result = ctor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node representing the destruction list of a `Destructor`.
|
||||||
|
*/
|
||||||
|
class DestructorDestructionsNode extends PrintASTNode, TDestructorDestructionsNode {
|
||||||
|
Destructor dtor;
|
||||||
|
|
||||||
|
DestructorDestructionsNode() {
|
||||||
|
this = TDestructorDestructionsNode(dtor)
|
||||||
|
}
|
||||||
|
|
||||||
|
override final string toString() {
|
||||||
|
result = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
override final Location getLocation() {
|
||||||
|
result = getRepresentativeLocation(dtor)
|
||||||
|
}
|
||||||
|
|
||||||
|
override final ASTNode getChild(int childIndex) {
|
||||||
|
result.getAST() = dtor.getDestruction(childIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
final Destructor getDestructor() {
|
||||||
|
result = dtor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node representing a `Function`.
|
||||||
|
*/
|
||||||
|
class FunctionNode extends ASTNode {
|
||||||
|
Function func;
|
||||||
|
|
||||||
|
FunctionNode() {
|
||||||
|
func = ast
|
||||||
|
}
|
||||||
|
|
||||||
|
override string toString() {
|
||||||
|
result = func.getFullSignature()
|
||||||
|
}
|
||||||
|
|
||||||
|
override PrintASTNode getChild(int childIndex) {
|
||||||
|
(
|
||||||
|
childIndex = 0 and
|
||||||
|
result.(ParametersNode).getFunction() = func
|
||||||
|
) or
|
||||||
|
(
|
||||||
|
childIndex = 1 and
|
||||||
|
result.(ConstructorInitializersNode).getConstructor() = func
|
||||||
|
) or
|
||||||
|
(
|
||||||
|
childIndex = 2 and
|
||||||
|
result.(ASTNode).getAST() = func.getEntryPoint()
|
||||||
|
) or
|
||||||
|
(
|
||||||
|
childIndex = 3 and
|
||||||
|
result.(DestructorDestructionsNode).getDestructor() = func
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getChildEdgeLabel(int childIndex) {
|
||||||
|
childIndex = 0 and result = "params" or
|
||||||
|
childIndex = 1 and result = "initializations" or
|
||||||
|
childIndex = 2 and result = "body" or
|
||||||
|
childIndex = 3 and result = "destructions"
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getOrder() {
|
||||||
|
this = rank[result](FunctionNode node, Function function, Location loc |
|
||||||
|
node.getAST() = function and loc = getRepresentativeLocation(function) |
|
||||||
|
node order by
|
||||||
|
loc.getFile().toString(),
|
||||||
|
loc.getStartLine(),
|
||||||
|
loc.getStartColumn(),
|
||||||
|
function.getFullSignature()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getProperty(string key) {
|
||||||
|
result = super.getProperty(key) or
|
||||||
|
key = "semmle.order" and result = getOrder().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
final Function getFunction() {
|
||||||
|
result = func
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate nodes(PrintASTNode node, string key, string value) {
|
||||||
|
node.shouldPrint() and
|
||||||
|
value = node.getProperty(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate edges(PrintASTNode source, PrintASTNode target, string key, string value) {
|
||||||
|
exists(int childIndex |
|
||||||
|
source.shouldPrint() and
|
||||||
|
target.shouldPrint() and
|
||||||
|
target = source.getChild(childIndex) and
|
||||||
|
(
|
||||||
|
key = "semmle.label" and value = source.getChildEdgeLabel(childIndex) or
|
||||||
|
key = "semmle.order" and value = childIndex.toString()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate graphProperties(string key, string value) {
|
||||||
|
key = "semmle.graphKind" and value = "tree"
|
||||||
}
|
}
|
||||||
|
|||||||
8
cpp/ql/src/semmle/code/cpp/ir/PrintIR.ql
Normal file
8
cpp/ql/src/semmle/code/cpp/ir/PrintIR.ql
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* @name Print IR
|
||||||
|
* @description Outputs a representation of the IR graph
|
||||||
|
* @id cpp/print-ir
|
||||||
|
* @kind graph
|
||||||
|
*/
|
||||||
|
|
||||||
|
import PrintIR
|
||||||
@@ -1,81 +1,92 @@
|
|||||||
private import IRInternal
|
private import IRInternal
|
||||||
private import IRBlockConstruction
|
private import IRBlockConstruction
|
||||||
import Instruction
|
import Instruction
|
||||||
import semmle.code.cpp.ir.EdgeKind
|
import semmle.code.cpp.ir.EdgeKind
|
||||||
|
|
||||||
class IRBlock extends TIRBlock {
|
class IRBlock extends TIRBlock {
|
||||||
final string toString() {
|
final string toString() {
|
||||||
result = getFirstInstruction(this).toString()
|
result = getFirstInstruction(this).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
final Location getLocation() {
|
final Location getLocation() {
|
||||||
result = getFirstInstruction().getLocation()
|
result = getFirstInstruction().getLocation()
|
||||||
}
|
}
|
||||||
|
|
||||||
final string getUniqueId() {
|
final string getUniqueId() {
|
||||||
result = getFirstInstruction(this).getUniqueId()
|
result = getFirstInstruction(this).getUniqueId()
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getInstruction(int index) {
|
/**
|
||||||
result = getInstruction(this, index)
|
* Gets the zero-based index of the block within its function. This is used
|
||||||
}
|
* by debugging and printing code only.
|
||||||
|
*/
|
||||||
final PhiInstruction getAPhiInstruction() {
|
int getDisplayIndex() {
|
||||||
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
this = rank[result + 1](IRBlock funcBlock |
|
||||||
}
|
funcBlock.getFunction() = getFunction() |
|
||||||
|
funcBlock order by funcBlock.getUniqueId()
|
||||||
final Instruction getAnInstruction() {
|
)
|
||||||
result = getInstruction(_) or
|
}
|
||||||
result = getAPhiInstruction()
|
|
||||||
}
|
final Instruction getInstruction(int index) {
|
||||||
|
result = getInstruction(this, index)
|
||||||
final Instruction getFirstInstruction() {
|
}
|
||||||
result = getFirstInstruction(this)
|
|
||||||
}
|
final PhiInstruction getAPhiInstruction() {
|
||||||
|
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
||||||
final Instruction getLastInstruction() {
|
}
|
||||||
result = getInstruction(getInstructionCount() - 1)
|
|
||||||
}
|
final Instruction getAnInstruction() {
|
||||||
|
result = getInstruction(_) or
|
||||||
final int getInstructionCount() {
|
result = getAPhiInstruction()
|
||||||
result = strictcount(getInstruction(_))
|
}
|
||||||
}
|
|
||||||
|
final Instruction getFirstInstruction() {
|
||||||
final FunctionIR getFunctionIR() {
|
result = getFirstInstruction(this)
|
||||||
result = getFirstInstruction(this).getFunctionIR()
|
}
|
||||||
}
|
|
||||||
|
final Instruction getLastInstruction() {
|
||||||
final Function getFunction() {
|
result = getInstruction(getInstructionCount() - 1)
|
||||||
result = getFirstInstruction(this).getFunction()
|
}
|
||||||
}
|
|
||||||
|
final int getInstructionCount() {
|
||||||
final IRBlock getASuccessor() {
|
result = strictcount(getInstruction(_))
|
||||||
blockSuccessor(this, result)
|
}
|
||||||
}
|
|
||||||
|
final FunctionIR getFunctionIR() {
|
||||||
final IRBlock getAPredecessor() {
|
result = getFirstInstruction(this).getFunctionIR()
|
||||||
blockSuccessor(result, this)
|
}
|
||||||
}
|
|
||||||
|
final Function getFunction() {
|
||||||
final IRBlock getSuccessor(EdgeKind kind) {
|
result = getFirstInstruction(this).getFunction()
|
||||||
blockSuccessor(this, result, kind)
|
}
|
||||||
}
|
|
||||||
|
final IRBlock getASuccessor() {
|
||||||
final predicate immediatelyDominates(IRBlock block) {
|
blockSuccessor(this, result)
|
||||||
blockImmediatelyDominates(this, block)
|
}
|
||||||
}
|
|
||||||
|
final IRBlock getAPredecessor() {
|
||||||
final predicate strictlyDominates(IRBlock block) {
|
blockSuccessor(result, this)
|
||||||
blockImmediatelyDominates+(this, block)
|
}
|
||||||
}
|
|
||||||
|
final IRBlock getSuccessor(EdgeKind kind) {
|
||||||
final predicate dominates(IRBlock block) {
|
blockSuccessor(this, result, kind)
|
||||||
strictlyDominates(block) or this = block
|
}
|
||||||
}
|
|
||||||
|
final predicate immediatelyDominates(IRBlock block) {
|
||||||
pragma[noinline]
|
blockImmediatelyDominates(this, block)
|
||||||
final IRBlock dominanceFrontier() {
|
}
|
||||||
dominates(result.getAPredecessor()) and
|
|
||||||
not strictlyDominates(result)
|
final predicate strictlyDominates(IRBlock block) {
|
||||||
}
|
blockImmediatelyDominates+(this, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final predicate dominates(IRBlock block) {
|
||||||
|
strictlyDominates(block) or this = block
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
final IRBlock dominanceFrontier() {
|
||||||
|
dominates(result.getAPredecessor()) and
|
||||||
|
not strictlyDominates(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -90,8 +90,132 @@ class Instruction extends Construction::TInstruction {
|
|||||||
this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
|
this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
|
||||||
}
|
}
|
||||||
|
|
||||||
string toString() {
|
final string toString() {
|
||||||
result = opcode.toString()
|
result = getResultString() + " = " + getOperationString() + " " + getOperandsString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string describing the operation of this instruction. This includes
|
||||||
|
* the opcode and the immediate value, if any. For example:
|
||||||
|
*
|
||||||
|
* VariableAddress[x]
|
||||||
|
*/
|
||||||
|
final string getOperationString() {
|
||||||
|
if exists(getImmediateString()) then
|
||||||
|
result = opcode.toString() + "[" + getImmediateString() + "]"
|
||||||
|
else
|
||||||
|
result = opcode.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string describing the immediate value of this instruction, if any.
|
||||||
|
*/
|
||||||
|
string getImmediateString() {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
private string getResultPrefix() {
|
||||||
|
if resultType instanceof VoidType then
|
||||||
|
result = "v"
|
||||||
|
else if hasMemoryResult() then
|
||||||
|
if isResultModeled() then
|
||||||
|
result = "m"
|
||||||
|
else
|
||||||
|
result = "mu"
|
||||||
|
else
|
||||||
|
result = "r"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the zero-based index of this instruction within its block. This is
|
||||||
|
* used by debugging and printing code only.
|
||||||
|
*/
|
||||||
|
int getDisplayIndexInBlock() {
|
||||||
|
exists(IRBlock block |
|
||||||
|
block = getBlock() and
|
||||||
|
(
|
||||||
|
exists(int index, int phiCount |
|
||||||
|
phiCount = count(block.getAPhiInstruction()) and
|
||||||
|
this = block.getInstruction(index) and
|
||||||
|
result = index + phiCount
|
||||||
|
) or
|
||||||
|
(
|
||||||
|
this instanceof PhiInstruction and
|
||||||
|
this = rank[result + 1](PhiInstruction phiInstr |
|
||||||
|
phiInstr = block.getAPhiInstruction() |
|
||||||
|
phiInstr order by phiInstr.getUniqueId()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[type]
|
||||||
|
private string getValueCategoryString(string type) {
|
||||||
|
if isGLValue() then
|
||||||
|
result = "glval<" + type + ">"
|
||||||
|
else
|
||||||
|
result = type
|
||||||
|
}
|
||||||
|
|
||||||
|
private string getResultTypeString() {
|
||||||
|
exists(string valcat |
|
||||||
|
valcat = getValueCategoryString(resultType.toString()) and
|
||||||
|
if resultType instanceof UnknownType and exists(getResultSize()) then
|
||||||
|
result = valcat + "[" + getResultSize().toString() + "]"
|
||||||
|
else
|
||||||
|
result = valcat
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a human-readable string that uniquely identifies this instruction
|
||||||
|
* within the function. This string is used to refer to this instruction when
|
||||||
|
* printing IR dumps.
|
||||||
|
*
|
||||||
|
* Example: `r1_1`
|
||||||
|
*/
|
||||||
|
string getResultId() {
|
||||||
|
result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
|
||||||
|
getDisplayIndexInBlock().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string describing the result of this instruction, suitable for
|
||||||
|
* display in IR dumps. This consists of the result ID plus the type of the
|
||||||
|
* result.
|
||||||
|
*
|
||||||
|
* Example: `r1_1(int*)`
|
||||||
|
*/
|
||||||
|
final string getResultString() {
|
||||||
|
result = getResultId() + "(" + getResultTypeString() + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string describing the specified 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 kind.
|
||||||
|
*
|
||||||
|
* For example: `this:r3_5`
|
||||||
|
*/
|
||||||
|
string getOperandString(OperandTag tag) {
|
||||||
|
exists(Instruction operand |
|
||||||
|
operand = getOperand(tag) and
|
||||||
|
result = tag.getLabel() + operand.getResultId()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string describing the operands of this instruction, suitable for
|
||||||
|
* display in IR dumps.
|
||||||
|
*
|
||||||
|
* Example: `func:r3_4, this:r3_5`
|
||||||
|
*/
|
||||||
|
string getOperandsString() {
|
||||||
|
result = concat(OperandTag tag, Instruction operand |
|
||||||
|
operand = getOperand(tag) |
|
||||||
|
tag.getLabel() + operand.getResultId(), ", " order by tag.getSortOrder()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -312,8 +436,8 @@ class VariableInstruction extends Instruction {
|
|||||||
var = Construction::getInstructionVariable(this)
|
var = Construction::getInstructionVariable(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + var.toString() + "]"
|
result = var.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
final IRVariable getVariable() {
|
final IRVariable getVariable() {
|
||||||
@@ -328,8 +452,8 @@ class FieldInstruction extends Instruction {
|
|||||||
field = Construction::getInstructionField(this)
|
field = Construction::getInstructionField(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + field.toString() + "]"
|
result = field.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
final Field getField() {
|
final Field getField() {
|
||||||
@@ -344,8 +468,8 @@ class FunctionInstruction extends Instruction {
|
|||||||
funcSymbol = Construction::getInstructionFunction(this)
|
funcSymbol = Construction::getInstructionFunction(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + funcSymbol.toString() + "]"
|
result = funcSymbol.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
final Function getFunctionSymbol() {
|
final Function getFunctionSymbol() {
|
||||||
@@ -360,8 +484,8 @@ class ConstantValueInstruction extends Instruction {
|
|||||||
value = Construction::getInstructionConstantValue(this)
|
value = Construction::getInstructionConstantValue(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + value + "]"
|
result = value
|
||||||
}
|
}
|
||||||
|
|
||||||
final string getValue() {
|
final string getValue() {
|
||||||
@@ -534,10 +658,8 @@ class StringConstantInstruction extends Instruction {
|
|||||||
value = Construction::getInstructionStringLiteral(this)
|
value = Construction::getInstructionStringLiteral(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" +
|
result = value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ")
|
||||||
value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ") +
|
|
||||||
"]"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final StringLiteral getValue() {
|
final StringLiteral getValue() {
|
||||||
@@ -627,8 +749,8 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
|||||||
elementSize = Construction::getInstructionElementSize(this)
|
elementSize = Construction::getInstructionElementSize(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + elementSize.toString() + "]"
|
result = elementSize.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
final int getElementSize() {
|
final int getElementSize() {
|
||||||
@@ -688,8 +810,8 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
|||||||
Construction::getInstructionInheritance(this, baseClass, derivedClass)
|
Construction::getInstructionInheritance(this, baseClass, derivedClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + derivedClass.toString() + " : " + baseClass.toString() + "]"
|
result = derivedClass.toString() + " : " + baseClass.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -908,8 +1030,8 @@ class CatchByTypeInstruction extends CatchInstruction {
|
|||||||
exceptionType = Construction::getInstructionExceptionType(this)
|
exceptionType = Construction::getInstructionExceptionType(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
final override string toString() {
|
final override string getImmediateString() {
|
||||||
result = super.toString() + "[" + exceptionType.toString() + "]"
|
result = exceptionType.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -944,6 +1066,10 @@ class UnmodeledUseInstruction extends Instruction {
|
|||||||
opcode instanceof Opcode::UnmodeledUse
|
opcode instanceof Opcode::UnmodeledUse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override string getOperandsString() {
|
||||||
|
result = "mu*"
|
||||||
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||||
tag instanceof UnmodeledUseOperand and
|
tag instanceof UnmodeledUseOperand and
|
||||||
result instanceof UnmodeledMemoryAccess
|
result instanceof UnmodeledMemoryAccess
|
||||||
|
|||||||
@@ -1,299 +1,312 @@
|
|||||||
private import IRInternal
|
private import IRInternal
|
||||||
import Instruction
|
import Instruction
|
||||||
import IRBlock
|
import IRBlock
|
||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
private newtype TOperandTag =
|
private newtype TOperandTag =
|
||||||
TLoadStoreAddressOperand() or
|
TLoadStoreAddressOperand() or
|
||||||
TCopySourceOperand() or
|
TCopySourceOperand() or
|
||||||
TUnaryOperand() or
|
TUnaryOperand() or
|
||||||
TLeftOperand() or
|
TLeftOperand() or
|
||||||
TRightOperand() or
|
TRightOperand() or
|
||||||
TReturnValueOperand() or
|
TReturnValueOperand() or
|
||||||
TExceptionOperand() or
|
TExceptionOperand() or
|
||||||
TConditionOperand() or
|
TConditionOperand() or
|
||||||
TUnmodeledUseOperand() or
|
TUnmodeledUseOperand() or
|
||||||
TCallTargetOperand() or
|
TCallTargetOperand() or
|
||||||
TThisArgumentOperand() or
|
TThisArgumentOperand() or
|
||||||
TPositionalArgumentOperand(int argIndex) {
|
TPositionalArgumentOperand(int argIndex) {
|
||||||
argIndex in [0..Construction::getMaxCallArgIndex()] or
|
argIndex in [0..Construction::getMaxCallArgIndex()] or
|
||||||
exists(BuiltInOperation op |
|
exists(BuiltInOperation op |
|
||||||
exists(op.getChild(argIndex))
|
exists(op.getChild(argIndex))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPhiOperand(IRBlock predecessorBlock) {
|
TPhiOperand(IRBlock predecessorBlock) {
|
||||||
exists(PhiInstruction phi |
|
exists(PhiInstruction phi |
|
||||||
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
|
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||||
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
||||||
* an `Instruction` is determined by the instruction's opcode.
|
* an `Instruction` is determined by the instruction's opcode.
|
||||||
*/
|
*/
|
||||||
abstract class OperandTag extends TOperandTag {
|
abstract class OperandTag extends TOperandTag {
|
||||||
abstract string toString();
|
abstract string toString();
|
||||||
abstract int getSortOrder();
|
|
||||||
}
|
abstract int getSortOrder();
|
||||||
|
|
||||||
// Note: individual subtypes are listed in the order that the operands should
|
string getLabel() {
|
||||||
// appear in the operand list of the instruction when printing.
|
result = ""
|
||||||
|
}
|
||||||
/**
|
}
|
||||||
* The address operand of an instruction that loads or stores a value from
|
|
||||||
* memory (e.g. `Load`, `Store`).
|
// Note: individual subtypes are listed in the order that the operands should
|
||||||
*/
|
// appear in the operand list of the instruction when printing.
|
||||||
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
|
|
||||||
override final string toString() {
|
/**
|
||||||
result = "LoadStoreAddress"
|
* The address operand of an instruction that loads or stores a value from
|
||||||
}
|
* memory (e.g. `Load`, `Store`).
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
|
||||||
result = 0
|
override final string toString() {
|
||||||
}
|
result = "LoadStoreAddress"
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadStoreAddressOperand loadStoreAddressOperand() {
|
override final int getSortOrder() {
|
||||||
result = TLoadStoreAddressOperand()
|
result = 0
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The source value operand of an instruction that copies this value to its
|
LoadStoreAddressOperand loadStoreAddressOperand() {
|
||||||
* result (e.g. `Copy`, `Load`, `Store`).
|
result = TLoadStoreAddressOperand()
|
||||||
*/
|
}
|
||||||
class CopySourceOperand extends OperandTag, TCopySourceOperand {
|
|
||||||
override final string toString() {
|
/**
|
||||||
result = "CopySource"
|
* The source value operand of an instruction that copies this value to its
|
||||||
}
|
* result (e.g. `Copy`, `Load`, `Store`).
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class CopySourceOperand extends OperandTag, TCopySourceOperand {
|
||||||
result = 1
|
override final string toString() {
|
||||||
}
|
result = "CopySource"
|
||||||
}
|
}
|
||||||
|
|
||||||
CopySourceOperand copySourceOperand() {
|
override final int getSortOrder() {
|
||||||
result = TCopySourceOperand()
|
result = 1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
CopySourceOperand copySourceOperand() {
|
||||||
*/
|
result = TCopySourceOperand()
|
||||||
class UnaryOperand extends OperandTag, TUnaryOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "Unary"
|
/**
|
||||||
}
|
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class UnaryOperand extends OperandTag, TUnaryOperand {
|
||||||
result = 2
|
override final string toString() {
|
||||||
}
|
result = "Unary"
|
||||||
}
|
}
|
||||||
|
|
||||||
UnaryOperand unaryOperand() {
|
override final int getSortOrder() {
|
||||||
result = TUnaryOperand()
|
result = 2
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
UnaryOperand unaryOperand() {
|
||||||
*/
|
result = TUnaryOperand()
|
||||||
class LeftOperand extends OperandTag, TLeftOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "Left"
|
/**
|
||||||
}
|
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class LeftOperand extends OperandTag, TLeftOperand {
|
||||||
result = 3
|
override final string toString() {
|
||||||
}
|
result = "Left"
|
||||||
}
|
}
|
||||||
|
|
||||||
LeftOperand leftOperand() {
|
override final int getSortOrder() {
|
||||||
result = TLeftOperand()
|
result = 3
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
LeftOperand leftOperand() {
|
||||||
*/
|
result = TLeftOperand()
|
||||||
class RightOperand extends OperandTag, TRightOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "Right"
|
/**
|
||||||
}
|
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class RightOperand extends OperandTag, TRightOperand {
|
||||||
result = 4
|
override final string toString() {
|
||||||
}
|
result = "Right"
|
||||||
}
|
}
|
||||||
|
|
||||||
RightOperand rightOperand() {
|
override final int getSortOrder() {
|
||||||
result = TRightOperand()
|
result = 4
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The return value operand of a `ReturnValue` instruction.
|
RightOperand rightOperand() {
|
||||||
*/
|
result = TRightOperand()
|
||||||
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "ReturnValue"
|
/**
|
||||||
}
|
* The return value operand of a `ReturnValue` instruction.
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
|
||||||
result = 5
|
override final string toString() {
|
||||||
}
|
result = "ReturnValue"
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValueOperand returnValueOperand() {
|
override final int getSortOrder() {
|
||||||
result = TReturnValueOperand()
|
result = 5
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The exception thrown by a `ThrowValue` instruction.
|
ReturnValueOperand returnValueOperand() {
|
||||||
*/
|
result = TReturnValueOperand()
|
||||||
class ExceptionOperand extends OperandTag, TExceptionOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "Exception"
|
/**
|
||||||
}
|
* The exception thrown by a `ThrowValue` instruction.
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class ExceptionOperand extends OperandTag, TExceptionOperand {
|
||||||
result = 6
|
override final string toString() {
|
||||||
}
|
result = "Exception"
|
||||||
}
|
}
|
||||||
|
|
||||||
ExceptionOperand exceptionOperand() {
|
override final int getSortOrder() {
|
||||||
result = TExceptionOperand()
|
result = 6
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
ExceptionOperand exceptionOperand() {
|
||||||
*/
|
result = TExceptionOperand()
|
||||||
class ConditionOperand extends OperandTag, TConditionOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "Condition"
|
/**
|
||||||
}
|
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class ConditionOperand extends OperandTag, TConditionOperand {
|
||||||
result = 7
|
override final string toString() {
|
||||||
}
|
result = "Condition"
|
||||||
}
|
}
|
||||||
|
|
||||||
ConditionOperand conditionOperand() {
|
override final int getSortOrder() {
|
||||||
result = TConditionOperand()
|
result = 7
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
ConditionOperand conditionOperand() {
|
||||||
* whose set of uses is unknown.
|
result = TConditionOperand()
|
||||||
*/
|
}
|
||||||
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
|
|
||||||
override final string toString() {
|
/**
|
||||||
result = "UnmodeledUse"
|
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||||
}
|
* whose set of uses is unknown.
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
|
||||||
result = 8
|
override final string toString() {
|
||||||
}
|
result = "UnmodeledUse"
|
||||||
}
|
}
|
||||||
|
|
||||||
UnmodeledUseOperand unmodeledUseOperand() {
|
override final int getSortOrder() {
|
||||||
result = TUnmodeledUseOperand()
|
result = 8
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The operand representing the target function of an `Invoke` instruction.
|
UnmodeledUseOperand unmodeledUseOperand() {
|
||||||
*/
|
result = TUnmodeledUseOperand()
|
||||||
class CallTargetOperand extends OperandTag, TCallTargetOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "CallTarget"
|
/**
|
||||||
}
|
* The operand representing the target function of an `Invoke` instruction.
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class CallTargetOperand extends OperandTag, TCallTargetOperand {
|
||||||
result = 9
|
override final string toString() {
|
||||||
}
|
result = "CallTarget"
|
||||||
}
|
}
|
||||||
|
|
||||||
CallTargetOperand callTargetOperand() {
|
override final int getSortOrder() {
|
||||||
result = TCallTargetOperand()
|
result = 9
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* An operand representing an argument to a function call. This includes both
|
CallTargetOperand callTargetOperand() {
|
||||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
result = TCallTargetOperand()
|
||||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
}
|
||||||
*/
|
|
||||||
abstract class ArgumentOperand extends OperandTag {
|
/**
|
||||||
}
|
* An operand representing an argument to a function call. This includes both
|
||||||
|
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||||
/**
|
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||||
* An operand representing the implicit 'this' argument to a member function
|
*/
|
||||||
* call.
|
abstract class ArgumentOperand extends OperandTag {
|
||||||
*/
|
}
|
||||||
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
|
|
||||||
ThisArgumentOperand() {
|
/**
|
||||||
this = TThisArgumentOperand()
|
* An operand representing the implicit 'this' argument to a member function
|
||||||
}
|
* call.
|
||||||
|
*/
|
||||||
override final string toString() {
|
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
|
||||||
result = "Arg(this)"
|
ThisArgumentOperand() {
|
||||||
}
|
this = TThisArgumentOperand()
|
||||||
|
}
|
||||||
override final int getSortOrder() {
|
|
||||||
result = 10
|
override final string toString() {
|
||||||
}
|
result = "Arg(this)"
|
||||||
}
|
}
|
||||||
|
|
||||||
ThisArgumentOperand thisArgumentOperand() {
|
override final int getSortOrder() {
|
||||||
result = TThisArgumentOperand()
|
result = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override final string getLabel() {
|
||||||
* An operand representing an argument to a function call.
|
result = "this:"
|
||||||
*/
|
}
|
||||||
class PositionalArgumentOperand extends ArgumentOperand,
|
}
|
||||||
TPositionalArgumentOperand {
|
|
||||||
int argIndex;
|
ThisArgumentOperand thisArgumentOperand() {
|
||||||
|
result = TThisArgumentOperand()
|
||||||
PositionalArgumentOperand() {
|
}
|
||||||
this = TPositionalArgumentOperand(argIndex)
|
|
||||||
}
|
/**
|
||||||
|
* An operand representing an argument to a function call.
|
||||||
override final string toString() {
|
*/
|
||||||
result = "Arg(" + argIndex + ")"
|
class PositionalArgumentOperand extends ArgumentOperand,
|
||||||
}
|
TPositionalArgumentOperand {
|
||||||
|
int argIndex;
|
||||||
override final int getSortOrder() {
|
|
||||||
result = 11 + argIndex
|
PositionalArgumentOperand() {
|
||||||
}
|
this = TPositionalArgumentOperand(argIndex)
|
||||||
|
}
|
||||||
final int getArgIndex() {
|
|
||||||
result = argIndex
|
override final string toString() {
|
||||||
}
|
result = "Arg(" + argIndex + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
|
override final int getSortOrder() {
|
||||||
result = TPositionalArgumentOperand(argIndex)
|
result = 11 + argIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
final int getArgIndex() {
|
||||||
* An operand of an SSA `Phi` instruction.
|
result = argIndex
|
||||||
*/
|
}
|
||||||
class PhiOperand extends OperandTag, TPhiOperand {
|
}
|
||||||
IRBlock predecessorBlock;
|
|
||||||
|
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
|
||||||
PhiOperand() {
|
result = TPositionalArgumentOperand(argIndex)
|
||||||
this = TPhiOperand(predecessorBlock)
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
override final string toString() {
|
* An operand of an SSA `Phi` instruction.
|
||||||
result = "Phi"
|
*/
|
||||||
}
|
class PhiOperand extends OperandTag, TPhiOperand {
|
||||||
|
IRBlock predecessorBlock;
|
||||||
override final int getSortOrder() {
|
|
||||||
result = 11
|
PhiOperand() {
|
||||||
}
|
this = TPhiOperand(predecessorBlock)
|
||||||
|
}
|
||||||
final IRBlock getPredecessorBlock() {
|
|
||||||
result = predecessorBlock
|
override final string toString() {
|
||||||
}
|
result = "Phi"
|
||||||
}
|
}
|
||||||
|
|
||||||
PhiOperand phiOperand(IRBlock predecessorBlock) {
|
override final int getSortOrder() {
|
||||||
result = TPhiOperand(predecessorBlock)
|
result = 11 + getPredecessorBlock().getDisplayIndex()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override final string getLabel() {
|
||||||
|
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||||
|
}
|
||||||
|
|
||||||
|
final IRBlock getPredecessorBlock() {
|
||||||
|
result = predecessorBlock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PhiOperand phiOperand(IRBlock predecessorBlock) {
|
||||||
|
result = TPhiOperand(predecessorBlock)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,175 +1,239 @@
|
|||||||
private import IRImpl
|
private import IRImpl
|
||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
private int getInstructionIndexInBlock(Instruction instr) {
|
private newtype TPrintableIRNode =
|
||||||
exists(IRBlock block |
|
TPrintableFunctionIR(FunctionIR funcIR) or
|
||||||
block = instr.getBlock() and
|
TPrintableIRBlock(IRBlock block) or
|
||||||
|
TPrintableInstruction(Instruction instr)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node to be emitted in the IR graph.
|
||||||
|
*/
|
||||||
|
abstract class PrintableIRNode extends TPrintableIRNode {
|
||||||
|
abstract string toString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the location to be emitted for the node.
|
||||||
|
*/
|
||||||
|
abstract Location getLocation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the label to be emitted for the node.
|
||||||
|
*/
|
||||||
|
abstract string getLabel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the order in which the node appears in its parent node.
|
||||||
|
*/
|
||||||
|
abstract int getOrder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the parent of this node.
|
||||||
|
*/
|
||||||
|
abstract PrintableIRNode getParent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the kind of graph represented by this node ("graph" or "tree").
|
||||||
|
*/
|
||||||
|
string getGraphKind() {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this node should always be rendered as text, even in a graphical
|
||||||
|
* viewer.
|
||||||
|
*/
|
||||||
|
predicate forceText() {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of the node property with the specified key.
|
||||||
|
*/
|
||||||
|
string getProperty(string key) {
|
||||||
|
key = "semmle.label" and result = getLabel() or
|
||||||
|
key = "semmle.order" and result = getOrder().toString() or
|
||||||
|
key = "semmle.graphKind" and result = getGraphKind() or
|
||||||
|
key = "semmle.forceText" and forceText() and result = "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An IR graph node representing a `FunctionIR` object.
|
||||||
|
*/
|
||||||
|
class PrintableFunctionIR extends PrintableIRNode, TPrintableFunctionIR {
|
||||||
|
FunctionIR funcIR;
|
||||||
|
|
||||||
|
PrintableFunctionIR() {
|
||||||
|
this = TPrintableFunctionIR(funcIR)
|
||||||
|
}
|
||||||
|
|
||||||
|
override string toString() {
|
||||||
|
result = funcIR.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Location getLocation() {
|
||||||
|
result = funcIR.getLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getLabel() {
|
||||||
|
result = funcIR.getFunction().getFullSignature()
|
||||||
|
}
|
||||||
|
|
||||||
|
override int getOrder() {
|
||||||
|
this = rank[result + 1](PrintableFunctionIR orderedFunc, Location location |
|
||||||
|
location = orderedFunc.getFunctionIR().getLocation() |
|
||||||
|
orderedFunc order by location.getFile().getURL(), location.getStartLine(),
|
||||||
|
location.getStartColumn(), orderedFunc.getLabel()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override final PrintableIRNode getParent() {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
final FunctionIR getFunctionIR() {
|
||||||
|
result = funcIR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An IR graph node representing an `IRBlock` object.
|
||||||
|
*/
|
||||||
|
class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
||||||
|
IRBlock block;
|
||||||
|
|
||||||
|
PrintableIRBlock() {
|
||||||
|
this = TPrintableIRBlock(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
override string toString() {
|
||||||
|
result = getLabel()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Location getLocation() {
|
||||||
|
result = block.getLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getLabel() {
|
||||||
|
result = "Block " + block.getDisplayIndex().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override int getOrder() {
|
||||||
|
result = block.getDisplayIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
override final string getGraphKind() {
|
||||||
|
result = "tree"
|
||||||
|
}
|
||||||
|
|
||||||
|
override final predicate forceText() {
|
||||||
|
any()
|
||||||
|
}
|
||||||
|
|
||||||
|
override final PrintableFunctionIR getParent() {
|
||||||
|
result.getFunctionIR() = block.getFunctionIR()
|
||||||
|
}
|
||||||
|
|
||||||
|
final IRBlock getBlock() {
|
||||||
|
result = block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An IR graph node representing an `Instruction`.
|
||||||
|
*/
|
||||||
|
class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
|
||||||
|
Instruction instr;
|
||||||
|
|
||||||
|
PrintableInstruction() {
|
||||||
|
this = TPrintableInstruction(instr)
|
||||||
|
}
|
||||||
|
|
||||||
|
override string toString() {
|
||||||
|
result = instr.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Location getLocation() {
|
||||||
|
result = instr.getLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getLabel() {
|
||||||
|
exists(IRBlock block |
|
||||||
|
instr = block.getAnInstruction() and
|
||||||
|
exists(string resultString, string operationString, string operandsString,
|
||||||
|
int resultWidth, int operationWidth |
|
||||||
|
resultString = instr.getResultString() and
|
||||||
|
operationString = instr.getOperationString() and
|
||||||
|
operandsString = instr.getOperandsString() and
|
||||||
|
columnWidths(block, resultWidth, operationWidth) and
|
||||||
|
result = resultString + getPaddingString(resultWidth - resultString.length()) +
|
||||||
|
" = " + operationString + getPaddingString(operationWidth - operationString.length()) +
|
||||||
|
" : " + operandsString
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override int getOrder() {
|
||||||
|
result = instr.getDisplayIndexInBlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
override final PrintableIRBlock getParent() {
|
||||||
|
result.getBlock() = instr.getBlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
final Instruction getInstruction() {
|
||||||
|
result = instr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {
|
||||||
|
resultWidth = max(Instruction instr | instr.getBlock() = block | instr.getResultString().length()) and
|
||||||
|
operationWidth = max(Instruction instr | instr.getBlock() = block | instr.getOperationString().length())
|
||||||
|
}
|
||||||
|
|
||||||
|
private int maxColumnWidth() {
|
||||||
|
result = max(Instruction instr, int width |
|
||||||
|
width = instr.getResultString().length() or
|
||||||
|
width = instr.getOperationString().length() or
|
||||||
|
width = instr.getOperandsString().length() |
|
||||||
|
width)
|
||||||
|
}
|
||||||
|
|
||||||
|
private string getPaddingString(int n) {
|
||||||
|
n = 0 and result = "" or
|
||||||
|
n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " "
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate nodes(PrintableIRNode node, string key, string value) {
|
||||||
|
value = node.getProperty(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getSuccessorIndex(IRBlock pred, IRBlock succ) {
|
||||||
|
succ = rank[result + 1](IRBlock aSucc, EdgeKind kind |
|
||||||
|
aSucc = pred.getSuccessor(kind) |
|
||||||
|
aSucc order by kind.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) {
|
||||||
|
exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock |
|
||||||
|
predBlock = pred.getBlock() and
|
||||||
|
succBlock = succ.getBlock() and
|
||||||
|
predBlock.getSuccessor(kind) = succBlock and
|
||||||
(
|
(
|
||||||
exists(int index, int phiCount |
|
(
|
||||||
phiCount = count(block.getAPhiInstruction()) and
|
key = "semmle.label" and
|
||||||
instr = block.getInstruction(index) and
|
value = kind.toString()
|
||||||
result = index + phiCount
|
|
||||||
) or
|
) or
|
||||||
(
|
(
|
||||||
instr instanceof PhiInstruction and
|
key = "semmle.order" and
|
||||||
instr = rank[result + 1](PhiInstruction phiInstr |
|
value = getSuccessorIndex(predBlock, succBlock).toString()
|
||||||
phiInstr = block.getAPhiInstruction() |
|
|
||||||
phiInstr order by phiInstr.getUniqueId()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private string getInstructionResultId(Instruction instr) {
|
query predicate parents(PrintableIRNode child, PrintableIRNode parent) {
|
||||||
result = getResultPrefix(instr) + getBlockId(instr.getBlock()) + "_" +
|
parent = child.getParent()
|
||||||
getInstructionIndexInBlock(instr).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
private string getResultPrefix(Instruction instr) {
|
|
||||||
if instr.hasMemoryResult() then
|
|
||||||
if instr.isResultModeled() then
|
|
||||||
result = "@m"
|
|
||||||
else
|
|
||||||
result = "@mu"
|
|
||||||
else
|
|
||||||
result = "@r"
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the identifier of the specified function scope.
|
|
||||||
* Currently just returns the signature of the function.
|
|
||||||
*/
|
|
||||||
private string getScopeId(Function func) {
|
|
||||||
result = func.getFullSignature()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the unique identifier of the block within its function.
|
|
||||||
* Currently returns a string representation of an integer in the range
|
|
||||||
* [0..numBlocks - 1].
|
|
||||||
*/
|
|
||||||
private string getBlockId(IRBlock block) {
|
|
||||||
exists(int rankIndex |
|
|
||||||
block = rank[rankIndex + 1](IRBlock funcBlock |
|
|
||||||
funcBlock.getFunction() = block.getFunction() |
|
|
||||||
funcBlock order by funcBlock.getUniqueId()
|
|
||||||
) and
|
|
||||||
result = rankIndex.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints the full signature and qualified name for each scope. This is primarily
|
|
||||||
* so that post-processing tools can identify function overloads, which will have
|
|
||||||
* different signatures but the same qualified name.
|
|
||||||
*/
|
|
||||||
query predicate printIRGraphScopes(string scopeId, string qualifiedName) {
|
|
||||||
exists(FunctionIR ir, Function func |
|
|
||||||
func = ir.getFunction() and
|
|
||||||
scopeId = getScopeId(func) and
|
|
||||||
qualifiedName = func.getQualifiedName()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
query predicate printIRGraphNodes(string scopeId, string blockId, string label, string location) {
|
|
||||||
exists(IRBlock block |
|
|
||||||
scopeId = getScopeId(block.getFunction()) and
|
|
||||||
blockId = getBlockId(block) and
|
|
||||||
label = "" and
|
|
||||||
location = ""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
query predicate printIRGraphInstructions(string scopeId, string blockId,
|
|
||||||
string id, string label, string location) {
|
|
||||||
exists(IRBlock block, Instruction instr |
|
|
||||||
instr = block.getAnInstruction() and
|
|
||||||
label = instr.toString() and
|
|
||||||
location = instr.getLocation().toString() and
|
|
||||||
scopeId = getScopeId(block.getFunction()) and
|
|
||||||
blockId = getBlockId(block) and
|
|
||||||
id = getInstructionIndexInBlock(instr).toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
query predicate printIRGraphEdges(string scopeId,
|
|
||||||
string predecessorId, string successorId, string label) {
|
|
||||||
exists(IRBlock predecessor, IRBlock successor, EdgeKind kind |
|
|
||||||
scopeId = getScopeId(predecessor.getFunction()) and
|
|
||||||
predecessor.getSuccessor(kind) = successor and
|
|
||||||
predecessorId = getBlockId(predecessor) and
|
|
||||||
successorId = getBlockId(successor) and
|
|
||||||
label = kind.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private string getValueCategoryString(Instruction instr) {
|
|
||||||
if instr.isGLValue() then
|
|
||||||
result = "glval:"
|
|
||||||
else
|
|
||||||
result = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
private string getResultTypeString(Instruction instr) {
|
|
||||||
exists(Type resultType, string valcat |
|
|
||||||
resultType = instr.getResultType() and
|
|
||||||
valcat = getValueCategoryString(instr) and
|
|
||||||
if resultType instanceof UnknownType and exists(instr.getResultSize()) then
|
|
||||||
result = valcat + resultType.toString() + "[" + instr.getResultSize().toString() + "]"
|
|
||||||
else
|
|
||||||
result = valcat + resultType.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
query predicate printIRGraphDestinationOperands(string scopeId, string blockId,
|
|
||||||
string instructionId, int operandId, string label) {
|
|
||||||
exists(IRBlock block, Instruction instr |
|
|
||||||
block.getAnInstruction() = instr and
|
|
||||||
scopeId = getScopeId(block.getFunction()) and
|
|
||||||
blockId = getBlockId(block) and
|
|
||||||
instructionId = getInstructionIndexInBlock(instr).toString() and
|
|
||||||
not instr.getResultType() instanceof VoidType and
|
|
||||||
operandId = 0 and
|
|
||||||
label = getInstructionResultId(instr) +
|
|
||||||
"(" + getResultTypeString(instr) + ")"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private string getOperandTagLabel(OperandTag tag) {
|
|
||||||
(
|
|
||||||
tag instanceof PhiOperand and
|
|
||||||
result = "from " + getBlockId(tag.(PhiOperand).getPredecessorBlock()) + ": "
|
|
||||||
)
|
|
||||||
or (
|
|
||||||
tag instanceof ThisArgumentOperand and
|
|
||||||
result = "this:"
|
|
||||||
)
|
|
||||||
or (
|
|
||||||
not tag instanceof PhiOperand and
|
|
||||||
not tag instanceof ThisArgumentOperand and
|
|
||||||
result = ""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
query predicate printIRGraphSourceOperands(string scopeId, string blockId,
|
|
||||||
string instructionId, int operandId, string label) {
|
|
||||||
exists(IRBlock block, Instruction instr |
|
|
||||||
block.getAnInstruction() = instr and
|
|
||||||
blockId = getBlockId(block) and
|
|
||||||
scopeId = getScopeId(block.getFunction()) and
|
|
||||||
instructionId = getInstructionIndexInBlock(instr).toString() and
|
|
||||||
if (instr instanceof UnmodeledUseInstruction) then (
|
|
||||||
operandId = 0 and
|
|
||||||
label = "@mu*"
|
|
||||||
)
|
|
||||||
else (
|
|
||||||
exists(OperandTag tag, Instruction operandInstr |
|
|
||||||
operandInstr = instr.getOperand(tag) and
|
|
||||||
operandId = tag.getSortOrder() and
|
|
||||||
label = getOperandTagLabel(tag) +
|
|
||||||
getInstructionResultId(operandInstr)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
8
cpp/ql/src/semmle/code/cpp/ssa/PrintAliasedSSAIR.ql
Normal file
8
cpp/ql/src/semmle/code/cpp/ssa/PrintAliasedSSAIR.ql
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* @name Print Aliased SSA IR
|
||||||
|
* @description Outputs a representation of the Aliased SSA IR graph
|
||||||
|
* @id cpp/print-aliased-ssa-ir
|
||||||
|
* @kind graph
|
||||||
|
*/
|
||||||
|
|
||||||
|
import PrintAliasedSSAIR
|
||||||
8
cpp/ql/src/semmle/code/cpp/ssa/PrintSSAIR.ql
Normal file
8
cpp/ql/src/semmle/code/cpp/ssa/PrintSSAIR.ql
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* @name Print SSA IR
|
||||||
|
* @description Outputs a representation of the SSA IR graph
|
||||||
|
* @id cpp/print-ssa-ir
|
||||||
|
* @kind graph
|
||||||
|
*/
|
||||||
|
|
||||||
|
import PrintSSAIR
|
||||||
@@ -1,81 +1,92 @@
|
|||||||
private import IRInternal
|
private import IRInternal
|
||||||
private import IRBlockConstruction
|
private import IRBlockConstruction
|
||||||
import Instruction
|
import Instruction
|
||||||
import semmle.code.cpp.ir.EdgeKind
|
import semmle.code.cpp.ir.EdgeKind
|
||||||
|
|
||||||
class IRBlock extends TIRBlock {
|
class IRBlock extends TIRBlock {
|
||||||
final string toString() {
|
final string toString() {
|
||||||
result = getFirstInstruction(this).toString()
|
result = getFirstInstruction(this).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
final Location getLocation() {
|
final Location getLocation() {
|
||||||
result = getFirstInstruction().getLocation()
|
result = getFirstInstruction().getLocation()
|
||||||
}
|
}
|
||||||
|
|
||||||
final string getUniqueId() {
|
final string getUniqueId() {
|
||||||
result = getFirstInstruction(this).getUniqueId()
|
result = getFirstInstruction(this).getUniqueId()
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getInstruction(int index) {
|
/**
|
||||||
result = getInstruction(this, index)
|
* Gets the zero-based index of the block within its function. This is used
|
||||||
}
|
* by debugging and printing code only.
|
||||||
|
*/
|
||||||
final PhiInstruction getAPhiInstruction() {
|
int getDisplayIndex() {
|
||||||
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
this = rank[result + 1](IRBlock funcBlock |
|
||||||
}
|
funcBlock.getFunction() = getFunction() |
|
||||||
|
funcBlock order by funcBlock.getUniqueId()
|
||||||
final Instruction getAnInstruction() {
|
)
|
||||||
result = getInstruction(_) or
|
}
|
||||||
result = getAPhiInstruction()
|
|
||||||
}
|
final Instruction getInstruction(int index) {
|
||||||
|
result = getInstruction(this, index)
|
||||||
final Instruction getFirstInstruction() {
|
}
|
||||||
result = getFirstInstruction(this)
|
|
||||||
}
|
final PhiInstruction getAPhiInstruction() {
|
||||||
|
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
||||||
final Instruction getLastInstruction() {
|
}
|
||||||
result = getInstruction(getInstructionCount() - 1)
|
|
||||||
}
|
final Instruction getAnInstruction() {
|
||||||
|
result = getInstruction(_) or
|
||||||
final int getInstructionCount() {
|
result = getAPhiInstruction()
|
||||||
result = strictcount(getInstruction(_))
|
}
|
||||||
}
|
|
||||||
|
final Instruction getFirstInstruction() {
|
||||||
final FunctionIR getFunctionIR() {
|
result = getFirstInstruction(this)
|
||||||
result = getFirstInstruction(this).getFunctionIR()
|
}
|
||||||
}
|
|
||||||
|
final Instruction getLastInstruction() {
|
||||||
final Function getFunction() {
|
result = getInstruction(getInstructionCount() - 1)
|
||||||
result = getFirstInstruction(this).getFunction()
|
}
|
||||||
}
|
|
||||||
|
final int getInstructionCount() {
|
||||||
final IRBlock getASuccessor() {
|
result = strictcount(getInstruction(_))
|
||||||
blockSuccessor(this, result)
|
}
|
||||||
}
|
|
||||||
|
final FunctionIR getFunctionIR() {
|
||||||
final IRBlock getAPredecessor() {
|
result = getFirstInstruction(this).getFunctionIR()
|
||||||
blockSuccessor(result, this)
|
}
|
||||||
}
|
|
||||||
|
final Function getFunction() {
|
||||||
final IRBlock getSuccessor(EdgeKind kind) {
|
result = getFirstInstruction(this).getFunction()
|
||||||
blockSuccessor(this, result, kind)
|
}
|
||||||
}
|
|
||||||
|
final IRBlock getASuccessor() {
|
||||||
final predicate immediatelyDominates(IRBlock block) {
|
blockSuccessor(this, result)
|
||||||
blockImmediatelyDominates(this, block)
|
}
|
||||||
}
|
|
||||||
|
final IRBlock getAPredecessor() {
|
||||||
final predicate strictlyDominates(IRBlock block) {
|
blockSuccessor(result, this)
|
||||||
blockImmediatelyDominates+(this, block)
|
}
|
||||||
}
|
|
||||||
|
final IRBlock getSuccessor(EdgeKind kind) {
|
||||||
final predicate dominates(IRBlock block) {
|
blockSuccessor(this, result, kind)
|
||||||
strictlyDominates(block) or this = block
|
}
|
||||||
}
|
|
||||||
|
final predicate immediatelyDominates(IRBlock block) {
|
||||||
pragma[noinline]
|
blockImmediatelyDominates(this, block)
|
||||||
final IRBlock dominanceFrontier() {
|
}
|
||||||
dominates(result.getAPredecessor()) and
|
|
||||||
not strictlyDominates(result)
|
final predicate strictlyDominates(IRBlock block) {
|
||||||
}
|
blockImmediatelyDominates+(this, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final predicate dominates(IRBlock block) {
|
||||||
|
strictlyDominates(block) or this = block
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
final IRBlock dominanceFrontier() {
|
||||||
|
dominates(result.getAPredecessor()) and
|
||||||
|
not strictlyDominates(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -90,8 +90,132 @@ class Instruction extends Construction::TInstruction {
|
|||||||
this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
|
this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
|
||||||
}
|
}
|
||||||
|
|
||||||
string toString() {
|
final string toString() {
|
||||||
result = opcode.toString()
|
result = getResultString() + " = " + getOperationString() + " " + getOperandsString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string describing the operation of this instruction. This includes
|
||||||
|
* the opcode and the immediate value, if any. For example:
|
||||||
|
*
|
||||||
|
* VariableAddress[x]
|
||||||
|
*/
|
||||||
|
final string getOperationString() {
|
||||||
|
if exists(getImmediateString()) then
|
||||||
|
result = opcode.toString() + "[" + getImmediateString() + "]"
|
||||||
|
else
|
||||||
|
result = opcode.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string describing the immediate value of this instruction, if any.
|
||||||
|
*/
|
||||||
|
string getImmediateString() {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
private string getResultPrefix() {
|
||||||
|
if resultType instanceof VoidType then
|
||||||
|
result = "v"
|
||||||
|
else if hasMemoryResult() then
|
||||||
|
if isResultModeled() then
|
||||||
|
result = "m"
|
||||||
|
else
|
||||||
|
result = "mu"
|
||||||
|
else
|
||||||
|
result = "r"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the zero-based index of this instruction within its block. This is
|
||||||
|
* used by debugging and printing code only.
|
||||||
|
*/
|
||||||
|
int getDisplayIndexInBlock() {
|
||||||
|
exists(IRBlock block |
|
||||||
|
block = getBlock() and
|
||||||
|
(
|
||||||
|
exists(int index, int phiCount |
|
||||||
|
phiCount = count(block.getAPhiInstruction()) and
|
||||||
|
this = block.getInstruction(index) and
|
||||||
|
result = index + phiCount
|
||||||
|
) or
|
||||||
|
(
|
||||||
|
this instanceof PhiInstruction and
|
||||||
|
this = rank[result + 1](PhiInstruction phiInstr |
|
||||||
|
phiInstr = block.getAPhiInstruction() |
|
||||||
|
phiInstr order by phiInstr.getUniqueId()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[type]
|
||||||
|
private string getValueCategoryString(string type) {
|
||||||
|
if isGLValue() then
|
||||||
|
result = "glval<" + type + ">"
|
||||||
|
else
|
||||||
|
result = type
|
||||||
|
}
|
||||||
|
|
||||||
|
private string getResultTypeString() {
|
||||||
|
exists(string valcat |
|
||||||
|
valcat = getValueCategoryString(resultType.toString()) and
|
||||||
|
if resultType instanceof UnknownType and exists(getResultSize()) then
|
||||||
|
result = valcat + "[" + getResultSize().toString() + "]"
|
||||||
|
else
|
||||||
|
result = valcat
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a human-readable string that uniquely identifies this instruction
|
||||||
|
* within the function. This string is used to refer to this instruction when
|
||||||
|
* printing IR dumps.
|
||||||
|
*
|
||||||
|
* Example: `r1_1`
|
||||||
|
*/
|
||||||
|
string getResultId() {
|
||||||
|
result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
|
||||||
|
getDisplayIndexInBlock().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string describing the result of this instruction, suitable for
|
||||||
|
* display in IR dumps. This consists of the result ID plus the type of the
|
||||||
|
* result.
|
||||||
|
*
|
||||||
|
* Example: `r1_1(int*)`
|
||||||
|
*/
|
||||||
|
final string getResultString() {
|
||||||
|
result = getResultId() + "(" + getResultTypeString() + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string describing the specified 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 kind.
|
||||||
|
*
|
||||||
|
* For example: `this:r3_5`
|
||||||
|
*/
|
||||||
|
string getOperandString(OperandTag tag) {
|
||||||
|
exists(Instruction operand |
|
||||||
|
operand = getOperand(tag) and
|
||||||
|
result = tag.getLabel() + operand.getResultId()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string describing the operands of this instruction, suitable for
|
||||||
|
* display in IR dumps.
|
||||||
|
*
|
||||||
|
* Example: `func:r3_4, this:r3_5`
|
||||||
|
*/
|
||||||
|
string getOperandsString() {
|
||||||
|
result = concat(OperandTag tag, Instruction operand |
|
||||||
|
operand = getOperand(tag) |
|
||||||
|
tag.getLabel() + operand.getResultId(), ", " order by tag.getSortOrder()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -312,8 +436,8 @@ class VariableInstruction extends Instruction {
|
|||||||
var = Construction::getInstructionVariable(this)
|
var = Construction::getInstructionVariable(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + var.toString() + "]"
|
result = var.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
final IRVariable getVariable() {
|
final IRVariable getVariable() {
|
||||||
@@ -328,8 +452,8 @@ class FieldInstruction extends Instruction {
|
|||||||
field = Construction::getInstructionField(this)
|
field = Construction::getInstructionField(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + field.toString() + "]"
|
result = field.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
final Field getField() {
|
final Field getField() {
|
||||||
@@ -344,8 +468,8 @@ class FunctionInstruction extends Instruction {
|
|||||||
funcSymbol = Construction::getInstructionFunction(this)
|
funcSymbol = Construction::getInstructionFunction(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + funcSymbol.toString() + "]"
|
result = funcSymbol.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
final Function getFunctionSymbol() {
|
final Function getFunctionSymbol() {
|
||||||
@@ -360,8 +484,8 @@ class ConstantValueInstruction extends Instruction {
|
|||||||
value = Construction::getInstructionConstantValue(this)
|
value = Construction::getInstructionConstantValue(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + value + "]"
|
result = value
|
||||||
}
|
}
|
||||||
|
|
||||||
final string getValue() {
|
final string getValue() {
|
||||||
@@ -534,10 +658,8 @@ class StringConstantInstruction extends Instruction {
|
|||||||
value = Construction::getInstructionStringLiteral(this)
|
value = Construction::getInstructionStringLiteral(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" +
|
result = value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ")
|
||||||
value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ") +
|
|
||||||
"]"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final StringLiteral getValue() {
|
final StringLiteral getValue() {
|
||||||
@@ -627,8 +749,8 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
|||||||
elementSize = Construction::getInstructionElementSize(this)
|
elementSize = Construction::getInstructionElementSize(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + elementSize.toString() + "]"
|
result = elementSize.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
final int getElementSize() {
|
final int getElementSize() {
|
||||||
@@ -688,8 +810,8 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
|||||||
Construction::getInstructionInheritance(this, baseClass, derivedClass)
|
Construction::getInstructionInheritance(this, baseClass, derivedClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + derivedClass.toString() + " : " + baseClass.toString() + "]"
|
result = derivedClass.toString() + " : " + baseClass.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -908,8 +1030,8 @@ class CatchByTypeInstruction extends CatchInstruction {
|
|||||||
exceptionType = Construction::getInstructionExceptionType(this)
|
exceptionType = Construction::getInstructionExceptionType(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
final override string toString() {
|
final override string getImmediateString() {
|
||||||
result = super.toString() + "[" + exceptionType.toString() + "]"
|
result = exceptionType.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -944,6 +1066,10 @@ class UnmodeledUseInstruction extends Instruction {
|
|||||||
opcode instanceof Opcode::UnmodeledUse
|
opcode instanceof Opcode::UnmodeledUse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override string getOperandsString() {
|
||||||
|
result = "mu*"
|
||||||
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||||
tag instanceof UnmodeledUseOperand and
|
tag instanceof UnmodeledUseOperand and
|
||||||
result instanceof UnmodeledMemoryAccess
|
result instanceof UnmodeledMemoryAccess
|
||||||
|
|||||||
@@ -1,299 +1,312 @@
|
|||||||
private import IRInternal
|
private import IRInternal
|
||||||
import Instruction
|
import Instruction
|
||||||
import IRBlock
|
import IRBlock
|
||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
private newtype TOperandTag =
|
private newtype TOperandTag =
|
||||||
TLoadStoreAddressOperand() or
|
TLoadStoreAddressOperand() or
|
||||||
TCopySourceOperand() or
|
TCopySourceOperand() or
|
||||||
TUnaryOperand() or
|
TUnaryOperand() or
|
||||||
TLeftOperand() or
|
TLeftOperand() or
|
||||||
TRightOperand() or
|
TRightOperand() or
|
||||||
TReturnValueOperand() or
|
TReturnValueOperand() or
|
||||||
TExceptionOperand() or
|
TExceptionOperand() or
|
||||||
TConditionOperand() or
|
TConditionOperand() or
|
||||||
TUnmodeledUseOperand() or
|
TUnmodeledUseOperand() or
|
||||||
TCallTargetOperand() or
|
TCallTargetOperand() or
|
||||||
TThisArgumentOperand() or
|
TThisArgumentOperand() or
|
||||||
TPositionalArgumentOperand(int argIndex) {
|
TPositionalArgumentOperand(int argIndex) {
|
||||||
argIndex in [0..Construction::getMaxCallArgIndex()] or
|
argIndex in [0..Construction::getMaxCallArgIndex()] or
|
||||||
exists(BuiltInOperation op |
|
exists(BuiltInOperation op |
|
||||||
exists(op.getChild(argIndex))
|
exists(op.getChild(argIndex))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPhiOperand(IRBlock predecessorBlock) {
|
TPhiOperand(IRBlock predecessorBlock) {
|
||||||
exists(PhiInstruction phi |
|
exists(PhiInstruction phi |
|
||||||
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
|
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||||
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
||||||
* an `Instruction` is determined by the instruction's opcode.
|
* an `Instruction` is determined by the instruction's opcode.
|
||||||
*/
|
*/
|
||||||
abstract class OperandTag extends TOperandTag {
|
abstract class OperandTag extends TOperandTag {
|
||||||
abstract string toString();
|
abstract string toString();
|
||||||
abstract int getSortOrder();
|
|
||||||
}
|
abstract int getSortOrder();
|
||||||
|
|
||||||
// Note: individual subtypes are listed in the order that the operands should
|
string getLabel() {
|
||||||
// appear in the operand list of the instruction when printing.
|
result = ""
|
||||||
|
}
|
||||||
/**
|
}
|
||||||
* The address operand of an instruction that loads or stores a value from
|
|
||||||
* memory (e.g. `Load`, `Store`).
|
// Note: individual subtypes are listed in the order that the operands should
|
||||||
*/
|
// appear in the operand list of the instruction when printing.
|
||||||
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
|
|
||||||
override final string toString() {
|
/**
|
||||||
result = "LoadStoreAddress"
|
* The address operand of an instruction that loads or stores a value from
|
||||||
}
|
* memory (e.g. `Load`, `Store`).
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
|
||||||
result = 0
|
override final string toString() {
|
||||||
}
|
result = "LoadStoreAddress"
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadStoreAddressOperand loadStoreAddressOperand() {
|
override final int getSortOrder() {
|
||||||
result = TLoadStoreAddressOperand()
|
result = 0
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The source value operand of an instruction that copies this value to its
|
LoadStoreAddressOperand loadStoreAddressOperand() {
|
||||||
* result (e.g. `Copy`, `Load`, `Store`).
|
result = TLoadStoreAddressOperand()
|
||||||
*/
|
}
|
||||||
class CopySourceOperand extends OperandTag, TCopySourceOperand {
|
|
||||||
override final string toString() {
|
/**
|
||||||
result = "CopySource"
|
* The source value operand of an instruction that copies this value to its
|
||||||
}
|
* result (e.g. `Copy`, `Load`, `Store`).
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class CopySourceOperand extends OperandTag, TCopySourceOperand {
|
||||||
result = 1
|
override final string toString() {
|
||||||
}
|
result = "CopySource"
|
||||||
}
|
}
|
||||||
|
|
||||||
CopySourceOperand copySourceOperand() {
|
override final int getSortOrder() {
|
||||||
result = TCopySourceOperand()
|
result = 1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
CopySourceOperand copySourceOperand() {
|
||||||
*/
|
result = TCopySourceOperand()
|
||||||
class UnaryOperand extends OperandTag, TUnaryOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "Unary"
|
/**
|
||||||
}
|
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class UnaryOperand extends OperandTag, TUnaryOperand {
|
||||||
result = 2
|
override final string toString() {
|
||||||
}
|
result = "Unary"
|
||||||
}
|
}
|
||||||
|
|
||||||
UnaryOperand unaryOperand() {
|
override final int getSortOrder() {
|
||||||
result = TUnaryOperand()
|
result = 2
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
UnaryOperand unaryOperand() {
|
||||||
*/
|
result = TUnaryOperand()
|
||||||
class LeftOperand extends OperandTag, TLeftOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "Left"
|
/**
|
||||||
}
|
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class LeftOperand extends OperandTag, TLeftOperand {
|
||||||
result = 3
|
override final string toString() {
|
||||||
}
|
result = "Left"
|
||||||
}
|
}
|
||||||
|
|
||||||
LeftOperand leftOperand() {
|
override final int getSortOrder() {
|
||||||
result = TLeftOperand()
|
result = 3
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
LeftOperand leftOperand() {
|
||||||
*/
|
result = TLeftOperand()
|
||||||
class RightOperand extends OperandTag, TRightOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "Right"
|
/**
|
||||||
}
|
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class RightOperand extends OperandTag, TRightOperand {
|
||||||
result = 4
|
override final string toString() {
|
||||||
}
|
result = "Right"
|
||||||
}
|
}
|
||||||
|
|
||||||
RightOperand rightOperand() {
|
override final int getSortOrder() {
|
||||||
result = TRightOperand()
|
result = 4
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The return value operand of a `ReturnValue` instruction.
|
RightOperand rightOperand() {
|
||||||
*/
|
result = TRightOperand()
|
||||||
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "ReturnValue"
|
/**
|
||||||
}
|
* The return value operand of a `ReturnValue` instruction.
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
|
||||||
result = 5
|
override final string toString() {
|
||||||
}
|
result = "ReturnValue"
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValueOperand returnValueOperand() {
|
override final int getSortOrder() {
|
||||||
result = TReturnValueOperand()
|
result = 5
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The exception thrown by a `ThrowValue` instruction.
|
ReturnValueOperand returnValueOperand() {
|
||||||
*/
|
result = TReturnValueOperand()
|
||||||
class ExceptionOperand extends OperandTag, TExceptionOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "Exception"
|
/**
|
||||||
}
|
* The exception thrown by a `ThrowValue` instruction.
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class ExceptionOperand extends OperandTag, TExceptionOperand {
|
||||||
result = 6
|
override final string toString() {
|
||||||
}
|
result = "Exception"
|
||||||
}
|
}
|
||||||
|
|
||||||
ExceptionOperand exceptionOperand() {
|
override final int getSortOrder() {
|
||||||
result = TExceptionOperand()
|
result = 6
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
ExceptionOperand exceptionOperand() {
|
||||||
*/
|
result = TExceptionOperand()
|
||||||
class ConditionOperand extends OperandTag, TConditionOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "Condition"
|
/**
|
||||||
}
|
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class ConditionOperand extends OperandTag, TConditionOperand {
|
||||||
result = 7
|
override final string toString() {
|
||||||
}
|
result = "Condition"
|
||||||
}
|
}
|
||||||
|
|
||||||
ConditionOperand conditionOperand() {
|
override final int getSortOrder() {
|
||||||
result = TConditionOperand()
|
result = 7
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
ConditionOperand conditionOperand() {
|
||||||
* whose set of uses is unknown.
|
result = TConditionOperand()
|
||||||
*/
|
}
|
||||||
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
|
|
||||||
override final string toString() {
|
/**
|
||||||
result = "UnmodeledUse"
|
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||||
}
|
* whose set of uses is unknown.
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
|
||||||
result = 8
|
override final string toString() {
|
||||||
}
|
result = "UnmodeledUse"
|
||||||
}
|
}
|
||||||
|
|
||||||
UnmodeledUseOperand unmodeledUseOperand() {
|
override final int getSortOrder() {
|
||||||
result = TUnmodeledUseOperand()
|
result = 8
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The operand representing the target function of an `Invoke` instruction.
|
UnmodeledUseOperand unmodeledUseOperand() {
|
||||||
*/
|
result = TUnmodeledUseOperand()
|
||||||
class CallTargetOperand extends OperandTag, TCallTargetOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "CallTarget"
|
/**
|
||||||
}
|
* The operand representing the target function of an `Invoke` instruction.
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class CallTargetOperand extends OperandTag, TCallTargetOperand {
|
||||||
result = 9
|
override final string toString() {
|
||||||
}
|
result = "CallTarget"
|
||||||
}
|
}
|
||||||
|
|
||||||
CallTargetOperand callTargetOperand() {
|
override final int getSortOrder() {
|
||||||
result = TCallTargetOperand()
|
result = 9
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* An operand representing an argument to a function call. This includes both
|
CallTargetOperand callTargetOperand() {
|
||||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
result = TCallTargetOperand()
|
||||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
}
|
||||||
*/
|
|
||||||
abstract class ArgumentOperand extends OperandTag {
|
/**
|
||||||
}
|
* An operand representing an argument to a function call. This includes both
|
||||||
|
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||||
/**
|
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||||
* An operand representing the implicit 'this' argument to a member function
|
*/
|
||||||
* call.
|
abstract class ArgumentOperand extends OperandTag {
|
||||||
*/
|
}
|
||||||
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
|
|
||||||
ThisArgumentOperand() {
|
/**
|
||||||
this = TThisArgumentOperand()
|
* An operand representing the implicit 'this' argument to a member function
|
||||||
}
|
* call.
|
||||||
|
*/
|
||||||
override final string toString() {
|
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
|
||||||
result = "Arg(this)"
|
ThisArgumentOperand() {
|
||||||
}
|
this = TThisArgumentOperand()
|
||||||
|
}
|
||||||
override final int getSortOrder() {
|
|
||||||
result = 10
|
override final string toString() {
|
||||||
}
|
result = "Arg(this)"
|
||||||
}
|
}
|
||||||
|
|
||||||
ThisArgumentOperand thisArgumentOperand() {
|
override final int getSortOrder() {
|
||||||
result = TThisArgumentOperand()
|
result = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override final string getLabel() {
|
||||||
* An operand representing an argument to a function call.
|
result = "this:"
|
||||||
*/
|
}
|
||||||
class PositionalArgumentOperand extends ArgumentOperand,
|
}
|
||||||
TPositionalArgumentOperand {
|
|
||||||
int argIndex;
|
ThisArgumentOperand thisArgumentOperand() {
|
||||||
|
result = TThisArgumentOperand()
|
||||||
PositionalArgumentOperand() {
|
}
|
||||||
this = TPositionalArgumentOperand(argIndex)
|
|
||||||
}
|
/**
|
||||||
|
* An operand representing an argument to a function call.
|
||||||
override final string toString() {
|
*/
|
||||||
result = "Arg(" + argIndex + ")"
|
class PositionalArgumentOperand extends ArgumentOperand,
|
||||||
}
|
TPositionalArgumentOperand {
|
||||||
|
int argIndex;
|
||||||
override final int getSortOrder() {
|
|
||||||
result = 11 + argIndex
|
PositionalArgumentOperand() {
|
||||||
}
|
this = TPositionalArgumentOperand(argIndex)
|
||||||
|
}
|
||||||
final int getArgIndex() {
|
|
||||||
result = argIndex
|
override final string toString() {
|
||||||
}
|
result = "Arg(" + argIndex + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
|
override final int getSortOrder() {
|
||||||
result = TPositionalArgumentOperand(argIndex)
|
result = 11 + argIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
final int getArgIndex() {
|
||||||
* An operand of an SSA `Phi` instruction.
|
result = argIndex
|
||||||
*/
|
}
|
||||||
class PhiOperand extends OperandTag, TPhiOperand {
|
}
|
||||||
IRBlock predecessorBlock;
|
|
||||||
|
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
|
||||||
PhiOperand() {
|
result = TPositionalArgumentOperand(argIndex)
|
||||||
this = TPhiOperand(predecessorBlock)
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
override final string toString() {
|
* An operand of an SSA `Phi` instruction.
|
||||||
result = "Phi"
|
*/
|
||||||
}
|
class PhiOperand extends OperandTag, TPhiOperand {
|
||||||
|
IRBlock predecessorBlock;
|
||||||
override final int getSortOrder() {
|
|
||||||
result = 11
|
PhiOperand() {
|
||||||
}
|
this = TPhiOperand(predecessorBlock)
|
||||||
|
}
|
||||||
final IRBlock getPredecessorBlock() {
|
|
||||||
result = predecessorBlock
|
override final string toString() {
|
||||||
}
|
result = "Phi"
|
||||||
}
|
}
|
||||||
|
|
||||||
PhiOperand phiOperand(IRBlock predecessorBlock) {
|
override final int getSortOrder() {
|
||||||
result = TPhiOperand(predecessorBlock)
|
result = 11 + getPredecessorBlock().getDisplayIndex()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override final string getLabel() {
|
||||||
|
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||||
|
}
|
||||||
|
|
||||||
|
final IRBlock getPredecessorBlock() {
|
||||||
|
result = predecessorBlock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PhiOperand phiOperand(IRBlock predecessorBlock) {
|
||||||
|
result = TPhiOperand(predecessorBlock)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,175 +1,239 @@
|
|||||||
private import IRImpl
|
private import IRImpl
|
||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
private int getInstructionIndexInBlock(Instruction instr) {
|
private newtype TPrintableIRNode =
|
||||||
exists(IRBlock block |
|
TPrintableFunctionIR(FunctionIR funcIR) or
|
||||||
block = instr.getBlock() and
|
TPrintableIRBlock(IRBlock block) or
|
||||||
|
TPrintableInstruction(Instruction instr)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node to be emitted in the IR graph.
|
||||||
|
*/
|
||||||
|
abstract class PrintableIRNode extends TPrintableIRNode {
|
||||||
|
abstract string toString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the location to be emitted for the node.
|
||||||
|
*/
|
||||||
|
abstract Location getLocation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the label to be emitted for the node.
|
||||||
|
*/
|
||||||
|
abstract string getLabel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the order in which the node appears in its parent node.
|
||||||
|
*/
|
||||||
|
abstract int getOrder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the parent of this node.
|
||||||
|
*/
|
||||||
|
abstract PrintableIRNode getParent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the kind of graph represented by this node ("graph" or "tree").
|
||||||
|
*/
|
||||||
|
string getGraphKind() {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this node should always be rendered as text, even in a graphical
|
||||||
|
* viewer.
|
||||||
|
*/
|
||||||
|
predicate forceText() {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of the node property with the specified key.
|
||||||
|
*/
|
||||||
|
string getProperty(string key) {
|
||||||
|
key = "semmle.label" and result = getLabel() or
|
||||||
|
key = "semmle.order" and result = getOrder().toString() or
|
||||||
|
key = "semmle.graphKind" and result = getGraphKind() or
|
||||||
|
key = "semmle.forceText" and forceText() and result = "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An IR graph node representing a `FunctionIR` object.
|
||||||
|
*/
|
||||||
|
class PrintableFunctionIR extends PrintableIRNode, TPrintableFunctionIR {
|
||||||
|
FunctionIR funcIR;
|
||||||
|
|
||||||
|
PrintableFunctionIR() {
|
||||||
|
this = TPrintableFunctionIR(funcIR)
|
||||||
|
}
|
||||||
|
|
||||||
|
override string toString() {
|
||||||
|
result = funcIR.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Location getLocation() {
|
||||||
|
result = funcIR.getLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getLabel() {
|
||||||
|
result = funcIR.getFunction().getFullSignature()
|
||||||
|
}
|
||||||
|
|
||||||
|
override int getOrder() {
|
||||||
|
this = rank[result + 1](PrintableFunctionIR orderedFunc, Location location |
|
||||||
|
location = orderedFunc.getFunctionIR().getLocation() |
|
||||||
|
orderedFunc order by location.getFile().getURL(), location.getStartLine(),
|
||||||
|
location.getStartColumn(), orderedFunc.getLabel()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override final PrintableIRNode getParent() {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
final FunctionIR getFunctionIR() {
|
||||||
|
result = funcIR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An IR graph node representing an `IRBlock` object.
|
||||||
|
*/
|
||||||
|
class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
||||||
|
IRBlock block;
|
||||||
|
|
||||||
|
PrintableIRBlock() {
|
||||||
|
this = TPrintableIRBlock(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
override string toString() {
|
||||||
|
result = getLabel()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Location getLocation() {
|
||||||
|
result = block.getLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getLabel() {
|
||||||
|
result = "Block " + block.getDisplayIndex().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override int getOrder() {
|
||||||
|
result = block.getDisplayIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
override final string getGraphKind() {
|
||||||
|
result = "tree"
|
||||||
|
}
|
||||||
|
|
||||||
|
override final predicate forceText() {
|
||||||
|
any()
|
||||||
|
}
|
||||||
|
|
||||||
|
override final PrintableFunctionIR getParent() {
|
||||||
|
result.getFunctionIR() = block.getFunctionIR()
|
||||||
|
}
|
||||||
|
|
||||||
|
final IRBlock getBlock() {
|
||||||
|
result = block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An IR graph node representing an `Instruction`.
|
||||||
|
*/
|
||||||
|
class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
|
||||||
|
Instruction instr;
|
||||||
|
|
||||||
|
PrintableInstruction() {
|
||||||
|
this = TPrintableInstruction(instr)
|
||||||
|
}
|
||||||
|
|
||||||
|
override string toString() {
|
||||||
|
result = instr.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Location getLocation() {
|
||||||
|
result = instr.getLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getLabel() {
|
||||||
|
exists(IRBlock block |
|
||||||
|
instr = block.getAnInstruction() and
|
||||||
|
exists(string resultString, string operationString, string operandsString,
|
||||||
|
int resultWidth, int operationWidth |
|
||||||
|
resultString = instr.getResultString() and
|
||||||
|
operationString = instr.getOperationString() and
|
||||||
|
operandsString = instr.getOperandsString() and
|
||||||
|
columnWidths(block, resultWidth, operationWidth) and
|
||||||
|
result = resultString + getPaddingString(resultWidth - resultString.length()) +
|
||||||
|
" = " + operationString + getPaddingString(operationWidth - operationString.length()) +
|
||||||
|
" : " + operandsString
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override int getOrder() {
|
||||||
|
result = instr.getDisplayIndexInBlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
override final PrintableIRBlock getParent() {
|
||||||
|
result.getBlock() = instr.getBlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
final Instruction getInstruction() {
|
||||||
|
result = instr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {
|
||||||
|
resultWidth = max(Instruction instr | instr.getBlock() = block | instr.getResultString().length()) and
|
||||||
|
operationWidth = max(Instruction instr | instr.getBlock() = block | instr.getOperationString().length())
|
||||||
|
}
|
||||||
|
|
||||||
|
private int maxColumnWidth() {
|
||||||
|
result = max(Instruction instr, int width |
|
||||||
|
width = instr.getResultString().length() or
|
||||||
|
width = instr.getOperationString().length() or
|
||||||
|
width = instr.getOperandsString().length() |
|
||||||
|
width)
|
||||||
|
}
|
||||||
|
|
||||||
|
private string getPaddingString(int n) {
|
||||||
|
n = 0 and result = "" or
|
||||||
|
n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " "
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate nodes(PrintableIRNode node, string key, string value) {
|
||||||
|
value = node.getProperty(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getSuccessorIndex(IRBlock pred, IRBlock succ) {
|
||||||
|
succ = rank[result + 1](IRBlock aSucc, EdgeKind kind |
|
||||||
|
aSucc = pred.getSuccessor(kind) |
|
||||||
|
aSucc order by kind.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) {
|
||||||
|
exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock |
|
||||||
|
predBlock = pred.getBlock() and
|
||||||
|
succBlock = succ.getBlock() and
|
||||||
|
predBlock.getSuccessor(kind) = succBlock and
|
||||||
(
|
(
|
||||||
exists(int index, int phiCount |
|
(
|
||||||
phiCount = count(block.getAPhiInstruction()) and
|
key = "semmle.label" and
|
||||||
instr = block.getInstruction(index) and
|
value = kind.toString()
|
||||||
result = index + phiCount
|
|
||||||
) or
|
) or
|
||||||
(
|
(
|
||||||
instr instanceof PhiInstruction and
|
key = "semmle.order" and
|
||||||
instr = rank[result + 1](PhiInstruction phiInstr |
|
value = getSuccessorIndex(predBlock, succBlock).toString()
|
||||||
phiInstr = block.getAPhiInstruction() |
|
|
||||||
phiInstr order by phiInstr.getUniqueId()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private string getInstructionResultId(Instruction instr) {
|
query predicate parents(PrintableIRNode child, PrintableIRNode parent) {
|
||||||
result = getResultPrefix(instr) + getBlockId(instr.getBlock()) + "_" +
|
parent = child.getParent()
|
||||||
getInstructionIndexInBlock(instr).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
private string getResultPrefix(Instruction instr) {
|
|
||||||
if instr.hasMemoryResult() then
|
|
||||||
if instr.isResultModeled() then
|
|
||||||
result = "@m"
|
|
||||||
else
|
|
||||||
result = "@mu"
|
|
||||||
else
|
|
||||||
result = "@r"
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the identifier of the specified function scope.
|
|
||||||
* Currently just returns the signature of the function.
|
|
||||||
*/
|
|
||||||
private string getScopeId(Function func) {
|
|
||||||
result = func.getFullSignature()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the unique identifier of the block within its function.
|
|
||||||
* Currently returns a string representation of an integer in the range
|
|
||||||
* [0..numBlocks - 1].
|
|
||||||
*/
|
|
||||||
private string getBlockId(IRBlock block) {
|
|
||||||
exists(int rankIndex |
|
|
||||||
block = rank[rankIndex + 1](IRBlock funcBlock |
|
|
||||||
funcBlock.getFunction() = block.getFunction() |
|
|
||||||
funcBlock order by funcBlock.getUniqueId()
|
|
||||||
) and
|
|
||||||
result = rankIndex.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints the full signature and qualified name for each scope. This is primarily
|
|
||||||
* so that post-processing tools can identify function overloads, which will have
|
|
||||||
* different signatures but the same qualified name.
|
|
||||||
*/
|
|
||||||
query predicate printIRGraphScopes(string scopeId, string qualifiedName) {
|
|
||||||
exists(FunctionIR ir, Function func |
|
|
||||||
func = ir.getFunction() and
|
|
||||||
scopeId = getScopeId(func) and
|
|
||||||
qualifiedName = func.getQualifiedName()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
query predicate printIRGraphNodes(string scopeId, string blockId, string label, string location) {
|
|
||||||
exists(IRBlock block |
|
|
||||||
scopeId = getScopeId(block.getFunction()) and
|
|
||||||
blockId = getBlockId(block) and
|
|
||||||
label = "" and
|
|
||||||
location = ""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
query predicate printIRGraphInstructions(string scopeId, string blockId,
|
|
||||||
string id, string label, string location) {
|
|
||||||
exists(IRBlock block, Instruction instr |
|
|
||||||
instr = block.getAnInstruction() and
|
|
||||||
label = instr.toString() and
|
|
||||||
location = instr.getLocation().toString() and
|
|
||||||
scopeId = getScopeId(block.getFunction()) and
|
|
||||||
blockId = getBlockId(block) and
|
|
||||||
id = getInstructionIndexInBlock(instr).toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
query predicate printIRGraphEdges(string scopeId,
|
|
||||||
string predecessorId, string successorId, string label) {
|
|
||||||
exists(IRBlock predecessor, IRBlock successor, EdgeKind kind |
|
|
||||||
scopeId = getScopeId(predecessor.getFunction()) and
|
|
||||||
predecessor.getSuccessor(kind) = successor and
|
|
||||||
predecessorId = getBlockId(predecessor) and
|
|
||||||
successorId = getBlockId(successor) and
|
|
||||||
label = kind.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private string getValueCategoryString(Instruction instr) {
|
|
||||||
if instr.isGLValue() then
|
|
||||||
result = "glval:"
|
|
||||||
else
|
|
||||||
result = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
private string getResultTypeString(Instruction instr) {
|
|
||||||
exists(Type resultType, string valcat |
|
|
||||||
resultType = instr.getResultType() and
|
|
||||||
valcat = getValueCategoryString(instr) and
|
|
||||||
if resultType instanceof UnknownType and exists(instr.getResultSize()) then
|
|
||||||
result = valcat + resultType.toString() + "[" + instr.getResultSize().toString() + "]"
|
|
||||||
else
|
|
||||||
result = valcat + resultType.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
query predicate printIRGraphDestinationOperands(string scopeId, string blockId,
|
|
||||||
string instructionId, int operandId, string label) {
|
|
||||||
exists(IRBlock block, Instruction instr |
|
|
||||||
block.getAnInstruction() = instr and
|
|
||||||
scopeId = getScopeId(block.getFunction()) and
|
|
||||||
blockId = getBlockId(block) and
|
|
||||||
instructionId = getInstructionIndexInBlock(instr).toString() and
|
|
||||||
not instr.getResultType() instanceof VoidType and
|
|
||||||
operandId = 0 and
|
|
||||||
label = getInstructionResultId(instr) +
|
|
||||||
"(" + getResultTypeString(instr) + ")"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private string getOperandTagLabel(OperandTag tag) {
|
|
||||||
(
|
|
||||||
tag instanceof PhiOperand and
|
|
||||||
result = "from " + getBlockId(tag.(PhiOperand).getPredecessorBlock()) + ": "
|
|
||||||
)
|
|
||||||
or (
|
|
||||||
tag instanceof ThisArgumentOperand and
|
|
||||||
result = "this:"
|
|
||||||
)
|
|
||||||
or (
|
|
||||||
not tag instanceof PhiOperand and
|
|
||||||
not tag instanceof ThisArgumentOperand and
|
|
||||||
result = ""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
query predicate printIRGraphSourceOperands(string scopeId, string blockId,
|
|
||||||
string instructionId, int operandId, string label) {
|
|
||||||
exists(IRBlock block, Instruction instr |
|
|
||||||
block.getAnInstruction() = instr and
|
|
||||||
blockId = getBlockId(block) and
|
|
||||||
scopeId = getScopeId(block.getFunction()) and
|
|
||||||
instructionId = getInstructionIndexInBlock(instr).toString() and
|
|
||||||
if (instr instanceof UnmodeledUseInstruction) then (
|
|
||||||
operandId = 0 and
|
|
||||||
label = "@mu*"
|
|
||||||
)
|
|
||||||
else (
|
|
||||||
exists(OperandTag tag, Instruction operandInstr |
|
|
||||||
operandInstr = instr.getOperand(tag) and
|
|
||||||
operandId = tag.getSortOrder() and
|
|
||||||
label = getOperandTagLabel(tag) +
|
|
||||||
getInstructionResultId(operandInstr)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,81 +1,92 @@
|
|||||||
private import IRInternal
|
private import IRInternal
|
||||||
private import IRBlockConstruction
|
private import IRBlockConstruction
|
||||||
import Instruction
|
import Instruction
|
||||||
import semmle.code.cpp.ir.EdgeKind
|
import semmle.code.cpp.ir.EdgeKind
|
||||||
|
|
||||||
class IRBlock extends TIRBlock {
|
class IRBlock extends TIRBlock {
|
||||||
final string toString() {
|
final string toString() {
|
||||||
result = getFirstInstruction(this).toString()
|
result = getFirstInstruction(this).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
final Location getLocation() {
|
final Location getLocation() {
|
||||||
result = getFirstInstruction().getLocation()
|
result = getFirstInstruction().getLocation()
|
||||||
}
|
}
|
||||||
|
|
||||||
final string getUniqueId() {
|
final string getUniqueId() {
|
||||||
result = getFirstInstruction(this).getUniqueId()
|
result = getFirstInstruction(this).getUniqueId()
|
||||||
}
|
}
|
||||||
|
|
||||||
final Instruction getInstruction(int index) {
|
/**
|
||||||
result = getInstruction(this, index)
|
* Gets the zero-based index of the block within its function. This is used
|
||||||
}
|
* by debugging and printing code only.
|
||||||
|
*/
|
||||||
final PhiInstruction getAPhiInstruction() {
|
int getDisplayIndex() {
|
||||||
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
this = rank[result + 1](IRBlock funcBlock |
|
||||||
}
|
funcBlock.getFunction() = getFunction() |
|
||||||
|
funcBlock order by funcBlock.getUniqueId()
|
||||||
final Instruction getAnInstruction() {
|
)
|
||||||
result = getInstruction(_) or
|
}
|
||||||
result = getAPhiInstruction()
|
|
||||||
}
|
final Instruction getInstruction(int index) {
|
||||||
|
result = getInstruction(this, index)
|
||||||
final Instruction getFirstInstruction() {
|
}
|
||||||
result = getFirstInstruction(this)
|
|
||||||
}
|
final PhiInstruction getAPhiInstruction() {
|
||||||
|
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
||||||
final Instruction getLastInstruction() {
|
}
|
||||||
result = getInstruction(getInstructionCount() - 1)
|
|
||||||
}
|
final Instruction getAnInstruction() {
|
||||||
|
result = getInstruction(_) or
|
||||||
final int getInstructionCount() {
|
result = getAPhiInstruction()
|
||||||
result = strictcount(getInstruction(_))
|
}
|
||||||
}
|
|
||||||
|
final Instruction getFirstInstruction() {
|
||||||
final FunctionIR getFunctionIR() {
|
result = getFirstInstruction(this)
|
||||||
result = getFirstInstruction(this).getFunctionIR()
|
}
|
||||||
}
|
|
||||||
|
final Instruction getLastInstruction() {
|
||||||
final Function getFunction() {
|
result = getInstruction(getInstructionCount() - 1)
|
||||||
result = getFirstInstruction(this).getFunction()
|
}
|
||||||
}
|
|
||||||
|
final int getInstructionCount() {
|
||||||
final IRBlock getASuccessor() {
|
result = strictcount(getInstruction(_))
|
||||||
blockSuccessor(this, result)
|
}
|
||||||
}
|
|
||||||
|
final FunctionIR getFunctionIR() {
|
||||||
final IRBlock getAPredecessor() {
|
result = getFirstInstruction(this).getFunctionIR()
|
||||||
blockSuccessor(result, this)
|
}
|
||||||
}
|
|
||||||
|
final Function getFunction() {
|
||||||
final IRBlock getSuccessor(EdgeKind kind) {
|
result = getFirstInstruction(this).getFunction()
|
||||||
blockSuccessor(this, result, kind)
|
}
|
||||||
}
|
|
||||||
|
final IRBlock getASuccessor() {
|
||||||
final predicate immediatelyDominates(IRBlock block) {
|
blockSuccessor(this, result)
|
||||||
blockImmediatelyDominates(this, block)
|
}
|
||||||
}
|
|
||||||
|
final IRBlock getAPredecessor() {
|
||||||
final predicate strictlyDominates(IRBlock block) {
|
blockSuccessor(result, this)
|
||||||
blockImmediatelyDominates+(this, block)
|
}
|
||||||
}
|
|
||||||
|
final IRBlock getSuccessor(EdgeKind kind) {
|
||||||
final predicate dominates(IRBlock block) {
|
blockSuccessor(this, result, kind)
|
||||||
strictlyDominates(block) or this = block
|
}
|
||||||
}
|
|
||||||
|
final predicate immediatelyDominates(IRBlock block) {
|
||||||
pragma[noinline]
|
blockImmediatelyDominates(this, block)
|
||||||
final IRBlock dominanceFrontier() {
|
}
|
||||||
dominates(result.getAPredecessor()) and
|
|
||||||
not strictlyDominates(result)
|
final predicate strictlyDominates(IRBlock block) {
|
||||||
}
|
blockImmediatelyDominates+(this, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final predicate dominates(IRBlock block) {
|
||||||
|
strictlyDominates(block) or this = block
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
final IRBlock dominanceFrontier() {
|
||||||
|
dominates(result.getAPredecessor()) and
|
||||||
|
not strictlyDominates(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -90,8 +90,132 @@ class Instruction extends Construction::TInstruction {
|
|||||||
this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
|
this = Construction::MkInstruction(funcIR, opcode, ast, instructionTag, resultType, glvalue)
|
||||||
}
|
}
|
||||||
|
|
||||||
string toString() {
|
final string toString() {
|
||||||
result = opcode.toString()
|
result = getResultString() + " = " + getOperationString() + " " + getOperandsString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string describing the operation of this instruction. This includes
|
||||||
|
* the opcode and the immediate value, if any. For example:
|
||||||
|
*
|
||||||
|
* VariableAddress[x]
|
||||||
|
*/
|
||||||
|
final string getOperationString() {
|
||||||
|
if exists(getImmediateString()) then
|
||||||
|
result = opcode.toString() + "[" + getImmediateString() + "]"
|
||||||
|
else
|
||||||
|
result = opcode.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string describing the immediate value of this instruction, if any.
|
||||||
|
*/
|
||||||
|
string getImmediateString() {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
private string getResultPrefix() {
|
||||||
|
if resultType instanceof VoidType then
|
||||||
|
result = "v"
|
||||||
|
else if hasMemoryResult() then
|
||||||
|
if isResultModeled() then
|
||||||
|
result = "m"
|
||||||
|
else
|
||||||
|
result = "mu"
|
||||||
|
else
|
||||||
|
result = "r"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the zero-based index of this instruction within its block. This is
|
||||||
|
* used by debugging and printing code only.
|
||||||
|
*/
|
||||||
|
int getDisplayIndexInBlock() {
|
||||||
|
exists(IRBlock block |
|
||||||
|
block = getBlock() and
|
||||||
|
(
|
||||||
|
exists(int index, int phiCount |
|
||||||
|
phiCount = count(block.getAPhiInstruction()) and
|
||||||
|
this = block.getInstruction(index) and
|
||||||
|
result = index + phiCount
|
||||||
|
) or
|
||||||
|
(
|
||||||
|
this instanceof PhiInstruction and
|
||||||
|
this = rank[result + 1](PhiInstruction phiInstr |
|
||||||
|
phiInstr = block.getAPhiInstruction() |
|
||||||
|
phiInstr order by phiInstr.getUniqueId()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[type]
|
||||||
|
private string getValueCategoryString(string type) {
|
||||||
|
if isGLValue() then
|
||||||
|
result = "glval<" + type + ">"
|
||||||
|
else
|
||||||
|
result = type
|
||||||
|
}
|
||||||
|
|
||||||
|
private string getResultTypeString() {
|
||||||
|
exists(string valcat |
|
||||||
|
valcat = getValueCategoryString(resultType.toString()) and
|
||||||
|
if resultType instanceof UnknownType and exists(getResultSize()) then
|
||||||
|
result = valcat + "[" + getResultSize().toString() + "]"
|
||||||
|
else
|
||||||
|
result = valcat
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a human-readable string that uniquely identifies this instruction
|
||||||
|
* within the function. This string is used to refer to this instruction when
|
||||||
|
* printing IR dumps.
|
||||||
|
*
|
||||||
|
* Example: `r1_1`
|
||||||
|
*/
|
||||||
|
string getResultId() {
|
||||||
|
result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
|
||||||
|
getDisplayIndexInBlock().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string describing the result of this instruction, suitable for
|
||||||
|
* display in IR dumps. This consists of the result ID plus the type of the
|
||||||
|
* result.
|
||||||
|
*
|
||||||
|
* Example: `r1_1(int*)`
|
||||||
|
*/
|
||||||
|
final string getResultString() {
|
||||||
|
result = getResultId() + "(" + getResultTypeString() + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string describing the specified 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 kind.
|
||||||
|
*
|
||||||
|
* For example: `this:r3_5`
|
||||||
|
*/
|
||||||
|
string getOperandString(OperandTag tag) {
|
||||||
|
exists(Instruction operand |
|
||||||
|
operand = getOperand(tag) and
|
||||||
|
result = tag.getLabel() + operand.getResultId()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string describing the operands of this instruction, suitable for
|
||||||
|
* display in IR dumps.
|
||||||
|
*
|
||||||
|
* Example: `func:r3_4, this:r3_5`
|
||||||
|
*/
|
||||||
|
string getOperandsString() {
|
||||||
|
result = concat(OperandTag tag, Instruction operand |
|
||||||
|
operand = getOperand(tag) |
|
||||||
|
tag.getLabel() + operand.getResultId(), ", " order by tag.getSortOrder()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -312,8 +436,8 @@ class VariableInstruction extends Instruction {
|
|||||||
var = Construction::getInstructionVariable(this)
|
var = Construction::getInstructionVariable(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + var.toString() + "]"
|
result = var.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
final IRVariable getVariable() {
|
final IRVariable getVariable() {
|
||||||
@@ -328,8 +452,8 @@ class FieldInstruction extends Instruction {
|
|||||||
field = Construction::getInstructionField(this)
|
field = Construction::getInstructionField(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + field.toString() + "]"
|
result = field.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
final Field getField() {
|
final Field getField() {
|
||||||
@@ -344,8 +468,8 @@ class FunctionInstruction extends Instruction {
|
|||||||
funcSymbol = Construction::getInstructionFunction(this)
|
funcSymbol = Construction::getInstructionFunction(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + funcSymbol.toString() + "]"
|
result = funcSymbol.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
final Function getFunctionSymbol() {
|
final Function getFunctionSymbol() {
|
||||||
@@ -360,8 +484,8 @@ class ConstantValueInstruction extends Instruction {
|
|||||||
value = Construction::getInstructionConstantValue(this)
|
value = Construction::getInstructionConstantValue(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + value + "]"
|
result = value
|
||||||
}
|
}
|
||||||
|
|
||||||
final string getValue() {
|
final string getValue() {
|
||||||
@@ -534,10 +658,8 @@ class StringConstantInstruction extends Instruction {
|
|||||||
value = Construction::getInstructionStringLiteral(this)
|
value = Construction::getInstructionStringLiteral(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" +
|
result = value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ")
|
||||||
value.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ") +
|
|
||||||
"]"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final StringLiteral getValue() {
|
final StringLiteral getValue() {
|
||||||
@@ -627,8 +749,8 @@ class PointerArithmeticInstruction extends BinaryInstruction {
|
|||||||
elementSize = Construction::getInstructionElementSize(this)
|
elementSize = Construction::getInstructionElementSize(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + elementSize.toString() + "]"
|
result = elementSize.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
final int getElementSize() {
|
final int getElementSize() {
|
||||||
@@ -688,8 +810,8 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
|||||||
Construction::getInstructionInheritance(this, baseClass, derivedClass)
|
Construction::getInstructionInheritance(this, baseClass, derivedClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
override final string toString() {
|
override final string getImmediateString() {
|
||||||
result = super.toString() + "[" + derivedClass.toString() + " : " + baseClass.toString() + "]"
|
result = derivedClass.toString() + " : " + baseClass.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -908,8 +1030,8 @@ class CatchByTypeInstruction extends CatchInstruction {
|
|||||||
exceptionType = Construction::getInstructionExceptionType(this)
|
exceptionType = Construction::getInstructionExceptionType(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
final override string toString() {
|
final override string getImmediateString() {
|
||||||
result = super.toString() + "[" + exceptionType.toString() + "]"
|
result = exceptionType.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -944,6 +1066,10 @@ class UnmodeledUseInstruction extends Instruction {
|
|||||||
opcode instanceof Opcode::UnmodeledUse
|
opcode instanceof Opcode::UnmodeledUse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override string getOperandsString() {
|
||||||
|
result = "mu*"
|
||||||
|
}
|
||||||
|
|
||||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||||
tag instanceof UnmodeledUseOperand and
|
tag instanceof UnmodeledUseOperand and
|
||||||
result instanceof UnmodeledMemoryAccess
|
result instanceof UnmodeledMemoryAccess
|
||||||
|
|||||||
@@ -1,299 +1,312 @@
|
|||||||
private import IRInternal
|
private import IRInternal
|
||||||
import Instruction
|
import Instruction
|
||||||
import IRBlock
|
import IRBlock
|
||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
private newtype TOperandTag =
|
private newtype TOperandTag =
|
||||||
TLoadStoreAddressOperand() or
|
TLoadStoreAddressOperand() or
|
||||||
TCopySourceOperand() or
|
TCopySourceOperand() or
|
||||||
TUnaryOperand() or
|
TUnaryOperand() or
|
||||||
TLeftOperand() or
|
TLeftOperand() or
|
||||||
TRightOperand() or
|
TRightOperand() or
|
||||||
TReturnValueOperand() or
|
TReturnValueOperand() or
|
||||||
TExceptionOperand() or
|
TExceptionOperand() or
|
||||||
TConditionOperand() or
|
TConditionOperand() or
|
||||||
TUnmodeledUseOperand() or
|
TUnmodeledUseOperand() or
|
||||||
TCallTargetOperand() or
|
TCallTargetOperand() or
|
||||||
TThisArgumentOperand() or
|
TThisArgumentOperand() or
|
||||||
TPositionalArgumentOperand(int argIndex) {
|
TPositionalArgumentOperand(int argIndex) {
|
||||||
argIndex in [0..Construction::getMaxCallArgIndex()] or
|
argIndex in [0..Construction::getMaxCallArgIndex()] or
|
||||||
exists(BuiltInOperation op |
|
exists(BuiltInOperation op |
|
||||||
exists(op.getChild(argIndex))
|
exists(op.getChild(argIndex))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPhiOperand(IRBlock predecessorBlock) {
|
TPhiOperand(IRBlock predecessorBlock) {
|
||||||
exists(PhiInstruction phi |
|
exists(PhiInstruction phi |
|
||||||
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
|
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||||
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
||||||
* an `Instruction` is determined by the instruction's opcode.
|
* an `Instruction` is determined by the instruction's opcode.
|
||||||
*/
|
*/
|
||||||
abstract class OperandTag extends TOperandTag {
|
abstract class OperandTag extends TOperandTag {
|
||||||
abstract string toString();
|
abstract string toString();
|
||||||
abstract int getSortOrder();
|
|
||||||
}
|
abstract int getSortOrder();
|
||||||
|
|
||||||
// Note: individual subtypes are listed in the order that the operands should
|
string getLabel() {
|
||||||
// appear in the operand list of the instruction when printing.
|
result = ""
|
||||||
|
}
|
||||||
/**
|
}
|
||||||
* The address operand of an instruction that loads or stores a value from
|
|
||||||
* memory (e.g. `Load`, `Store`).
|
// Note: individual subtypes are listed in the order that the operands should
|
||||||
*/
|
// appear in the operand list of the instruction when printing.
|
||||||
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
|
|
||||||
override final string toString() {
|
/**
|
||||||
result = "LoadStoreAddress"
|
* The address operand of an instruction that loads or stores a value from
|
||||||
}
|
* memory (e.g. `Load`, `Store`).
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
|
||||||
result = 0
|
override final string toString() {
|
||||||
}
|
result = "LoadStoreAddress"
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadStoreAddressOperand loadStoreAddressOperand() {
|
override final int getSortOrder() {
|
||||||
result = TLoadStoreAddressOperand()
|
result = 0
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The source value operand of an instruction that copies this value to its
|
LoadStoreAddressOperand loadStoreAddressOperand() {
|
||||||
* result (e.g. `Copy`, `Load`, `Store`).
|
result = TLoadStoreAddressOperand()
|
||||||
*/
|
}
|
||||||
class CopySourceOperand extends OperandTag, TCopySourceOperand {
|
|
||||||
override final string toString() {
|
/**
|
||||||
result = "CopySource"
|
* The source value operand of an instruction that copies this value to its
|
||||||
}
|
* result (e.g. `Copy`, `Load`, `Store`).
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class CopySourceOperand extends OperandTag, TCopySourceOperand {
|
||||||
result = 1
|
override final string toString() {
|
||||||
}
|
result = "CopySource"
|
||||||
}
|
}
|
||||||
|
|
||||||
CopySourceOperand copySourceOperand() {
|
override final int getSortOrder() {
|
||||||
result = TCopySourceOperand()
|
result = 1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
CopySourceOperand copySourceOperand() {
|
||||||
*/
|
result = TCopySourceOperand()
|
||||||
class UnaryOperand extends OperandTag, TUnaryOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "Unary"
|
/**
|
||||||
}
|
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class UnaryOperand extends OperandTag, TUnaryOperand {
|
||||||
result = 2
|
override final string toString() {
|
||||||
}
|
result = "Unary"
|
||||||
}
|
}
|
||||||
|
|
||||||
UnaryOperand unaryOperand() {
|
override final int getSortOrder() {
|
||||||
result = TUnaryOperand()
|
result = 2
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
UnaryOperand unaryOperand() {
|
||||||
*/
|
result = TUnaryOperand()
|
||||||
class LeftOperand extends OperandTag, TLeftOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "Left"
|
/**
|
||||||
}
|
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class LeftOperand extends OperandTag, TLeftOperand {
|
||||||
result = 3
|
override final string toString() {
|
||||||
}
|
result = "Left"
|
||||||
}
|
}
|
||||||
|
|
||||||
LeftOperand leftOperand() {
|
override final int getSortOrder() {
|
||||||
result = TLeftOperand()
|
result = 3
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
LeftOperand leftOperand() {
|
||||||
*/
|
result = TLeftOperand()
|
||||||
class RightOperand extends OperandTag, TRightOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "Right"
|
/**
|
||||||
}
|
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class RightOperand extends OperandTag, TRightOperand {
|
||||||
result = 4
|
override final string toString() {
|
||||||
}
|
result = "Right"
|
||||||
}
|
}
|
||||||
|
|
||||||
RightOperand rightOperand() {
|
override final int getSortOrder() {
|
||||||
result = TRightOperand()
|
result = 4
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The return value operand of a `ReturnValue` instruction.
|
RightOperand rightOperand() {
|
||||||
*/
|
result = TRightOperand()
|
||||||
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "ReturnValue"
|
/**
|
||||||
}
|
* The return value operand of a `ReturnValue` instruction.
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
|
||||||
result = 5
|
override final string toString() {
|
||||||
}
|
result = "ReturnValue"
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValueOperand returnValueOperand() {
|
override final int getSortOrder() {
|
||||||
result = TReturnValueOperand()
|
result = 5
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The exception thrown by a `ThrowValue` instruction.
|
ReturnValueOperand returnValueOperand() {
|
||||||
*/
|
result = TReturnValueOperand()
|
||||||
class ExceptionOperand extends OperandTag, TExceptionOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "Exception"
|
/**
|
||||||
}
|
* The exception thrown by a `ThrowValue` instruction.
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class ExceptionOperand extends OperandTag, TExceptionOperand {
|
||||||
result = 6
|
override final string toString() {
|
||||||
}
|
result = "Exception"
|
||||||
}
|
}
|
||||||
|
|
||||||
ExceptionOperand exceptionOperand() {
|
override final int getSortOrder() {
|
||||||
result = TExceptionOperand()
|
result = 6
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
ExceptionOperand exceptionOperand() {
|
||||||
*/
|
result = TExceptionOperand()
|
||||||
class ConditionOperand extends OperandTag, TConditionOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "Condition"
|
/**
|
||||||
}
|
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class ConditionOperand extends OperandTag, TConditionOperand {
|
||||||
result = 7
|
override final string toString() {
|
||||||
}
|
result = "Condition"
|
||||||
}
|
}
|
||||||
|
|
||||||
ConditionOperand conditionOperand() {
|
override final int getSortOrder() {
|
||||||
result = TConditionOperand()
|
result = 7
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
ConditionOperand conditionOperand() {
|
||||||
* whose set of uses is unknown.
|
result = TConditionOperand()
|
||||||
*/
|
}
|
||||||
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
|
|
||||||
override final string toString() {
|
/**
|
||||||
result = "UnmodeledUse"
|
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||||
}
|
* whose set of uses is unknown.
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
|
||||||
result = 8
|
override final string toString() {
|
||||||
}
|
result = "UnmodeledUse"
|
||||||
}
|
}
|
||||||
|
|
||||||
UnmodeledUseOperand unmodeledUseOperand() {
|
override final int getSortOrder() {
|
||||||
result = TUnmodeledUseOperand()
|
result = 8
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* The operand representing the target function of an `Invoke` instruction.
|
UnmodeledUseOperand unmodeledUseOperand() {
|
||||||
*/
|
result = TUnmodeledUseOperand()
|
||||||
class CallTargetOperand extends OperandTag, TCallTargetOperand {
|
}
|
||||||
override final string toString() {
|
|
||||||
result = "CallTarget"
|
/**
|
||||||
}
|
* The operand representing the target function of an `Invoke` instruction.
|
||||||
|
*/
|
||||||
override final int getSortOrder() {
|
class CallTargetOperand extends OperandTag, TCallTargetOperand {
|
||||||
result = 9
|
override final string toString() {
|
||||||
}
|
result = "CallTarget"
|
||||||
}
|
}
|
||||||
|
|
||||||
CallTargetOperand callTargetOperand() {
|
override final int getSortOrder() {
|
||||||
result = TCallTargetOperand()
|
result = 9
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* An operand representing an argument to a function call. This includes both
|
CallTargetOperand callTargetOperand() {
|
||||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
result = TCallTargetOperand()
|
||||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
}
|
||||||
*/
|
|
||||||
abstract class ArgumentOperand extends OperandTag {
|
/**
|
||||||
}
|
* An operand representing an argument to a function call. This includes both
|
||||||
|
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||||
/**
|
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||||
* An operand representing the implicit 'this' argument to a member function
|
*/
|
||||||
* call.
|
abstract class ArgumentOperand extends OperandTag {
|
||||||
*/
|
}
|
||||||
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
|
|
||||||
ThisArgumentOperand() {
|
/**
|
||||||
this = TThisArgumentOperand()
|
* An operand representing the implicit 'this' argument to a member function
|
||||||
}
|
* call.
|
||||||
|
*/
|
||||||
override final string toString() {
|
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
|
||||||
result = "Arg(this)"
|
ThisArgumentOperand() {
|
||||||
}
|
this = TThisArgumentOperand()
|
||||||
|
}
|
||||||
override final int getSortOrder() {
|
|
||||||
result = 10
|
override final string toString() {
|
||||||
}
|
result = "Arg(this)"
|
||||||
}
|
}
|
||||||
|
|
||||||
ThisArgumentOperand thisArgumentOperand() {
|
override final int getSortOrder() {
|
||||||
result = TThisArgumentOperand()
|
result = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override final string getLabel() {
|
||||||
* An operand representing an argument to a function call.
|
result = "this:"
|
||||||
*/
|
}
|
||||||
class PositionalArgumentOperand extends ArgumentOperand,
|
}
|
||||||
TPositionalArgumentOperand {
|
|
||||||
int argIndex;
|
ThisArgumentOperand thisArgumentOperand() {
|
||||||
|
result = TThisArgumentOperand()
|
||||||
PositionalArgumentOperand() {
|
}
|
||||||
this = TPositionalArgumentOperand(argIndex)
|
|
||||||
}
|
/**
|
||||||
|
* An operand representing an argument to a function call.
|
||||||
override final string toString() {
|
*/
|
||||||
result = "Arg(" + argIndex + ")"
|
class PositionalArgumentOperand extends ArgumentOperand,
|
||||||
}
|
TPositionalArgumentOperand {
|
||||||
|
int argIndex;
|
||||||
override final int getSortOrder() {
|
|
||||||
result = 11 + argIndex
|
PositionalArgumentOperand() {
|
||||||
}
|
this = TPositionalArgumentOperand(argIndex)
|
||||||
|
}
|
||||||
final int getArgIndex() {
|
|
||||||
result = argIndex
|
override final string toString() {
|
||||||
}
|
result = "Arg(" + argIndex + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
|
override final int getSortOrder() {
|
||||||
result = TPositionalArgumentOperand(argIndex)
|
result = 11 + argIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
final int getArgIndex() {
|
||||||
* An operand of an SSA `Phi` instruction.
|
result = argIndex
|
||||||
*/
|
}
|
||||||
class PhiOperand extends OperandTag, TPhiOperand {
|
}
|
||||||
IRBlock predecessorBlock;
|
|
||||||
|
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
|
||||||
PhiOperand() {
|
result = TPositionalArgumentOperand(argIndex)
|
||||||
this = TPhiOperand(predecessorBlock)
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
override final string toString() {
|
* An operand of an SSA `Phi` instruction.
|
||||||
result = "Phi"
|
*/
|
||||||
}
|
class PhiOperand extends OperandTag, TPhiOperand {
|
||||||
|
IRBlock predecessorBlock;
|
||||||
override final int getSortOrder() {
|
|
||||||
result = 11
|
PhiOperand() {
|
||||||
}
|
this = TPhiOperand(predecessorBlock)
|
||||||
|
}
|
||||||
final IRBlock getPredecessorBlock() {
|
|
||||||
result = predecessorBlock
|
override final string toString() {
|
||||||
}
|
result = "Phi"
|
||||||
}
|
}
|
||||||
|
|
||||||
PhiOperand phiOperand(IRBlock predecessorBlock) {
|
override final int getSortOrder() {
|
||||||
result = TPhiOperand(predecessorBlock)
|
result = 11 + getPredecessorBlock().getDisplayIndex()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override final string getLabel() {
|
||||||
|
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||||
|
}
|
||||||
|
|
||||||
|
final IRBlock getPredecessorBlock() {
|
||||||
|
result = predecessorBlock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PhiOperand phiOperand(IRBlock predecessorBlock) {
|
||||||
|
result = TPhiOperand(predecessorBlock)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,175 +1,239 @@
|
|||||||
private import IRImpl
|
private import IRImpl
|
||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
private int getInstructionIndexInBlock(Instruction instr) {
|
private newtype TPrintableIRNode =
|
||||||
exists(IRBlock block |
|
TPrintableFunctionIR(FunctionIR funcIR) or
|
||||||
block = instr.getBlock() and
|
TPrintableIRBlock(IRBlock block) or
|
||||||
|
TPrintableInstruction(Instruction instr)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node to be emitted in the IR graph.
|
||||||
|
*/
|
||||||
|
abstract class PrintableIRNode extends TPrintableIRNode {
|
||||||
|
abstract string toString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the location to be emitted for the node.
|
||||||
|
*/
|
||||||
|
abstract Location getLocation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the label to be emitted for the node.
|
||||||
|
*/
|
||||||
|
abstract string getLabel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the order in which the node appears in its parent node.
|
||||||
|
*/
|
||||||
|
abstract int getOrder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the parent of this node.
|
||||||
|
*/
|
||||||
|
abstract PrintableIRNode getParent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the kind of graph represented by this node ("graph" or "tree").
|
||||||
|
*/
|
||||||
|
string getGraphKind() {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this node should always be rendered as text, even in a graphical
|
||||||
|
* viewer.
|
||||||
|
*/
|
||||||
|
predicate forceText() {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of the node property with the specified key.
|
||||||
|
*/
|
||||||
|
string getProperty(string key) {
|
||||||
|
key = "semmle.label" and result = getLabel() or
|
||||||
|
key = "semmle.order" and result = getOrder().toString() or
|
||||||
|
key = "semmle.graphKind" and result = getGraphKind() or
|
||||||
|
key = "semmle.forceText" and forceText() and result = "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An IR graph node representing a `FunctionIR` object.
|
||||||
|
*/
|
||||||
|
class PrintableFunctionIR extends PrintableIRNode, TPrintableFunctionIR {
|
||||||
|
FunctionIR funcIR;
|
||||||
|
|
||||||
|
PrintableFunctionIR() {
|
||||||
|
this = TPrintableFunctionIR(funcIR)
|
||||||
|
}
|
||||||
|
|
||||||
|
override string toString() {
|
||||||
|
result = funcIR.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Location getLocation() {
|
||||||
|
result = funcIR.getLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getLabel() {
|
||||||
|
result = funcIR.getFunction().getFullSignature()
|
||||||
|
}
|
||||||
|
|
||||||
|
override int getOrder() {
|
||||||
|
this = rank[result + 1](PrintableFunctionIR orderedFunc, Location location |
|
||||||
|
location = orderedFunc.getFunctionIR().getLocation() |
|
||||||
|
orderedFunc order by location.getFile().getURL(), location.getStartLine(),
|
||||||
|
location.getStartColumn(), orderedFunc.getLabel()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override final PrintableIRNode getParent() {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
final FunctionIR getFunctionIR() {
|
||||||
|
result = funcIR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An IR graph node representing an `IRBlock` object.
|
||||||
|
*/
|
||||||
|
class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
||||||
|
IRBlock block;
|
||||||
|
|
||||||
|
PrintableIRBlock() {
|
||||||
|
this = TPrintableIRBlock(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
override string toString() {
|
||||||
|
result = getLabel()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Location getLocation() {
|
||||||
|
result = block.getLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getLabel() {
|
||||||
|
result = "Block " + block.getDisplayIndex().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override int getOrder() {
|
||||||
|
result = block.getDisplayIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
override final string getGraphKind() {
|
||||||
|
result = "tree"
|
||||||
|
}
|
||||||
|
|
||||||
|
override final predicate forceText() {
|
||||||
|
any()
|
||||||
|
}
|
||||||
|
|
||||||
|
override final PrintableFunctionIR getParent() {
|
||||||
|
result.getFunctionIR() = block.getFunctionIR()
|
||||||
|
}
|
||||||
|
|
||||||
|
final IRBlock getBlock() {
|
||||||
|
result = block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An IR graph node representing an `Instruction`.
|
||||||
|
*/
|
||||||
|
class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
|
||||||
|
Instruction instr;
|
||||||
|
|
||||||
|
PrintableInstruction() {
|
||||||
|
this = TPrintableInstruction(instr)
|
||||||
|
}
|
||||||
|
|
||||||
|
override string toString() {
|
||||||
|
result = instr.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Location getLocation() {
|
||||||
|
result = instr.getLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getLabel() {
|
||||||
|
exists(IRBlock block |
|
||||||
|
instr = block.getAnInstruction() and
|
||||||
|
exists(string resultString, string operationString, string operandsString,
|
||||||
|
int resultWidth, int operationWidth |
|
||||||
|
resultString = instr.getResultString() and
|
||||||
|
operationString = instr.getOperationString() and
|
||||||
|
operandsString = instr.getOperandsString() and
|
||||||
|
columnWidths(block, resultWidth, operationWidth) and
|
||||||
|
result = resultString + getPaddingString(resultWidth - resultString.length()) +
|
||||||
|
" = " + operationString + getPaddingString(operationWidth - operationString.length()) +
|
||||||
|
" : " + operandsString
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override int getOrder() {
|
||||||
|
result = instr.getDisplayIndexInBlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
override final PrintableIRBlock getParent() {
|
||||||
|
result.getBlock() = instr.getBlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
final Instruction getInstruction() {
|
||||||
|
result = instr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {
|
||||||
|
resultWidth = max(Instruction instr | instr.getBlock() = block | instr.getResultString().length()) and
|
||||||
|
operationWidth = max(Instruction instr | instr.getBlock() = block | instr.getOperationString().length())
|
||||||
|
}
|
||||||
|
|
||||||
|
private int maxColumnWidth() {
|
||||||
|
result = max(Instruction instr, int width |
|
||||||
|
width = instr.getResultString().length() or
|
||||||
|
width = instr.getOperationString().length() or
|
||||||
|
width = instr.getOperandsString().length() |
|
||||||
|
width)
|
||||||
|
}
|
||||||
|
|
||||||
|
private string getPaddingString(int n) {
|
||||||
|
n = 0 and result = "" or
|
||||||
|
n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " "
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate nodes(PrintableIRNode node, string key, string value) {
|
||||||
|
value = node.getProperty(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getSuccessorIndex(IRBlock pred, IRBlock succ) {
|
||||||
|
succ = rank[result + 1](IRBlock aSucc, EdgeKind kind |
|
||||||
|
aSucc = pred.getSuccessor(kind) |
|
||||||
|
aSucc order by kind.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) {
|
||||||
|
exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock |
|
||||||
|
predBlock = pred.getBlock() and
|
||||||
|
succBlock = succ.getBlock() and
|
||||||
|
predBlock.getSuccessor(kind) = succBlock and
|
||||||
(
|
(
|
||||||
exists(int index, int phiCount |
|
(
|
||||||
phiCount = count(block.getAPhiInstruction()) and
|
key = "semmle.label" and
|
||||||
instr = block.getInstruction(index) and
|
value = kind.toString()
|
||||||
result = index + phiCount
|
|
||||||
) or
|
) or
|
||||||
(
|
(
|
||||||
instr instanceof PhiInstruction and
|
key = "semmle.order" and
|
||||||
instr = rank[result + 1](PhiInstruction phiInstr |
|
value = getSuccessorIndex(predBlock, succBlock).toString()
|
||||||
phiInstr = block.getAPhiInstruction() |
|
|
||||||
phiInstr order by phiInstr.getUniqueId()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private string getInstructionResultId(Instruction instr) {
|
query predicate parents(PrintableIRNode child, PrintableIRNode parent) {
|
||||||
result = getResultPrefix(instr) + getBlockId(instr.getBlock()) + "_" +
|
parent = child.getParent()
|
||||||
getInstructionIndexInBlock(instr).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
private string getResultPrefix(Instruction instr) {
|
|
||||||
if instr.hasMemoryResult() then
|
|
||||||
if instr.isResultModeled() then
|
|
||||||
result = "@m"
|
|
||||||
else
|
|
||||||
result = "@mu"
|
|
||||||
else
|
|
||||||
result = "@r"
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the identifier of the specified function scope.
|
|
||||||
* Currently just returns the signature of the function.
|
|
||||||
*/
|
|
||||||
private string getScopeId(Function func) {
|
|
||||||
result = func.getFullSignature()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the unique identifier of the block within its function.
|
|
||||||
* Currently returns a string representation of an integer in the range
|
|
||||||
* [0..numBlocks - 1].
|
|
||||||
*/
|
|
||||||
private string getBlockId(IRBlock block) {
|
|
||||||
exists(int rankIndex |
|
|
||||||
block = rank[rankIndex + 1](IRBlock funcBlock |
|
|
||||||
funcBlock.getFunction() = block.getFunction() |
|
|
||||||
funcBlock order by funcBlock.getUniqueId()
|
|
||||||
) and
|
|
||||||
result = rankIndex.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints the full signature and qualified name for each scope. This is primarily
|
|
||||||
* so that post-processing tools can identify function overloads, which will have
|
|
||||||
* different signatures but the same qualified name.
|
|
||||||
*/
|
|
||||||
query predicate printIRGraphScopes(string scopeId, string qualifiedName) {
|
|
||||||
exists(FunctionIR ir, Function func |
|
|
||||||
func = ir.getFunction() and
|
|
||||||
scopeId = getScopeId(func) and
|
|
||||||
qualifiedName = func.getQualifiedName()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
query predicate printIRGraphNodes(string scopeId, string blockId, string label, string location) {
|
|
||||||
exists(IRBlock block |
|
|
||||||
scopeId = getScopeId(block.getFunction()) and
|
|
||||||
blockId = getBlockId(block) and
|
|
||||||
label = "" and
|
|
||||||
location = ""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
query predicate printIRGraphInstructions(string scopeId, string blockId,
|
|
||||||
string id, string label, string location) {
|
|
||||||
exists(IRBlock block, Instruction instr |
|
|
||||||
instr = block.getAnInstruction() and
|
|
||||||
label = instr.toString() and
|
|
||||||
location = instr.getLocation().toString() and
|
|
||||||
scopeId = getScopeId(block.getFunction()) and
|
|
||||||
blockId = getBlockId(block) and
|
|
||||||
id = getInstructionIndexInBlock(instr).toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
query predicate printIRGraphEdges(string scopeId,
|
|
||||||
string predecessorId, string successorId, string label) {
|
|
||||||
exists(IRBlock predecessor, IRBlock successor, EdgeKind kind |
|
|
||||||
scopeId = getScopeId(predecessor.getFunction()) and
|
|
||||||
predecessor.getSuccessor(kind) = successor and
|
|
||||||
predecessorId = getBlockId(predecessor) and
|
|
||||||
successorId = getBlockId(successor) and
|
|
||||||
label = kind.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private string getValueCategoryString(Instruction instr) {
|
|
||||||
if instr.isGLValue() then
|
|
||||||
result = "glval:"
|
|
||||||
else
|
|
||||||
result = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
private string getResultTypeString(Instruction instr) {
|
|
||||||
exists(Type resultType, string valcat |
|
|
||||||
resultType = instr.getResultType() and
|
|
||||||
valcat = getValueCategoryString(instr) and
|
|
||||||
if resultType instanceof UnknownType and exists(instr.getResultSize()) then
|
|
||||||
result = valcat + resultType.toString() + "[" + instr.getResultSize().toString() + "]"
|
|
||||||
else
|
|
||||||
result = valcat + resultType.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
query predicate printIRGraphDestinationOperands(string scopeId, string blockId,
|
|
||||||
string instructionId, int operandId, string label) {
|
|
||||||
exists(IRBlock block, Instruction instr |
|
|
||||||
block.getAnInstruction() = instr and
|
|
||||||
scopeId = getScopeId(block.getFunction()) and
|
|
||||||
blockId = getBlockId(block) and
|
|
||||||
instructionId = getInstructionIndexInBlock(instr).toString() and
|
|
||||||
not instr.getResultType() instanceof VoidType and
|
|
||||||
operandId = 0 and
|
|
||||||
label = getInstructionResultId(instr) +
|
|
||||||
"(" + getResultTypeString(instr) + ")"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private string getOperandTagLabel(OperandTag tag) {
|
|
||||||
(
|
|
||||||
tag instanceof PhiOperand and
|
|
||||||
result = "from " + getBlockId(tag.(PhiOperand).getPredecessorBlock()) + ": "
|
|
||||||
)
|
|
||||||
or (
|
|
||||||
tag instanceof ThisArgumentOperand and
|
|
||||||
result = "this:"
|
|
||||||
)
|
|
||||||
or (
|
|
||||||
not tag instanceof PhiOperand and
|
|
||||||
not tag instanceof ThisArgumentOperand and
|
|
||||||
result = ""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
query predicate printIRGraphSourceOperands(string scopeId, string blockId,
|
|
||||||
string instructionId, int operandId, string label) {
|
|
||||||
exists(IRBlock block, Instruction instr |
|
|
||||||
block.getAnInstruction() = instr and
|
|
||||||
blockId = getBlockId(block) and
|
|
||||||
scopeId = getScopeId(block.getFunction()) and
|
|
||||||
instructionId = getInstructionIndexInBlock(instr).toString() and
|
|
||||||
if (instr instanceof UnmodeledUseInstruction) then (
|
|
||||||
operandId = 0 and
|
|
||||||
label = "@mu*"
|
|
||||||
)
|
|
||||||
else (
|
|
||||||
exists(OperandTag tag, Instruction operandInstr |
|
|
||||||
operandInstr = instr.getOperand(tag) and
|
|
||||||
operandId = tag.getSortOrder() and
|
|
||||||
label = getOperandTagLabel(tag) +
|
|
||||||
getInstructionResultId(operandInstr)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
void v(int i) {
|
void AddressOf(int i) {
|
||||||
int *j = &i;
|
int *j = &i;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ struct S {
|
|||||||
char* name;
|
char* name;
|
||||||
};
|
};
|
||||||
|
|
||||||
void v()
|
void ArrayToPointer()
|
||||||
{
|
{
|
||||||
char c[] = "hello";
|
char c[] = "hello";
|
||||||
struct S s;
|
struct S s;
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
void v(char *c, void *v) {
|
void Cast(char *c, void *v) {
|
||||||
c = (char *)v;
|
c = (char *)v;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
void v() {
|
void ConditionDecl() {
|
||||||
int j = 0;
|
int j = 0;
|
||||||
while(int k = j < 5) {
|
while(int k = j < 5) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class E {
|
|||||||
public:
|
public:
|
||||||
};
|
};
|
||||||
|
|
||||||
void v(C *c, D *d, E *e) {
|
void ConstructorCall(C *c, D *d, E *e) {
|
||||||
c = new C(5);
|
c = new C(5);
|
||||||
d = new D();
|
d = new D();
|
||||||
e = new E();
|
e = new E();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
void v() {
|
void Conversion1() {
|
||||||
int i = (int)1;
|
int i = (int)1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
void v(int x) {
|
void Conversion2(int x) {
|
||||||
x = (int)5 + (int)7;
|
x = (int)5 + (int)7;
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
void v(int x) {
|
void Conversion3(int x) {
|
||||||
x = (bool)(int)5 + ((int)7);
|
x = (bool)(int)5 + ((int)7);
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
void v(int x) {
|
void Conversion4(int x) {
|
||||||
x = ((int)7);
|
x = ((int)7);
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@ class D {
|
|||||||
public:
|
public:
|
||||||
};
|
};
|
||||||
|
|
||||||
void v(C *c, D *d) {
|
void DestructorCall(C *c, D *d) {
|
||||||
delete c;
|
delete c;
|
||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
@@ -5,10 +5,10 @@ class Derived : public Base {
|
|||||||
void f() { }
|
void f() { }
|
||||||
};
|
};
|
||||||
|
|
||||||
void v(Base *bp, Derived *d) {
|
void DynamicCast(Base *bp, Derived *d) {
|
||||||
d = dynamic_cast<Derived *>(bp);
|
d = dynamic_cast<Derived *>(bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void v_ref(Base &bp, Derived &d) {
|
void DynamicCastRef(Base &bp, Derived &d) {
|
||||||
d = dynamic_cast<Derived &>(bp);
|
d = dynamic_cast<Derived &>(bp);
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
void v(int i) {
|
void Parenthesis(int i) {
|
||||||
i = (i + 1) * 2;
|
i = (i + 1) * 2;
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
void v(int *i, int j) {
|
void PointerDereference(int *i, int j) {
|
||||||
j = *i;
|
j = *i;
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
there is an implicit compiler-generated dereference node before the access to the variable 'i'
|
there is an implicit compiler-generated dereference node before the access to the variable 'i'
|
||||||
*/
|
*/
|
||||||
void v(int &i, int j) {
|
void ReferenceDereference(int &i, int j) {
|
||||||
j = i;
|
j = i;
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
int& v(int *i) {
|
int& ReferenceTo(int *i) {
|
||||||
return *i;
|
return *i;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
void v(int array[]) {
|
void Sizeof(int array[]) {
|
||||||
int i = sizeof(int);
|
int i = sizeof(int);
|
||||||
int j = sizeof(array);
|
int j = sizeof(array);
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
void v() {
|
void StatementExpr() {
|
||||||
int j = ({ int i = 5; i; });
|
int j = ({ int i = 5; i; });
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ struct X {
|
|||||||
static int i;
|
static int i;
|
||||||
};
|
};
|
||||||
|
|
||||||
void v(int i, X &xref) {
|
void StaticMemberAccess(int i, X &xref) {
|
||||||
// i = X::i;
|
// i = X::i;
|
||||||
i = xref.i;
|
i = xref.i;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
void v(int i[], int j) {
|
void Subscript(int i[], int j) {
|
||||||
j = i[5];
|
j = i[5];
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@ class F {
|
|||||||
public:
|
public:
|
||||||
F() { }
|
F() { }
|
||||||
};
|
};
|
||||||
void f(int i) {
|
void Throw(int i) {
|
||||||
try {
|
try {
|
||||||
if(i)
|
if(i)
|
||||||
throw E();
|
throw E();
|
||||||
|
|||||||
@@ -15,6 +15,6 @@ class Base {
|
|||||||
class Derived : public Base {
|
class Derived : public Base {
|
||||||
};
|
};
|
||||||
|
|
||||||
void v(Base *bp) {
|
void TypeId(Base *bp) {
|
||||||
const char *name = typeid(bp).name();
|
const char *name = typeid(bp).name();
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
template<class T>
|
template<class T>
|
||||||
void v(T x, T *y) {
|
void CallDestructor(T x, T *y) {
|
||||||
x.T::~T();
|
x.T::~T();
|
||||||
y->T::~T();
|
y->T::~T();
|
||||||
}
|
}
|
||||||
|
|
||||||
void f(int i) {
|
void Vacuous(int i) {
|
||||||
// An int doesn't have a destructor, but we get to call it anyway through a
|
// An int doesn't have a destructor, but we get to call it anyway through a
|
||||||
// template.
|
// template.
|
||||||
v(i, &i);
|
CallDestructor(i, &i);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ typedef __builtin_va_list __gnuc_va_list;
|
|||||||
#define va_copy(d,s) __builtin_va_copy(d,s)
|
#define va_copy(d,s) __builtin_va_copy(d,s)
|
||||||
typedef __gnuc_va_list va_list;
|
typedef __gnuc_va_list va_list;
|
||||||
|
|
||||||
void output(const char *text, ...) {
|
void VarArgs(const char *text, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, text);
|
va_start(args, text);
|
||||||
va_end (args);
|
va_end (args);
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ where
|
|||||||
resultPointsTo(instr, var, bitOffset) and
|
resultPointsTo(instr, var, bitOffset) and
|
||||||
pointsTo = var.toString() + getBitOffsetString(bitOffset)
|
pointsTo = var.toString() + getBitOffsetString(bitOffset)
|
||||||
)
|
)
|
||||||
select instr, pointsTo
|
select instr.getLocation().toString(), instr.getOperationString(), pointsTo
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +0,0 @@
|
|||||||
import semmle.code.cpp.ssa.AliasedSSAIR
|
|
||||||
import semmle.code.cpp.ssa.PrintAliasedSSAIR
|
|
||||||
|
|
||||||
from Instruction instr
|
|
||||||
where none()
|
|
||||||
select instr
|
|
||||||
1
cpp/ql/test/library-tests/ir/ir/aliased_ssa_ir.qlref
Normal file
1
cpp/ql/test/library-tests/ir/ir/aliased_ssa_ir.qlref
Normal file
@@ -0,0 +1 @@
|
|||||||
|
semmle/code/cpp/ssa/PrintAliasedSSAIR.ql
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
|||||||
import default
|
|
||||||
import semmle.code.cpp.ir.IR
|
|
||||||
import semmle.code.cpp.ir.PrintIR
|
|
||||||
|
|
||||||
from Instruction instr
|
|
||||||
where none()
|
|
||||||
select instr
|
|
||||||
1
cpp/ql/test/library-tests/ir/ir/ir.qlref
Normal file
1
cpp/ql/test/library-tests/ir/ir/ir.qlref
Normal file
@@ -0,0 +1 @@
|
|||||||
|
semmle/code/cpp/ir/PrintIR.ql
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +0,0 @@
|
|||||||
import semmle.code.cpp.ssa.SSAIR
|
|
||||||
import semmle.code.cpp.ssa.PrintSSAIR
|
|
||||||
|
|
||||||
from Instruction instr
|
|
||||||
where none()
|
|
||||||
select instr
|
|
||||||
1
cpp/ql/test/library-tests/ir/ir/ssa_ir.qlref
Normal file
1
cpp/ql/test/library-tests/ir/ir/ssa_ir.qlref
Normal file
@@ -0,0 +1 @@
|
|||||||
|
semmle/code/cpp/ssa/PrintSSAIR.ql
|
||||||
Reference in New Issue
Block a user