C++: Initial attempt at IR-based value numbering

This commit is contained in:
Dave Bartolomeo
2018-09-17 17:19:05 -07:00
parent 782e91bb97
commit 46b2c19c66
23 changed files with 1689 additions and 0 deletions

View File

@@ -54,5 +54,10 @@
"C++ SSA SSAConstruction": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll"
],
"C++ IR ValueNumber": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/gvn/ValueNumber.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/gvn/ValueNumber.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/gvn/ValueNumber.qll"
]
}

View File

@@ -0,0 +1,7 @@
# The C/C++ Intermediate Representation
## Introduction
The Intermediate Representation (IR) library provides a representation of the semantics of the program, independent of the syntax used to express those semantics. The IR is similar in design to representations used in optimizing compilers, such as LLVM IR.
## Memory Access

View File

@@ -0,0 +1 @@
import implementation.aliased_ssa.PrintIR

View File

@@ -5,3 +5,30 @@ import IRVariable
import OperandTag
import semmle.code.cpp.ir.implementation.EdgeKind
import semmle.code.cpp.ir.implementation.MemoryAccessKind
private newtype TIRPropertyProvider = MkIRPropertyProvider()
/**
* Class that provides additional properties to be dumped for IR instructions and blocks when using
* the PrintIR module. Libraries that compute additional facts about IR elements can extend the
* single instance of this class to specify the additional properties computed by the library.
*/
class IRPropertyProvider extends TIRPropertyProvider {
string toString() {
result = "IRPropertyProvider"
}
/**
* Gets the value of the property named `key` for the specified instruction.
*/
string getInstructionProperty(Instruction instruction, string key) {
none()
}
/**
* Gets the value of the property named `key` for the specified block.
*/
string getBlockProperty(IRBlock block, string key) {
none()
}
}

View File

@@ -301,6 +301,13 @@ class Instruction extends Construction::TInstruction {
result = ast.getLocation()
}
/**
* Gets the `Expr` whose results is computed by this instruction, if any.
*/
final Expr getResultExpression() {
result = Construction::getInstructionResultExpression(this)
}
/**
* Gets the type of the result produced by this instruction. If the
* instruction does not produce a result, its result type will be `VoidType`.
@@ -554,6 +561,15 @@ class InitializeParameterInstruction extends VariableInstruction {
}
}
/**
* An instruction that initializes the `this` pointer parameter of the enclosing function.
*/
class InitializeThisInstruction extends Instruction {
InitializeThisInstruction() {
opcode instanceof Opcode::InitializeThis
}
}
class FieldAddressInstruction extends FieldInstruction {
FieldAddressInstruction() {
opcode instanceof Opcode::FieldAddress

View File

@@ -1,6 +1,18 @@
private import IR
import cpp
private string getAdditionalInstructionProperty(Instruction instr, string key) {
exists(IRPropertyProvider provider |
result = provider.getInstructionProperty(instr, key)
)
}
private string getAdditionalBlockProperty(IRBlock block, string key) {
exists(IRPropertyProvider provider |
result = provider.getBlockProperty(block, key)
)
}
private newtype TPrintableIRNode =
TPrintableFunctionIR(FunctionIR funcIR) or
TPrintableIRBlock(IRBlock block) or
@@ -135,6 +147,11 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
result.getFunctionIR() = block.getFunctionIR()
}
override string getProperty(string key) {
result = PrintableIRNode.super.getProperty(key) or
result = getAdditionalBlockProperty(block, key)
}
final IRBlock getBlock() {
result = block
}
@@ -185,6 +202,11 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
final Instruction getInstruction() {
result = instr
}
override string getProperty(string key) {
result = PrintableIRNode.super.getProperty(key) or
result = getAdditionalInstructionProperty(instr, key)
}
}
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {

View File

@@ -195,6 +195,10 @@ cached private module Cached {
)
}
cached Expr getInstructionResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getResultExpression()
}
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
result = getNewInstruction(getOldInstruction(instruction).getSuccessor(kind))
}

View File

@@ -0,0 +1,264 @@
private import ValueNumberInternal
import cpp
private import IR
/**
* Provides additional information about value numbering in IR dumps.
*/
class ValueNumberPropertyProvider extends IRPropertyProvider {
override string getInstructionProperty(Instruction instr, string key) {
exists(ValueNumber vn |
vn = valueNumber(instr) and
key = "valnum" and
if strictcount(vn.getAnInstruction()) > 1 then
result = vn.toString()
else
result = "unique"
)
}
}
newtype TValueNumber =
TVariableAddressValueNumber(FunctionIR funcIR, IRVariable var) {
variableAddressValueNumber(_, funcIR, var)
} or
TInitializeParameterValueNumber(FunctionIR funcIR, IRVariable var) {
initializeParameterValueNumber(_, funcIR, var)
} or
TInitializeThisValueNumber(FunctionIR funcIR) {
initializeThisValueNumber(_, funcIR)
} or
TConstantValueNumber(FunctionIR funcIR, Type type, string value) {
constantValueNumber(_, funcIR, type, value)
} or
TFieldAddressValueNumber(FunctionIR funcIR, Field field, ValueNumber objectAddress) {
fieldAddressValueNumber(_, funcIR, field, objectAddress)
} or
TBinaryValueNumber(FunctionIR funcIR, Opcode opcode, Type type, ValueNumber leftOperand,
ValueNumber rightOperand) {
binaryValueNumber(_, funcIR, opcode, type, leftOperand, rightOperand)
} or
TPointerArithmeticValueNumber(FunctionIR funcIR, Opcode opcode, Type type, int elementSize,
ValueNumber leftOperand, ValueNumber rightOperand) {
pointerArithmeticValueNumber(_, funcIR, opcode, type, elementSize, leftOperand, rightOperand)
} or
TUnaryValueNumber(FunctionIR funcIR, Opcode opcode, Type type, ValueNumber operand) {
unaryValueNumber(_, funcIR, opcode, type, operand)
} or
TUniqueValueNumber(FunctionIR funcIR, Instruction instr) {
uniqueValueNumber(instr, funcIR)
}
/**
* The value number assigned to a particular set of instructions that produce equivalent results.
*/
class ValueNumber extends TValueNumber {
final string toString() {
result = getExampleInstruction().getResultId()
}
final Location getLocation() {
result = getExampleInstruction().getLocation()
}
/**
* Gets the instructions that have been assigned this value number. This will always produce at
* least one result.
*/
final Instruction getAnInstruction() {
this = valueNumber(result)
}
/**
* Gets one of the instructions that was assigned this value number. The chosen instuction is
* deterministic but arbitrary. Intended for use only in debugging.
*/
final Instruction getExampleInstruction() {
result = min(Instruction instr |
instr = getAnInstruction() |
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
)
}
}
class BinaryValueNumber extends ValueNumber, TBinaryValueNumber {}
class UnaryValueNumber extends ValueNumber, TUnaryValueNumber {}
class ConstantValueNumber extends ValueNumber, TConstantValueNumber {}
class FieldAddressValueNumber extends ValueNumber, TFieldAddressValueNumber {}
class PointerArithmeticValueNumber extends ValueNumber, TPointerArithmeticValueNumber {}
class UniqueValueNumber extends ValueNumber, TUniqueValueNumber {}
/**
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
* operand.
* For example:
* ```
* Point p = { 1, 2 };
* Point q = p;
* int a = p.x;
* ```
* The use of `p` on line 2 is linked to the definition of `p` on line 1, and is congruent to that
* definition because it accesses the exact same memory.
* The use of `p.x` on line 3 is linked to the definition of `p` on line 1 as well, but is not
* congruent to that definition because `p.x` accesses only a subset of the memory defined by `p`.
*
* This concept should probably be exposed in the public IR API.
*/
private class CongruentCopyInstruction extends CopyInstruction {
CongruentCopyInstruction() {
exists(Instruction def |
def = this.getSourceValue() and
(
def.getResultMemoryAccess() instanceof IndirectMemoryAccess or
not def.hasMemoryResult()
)
)
}
}
/**
* Holds if this library knows how to assign a value number to the specified instruction, other than
* a `unique` value number that is never shared by multiple instructions.
*/
private predicate numberableInstruction(Instruction instr) {
instr instanceof VariableAddressInstruction or
instr instanceof InitializeParameterInstruction or
instr instanceof InitializeThisInstruction or
instr instanceof ConstantInstruction or
instr instanceof FieldAddressInstruction or
instr instanceof BinaryInstruction or
instr instanceof UnaryInstruction or
instr instanceof PointerArithmeticInstruction or
instr instanceof CongruentCopyInstruction
}
private predicate variableAddressValueNumber(VariableAddressInstruction instr, FunctionIR funcIR,
IRVariable var) {
instr.getFunctionIR() = funcIR and
instr.getVariable() = var
}
private predicate initializeParameterValueNumber(InitializeParameterInstruction instr,
FunctionIR funcIR, IRVariable var) {
instr.getFunctionIR() = funcIR and
instr.getVariable() = var
}
private predicate initializeThisValueNumber(InitializeThisInstruction instr, FunctionIR funcIR) {
instr.getFunctionIR() = funcIR
}
private predicate constantValueNumber(ConstantInstruction instr, FunctionIR funcIR, Type type,
string value) {
instr.getFunctionIR() = funcIR and
instr.getResultType() = type and
instr.getValue() = value
}
private predicate fieldAddressValueNumber(FieldAddressInstruction instr, FunctionIR funcIR,
Field field, ValueNumber objectAddress) {
instr.getFunctionIR() = funcIR and
instr.getField() = field and
valueNumber(instr.getObjectAddress()) = objectAddress
}
private predicate binaryValueNumber(BinaryInstruction instr, FunctionIR funcIR, Opcode opcode,
Type type, ValueNumber leftOperand, ValueNumber rightOperand) {
instr.getFunctionIR() = funcIR and
(not instr instanceof PointerArithmeticInstruction) and
instr.getOpcode() = opcode and
instr.getResultType() = type and
valueNumber(instr.getLeftOperand()) = leftOperand and
valueNumber(instr.getRightOperand()) = rightOperand
}
private predicate pointerArithmeticValueNumber(PointerArithmeticInstruction instr,
FunctionIR funcIR, Opcode opcode, Type type, int elementSize, ValueNumber leftOperand,
ValueNumber rightOperand) {
instr.getFunctionIR() = funcIR and
instr.getOpcode() = opcode and
instr.getResultType() = type and
instr.getElementSize() = elementSize and
valueNumber(instr.getLeftOperand()) = leftOperand and
valueNumber(instr.getRightOperand()) = rightOperand
}
private predicate unaryValueNumber(UnaryInstruction instr, FunctionIR funcIR, Opcode opcode,
Type type, ValueNumber operand) {
instr.getFunctionIR() = funcIR and
(not instr instanceof InheritanceConversionInstruction) and
(not instr instanceof FieldAddressInstruction) and
instr.getOpcode() = opcode and
instr.getResultType() = type and
valueNumber(instr.getOperand()) = operand
}
/**
* Holds if `instr` should be assigned a unique value number because this library does not know how
* to determine if two instances of that instruction are equivalent.
*/
private predicate uniqueValueNumber(Instruction instr, FunctionIR funcIR) {
instr.getFunctionIR() = funcIR and
(not instr.getResultType() instanceof VoidType) and
not numberableInstruction(instr)
}
/**
* Gets the value number assigned to `instr`, if any. Returns at most one result.
*/
ValueNumber valueNumber(Instruction instr) {
result = nonUniqueValueNumber(instr) or
exists(FunctionIR funcIR |
uniqueValueNumber(instr, funcIR) and
result = TUniqueValueNumber(funcIR, instr)
)
}
/**
* Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique
* value number.
*/
private ValueNumber nonUniqueValueNumber(Instruction instr) {
exists(FunctionIR funcIR |
funcIR = instr.getFunctionIR() and
(
exists(IRVariable var |
variableAddressValueNumber(instr, funcIR, var) and
result = TVariableAddressValueNumber(funcIR, var)
) or
exists(IRVariable var |
initializeParameterValueNumber(instr, funcIR, var) and
result = TInitializeParameterValueNumber(funcIR, var)
) or
(
initializeThisValueNumber(instr, funcIR) and
result = TInitializeThisValueNumber(funcIR)
) or
exists(Type type, string value |
constantValueNumber(instr, funcIR, type, value) and
result = TConstantValueNumber(funcIR, type, value)
) or
exists(Field field, ValueNumber objectAddress |
fieldAddressValueNumber(instr, funcIR, field, objectAddress) and
result = TFieldAddressValueNumber(funcIR, field, objectAddress)
) or
exists(Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand |
binaryValueNumber(instr, funcIR, opcode, type, leftOperand, rightOperand) and
result = TBinaryValueNumber(funcIR, opcode, type, leftOperand, rightOperand)
) or
exists(Opcode opcode, Type type, ValueNumber operand |
unaryValueNumber(instr, funcIR, opcode, type, operand) and
result = TUnaryValueNumber(funcIR, opcode, type, operand)
) or
exists(Opcode opcode, Type type, int elementSize, ValueNumber leftOperand,
ValueNumber rightOperand |
pointerArithmeticValueNumber(instr, funcIR, opcode, type, elementSize, leftOperand,
rightOperand) and
result = TPointerArithmeticValueNumber(funcIR, opcode, type, elementSize, leftOperand,
rightOperand)
) or
// The value number of a copy is just the value number of its source value.
result = valueNumber(instr.(CongruentCopyInstruction).getSourceValue())
)
)
}

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as IR

View File

@@ -5,3 +5,30 @@ import IRVariable
import OperandTag
import semmle.code.cpp.ir.implementation.EdgeKind
import semmle.code.cpp.ir.implementation.MemoryAccessKind
private newtype TIRPropertyProvider = MkIRPropertyProvider()
/**
* Class that provides additional properties to be dumped for IR instructions and blocks when using
* the PrintIR module. Libraries that compute additional facts about IR elements can extend the
* single instance of this class to specify the additional properties computed by the library.
*/
class IRPropertyProvider extends TIRPropertyProvider {
string toString() {
result = "IRPropertyProvider"
}
/**
* Gets the value of the property named `key` for the specified instruction.
*/
string getInstructionProperty(Instruction instruction, string key) {
none()
}
/**
* Gets the value of the property named `key` for the specified block.
*/
string getBlockProperty(IRBlock block, string key) {
none()
}
}

View File

@@ -301,6 +301,13 @@ class Instruction extends Construction::TInstruction {
result = ast.getLocation()
}
/**
* Gets the `Expr` whose results is computed by this instruction, if any.
*/
final Expr getResultExpression() {
result = Construction::getInstructionResultExpression(this)
}
/**
* Gets the type of the result produced by this instruction. If the
* instruction does not produce a result, its result type will be `VoidType`.
@@ -554,6 +561,15 @@ class InitializeParameterInstruction extends VariableInstruction {
}
}
/**
* An instruction that initializes the `this` pointer parameter of the enclosing function.
*/
class InitializeThisInstruction extends Instruction {
InitializeThisInstruction() {
opcode instanceof Opcode::InitializeThis
}
}
class FieldAddressInstruction extends FieldInstruction {
FieldAddressInstruction() {
opcode instanceof Opcode::FieldAddress

View File

@@ -1,6 +1,18 @@
private import IR
import cpp
private string getAdditionalInstructionProperty(Instruction instr, string key) {
exists(IRPropertyProvider provider |
result = provider.getInstructionProperty(instr, key)
)
}
private string getAdditionalBlockProperty(IRBlock block, string key) {
exists(IRPropertyProvider provider |
result = provider.getBlockProperty(block, key)
)
}
private newtype TPrintableIRNode =
TPrintableFunctionIR(FunctionIR funcIR) or
TPrintableIRBlock(IRBlock block) or
@@ -135,6 +147,11 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
result.getFunctionIR() = block.getFunctionIR()
}
override string getProperty(string key) {
result = PrintableIRNode.super.getProperty(key) or
result = getAdditionalBlockProperty(block, key)
}
final IRBlock getBlock() {
result = block
}
@@ -185,6 +202,11 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
final Instruction getInstruction() {
result = instr
}
override string getProperty(string key) {
result = PrintableIRNode.super.getProperty(key) or
result = getAdditionalInstructionProperty(instr, key)
}
}
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {

View File

@@ -4,6 +4,7 @@ import IRBlockConstruction as BlockConstruction
private import semmle.code.cpp.ir.internal.TempVariableTag
private import InstructionTag
private import TranslatedElement
private import TranslatedExpr
private import TranslatedFunction
class InstructionTagType extends TInstructionTag {
@@ -73,6 +74,13 @@ cached private module Cached {
none()
}
cached Expr getInstructionResultExpression(Instruction instruction) {
exists(TranslatedExpr translatedExpr |
translatedExpr = getTranslatedExpr(result) and
instruction = translatedExpr.getResult()
)
}
cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) {
result = getInstructionTranslatedElement(instruction).getInstructionOperand(
instruction.getTag(), tag)

View File

@@ -0,0 +1,264 @@
private import ValueNumberInternal
import cpp
private import IR
/**
* Provides additional information about value numbering in IR dumps.
*/
class ValueNumberPropertyProvider extends IRPropertyProvider {
override string getInstructionProperty(Instruction instr, string key) {
exists(ValueNumber vn |
vn = valueNumber(instr) and
key = "valnum" and
if strictcount(vn.getAnInstruction()) > 1 then
result = vn.toString()
else
result = "unique"
)
}
}
newtype TValueNumber =
TVariableAddressValueNumber(FunctionIR funcIR, IRVariable var) {
variableAddressValueNumber(_, funcIR, var)
} or
TInitializeParameterValueNumber(FunctionIR funcIR, IRVariable var) {
initializeParameterValueNumber(_, funcIR, var)
} or
TInitializeThisValueNumber(FunctionIR funcIR) {
initializeThisValueNumber(_, funcIR)
} or
TConstantValueNumber(FunctionIR funcIR, Type type, string value) {
constantValueNumber(_, funcIR, type, value)
} or
TFieldAddressValueNumber(FunctionIR funcIR, Field field, ValueNumber objectAddress) {
fieldAddressValueNumber(_, funcIR, field, objectAddress)
} or
TBinaryValueNumber(FunctionIR funcIR, Opcode opcode, Type type, ValueNumber leftOperand,
ValueNumber rightOperand) {
binaryValueNumber(_, funcIR, opcode, type, leftOperand, rightOperand)
} or
TPointerArithmeticValueNumber(FunctionIR funcIR, Opcode opcode, Type type, int elementSize,
ValueNumber leftOperand, ValueNumber rightOperand) {
pointerArithmeticValueNumber(_, funcIR, opcode, type, elementSize, leftOperand, rightOperand)
} or
TUnaryValueNumber(FunctionIR funcIR, Opcode opcode, Type type, ValueNumber operand) {
unaryValueNumber(_, funcIR, opcode, type, operand)
} or
TUniqueValueNumber(FunctionIR funcIR, Instruction instr) {
uniqueValueNumber(instr, funcIR)
}
/**
* The value number assigned to a particular set of instructions that produce equivalent results.
*/
class ValueNumber extends TValueNumber {
final string toString() {
result = getExampleInstruction().getResultId()
}
final Location getLocation() {
result = getExampleInstruction().getLocation()
}
/**
* Gets the instructions that have been assigned this value number. This will always produce at
* least one result.
*/
final Instruction getAnInstruction() {
this = valueNumber(result)
}
/**
* Gets one of the instructions that was assigned this value number. The chosen instuction is
* deterministic but arbitrary. Intended for use only in debugging.
*/
final Instruction getExampleInstruction() {
result = min(Instruction instr |
instr = getAnInstruction() |
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
)
}
}
class BinaryValueNumber extends ValueNumber, TBinaryValueNumber {}
class UnaryValueNumber extends ValueNumber, TUnaryValueNumber {}
class ConstantValueNumber extends ValueNumber, TConstantValueNumber {}
class FieldAddressValueNumber extends ValueNumber, TFieldAddressValueNumber {}
class PointerArithmeticValueNumber extends ValueNumber, TPointerArithmeticValueNumber {}
class UniqueValueNumber extends ValueNumber, TUniqueValueNumber {}
/**
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
* operand.
* For example:
* ```
* Point p = { 1, 2 };
* Point q = p;
* int a = p.x;
* ```
* The use of `p` on line 2 is linked to the definition of `p` on line 1, and is congruent to that
* definition because it accesses the exact same memory.
* The use of `p.x` on line 3 is linked to the definition of `p` on line 1 as well, but is not
* congruent to that definition because `p.x` accesses only a subset of the memory defined by `p`.
*
* This concept should probably be exposed in the public IR API.
*/
private class CongruentCopyInstruction extends CopyInstruction {
CongruentCopyInstruction() {
exists(Instruction def |
def = this.getSourceValue() and
(
def.getResultMemoryAccess() instanceof IndirectMemoryAccess or
not def.hasMemoryResult()
)
)
}
}
/**
* Holds if this library knows how to assign a value number to the specified instruction, other than
* a `unique` value number that is never shared by multiple instructions.
*/
private predicate numberableInstruction(Instruction instr) {
instr instanceof VariableAddressInstruction or
instr instanceof InitializeParameterInstruction or
instr instanceof InitializeThisInstruction or
instr instanceof ConstantInstruction or
instr instanceof FieldAddressInstruction or
instr instanceof BinaryInstruction or
instr instanceof UnaryInstruction or
instr instanceof PointerArithmeticInstruction or
instr instanceof CongruentCopyInstruction
}
private predicate variableAddressValueNumber(VariableAddressInstruction instr, FunctionIR funcIR,
IRVariable var) {
instr.getFunctionIR() = funcIR and
instr.getVariable() = var
}
private predicate initializeParameterValueNumber(InitializeParameterInstruction instr,
FunctionIR funcIR, IRVariable var) {
instr.getFunctionIR() = funcIR and
instr.getVariable() = var
}
private predicate initializeThisValueNumber(InitializeThisInstruction instr, FunctionIR funcIR) {
instr.getFunctionIR() = funcIR
}
private predicate constantValueNumber(ConstantInstruction instr, FunctionIR funcIR, Type type,
string value) {
instr.getFunctionIR() = funcIR and
instr.getResultType() = type and
instr.getValue() = value
}
private predicate fieldAddressValueNumber(FieldAddressInstruction instr, FunctionIR funcIR,
Field field, ValueNumber objectAddress) {
instr.getFunctionIR() = funcIR and
instr.getField() = field and
valueNumber(instr.getObjectAddress()) = objectAddress
}
private predicate binaryValueNumber(BinaryInstruction instr, FunctionIR funcIR, Opcode opcode,
Type type, ValueNumber leftOperand, ValueNumber rightOperand) {
instr.getFunctionIR() = funcIR and
(not instr instanceof PointerArithmeticInstruction) and
instr.getOpcode() = opcode and
instr.getResultType() = type and
valueNumber(instr.getLeftOperand()) = leftOperand and
valueNumber(instr.getRightOperand()) = rightOperand
}
private predicate pointerArithmeticValueNumber(PointerArithmeticInstruction instr,
FunctionIR funcIR, Opcode opcode, Type type, int elementSize, ValueNumber leftOperand,
ValueNumber rightOperand) {
instr.getFunctionIR() = funcIR and
instr.getOpcode() = opcode and
instr.getResultType() = type and
instr.getElementSize() = elementSize and
valueNumber(instr.getLeftOperand()) = leftOperand and
valueNumber(instr.getRightOperand()) = rightOperand
}
private predicate unaryValueNumber(UnaryInstruction instr, FunctionIR funcIR, Opcode opcode,
Type type, ValueNumber operand) {
instr.getFunctionIR() = funcIR and
(not instr instanceof InheritanceConversionInstruction) and
(not instr instanceof FieldAddressInstruction) and
instr.getOpcode() = opcode and
instr.getResultType() = type and
valueNumber(instr.getOperand()) = operand
}
/**
* Holds if `instr` should be assigned a unique value number because this library does not know how
* to determine if two instances of that instruction are equivalent.
*/
private predicate uniqueValueNumber(Instruction instr, FunctionIR funcIR) {
instr.getFunctionIR() = funcIR and
(not instr.getResultType() instanceof VoidType) and
not numberableInstruction(instr)
}
/**
* Gets the value number assigned to `instr`, if any. Returns at most one result.
*/
ValueNumber valueNumber(Instruction instr) {
result = nonUniqueValueNumber(instr) or
exists(FunctionIR funcIR |
uniqueValueNumber(instr, funcIR) and
result = TUniqueValueNumber(funcIR, instr)
)
}
/**
* Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique
* value number.
*/
private ValueNumber nonUniqueValueNumber(Instruction instr) {
exists(FunctionIR funcIR |
funcIR = instr.getFunctionIR() and
(
exists(IRVariable var |
variableAddressValueNumber(instr, funcIR, var) and
result = TVariableAddressValueNumber(funcIR, var)
) or
exists(IRVariable var |
initializeParameterValueNumber(instr, funcIR, var) and
result = TInitializeParameterValueNumber(funcIR, var)
) or
(
initializeThisValueNumber(instr, funcIR) and
result = TInitializeThisValueNumber(funcIR)
) or
exists(Type type, string value |
constantValueNumber(instr, funcIR, type, value) and
result = TConstantValueNumber(funcIR, type, value)
) or
exists(Field field, ValueNumber objectAddress |
fieldAddressValueNumber(instr, funcIR, field, objectAddress) and
result = TFieldAddressValueNumber(funcIR, field, objectAddress)
) or
exists(Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand |
binaryValueNumber(instr, funcIR, opcode, type, leftOperand, rightOperand) and
result = TBinaryValueNumber(funcIR, opcode, type, leftOperand, rightOperand)
) or
exists(Opcode opcode, Type type, ValueNumber operand |
unaryValueNumber(instr, funcIR, opcode, type, operand) and
result = TUnaryValueNumber(funcIR, opcode, type, operand)
) or
exists(Opcode opcode, Type type, int elementSize, ValueNumber leftOperand,
ValueNumber rightOperand |
pointerArithmeticValueNumber(instr, funcIR, opcode, type, elementSize, leftOperand,
rightOperand) and
result = TPointerArithmeticValueNumber(funcIR, opcode, type, elementSize, leftOperand,
rightOperand)
) or
// The value number of a copy is just the value number of its source value.
result = valueNumber(instr.(CongruentCopyInstruction).getSourceValue())
)
)
}

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.raw.IR as IR

View File

@@ -5,3 +5,30 @@ import IRVariable
import OperandTag
import semmle.code.cpp.ir.implementation.EdgeKind
import semmle.code.cpp.ir.implementation.MemoryAccessKind
private newtype TIRPropertyProvider = MkIRPropertyProvider()
/**
* Class that provides additional properties to be dumped for IR instructions and blocks when using
* the PrintIR module. Libraries that compute additional facts about IR elements can extend the
* single instance of this class to specify the additional properties computed by the library.
*/
class IRPropertyProvider extends TIRPropertyProvider {
string toString() {
result = "IRPropertyProvider"
}
/**
* Gets the value of the property named `key` for the specified instruction.
*/
string getInstructionProperty(Instruction instruction, string key) {
none()
}
/**
* Gets the value of the property named `key` for the specified block.
*/
string getBlockProperty(IRBlock block, string key) {
none()
}
}

View File

@@ -301,6 +301,13 @@ class Instruction extends Construction::TInstruction {
result = ast.getLocation()
}
/**
* Gets the `Expr` whose results is computed by this instruction, if any.
*/
final Expr getResultExpression() {
result = Construction::getInstructionResultExpression(this)
}
/**
* Gets the type of the result produced by this instruction. If the
* instruction does not produce a result, its result type will be `VoidType`.
@@ -554,6 +561,15 @@ class InitializeParameterInstruction extends VariableInstruction {
}
}
/**
* An instruction that initializes the `this` pointer parameter of the enclosing function.
*/
class InitializeThisInstruction extends Instruction {
InitializeThisInstruction() {
opcode instanceof Opcode::InitializeThis
}
}
class FieldAddressInstruction extends FieldInstruction {
FieldAddressInstruction() {
opcode instanceof Opcode::FieldAddress

View File

@@ -1,6 +1,18 @@
private import IR
import cpp
private string getAdditionalInstructionProperty(Instruction instr, string key) {
exists(IRPropertyProvider provider |
result = provider.getInstructionProperty(instr, key)
)
}
private string getAdditionalBlockProperty(IRBlock block, string key) {
exists(IRPropertyProvider provider |
result = provider.getBlockProperty(block, key)
)
}
private newtype TPrintableIRNode =
TPrintableFunctionIR(FunctionIR funcIR) or
TPrintableIRBlock(IRBlock block) or
@@ -135,6 +147,11 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
result.getFunctionIR() = block.getFunctionIR()
}
override string getProperty(string key) {
result = PrintableIRNode.super.getProperty(key) or
result = getAdditionalBlockProperty(block, key)
}
final IRBlock getBlock() {
result = block
}
@@ -185,6 +202,11 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
final Instruction getInstruction() {
result = instr
}
override string getProperty(string key) {
result = PrintableIRNode.super.getProperty(key) or
result = getAdditionalInstructionProperty(instr, key)
}
}
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {

View File

@@ -195,6 +195,10 @@ cached private module Cached {
)
}
cached Expr getInstructionResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getResultExpression()
}
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
result = getNewInstruction(getOldInstruction(instruction).getSuccessor(kind))
}

View File

@@ -0,0 +1,264 @@
private import ValueNumberInternal
import cpp
private import IR
/**
* Provides additional information about value numbering in IR dumps.
*/
class ValueNumberPropertyProvider extends IRPropertyProvider {
override string getInstructionProperty(Instruction instr, string key) {
exists(ValueNumber vn |
vn = valueNumber(instr) and
key = "valnum" and
if strictcount(vn.getAnInstruction()) > 1 then
result = vn.toString()
else
result = "unique"
)
}
}
newtype TValueNumber =
TVariableAddressValueNumber(FunctionIR funcIR, IRVariable var) {
variableAddressValueNumber(_, funcIR, var)
} or
TInitializeParameterValueNumber(FunctionIR funcIR, IRVariable var) {
initializeParameterValueNumber(_, funcIR, var)
} or
TInitializeThisValueNumber(FunctionIR funcIR) {
initializeThisValueNumber(_, funcIR)
} or
TConstantValueNumber(FunctionIR funcIR, Type type, string value) {
constantValueNumber(_, funcIR, type, value)
} or
TFieldAddressValueNumber(FunctionIR funcIR, Field field, ValueNumber objectAddress) {
fieldAddressValueNumber(_, funcIR, field, objectAddress)
} or
TBinaryValueNumber(FunctionIR funcIR, Opcode opcode, Type type, ValueNumber leftOperand,
ValueNumber rightOperand) {
binaryValueNumber(_, funcIR, opcode, type, leftOperand, rightOperand)
} or
TPointerArithmeticValueNumber(FunctionIR funcIR, Opcode opcode, Type type, int elementSize,
ValueNumber leftOperand, ValueNumber rightOperand) {
pointerArithmeticValueNumber(_, funcIR, opcode, type, elementSize, leftOperand, rightOperand)
} or
TUnaryValueNumber(FunctionIR funcIR, Opcode opcode, Type type, ValueNumber operand) {
unaryValueNumber(_, funcIR, opcode, type, operand)
} or
TUniqueValueNumber(FunctionIR funcIR, Instruction instr) {
uniqueValueNumber(instr, funcIR)
}
/**
* The value number assigned to a particular set of instructions that produce equivalent results.
*/
class ValueNumber extends TValueNumber {
final string toString() {
result = getExampleInstruction().getResultId()
}
final Location getLocation() {
result = getExampleInstruction().getLocation()
}
/**
* Gets the instructions that have been assigned this value number. This will always produce at
* least one result.
*/
final Instruction getAnInstruction() {
this = valueNumber(result)
}
/**
* Gets one of the instructions that was assigned this value number. The chosen instuction is
* deterministic but arbitrary. Intended for use only in debugging.
*/
final Instruction getExampleInstruction() {
result = min(Instruction instr |
instr = getAnInstruction() |
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
)
}
}
class BinaryValueNumber extends ValueNumber, TBinaryValueNumber {}
class UnaryValueNumber extends ValueNumber, TUnaryValueNumber {}
class ConstantValueNumber extends ValueNumber, TConstantValueNumber {}
class FieldAddressValueNumber extends ValueNumber, TFieldAddressValueNumber {}
class PointerArithmeticValueNumber extends ValueNumber, TPointerArithmeticValueNumber {}
class UniqueValueNumber extends ValueNumber, TUniqueValueNumber {}
/**
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
* operand.
* For example:
* ```
* Point p = { 1, 2 };
* Point q = p;
* int a = p.x;
* ```
* The use of `p` on line 2 is linked to the definition of `p` on line 1, and is congruent to that
* definition because it accesses the exact same memory.
* The use of `p.x` on line 3 is linked to the definition of `p` on line 1 as well, but is not
* congruent to that definition because `p.x` accesses only a subset of the memory defined by `p`.
*
* This concept should probably be exposed in the public IR API.
*/
private class CongruentCopyInstruction extends CopyInstruction {
CongruentCopyInstruction() {
exists(Instruction def |
def = this.getSourceValue() and
(
def.getResultMemoryAccess() instanceof IndirectMemoryAccess or
not def.hasMemoryResult()
)
)
}
}
/**
* Holds if this library knows how to assign a value number to the specified instruction, other than
* a `unique` value number that is never shared by multiple instructions.
*/
private predicate numberableInstruction(Instruction instr) {
instr instanceof VariableAddressInstruction or
instr instanceof InitializeParameterInstruction or
instr instanceof InitializeThisInstruction or
instr instanceof ConstantInstruction or
instr instanceof FieldAddressInstruction or
instr instanceof BinaryInstruction or
instr instanceof UnaryInstruction or
instr instanceof PointerArithmeticInstruction or
instr instanceof CongruentCopyInstruction
}
private predicate variableAddressValueNumber(VariableAddressInstruction instr, FunctionIR funcIR,
IRVariable var) {
instr.getFunctionIR() = funcIR and
instr.getVariable() = var
}
private predicate initializeParameterValueNumber(InitializeParameterInstruction instr,
FunctionIR funcIR, IRVariable var) {
instr.getFunctionIR() = funcIR and
instr.getVariable() = var
}
private predicate initializeThisValueNumber(InitializeThisInstruction instr, FunctionIR funcIR) {
instr.getFunctionIR() = funcIR
}
private predicate constantValueNumber(ConstantInstruction instr, FunctionIR funcIR, Type type,
string value) {
instr.getFunctionIR() = funcIR and
instr.getResultType() = type and
instr.getValue() = value
}
private predicate fieldAddressValueNumber(FieldAddressInstruction instr, FunctionIR funcIR,
Field field, ValueNumber objectAddress) {
instr.getFunctionIR() = funcIR and
instr.getField() = field and
valueNumber(instr.getObjectAddress()) = objectAddress
}
private predicate binaryValueNumber(BinaryInstruction instr, FunctionIR funcIR, Opcode opcode,
Type type, ValueNumber leftOperand, ValueNumber rightOperand) {
instr.getFunctionIR() = funcIR and
(not instr instanceof PointerArithmeticInstruction) and
instr.getOpcode() = opcode and
instr.getResultType() = type and
valueNumber(instr.getLeftOperand()) = leftOperand and
valueNumber(instr.getRightOperand()) = rightOperand
}
private predicate pointerArithmeticValueNumber(PointerArithmeticInstruction instr,
FunctionIR funcIR, Opcode opcode, Type type, int elementSize, ValueNumber leftOperand,
ValueNumber rightOperand) {
instr.getFunctionIR() = funcIR and
instr.getOpcode() = opcode and
instr.getResultType() = type and
instr.getElementSize() = elementSize and
valueNumber(instr.getLeftOperand()) = leftOperand and
valueNumber(instr.getRightOperand()) = rightOperand
}
private predicate unaryValueNumber(UnaryInstruction instr, FunctionIR funcIR, Opcode opcode,
Type type, ValueNumber operand) {
instr.getFunctionIR() = funcIR and
(not instr instanceof InheritanceConversionInstruction) and
(not instr instanceof FieldAddressInstruction) and
instr.getOpcode() = opcode and
instr.getResultType() = type and
valueNumber(instr.getOperand()) = operand
}
/**
* Holds if `instr` should be assigned a unique value number because this library does not know how
* to determine if two instances of that instruction are equivalent.
*/
private predicate uniqueValueNumber(Instruction instr, FunctionIR funcIR) {
instr.getFunctionIR() = funcIR and
(not instr.getResultType() instanceof VoidType) and
not numberableInstruction(instr)
}
/**
* Gets the value number assigned to `instr`, if any. Returns at most one result.
*/
ValueNumber valueNumber(Instruction instr) {
result = nonUniqueValueNumber(instr) or
exists(FunctionIR funcIR |
uniqueValueNumber(instr, funcIR) and
result = TUniqueValueNumber(funcIR, instr)
)
}
/**
* Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique
* value number.
*/
private ValueNumber nonUniqueValueNumber(Instruction instr) {
exists(FunctionIR funcIR |
funcIR = instr.getFunctionIR() and
(
exists(IRVariable var |
variableAddressValueNumber(instr, funcIR, var) and
result = TVariableAddressValueNumber(funcIR, var)
) or
exists(IRVariable var |
initializeParameterValueNumber(instr, funcIR, var) and
result = TInitializeParameterValueNumber(funcIR, var)
) or
(
initializeThisValueNumber(instr, funcIR) and
result = TInitializeThisValueNumber(funcIR)
) or
exists(Type type, string value |
constantValueNumber(instr, funcIR, type, value) and
result = TConstantValueNumber(funcIR, type, value)
) or
exists(Field field, ValueNumber objectAddress |
fieldAddressValueNumber(instr, funcIR, field, objectAddress) and
result = TFieldAddressValueNumber(funcIR, field, objectAddress)
) or
exists(Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand |
binaryValueNumber(instr, funcIR, opcode, type, leftOperand, rightOperand) and
result = TBinaryValueNumber(funcIR, opcode, type, leftOperand, rightOperand)
) or
exists(Opcode opcode, Type type, ValueNumber operand |
unaryValueNumber(instr, funcIR, opcode, type, operand) and
result = TUnaryValueNumber(funcIR, opcode, type, operand)
) or
exists(Opcode opcode, Type type, int elementSize, ValueNumber leftOperand,
ValueNumber rightOperand |
pointerArithmeticValueNumber(instr, funcIR, opcode, type, elementSize, leftOperand,
rightOperand) and
result = TPointerArithmeticValueNumber(funcIR, opcode, type, elementSize, leftOperand,
rightOperand)
) or
// The value number of a copy is just the value number of its source value.
result = valueNumber(instr.(CongruentCopyInstruction).getSourceValue())
)
)
}

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR

View File

@@ -0,0 +1,664 @@
test.cpp:
# 1| test00(int, int) -> int
# 1| Block 0
# 1| v0_0(void) = EnterFunction :
# 1| mu0_1(unknown) = UnmodeledDefinition :
# 1| valnum = unique
# 1| r0_2(glval<int>) = VariableAddress[p0] :
# 1| valnum = r0_2
# 1| m0_3(int) = InitializeParameter[p0] : r0_2
# 1| valnum = m0_3
# 1| r0_4(glval<int>) = VariableAddress[p1] :
# 1| valnum = r0_4
# 1| m0_5(int) = InitializeParameter[p1] : r0_4
# 1| valnum = m0_5
# 2| r0_6(glval<int>) = VariableAddress[x] :
# 2| valnum = r0_6
# 2| m0_7(int) = Uninitialized : r0_6
# 2| valnum = unique
# 2| r0_8(glval<int>) = VariableAddress[y] :
# 2| valnum = r0_8
# 2| m0_9(int) = Uninitialized : r0_8
# 2| valnum = unique
# 3| r0_10(glval<unsigned char>) = VariableAddress[b] :
# 3| valnum = unique
# 3| m0_11(unsigned char) = Uninitialized : r0_10
# 3| valnum = unique
# 5| r0_12(glval<int>) = VariableAddress[p0] :
# 5| valnum = r0_2
# 5| r0_13(int) = Load : r0_12, m0_3
# 5| valnum = m0_3
# 5| r0_14(glval<int>) = VariableAddress[p1] :
# 5| valnum = r0_4
# 5| r0_15(int) = Load : r0_14, m0_5
# 5| valnum = m0_5
# 5| r0_16(int) = Add : r0_13, r0_15
# 5| valnum = r0_16
# 5| r0_17(glval<int>) = VariableAddress[x] :
# 5| valnum = r0_6
# 5| m0_18(int) = Store : r0_17, r0_16
# 5| valnum = r0_16
# 6| r0_19(glval<int>) = VariableAddress[p0] :
# 6| valnum = r0_2
# 6| r0_20(int) = Load : r0_19, m0_3
# 6| valnum = m0_3
# 6| r0_21(glval<int>) = VariableAddress[p1] :
# 6| valnum = r0_4
# 6| r0_22(int) = Load : r0_21, m0_5
# 6| valnum = m0_5
# 6| r0_23(int) = Add : r0_20, r0_22
# 6| valnum = r0_16
# 6| r0_24(glval<int>) = VariableAddress[x] :
# 6| valnum = r0_6
# 6| m0_25(int) = Store : r0_24, r0_23
# 6| valnum = r0_16
# 7| r0_26(glval<int>) = VariableAddress[x] :
# 7| valnum = r0_6
# 7| r0_27(int) = Load : r0_26, m0_25
# 7| valnum = r0_16
# 7| r0_28(glval<int>) = VariableAddress[y] :
# 7| valnum = r0_8
# 7| m0_29(int) = Store : r0_28, r0_27
# 7| valnum = r0_16
# 8| v0_30(void) = NoOp :
# 1| r0_31(glval<int>) = VariableAddress[#return] :
# 1| valnum = unique
# 1| v0_32(void) = ReturnValue : r0_31
# 1| v0_33(void) = UnmodeledUse : mu*
# 1| v0_34(void) = ExitFunction :
# 53| 1644
# 53| valnum = unique
# 56| 1646
# 56| valnum = unique
# 88| 1755
# 88| valnum = unique
# 12| test01(int, int) -> int
# 12| Block 0
# 12| v0_0(void) = EnterFunction :
# 12| mu0_1(unknown) = UnmodeledDefinition :
# 12| valnum = unique
# 12| r0_2(glval<int>) = VariableAddress[p0] :
# 12| valnum = r0_2
# 12| m0_3(int) = InitializeParameter[p0] : r0_2
# 12| valnum = m0_3
# 12| r0_4(glval<int>) = VariableAddress[p1] :
# 12| valnum = r0_4
# 12| m0_5(int) = InitializeParameter[p1] : r0_4
# 12| valnum = m0_5
# 13| r0_6(glval<int>) = VariableAddress[x] :
# 13| valnum = r0_6
# 13| m0_7(int) = Uninitialized : r0_6
# 13| valnum = unique
# 13| r0_8(glval<int>) = VariableAddress[y] :
# 13| valnum = r0_8
# 13| m0_9(int) = Uninitialized : r0_8
# 13| valnum = unique
# 14| r0_10(glval<unsigned char>) = VariableAddress[b] :
# 14| valnum = unique
# 14| m0_11(unsigned char) = Uninitialized : r0_10
# 14| valnum = unique
# 16| r0_12(glval<int>) = VariableAddress[p0] :
# 16| valnum = r0_2
# 16| r0_13(int) = Load : r0_12, m0_3
# 16| valnum = m0_3
# 16| r0_14(glval<int>) = VariableAddress[p1] :
# 16| valnum = r0_4
# 16| r0_15(int) = Load : r0_14, m0_5
# 16| valnum = m0_5
# 16| r0_16(int) = Add : r0_13, r0_15
# 16| valnum = r0_16
# 16| r0_17(glval<int>) = VariableAddress[global01] :
# 16| valnum = r0_17
# 16| r0_18(int) = Load : r0_17, mu0_1
# 16| valnum = unique
# 16| r0_19(int) = Add : r0_16, r0_18
# 16| valnum = r0_19
# 16| r0_20(glval<int>) = VariableAddress[x] :
# 16| valnum = r0_6
# 16| m0_21(int) = Store : r0_20, r0_19
# 16| valnum = r0_19
# 17| r0_22(glval<int>) = VariableAddress[p0] :
# 17| valnum = r0_2
# 17| r0_23(int) = Load : r0_22, m0_3
# 17| valnum = m0_3
# 17| r0_24(glval<int>) = VariableAddress[p1] :
# 17| valnum = r0_4
# 17| r0_25(int) = Load : r0_24, m0_5
# 17| valnum = m0_5
# 17| r0_26(int) = Add : r0_23, r0_25
# 17| valnum = r0_16
# 17| r0_27(glval<int>) = VariableAddress[global01] :
# 17| valnum = r0_17
# 17| r0_28(int) = Load : r0_27, mu0_1
# 17| valnum = unique
# 17| r0_29(int) = Add : r0_26, r0_28
# 17| valnum = r0_29
# 17| r0_30(glval<int>) = VariableAddress[x] :
# 17| valnum = r0_6
# 17| m0_31(int) = Store : r0_30, r0_29
# 17| valnum = r0_29
# 18| r0_32(glval<int>) = VariableAddress[x] :
# 18| valnum = r0_6
# 18| r0_33(int) = Load : r0_32, m0_31
# 18| valnum = r0_29
# 18| r0_34(glval<int>) = VariableAddress[y] :
# 18| valnum = r0_8
# 18| m0_35(int) = Store : r0_34, r0_33
# 18| valnum = r0_29
# 19| v0_36(void) = NoOp :
# 12| r0_37(glval<int>) = VariableAddress[#return] :
# 12| valnum = unique
# 12| v0_38(void) = ReturnValue : r0_37
# 12| v0_39(void) = UnmodeledUse : mu*
# 12| v0_40(void) = ExitFunction :
# 25| test02(int, int) -> int
# 25| Block 0
# 25| v0_0(void) = EnterFunction :
# 25| mu0_1(unknown) = UnmodeledDefinition :
# 25| valnum = unique
# 25| r0_2(glval<int>) = VariableAddress[p0] :
# 25| valnum = r0_2
# 25| m0_3(int) = InitializeParameter[p0] : r0_2
# 25| valnum = m0_3
# 25| r0_4(glval<int>) = VariableAddress[p1] :
# 25| valnum = r0_4
# 25| m0_5(int) = InitializeParameter[p1] : r0_4
# 25| valnum = m0_5
# 26| r0_6(glval<int>) = VariableAddress[x] :
# 26| valnum = r0_6
# 26| m0_7(int) = Uninitialized : r0_6
# 26| valnum = unique
# 26| r0_8(glval<int>) = VariableAddress[y] :
# 26| valnum = r0_8
# 26| m0_9(int) = Uninitialized : r0_8
# 26| valnum = unique
# 27| r0_10(glval<unsigned char>) = VariableAddress[b] :
# 27| valnum = unique
# 27| m0_11(unsigned char) = Uninitialized : r0_10
# 27| valnum = unique
# 29| r0_12(glval<int>) = VariableAddress[p0] :
# 29| valnum = r0_2
# 29| r0_13(int) = Load : r0_12, m0_3
# 29| valnum = m0_3
# 29| r0_14(glval<int>) = VariableAddress[p1] :
# 29| valnum = r0_4
# 29| r0_15(int) = Load : r0_14, m0_5
# 29| valnum = m0_5
# 29| r0_16(int) = Add : r0_13, r0_15
# 29| valnum = r0_16
# 29| r0_17(glval<int>) = VariableAddress[global02] :
# 29| valnum = r0_17
# 29| r0_18(int) = Load : r0_17, mu0_1
# 29| valnum = unique
# 29| r0_19(int) = Add : r0_16, r0_18
# 29| valnum = r0_19
# 29| r0_20(glval<int>) = VariableAddress[x] :
# 29| valnum = r0_6
# 29| m0_21(int) = Store : r0_20, r0_19
# 29| valnum = r0_19
# 30| r0_22(glval<unknown>) = FunctionAddress[change_global02] :
# 30| valnum = unique
# 30| v0_23(void) = Call : r0_22
# 31| r0_24(glval<int>) = VariableAddress[p0] :
# 31| valnum = r0_2
# 31| r0_25(int) = Load : r0_24, m0_3
# 31| valnum = m0_3
# 31| r0_26(glval<int>) = VariableAddress[p1] :
# 31| valnum = r0_4
# 31| r0_27(int) = Load : r0_26, m0_5
# 31| valnum = m0_5
# 31| r0_28(int) = Add : r0_25, r0_27
# 31| valnum = r0_16
# 31| r0_29(glval<int>) = VariableAddress[global02] :
# 31| valnum = r0_17
# 31| r0_30(int) = Load : r0_29, mu0_1
# 31| valnum = unique
# 31| r0_31(int) = Add : r0_28, r0_30
# 31| valnum = r0_31
# 31| r0_32(glval<int>) = VariableAddress[x] :
# 31| valnum = r0_6
# 31| m0_33(int) = Store : r0_32, r0_31
# 31| valnum = r0_31
# 32| r0_34(glval<int>) = VariableAddress[x] :
# 32| valnum = r0_6
# 32| r0_35(int) = Load : r0_34, m0_33
# 32| valnum = r0_31
# 32| r0_36(glval<int>) = VariableAddress[y] :
# 32| valnum = r0_8
# 32| m0_37(int) = Store : r0_36, r0_35
# 32| valnum = r0_31
# 33| v0_38(void) = NoOp :
# 25| r0_39(glval<int>) = VariableAddress[#return] :
# 25| valnum = unique
# 25| v0_40(void) = ReturnValue : r0_39
# 25| v0_41(void) = UnmodeledUse : mu*
# 25| v0_42(void) = ExitFunction :
# 39| test03(int, int, int *) -> int
# 39| Block 0
# 39| v0_0(void) = EnterFunction :
# 39| mu0_1(unknown) = UnmodeledDefinition :
# 39| valnum = unique
# 39| r0_2(glval<int>) = VariableAddress[p0] :
# 39| valnum = r0_2
# 39| m0_3(int) = InitializeParameter[p0] : r0_2
# 39| valnum = m0_3
# 39| r0_4(glval<int>) = VariableAddress[p1] :
# 39| valnum = r0_4
# 39| m0_5(int) = InitializeParameter[p1] : r0_4
# 39| valnum = m0_5
# 39| r0_6(glval<int *>) = VariableAddress[p2] :
# 39| valnum = r0_6
# 39| m0_7(int *) = InitializeParameter[p2] : r0_6
# 39| valnum = m0_7
# 40| r0_8(glval<int>) = VariableAddress[x] :
# 40| valnum = r0_8
# 40| m0_9(int) = Uninitialized : r0_8
# 40| valnum = unique
# 40| r0_10(glval<int>) = VariableAddress[y] :
# 40| valnum = r0_10
# 40| m0_11(int) = Uninitialized : r0_10
# 40| valnum = unique
# 41| r0_12(glval<unsigned char>) = VariableAddress[b] :
# 41| valnum = unique
# 41| m0_13(unsigned char) = Uninitialized : r0_12
# 41| valnum = unique
# 43| r0_14(glval<int>) = VariableAddress[p0] :
# 43| valnum = r0_2
# 43| r0_15(int) = Load : r0_14, m0_3
# 43| valnum = m0_3
# 43| r0_16(glval<int>) = VariableAddress[p1] :
# 43| valnum = r0_4
# 43| r0_17(int) = Load : r0_16, m0_5
# 43| valnum = m0_5
# 43| r0_18(int) = Add : r0_15, r0_17
# 43| valnum = r0_18
# 43| r0_19(glval<int>) = VariableAddress[global03] :
# 43| valnum = r0_19
# 43| r0_20(int) = Load : r0_19, mu0_1
# 43| valnum = unique
# 43| r0_21(int) = Add : r0_18, r0_20
# 43| valnum = r0_21
# 43| r0_22(glval<int>) = VariableAddress[x] :
# 43| valnum = r0_8
# 43| m0_23(int) = Store : r0_22, r0_21
# 43| valnum = r0_21
# 44| r0_24(int) = Constant[0] :
# 44| valnum = r0_24
# 44| r0_25(glval<int *>) = VariableAddress[p2] :
# 44| valnum = r0_6
# 44| r0_26(int *) = Load : r0_25, m0_7
# 44| valnum = m0_7
# 44| mu0_27(int) = Store : r0_26, r0_24
# 44| valnum = r0_24
# 45| r0_28(glval<int>) = VariableAddress[p0] :
# 45| valnum = r0_2
# 45| r0_29(int) = Load : r0_28, m0_3
# 45| valnum = m0_3
# 45| r0_30(glval<int>) = VariableAddress[p1] :
# 45| valnum = r0_4
# 45| r0_31(int) = Load : r0_30, m0_5
# 45| valnum = m0_5
# 45| r0_32(int) = Add : r0_29, r0_31
# 45| valnum = r0_18
# 45| r0_33(glval<int>) = VariableAddress[global03] :
# 45| valnum = r0_19
# 45| r0_34(int) = Load : r0_33, mu0_1
# 45| valnum = unique
# 45| r0_35(int) = Add : r0_32, r0_34
# 45| valnum = r0_35
# 45| r0_36(glval<int>) = VariableAddress[x] :
# 45| valnum = r0_8
# 45| m0_37(int) = Store : r0_36, r0_35
# 45| valnum = r0_35
# 46| r0_38(glval<int>) = VariableAddress[x] :
# 46| valnum = r0_8
# 46| r0_39(int) = Load : r0_38, m0_37
# 46| valnum = r0_35
# 46| r0_40(glval<int>) = VariableAddress[y] :
# 46| valnum = r0_10
# 46| m0_41(int) = Store : r0_40, r0_39
# 46| valnum = r0_35
# 47| v0_42(void) = NoOp :
# 39| r0_43(glval<int>) = VariableAddress[#return] :
# 39| valnum = unique
# 39| v0_44(void) = ReturnValue : r0_43
# 39| v0_45(void) = UnmodeledUse : mu*
# 39| v0_46(void) = ExitFunction :
# 49| my_strspn(const char *, const char *) -> unsigned int
# 49| Block 0
# 49| v0_0(void) = EnterFunction :
# 49| mu0_1(unknown) = UnmodeledDefinition :
# 49| valnum = unique
# 49| r0_2(glval<char *>) = VariableAddress[str] :
# 49| valnum = r0_2
# 49| m0_3(char *) = InitializeParameter[str] : r0_2
# 49| valnum = m0_3
# 49| r0_4(glval<char *>) = VariableAddress[chars] :
# 49| valnum = r0_4
# 49| m0_5(char *) = InitializeParameter[chars] : r0_4
# 49| valnum = m0_5
# 50| r0_6(glval<char *>) = VariableAddress[ptr] :
# 50| valnum = r0_6
# 50| m0_7(char *) = Uninitialized : r0_6
# 50| valnum = unique
# 51| r0_8(glval<unsigned int>) = VariableAddress[result] :
# 51| valnum = r0_8
# 51| r0_9(unsigned int) = Constant[0] :
# 51| valnum = r0_9
# 51| m0_10(unsigned int) = Store : r0_8, r0_9
# 51| valnum = r0_9
#-----| Goto -> Block 1
# 53| Block 1
# 53| m1_0(unsigned int) = Phi : from 0:m0_10, from 8:m8_4
# 53| valnum = unique
# 53| r1_1(glval<char *>) = VariableAddress[str] :
# 53| valnum = r0_2
# 53| r1_2(char *) = Load : r1_1, m0_3
# 53| valnum = m0_3
# 53| r1_3(char) = Load : r1_2, mu0_1
# 53| valnum = unique
# 53| r1_4(int) = Convert : r1_3
# 53| valnum = unique
# 53| r1_5(int) = Constant[0] :
# 53| valnum = r1_5
# 53| r1_6(bool) = CompareNE : r1_4, r1_5
# 53| valnum = unique
# 53| v1_7(void) = ConditionalBranch : r1_6
#-----| False -> Block 9
#-----| True -> Block 2
# 55| Block 2
# 55| r2_0(glval<char *>) = VariableAddress[chars] :
# 55| valnum = r0_4
# 55| r2_1(char *) = Load : r2_0, m0_5
# 55| valnum = m0_5
# 55| r2_2(glval<char *>) = VariableAddress[ptr] :
# 55| valnum = r0_6
# 55| m2_3(char *) = Store : r2_2, r2_1
# 55| valnum = m0_5
#-----| Goto -> Block 3
# 56| Block 3
# 56| m3_0(char *) = Phi : from 2:m2_3, from 5:m5_4
# 56| valnum = unique
# 56| r3_1(glval<char *>) = VariableAddress[ptr] :
# 56| valnum = r0_6
# 56| r3_2(char *) = Load : r3_1, m3_0
# 56| valnum = unique
# 56| r3_3(char) = Load : r3_2, mu0_1
# 56| valnum = unique
# 56| r3_4(int) = Convert : r3_3
# 56| valnum = unique
# 56| r3_5(glval<char *>) = VariableAddress[str] :
# 56| valnum = r0_2
# 56| r3_6(char *) = Load : r3_5, m0_3
# 56| valnum = m0_3
# 56| r3_7(char) = Load : r3_6, mu0_1
# 56| valnum = unique
# 56| r3_8(int) = Convert : r3_7
# 56| valnum = unique
# 56| r3_9(bool) = CompareNE : r3_4, r3_8
# 56| valnum = unique
# 56| v3_10(void) = ConditionalBranch : r3_9
#-----| False -> Block 6
#-----| True -> Block 4
# 56| Block 4
# 56| r4_0(glval<char *>) = VariableAddress[ptr] :
# 56| valnum = r0_6
# 56| r4_1(char *) = Load : r4_0, m3_0
# 56| valnum = unique
# 56| r4_2(char) = Load : r4_1, mu0_1
# 56| valnum = unique
# 56| r4_3(int) = Convert : r4_2
# 56| valnum = unique
# 56| r4_4(int) = Constant[0] :
# 56| valnum = r1_5
# 56| r4_5(bool) = CompareNE : r4_3, r4_4
# 56| valnum = unique
# 56| v4_6(void) = ConditionalBranch : r4_5
#-----| False -> Block 6
#-----| True -> Block 5
# 56| Block 5
# 56| r5_0(glval<char *>) = VariableAddress[ptr] :
# 56| valnum = r0_6
# 56| r5_1(char *) = Load : r5_0, m3_0
# 56| valnum = unique
# 56| r5_2(int) = Constant[1] :
# 56| valnum = unique
# 56| r5_3(char *) = PointerAdd[1] : r5_1, r5_2
# 56| valnum = r5_3
# 56| m5_4(char *) = Store : r5_0, r5_3
# 56| valnum = r5_3
#-----| Goto -> Block 3
# 59| Block 6
# 59| r6_0(glval<char *>) = VariableAddress[ptr] :
# 59| valnum = r0_6
# 59| r6_1(char *) = Load : r6_0, m3_0
# 59| valnum = unique
# 59| r6_2(char) = Load : r6_1, mu0_1
# 59| valnum = unique
# 59| r6_3(int) = Convert : r6_2
# 59| valnum = unique
# 59| r6_4(int) = Constant[0] :
# 59| valnum = r1_5
# 59| r6_5(bool) = CompareEQ : r6_3, r6_4
# 59| valnum = unique
# 59| v6_6(void) = ConditionalBranch : r6_5
#-----| False -> Block 8
#-----| True -> Block 7
# 60| Block 7
# 60| v7_0(void) = NoOp :
#-----| Goto -> Block 9
# 62| Block 8
# 62| r8_0(glval<unsigned int>) = VariableAddress[result] :
# 62| valnum = r0_8
# 62| r8_1(unsigned int) = Load : r8_0, m1_0
# 62| valnum = unique
# 62| r8_2(unsigned int) = Constant[1] :
# 62| valnum = unique
# 62| r8_3(unsigned int) = Add : r8_1, r8_2
# 62| valnum = r8_3
# 62| m8_4(unsigned int) = Store : r8_0, r8_3
# 62| valnum = r8_3
#-----| Goto -> Block 1
# 63| Block 9
# 63| v9_0(void) = NoOp :
# 65| r9_1(glval<unsigned int>) = VariableAddress[#return] :
# 65| valnum = r9_1
# 65| r9_2(glval<unsigned int>) = VariableAddress[result] :
# 65| valnum = r0_8
# 65| r9_3(unsigned int) = Load : r9_2, m1_0
# 65| valnum = r9_3
# 65| m9_4(unsigned int) = Store : r9_1, r9_3
# 65| valnum = r9_3
# 49| r9_5(glval<unsigned int>) = VariableAddress[#return] :
# 49| valnum = r9_1
# 49| v9_6(void) = ReturnValue : r9_5, m9_4
# 49| v9_7(void) = UnmodeledUse : mu*
# 49| v9_8(void) = ExitFunction :
# 75| test04(two_values *) -> void
# 75| Block 0
# 75| v0_0(void) = EnterFunction :
# 75| mu0_1(unknown) = UnmodeledDefinition :
# 75| valnum = unique
# 75| r0_2(glval<two_values *>) = VariableAddress[vals] :
# 75| valnum = r0_2
# 75| m0_3(two_values *) = InitializeParameter[vals] : r0_2
# 75| valnum = m0_3
# 77| r0_4(glval<signed short>) = VariableAddress[v] :
# 77| valnum = r0_4
# 77| r0_5(glval<unknown>) = FunctionAddress[getAValue] :
# 77| valnum = unique
# 77| r0_6(int) = Call : r0_5
# 77| valnum = unique
# 77| r0_7(signed short) = Convert : r0_6
# 77| valnum = r0_7
# 77| m0_8(signed short) = Store : r0_4, r0_7
# 77| valnum = r0_7
# 79| r0_9(glval<signed short>) = VariableAddress[v] :
# 79| valnum = r0_4
# 79| r0_10(signed short) = Load : r0_9, m0_8
# 79| valnum = r0_7
# 79| r0_11(int) = Convert : r0_10
# 79| valnum = unique
# 79| r0_12(glval<two_values *>) = VariableAddress[vals] :
# 79| valnum = r0_2
# 79| r0_13(two_values *) = Load : r0_12, m0_3
# 79| valnum = m0_3
# 79| r0_14(glval<signed short>) = FieldAddress[val1] : r0_13
# 79| valnum = unique
# 79| r0_15(signed short) = Load : r0_14, mu0_1
# 79| valnum = unique
# 79| r0_16(int) = Convert : r0_15
# 79| valnum = unique
# 79| r0_17(glval<two_values *>) = VariableAddress[vals] :
# 79| valnum = r0_2
# 79| r0_18(two_values *) = Load : r0_17, m0_3
# 79| valnum = m0_3
# 79| r0_19(glval<signed short>) = FieldAddress[val2] : r0_18
# 79| valnum = unique
# 79| r0_20(signed short) = Load : r0_19, mu0_1
# 79| valnum = unique
# 79| r0_21(int) = Convert : r0_20
# 79| valnum = unique
# 79| r0_22(int) = Add : r0_16, r0_21
# 79| valnum = unique
# 79| r0_23(bool) = CompareLT : r0_11, r0_22
# 79| valnum = unique
# 79| v0_24(void) = ConditionalBranch : r0_23
#-----| False -> Block 2
#-----| True -> Block 1
# 80| Block 1
# 80| r1_0(glval<unknown>) = FunctionAddress[getAValue] :
# 80| valnum = unique
# 80| r1_1(int) = Call : r1_0
# 80| valnum = unique
# 80| r1_2(signed short) = Convert : r1_1
# 80| valnum = r1_2
# 80| r1_3(glval<signed short>) = VariableAddress[v] :
# 80| valnum = r0_4
# 80| m1_4(signed short) = Store : r1_3, r1_2
# 80| valnum = r1_2
#-----| Goto -> Block 2
# 82| Block 2
# 82| v2_0(void) = NoOp :
# 75| v2_1(void) = ReturnVoid :
# 75| v2_2(void) = UnmodeledUse : mu*
# 75| v2_3(void) = ExitFunction :
# 84| test05(int, int, void *) -> void
# 84| Block 0
# 84| v0_0(void) = EnterFunction :
# 84| mu0_1(unknown) = UnmodeledDefinition :
# 84| valnum = unique
# 84| r0_2(glval<int>) = VariableAddress[x] :
# 84| valnum = r0_2
# 84| m0_3(int) = InitializeParameter[x] : r0_2
# 84| valnum = m0_3
# 84| r0_4(glval<int>) = VariableAddress[y] :
# 84| valnum = r0_4
# 84| m0_5(int) = InitializeParameter[y] : r0_4
# 84| valnum = m0_5
# 84| r0_6(glval<void *>) = VariableAddress[p] :
# 84| valnum = r0_6
# 84| m0_7(void *) = InitializeParameter[p] : r0_6
# 84| valnum = m0_7
# 86| r0_8(glval<int>) = VariableAddress[v] :
# 86| valnum = r0_8
# 86| m0_9(int) = Uninitialized : r0_8
# 86| valnum = unique
# 88| r0_10(glval<void *>) = VariableAddress[p] :
# 88| valnum = r0_6
# 88| r0_11(void *) = Load : r0_10, m0_7
# 88| valnum = m0_7
# 88| r0_12(void *) = Constant[0] :
# 88| valnum = unique
# 88| r0_13(bool) = CompareNE : r0_11, r0_12
# 88| valnum = unique
# 88| v0_14(void) = ConditionalBranch : r0_13
#-----| False -> Block 2
#-----| True -> Block 1
# 88| Block 1
# 88| r1_0(glval<int>) = VariableAddress[x] :
# 88| valnum = r0_2
# 88| r1_1(int) = Load : r1_0, m0_3
# 88| valnum = m0_3
# 88| r1_2(glval<int>) = VariableAddress[#temp88:7] :
# 88| valnum = r1_2
# 88| m1_3(int) = Store : r1_2, r1_1
# 88| valnum = m0_3
#-----| Goto -> Block 3
# 88| Block 2
# 88| r2_0(glval<int>) = VariableAddress[y] :
# 88| valnum = r0_4
# 88| r2_1(int) = Load : r2_0, m0_5
# 88| valnum = m0_5
# 88| r2_2(glval<int>) = VariableAddress[#temp88:7] :
# 88| valnum = r1_2
# 88| m2_3(int) = Store : r2_2, r2_1
# 88| valnum = m0_5
#-----| Goto -> Block 3
# 88| Block 3
# 88| m3_0(int) = Phi : from 1:m1_3, from 2:m2_3
# 88| valnum = unique
# 88| r3_1(glval<int>) = VariableAddress[#temp88:7] :
# 88| valnum = r1_2
# 88| r3_2(int) = Load : r3_1, m3_0
# 88| valnum = r3_2
# 88| r3_3(glval<int>) = VariableAddress[v] :
# 88| valnum = r0_8
# 88| m3_4(int) = Store : r3_3, r3_2
# 88| valnum = r3_2
# 89| v3_5(void) = NoOp :
# 84| v3_6(void) = ReturnVoid :
# 84| v3_7(void) = UnmodeledUse : mu*
# 84| v3_8(void) = ExitFunction :
# 91| regression_test00() -> int
# 91| Block 0
# 91| v0_0(void) = EnterFunction :
# 91| mu0_1(unknown) = UnmodeledDefinition :
# 91| valnum = unique
# 92| r0_2(glval<int>) = VariableAddress[x] :
# 92| valnum = r0_2
# 92| r0_3(int) = Constant[10] :
# 92| valnum = r0_3
# 92| r0_4(glval<int>) = VariableAddress[x] :
# 92| valnum = r0_2
# 92| m0_5(int) = Store : r0_4, r0_3
# 92| valnum = r0_3
# 92| m0_6(int) = Store : r0_2, r0_3
# 92| valnum = r0_3
# 93| r0_7(glval<int>) = VariableAddress[#return] :
# 93| valnum = r0_7
# 93| r0_8(glval<int>) = VariableAddress[x] :
# 93| valnum = r0_2
# 93| r0_9(int) = Load : r0_8, m0_6
# 93| valnum = r0_3
# 93| m0_10(int) = Store : r0_7, r0_9
# 93| valnum = r0_3
# 91| r0_11(glval<int>) = VariableAddress[#return] :
# 91| valnum = r0_7
# 91| v0_12(void) = ReturnValue : r0_11, m0_10
# 91| v0_13(void) = UnmodeledUse : mu*
# 91| v0_14(void) = ExitFunction :

View File

@@ -0,0 +1,6 @@
/**
* @kind graph
*/
import semmle.code.cpp.ir.PrintIR
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.gvn.ValueNumber