mirror of
https://github.com/github/codeql.git
synced 2026-04-28 02:05:14 +02:00
Merge pull request #2765 from MathiasVP/ir-gvn-ast-wrapper-fixup
C++: Make AST GVN a wrapper for IR-based GVN
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
private import internal.ValueNumberingInternal
|
||||
private import internal.ValueNumberingImports
|
||||
private import IR
|
||||
|
||||
/**
|
||||
* Provides additional information about value numbering in IR dumps.
|
||||
@@ -10,62 +9,38 @@ class ValueNumberPropertyProvider extends IRPropertyProvider {
|
||||
exists(ValueNumber vn |
|
||||
vn = valueNumber(instr) and
|
||||
key = "valnum" and
|
||||
if strictcount(vn.getAnInstruction()) > 1 then result = vn.toString() else result = "unique"
|
||||
if strictcount(vn.getAnInstruction()) > 1
|
||||
then result = vn.getDebugString()
|
||||
else result = "unique"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
variableAddressValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
constantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
stringConstantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, ValueNumber objectAddress) {
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
) {
|
||||
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
) {
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, type, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass,
|
||||
ValueNumber operand
|
||||
) {
|
||||
inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
|
||||
} or
|
||||
TLoadTotalOverlapValueNumber(
|
||||
IRFunction irFunc, IRType type, ValueNumber memOperand, ValueNumber operand
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* 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 string toString() { result = "GVN" }
|
||||
|
||||
final Language::Location getLocation() { result = getExampleInstruction().getLocation() }
|
||||
final string getDebugString() { result = strictconcat(getAnInstruction().getResultId(), ", ") }
|
||||
|
||||
final Language::Location getLocation() {
|
||||
if
|
||||
exists(Instruction i |
|
||||
i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation
|
||||
)
|
||||
then
|
||||
result =
|
||||
min(Language::Location l |
|
||||
l = getAnInstruction().getLocation() and not l instanceof UnknownLocation
|
||||
|
|
||||
l
|
||||
order by
|
||||
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
|
||||
l.getEndColumn()
|
||||
)
|
||||
else result instanceof UnknownDefaultLocation
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instructions that have been assigned this value number. This will always produce at
|
||||
@@ -90,260 +65,39 @@ class ValueNumber extends TValueNumber {
|
||||
* Gets an `Operand` whose definition is exact and has this value number.
|
||||
*/
|
||||
final Operand getAUse() { this = valueNumber(result.getDef()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
*/
|
||||
class CongruentCopyInstruction extends CopyInstruction {
|
||||
CongruentCopyInstruction() {
|
||||
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||
final string getKind() {
|
||||
this instanceof TVariableAddressValueNumber and result = "VariableAddress"
|
||||
or
|
||||
this instanceof TInitializeParameterValueNumber and result = "InitializeParameter"
|
||||
or
|
||||
this instanceof TInitializeThisValueNumber and result = "InitializeThis"
|
||||
or
|
||||
this instanceof TStringConstantValueNumber and result = "StringConstant"
|
||||
or
|
||||
this instanceof TFieldAddressValueNumber and result = "FieldAddress"
|
||||
or
|
||||
this instanceof TBinaryValueNumber and result = "Binary"
|
||||
or
|
||||
this instanceof TPointerArithmeticValueNumber and result = "PointerArithmetic"
|
||||
or
|
||||
this instanceof TUnaryValueNumber and result = "Unary"
|
||||
or
|
||||
this instanceof TInheritanceConversionValueNumber and result = "InheritanceConversion"
|
||||
or
|
||||
this instanceof TLoadTotalOverlapValueNumber and result = "LoadTotalOverlap"
|
||||
or
|
||||
this instanceof TUniqueValueNumber and result = "Unique"
|
||||
}
|
||||
}
|
||||
|
||||
class LoadTotalOverlapInstruction extends LoadInstruction {
|
||||
LoadTotalOverlapInstruction() {
|
||||
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustTotallyOverlap
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 StringConstantInstruction
|
||||
or
|
||||
instr instanceof FieldAddressInstruction
|
||||
or
|
||||
instr instanceof BinaryInstruction
|
||||
or
|
||||
instr instanceof UnaryInstruction and not instr instanceof CopyInstruction
|
||||
or
|
||||
instr instanceof PointerArithmeticInstruction
|
||||
or
|
||||
instr instanceof CongruentCopyInstruction
|
||||
or
|
||||
instr instanceof LoadTotalOverlapInstruction
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
|
||||
private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field, ValueNumber objectAddress
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getField() = field and
|
||||
valueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
valueNumber(instr.getLeft()) = leftOperand and
|
||||
valueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
|
||||
int elementSize, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
valueNumber(instr.getLeft()) = leftOperand and
|
||||
valueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
valueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getBaseClass() = baseClass and
|
||||
instr.getDerivedClass() = derivedClass and
|
||||
valueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
private predicate loadTotalOverlapValueNumber(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, ValueNumber memOperand,
|
||||
ValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
valueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and
|
||||
valueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = 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, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
not numberableInstruction(instr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any. Returns at most one result.
|
||||
*/
|
||||
cached
|
||||
ValueNumber valueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
}
|
||||
ValueNumber valueNumber(Instruction instr) { result = tvalueNumber(instr) }
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to the exact definition of `op`, if any.
|
||||
* Returns at most one result.
|
||||
*/
|
||||
ValueNumber valueNumberOfOperand(Operand op) { result = valueNumber(op.getDef()) }
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique
|
||||
* value number.
|
||||
*/
|
||||
private ValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(IRVariable var |
|
||||
variableAddressValueNumber(instr, irFunc, var) and
|
||||
result = TVariableAddressValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(IRVariable var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, ValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, ValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, type, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
|
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, ValueNumber memOperand, ValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = valueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
)
|
||||
)
|
||||
}
|
||||
ValueNumber valueNumberOfOperand(Operand op) { result = tvalueNumberOfOperand(op) }
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import semmle.code.cpp.Location
|
||||
|
||||
@@ -1 +1,303 @@
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as IR
|
||||
private import ValueNumberingImports
|
||||
private import cpp
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
variableAddressValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
constantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
stringConstantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Field field, TValueNumber objectAddress) {
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, type, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
|
||||
} or
|
||||
TLoadTotalOverlapValueNumber(
|
||||
IRFunction irFunc, IRType type, TValueNumber memOperand, TValueNumber operand
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
*/
|
||||
class CongruentCopyInstruction extends CopyInstruction {
|
||||
CongruentCopyInstruction() {
|
||||
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||
}
|
||||
}
|
||||
|
||||
class LoadTotalOverlapInstruction extends LoadInstruction {
|
||||
LoadTotalOverlapInstruction() {
|
||||
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustTotallyOverlap
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 StringConstantInstruction
|
||||
or
|
||||
instr instanceof FieldAddressInstruction
|
||||
or
|
||||
instr instanceof BinaryInstruction
|
||||
or
|
||||
instr instanceof UnaryInstruction and not instr instanceof CopyInstruction
|
||||
or
|
||||
instr instanceof PointerArithmeticInstruction
|
||||
or
|
||||
instr instanceof CongruentCopyInstruction
|
||||
or
|
||||
instr instanceof LoadTotalOverlapInstruction
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
|
||||
private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field,
|
||||
TValueNumber objectAddress
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getField() = field and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getLeft()) = leftOperand and
|
||||
tvalueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
|
||||
int elementSize, TValueNumber leftOperand, TValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
tvalueNumber(instr.getLeft()) = leftOperand and
|
||||
tvalueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getBaseClass() = baseClass and
|
||||
instr.getDerivedClass() = derivedClass and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
private predicate loadTotalOverlapValueNumber(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber memOperand,
|
||||
TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and
|
||||
tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = 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, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
not numberableInstruction(instr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any. Returns at most one result.
|
||||
*/
|
||||
cached
|
||||
TValueNumber tvalueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to the exact definition of `op`, if any.
|
||||
* Returns at most one result.
|
||||
*/
|
||||
TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef()) }
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique
|
||||
* value number.
|
||||
*/
|
||||
private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(IRVariable var |
|
||||
variableAddressValueNumber(instr, irFunc, var) and
|
||||
result = TVariableAddressValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(IRVariable var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, type, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
|
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
private import internal.ValueNumberingInternal
|
||||
private import internal.ValueNumberingImports
|
||||
private import IR
|
||||
|
||||
/**
|
||||
* Provides additional information about value numbering in IR dumps.
|
||||
@@ -10,62 +9,38 @@ class ValueNumberPropertyProvider extends IRPropertyProvider {
|
||||
exists(ValueNumber vn |
|
||||
vn = valueNumber(instr) and
|
||||
key = "valnum" and
|
||||
if strictcount(vn.getAnInstruction()) > 1 then result = vn.toString() else result = "unique"
|
||||
if strictcount(vn.getAnInstruction()) > 1
|
||||
then result = vn.getDebugString()
|
||||
else result = "unique"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
variableAddressValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
constantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
stringConstantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, ValueNumber objectAddress) {
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
) {
|
||||
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
) {
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, type, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass,
|
||||
ValueNumber operand
|
||||
) {
|
||||
inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
|
||||
} or
|
||||
TLoadTotalOverlapValueNumber(
|
||||
IRFunction irFunc, IRType type, ValueNumber memOperand, ValueNumber operand
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* 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 string toString() { result = "GVN" }
|
||||
|
||||
final Language::Location getLocation() { result = getExampleInstruction().getLocation() }
|
||||
final string getDebugString() { result = strictconcat(getAnInstruction().getResultId(), ", ") }
|
||||
|
||||
final Language::Location getLocation() {
|
||||
if
|
||||
exists(Instruction i |
|
||||
i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation
|
||||
)
|
||||
then
|
||||
result =
|
||||
min(Language::Location l |
|
||||
l = getAnInstruction().getLocation() and not l instanceof UnknownLocation
|
||||
|
|
||||
l
|
||||
order by
|
||||
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
|
||||
l.getEndColumn()
|
||||
)
|
||||
else result instanceof UnknownDefaultLocation
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instructions that have been assigned this value number. This will always produce at
|
||||
@@ -90,260 +65,39 @@ class ValueNumber extends TValueNumber {
|
||||
* Gets an `Operand` whose definition is exact and has this value number.
|
||||
*/
|
||||
final Operand getAUse() { this = valueNumber(result.getDef()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
*/
|
||||
class CongruentCopyInstruction extends CopyInstruction {
|
||||
CongruentCopyInstruction() {
|
||||
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||
final string getKind() {
|
||||
this instanceof TVariableAddressValueNumber and result = "VariableAddress"
|
||||
or
|
||||
this instanceof TInitializeParameterValueNumber and result = "InitializeParameter"
|
||||
or
|
||||
this instanceof TInitializeThisValueNumber and result = "InitializeThis"
|
||||
or
|
||||
this instanceof TStringConstantValueNumber and result = "StringConstant"
|
||||
or
|
||||
this instanceof TFieldAddressValueNumber and result = "FieldAddress"
|
||||
or
|
||||
this instanceof TBinaryValueNumber and result = "Binary"
|
||||
or
|
||||
this instanceof TPointerArithmeticValueNumber and result = "PointerArithmetic"
|
||||
or
|
||||
this instanceof TUnaryValueNumber and result = "Unary"
|
||||
or
|
||||
this instanceof TInheritanceConversionValueNumber and result = "InheritanceConversion"
|
||||
or
|
||||
this instanceof TLoadTotalOverlapValueNumber and result = "LoadTotalOverlap"
|
||||
or
|
||||
this instanceof TUniqueValueNumber and result = "Unique"
|
||||
}
|
||||
}
|
||||
|
||||
class LoadTotalOverlapInstruction extends LoadInstruction {
|
||||
LoadTotalOverlapInstruction() {
|
||||
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustTotallyOverlap
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 StringConstantInstruction
|
||||
or
|
||||
instr instanceof FieldAddressInstruction
|
||||
or
|
||||
instr instanceof BinaryInstruction
|
||||
or
|
||||
instr instanceof UnaryInstruction and not instr instanceof CopyInstruction
|
||||
or
|
||||
instr instanceof PointerArithmeticInstruction
|
||||
or
|
||||
instr instanceof CongruentCopyInstruction
|
||||
or
|
||||
instr instanceof LoadTotalOverlapInstruction
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
|
||||
private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field, ValueNumber objectAddress
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getField() = field and
|
||||
valueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
valueNumber(instr.getLeft()) = leftOperand and
|
||||
valueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
|
||||
int elementSize, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
valueNumber(instr.getLeft()) = leftOperand and
|
||||
valueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
valueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getBaseClass() = baseClass and
|
||||
instr.getDerivedClass() = derivedClass and
|
||||
valueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
private predicate loadTotalOverlapValueNumber(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, ValueNumber memOperand,
|
||||
ValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
valueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and
|
||||
valueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = 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, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
not numberableInstruction(instr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any. Returns at most one result.
|
||||
*/
|
||||
cached
|
||||
ValueNumber valueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
}
|
||||
ValueNumber valueNumber(Instruction instr) { result = tvalueNumber(instr) }
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to the exact definition of `op`, if any.
|
||||
* Returns at most one result.
|
||||
*/
|
||||
ValueNumber valueNumberOfOperand(Operand op) { result = valueNumber(op.getDef()) }
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique
|
||||
* value number.
|
||||
*/
|
||||
private ValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(IRVariable var |
|
||||
variableAddressValueNumber(instr, irFunc, var) and
|
||||
result = TVariableAddressValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(IRVariable var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, ValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, ValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, type, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
|
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, ValueNumber memOperand, ValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = valueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
)
|
||||
)
|
||||
}
|
||||
ValueNumber valueNumberOfOperand(Operand op) { result = tvalueNumberOfOperand(op) }
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import semmle.code.cpp.Location
|
||||
|
||||
@@ -1 +1,303 @@
|
||||
import semmle.code.cpp.ir.implementation.raw.IR as IR
|
||||
private import ValueNumberingImports
|
||||
private import cpp
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
variableAddressValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
constantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
stringConstantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Field field, TValueNumber objectAddress) {
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, type, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
|
||||
} or
|
||||
TLoadTotalOverlapValueNumber(
|
||||
IRFunction irFunc, IRType type, TValueNumber memOperand, TValueNumber operand
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
*/
|
||||
class CongruentCopyInstruction extends CopyInstruction {
|
||||
CongruentCopyInstruction() {
|
||||
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||
}
|
||||
}
|
||||
|
||||
class LoadTotalOverlapInstruction extends LoadInstruction {
|
||||
LoadTotalOverlapInstruction() {
|
||||
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustTotallyOverlap
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 StringConstantInstruction
|
||||
or
|
||||
instr instanceof FieldAddressInstruction
|
||||
or
|
||||
instr instanceof BinaryInstruction
|
||||
or
|
||||
instr instanceof UnaryInstruction and not instr instanceof CopyInstruction
|
||||
or
|
||||
instr instanceof PointerArithmeticInstruction
|
||||
or
|
||||
instr instanceof CongruentCopyInstruction
|
||||
or
|
||||
instr instanceof LoadTotalOverlapInstruction
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
|
||||
private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field,
|
||||
TValueNumber objectAddress
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getField() = field and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getLeft()) = leftOperand and
|
||||
tvalueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
|
||||
int elementSize, TValueNumber leftOperand, TValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
tvalueNumber(instr.getLeft()) = leftOperand and
|
||||
tvalueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getBaseClass() = baseClass and
|
||||
instr.getDerivedClass() = derivedClass and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
private predicate loadTotalOverlapValueNumber(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber memOperand,
|
||||
TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and
|
||||
tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = 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, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
not numberableInstruction(instr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any. Returns at most one result.
|
||||
*/
|
||||
cached
|
||||
TValueNumber tvalueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to the exact definition of `op`, if any.
|
||||
* Returns at most one result.
|
||||
*/
|
||||
TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef()) }
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique
|
||||
* value number.
|
||||
*/
|
||||
private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(IRVariable var |
|
||||
variableAddressValueNumber(instr, irFunc, var) and
|
||||
result = TVariableAddressValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(IRVariable var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, type, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
|
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
private import internal.ValueNumberingInternal
|
||||
private import internal.ValueNumberingImports
|
||||
private import IR
|
||||
|
||||
/**
|
||||
* Provides additional information about value numbering in IR dumps.
|
||||
@@ -10,62 +9,38 @@ class ValueNumberPropertyProvider extends IRPropertyProvider {
|
||||
exists(ValueNumber vn |
|
||||
vn = valueNumber(instr) and
|
||||
key = "valnum" and
|
||||
if strictcount(vn.getAnInstruction()) > 1 then result = vn.toString() else result = "unique"
|
||||
if strictcount(vn.getAnInstruction()) > 1
|
||||
then result = vn.getDebugString()
|
||||
else result = "unique"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
variableAddressValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
constantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
stringConstantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, ValueNumber objectAddress) {
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
) {
|
||||
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
) {
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, type, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass,
|
||||
ValueNumber operand
|
||||
) {
|
||||
inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
|
||||
} or
|
||||
TLoadTotalOverlapValueNumber(
|
||||
IRFunction irFunc, IRType type, ValueNumber memOperand, ValueNumber operand
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* 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 string toString() { result = "GVN" }
|
||||
|
||||
final Language::Location getLocation() { result = getExampleInstruction().getLocation() }
|
||||
final string getDebugString() { result = strictconcat(getAnInstruction().getResultId(), ", ") }
|
||||
|
||||
final Language::Location getLocation() {
|
||||
if
|
||||
exists(Instruction i |
|
||||
i = getAnInstruction() and not i.getLocation() instanceof UnknownLocation
|
||||
)
|
||||
then
|
||||
result =
|
||||
min(Language::Location l |
|
||||
l = getAnInstruction().getLocation() and not l instanceof UnknownLocation
|
||||
|
|
||||
l
|
||||
order by
|
||||
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
|
||||
l.getEndColumn()
|
||||
)
|
||||
else result instanceof UnknownDefaultLocation
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instructions that have been assigned this value number. This will always produce at
|
||||
@@ -90,260 +65,39 @@ class ValueNumber extends TValueNumber {
|
||||
* Gets an `Operand` whose definition is exact and has this value number.
|
||||
*/
|
||||
final Operand getAUse() { this = valueNumber(result.getDef()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
*/
|
||||
class CongruentCopyInstruction extends CopyInstruction {
|
||||
CongruentCopyInstruction() {
|
||||
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||
final string getKind() {
|
||||
this instanceof TVariableAddressValueNumber and result = "VariableAddress"
|
||||
or
|
||||
this instanceof TInitializeParameterValueNumber and result = "InitializeParameter"
|
||||
or
|
||||
this instanceof TInitializeThisValueNumber and result = "InitializeThis"
|
||||
or
|
||||
this instanceof TStringConstantValueNumber and result = "StringConstant"
|
||||
or
|
||||
this instanceof TFieldAddressValueNumber and result = "FieldAddress"
|
||||
or
|
||||
this instanceof TBinaryValueNumber and result = "Binary"
|
||||
or
|
||||
this instanceof TPointerArithmeticValueNumber and result = "PointerArithmetic"
|
||||
or
|
||||
this instanceof TUnaryValueNumber and result = "Unary"
|
||||
or
|
||||
this instanceof TInheritanceConversionValueNumber and result = "InheritanceConversion"
|
||||
or
|
||||
this instanceof TLoadTotalOverlapValueNumber and result = "LoadTotalOverlap"
|
||||
or
|
||||
this instanceof TUniqueValueNumber and result = "Unique"
|
||||
}
|
||||
}
|
||||
|
||||
class LoadTotalOverlapInstruction extends LoadInstruction {
|
||||
LoadTotalOverlapInstruction() {
|
||||
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustTotallyOverlap
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 StringConstantInstruction
|
||||
or
|
||||
instr instanceof FieldAddressInstruction
|
||||
or
|
||||
instr instanceof BinaryInstruction
|
||||
or
|
||||
instr instanceof UnaryInstruction and not instr instanceof CopyInstruction
|
||||
or
|
||||
instr instanceof PointerArithmeticInstruction
|
||||
or
|
||||
instr instanceof CongruentCopyInstruction
|
||||
or
|
||||
instr instanceof LoadTotalOverlapInstruction
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
|
||||
private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field, ValueNumber objectAddress
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getField() = field and
|
||||
valueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
valueNumber(instr.getLeft()) = leftOperand and
|
||||
valueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
|
||||
int elementSize, ValueNumber leftOperand, ValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
valueNumber(instr.getLeft()) = leftOperand and
|
||||
valueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
valueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getBaseClass() = baseClass and
|
||||
instr.getDerivedClass() = derivedClass and
|
||||
valueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
private predicate loadTotalOverlapValueNumber(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, ValueNumber memOperand,
|
||||
ValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
valueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and
|
||||
valueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = 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, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
not numberableInstruction(instr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any. Returns at most one result.
|
||||
*/
|
||||
cached
|
||||
ValueNumber valueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
}
|
||||
ValueNumber valueNumber(Instruction instr) { result = tvalueNumber(instr) }
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to the exact definition of `op`, if any.
|
||||
* Returns at most one result.
|
||||
*/
|
||||
ValueNumber valueNumberOfOperand(Operand op) { result = valueNumber(op.getDef()) }
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique
|
||||
* value number.
|
||||
*/
|
||||
private ValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(IRVariable var |
|
||||
variableAddressValueNumber(instr, irFunc, var) and
|
||||
result = TVariableAddressValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(IRVariable var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, ValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, ValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, type, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand
|
||||
|
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, ValueNumber memOperand, ValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = valueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
)
|
||||
)
|
||||
}
|
||||
ValueNumber valueNumberOfOperand(Operand op) { result = tvalueNumberOfOperand(op) }
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import semmle.code.cpp.Location
|
||||
|
||||
@@ -1 +1,303 @@
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR
|
||||
private import ValueNumberingImports
|
||||
private import cpp
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
variableAddressValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
constantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
|
||||
stringConstantValueNumber(_, irFunc, type, value)
|
||||
} or
|
||||
TFieldAddressValueNumber(IRFunction irFunc, Field field, TValueNumber objectAddress) {
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, type, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
|
||||
} or
|
||||
TLoadTotalOverlapValueNumber(
|
||||
IRFunction irFunc, IRType type, TValueNumber memOperand, TValueNumber operand
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
*/
|
||||
class CongruentCopyInstruction extends CopyInstruction {
|
||||
CongruentCopyInstruction() {
|
||||
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||
}
|
||||
}
|
||||
|
||||
class LoadTotalOverlapInstruction extends LoadInstruction {
|
||||
LoadTotalOverlapInstruction() {
|
||||
this.getSourceValueOperand().getDefinitionOverlap() instanceof MustTotallyOverlap
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 StringConstantInstruction
|
||||
or
|
||||
instr instanceof FieldAddressInstruction
|
||||
or
|
||||
instr instanceof BinaryInstruction
|
||||
or
|
||||
instr instanceof UnaryInstruction and not instr instanceof CopyInstruction
|
||||
or
|
||||
instr instanceof PointerArithmeticInstruction
|
||||
or
|
||||
instr instanceof CongruentCopyInstruction
|
||||
or
|
||||
instr instanceof LoadTotalOverlapInstruction
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
|
||||
private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field,
|
||||
TValueNumber objectAddress
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getField() = field and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getLeft()) = leftOperand and
|
||||
tvalueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
|
||||
int elementSize, TValueNumber leftOperand, TValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
tvalueNumber(instr.getLeft()) = leftOperand and
|
||||
tvalueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getBaseClass() = baseClass and
|
||||
instr.getDerivedClass() = derivedClass and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
private predicate loadTotalOverlapValueNumber(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber memOperand,
|
||||
TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and
|
||||
tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = 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, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
not numberableInstruction(instr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any. Returns at most one result.
|
||||
*/
|
||||
cached
|
||||
TValueNumber tvalueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to the exact definition of `op`, if any.
|
||||
* Returns at most one result.
|
||||
*/
|
||||
TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef()) }
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique
|
||||
* value number.
|
||||
*/
|
||||
private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(IRVariable var |
|
||||
variableAddressValueNumber(instr, irFunc, var) and
|
||||
result = TVariableAddressValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(IRVariable var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, type, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
|
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
114
cpp/ql/src/semmle/code/cpp/ir/internal/ASTValueNumbering.qll
Normal file
114
cpp/ql/src/semmle/code/cpp/ir/internal/ASTValueNumbering.qll
Normal file
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Provides an implementation of Global Value Numbering.
|
||||
* See https://en.wikipedia.org/wiki/Global_value_numbering
|
||||
*
|
||||
* The predicate `globalValueNumber` converts an expression into a `GVN`,
|
||||
* which is an abstract type representing the value of the expression. If
|
||||
* two expressions have the same `GVN` then they compute the same value.
|
||||
* For example:
|
||||
*
|
||||
* ```
|
||||
* void f(int x, int y) {
|
||||
* g(x+y, x+y);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* In this example, both arguments in the call to `g` compute the same value,
|
||||
* so both arguments have the same `GVN`. In other words, we can find
|
||||
* this call with the following query:
|
||||
*
|
||||
* ```
|
||||
* from FunctionCall call, GVN v
|
||||
* where v = globalValueNumber(call.getArgument(0))
|
||||
* and v = globalValueNumber(call.getArgument(1))
|
||||
* select call
|
||||
* ```
|
||||
*
|
||||
* The analysis is conservative, so two expressions might have different
|
||||
* `GVN`s even though the actually always compute the same value. The most
|
||||
* common reason for this is that the analysis cannot prove that there
|
||||
* are no side-effects that might cause the computed value to change.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
private import semmle.code.cpp.ir.implementation.aliased_ssa.gvn.internal.ValueNumberingInternal
|
||||
private import semmle.code.cpp.ir.IR
|
||||
|
||||
/**
|
||||
* A Global Value Number. A GVN is an abstract representation of the value
|
||||
* computed by an expression. The relationship between `Expr` and `GVN` is
|
||||
* many-to-one: every `Expr` has exactly one `GVN`, but multiple
|
||||
* expressions can have the same `GVN`. If two expressions have the same
|
||||
* `GVN`, it means that they compute the same value at run time. The `GVN`
|
||||
* is an opaque value, so you cannot deduce what the run-time value of an
|
||||
* expression will be from its `GVN`. The only use for the `GVN` of an
|
||||
* expression is to find other expressions that compute the same value.
|
||||
* Use the predicate `globalValueNumber` to get the `GVN` for an `Expr`.
|
||||
*
|
||||
* Note: `GVN` has `toString` and `getLocation` methods, so that it can be
|
||||
* displayed in a results list. These work by picking an arbitrary
|
||||
* expression with this `GVN` and using its `toString` and `getLocation`
|
||||
* methods.
|
||||
*/
|
||||
class GVN extends TValueNumber {
|
||||
GVN() {
|
||||
exists(Instruction instr |
|
||||
this = tvalueNumber(instr) and exists(instr.getUnconvertedResultExpression())
|
||||
)
|
||||
}
|
||||
|
||||
private Instruction getAnInstruction() { this = tvalueNumber(result) }
|
||||
|
||||
final string toString() { result = "GVN" }
|
||||
|
||||
final string getDebugString() { result = strictconcat(getAnExpr().toString(), ", ") }
|
||||
|
||||
final Location getLocation() {
|
||||
if exists(Expr e | e = getAnExpr() and not e.getLocation() instanceof UnknownLocation)
|
||||
then
|
||||
result =
|
||||
min(Location l |
|
||||
l = getAnExpr().getLocation() and not l instanceof UnknownLocation
|
||||
|
|
||||
l
|
||||
order by
|
||||
l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
|
||||
l.getEndColumn()
|
||||
)
|
||||
else result instanceof UnknownDefaultLocation
|
||||
}
|
||||
|
||||
final string getKind() {
|
||||
this instanceof TVariableAddressValueNumber and result = "VariableAddress"
|
||||
or
|
||||
this instanceof TInitializeParameterValueNumber and result = "InitializeParameter"
|
||||
or
|
||||
this instanceof TInitializeThisValueNumber and result = "InitializeThis"
|
||||
or
|
||||
this instanceof TStringConstantValueNumber and result = "StringConstant"
|
||||
or
|
||||
this instanceof TFieldAddressValueNumber and result = "FieldAddress"
|
||||
or
|
||||
this instanceof TBinaryValueNumber and result = "Binary"
|
||||
or
|
||||
this instanceof TPointerArithmeticValueNumber and result = "PointerArithmetic"
|
||||
or
|
||||
this instanceof TUnaryValueNumber and result = "Unary"
|
||||
or
|
||||
this instanceof TInheritanceConversionValueNumber and result = "InheritanceConversion"
|
||||
or
|
||||
this instanceof TUniqueValueNumber and result = "Unique"
|
||||
}
|
||||
|
||||
/** Gets an expression that has this GVN. */
|
||||
Expr getAnExpr() { result = getAnUnconvertedExpr() }
|
||||
|
||||
/** Gets an expression that has this GVN. */
|
||||
Expr getAnUnconvertedExpr() { result = getAnInstruction().getUnconvertedResultExpression() }
|
||||
|
||||
/** Gets an expression that has this GVN. */
|
||||
Expr getAConvertedExpr() { result = getAnInstruction().getConvertedResultExpression() }
|
||||
}
|
||||
|
||||
/** Gets the global value number of expression `e`. */
|
||||
GVN globalValueNumber(Expr e) { e = result.getAnExpr() }
|
||||
@@ -0,0 +1,142 @@
|
||||
| test.cpp:5:3:5:13 | ... = ... | test.cpp:5:3:5:13 | ... = ... | AST only |
|
||||
| test.cpp:6:3:6:13 | ... = ... | test.cpp:6:3:6:13 | ... = ... | AST only |
|
||||
| test.cpp:7:3:7:7 | ... = ... | test.cpp:7:3:7:7 | ... = ... | AST only |
|
||||
| test.cpp:10:16:10:16 | 1 | test.cpp:10:16:10:16 | 1 | AST only |
|
||||
| test.cpp:16:3:16:24 | ... = ... | test.cpp:16:3:16:24 | ... = ... | AST only |
|
||||
| test.cpp:17:3:17:24 | ... = ... | test.cpp:17:3:17:24 | ... = ... | AST only |
|
||||
| test.cpp:18:3:18:7 | ... = ... | test.cpp:18:3:18:7 | ... = ... | AST only |
|
||||
| test.cpp:21:16:21:16 | 2 | test.cpp:21:16:21:16 | 2 | AST only |
|
||||
| test.cpp:29:3:29:3 | x | test.cpp:31:3:31:3 | x | IR only |
|
||||
| test.cpp:29:3:29:24 | ... = ... | test.cpp:29:3:29:24 | ... = ... | AST only |
|
||||
| test.cpp:30:3:30:17 | call to change_global02 | test.cpp:30:3:30:17 | call to change_global02 | AST only |
|
||||
| test.cpp:31:3:31:3 | x | test.cpp:29:3:29:3 | x | IR only |
|
||||
| test.cpp:31:3:31:24 | ... = ... | test.cpp:31:3:31:24 | ... = ... | AST only |
|
||||
| test.cpp:32:3:32:7 | ... = ... | test.cpp:32:3:32:7 | ... = ... | AST only |
|
||||
| test.cpp:35:16:35:16 | 3 | test.cpp:35:16:35:16 | 3 | AST only |
|
||||
| test.cpp:43:3:43:3 | x | test.cpp:45:3:45:3 | x | IR only |
|
||||
| test.cpp:43:3:43:24 | ... = ... | test.cpp:43:3:43:24 | ... = ... | AST only |
|
||||
| test.cpp:43:7:43:24 | ... + ... | test.cpp:45:7:45:24 | ... + ... | IR only |
|
||||
| test.cpp:43:7:43:24 | ... + ... | test.cpp:46:7:46:7 | x | IR only |
|
||||
| test.cpp:43:17:43:24 | global03 | test.cpp:45:17:45:24 | global03 | IR only |
|
||||
| test.cpp:44:3:44:5 | * ... | test.cpp:44:4:44:5 | p2 | IR only |
|
||||
| test.cpp:44:3:44:9 | ... = ... | test.cpp:44:3:44:9 | ... = ... | AST only |
|
||||
| test.cpp:44:4:44:5 | p2 | test.cpp:44:3:44:5 | * ... | IR only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:45:3:45:3 | x | test.cpp:43:3:43:3 | x | IR only |
|
||||
| test.cpp:45:3:45:24 | ... = ... | test.cpp:45:3:45:24 | ... = ... | AST only |
|
||||
| test.cpp:45:7:45:24 | ... + ... | test.cpp:43:7:43:24 | ... + ... | IR only |
|
||||
| test.cpp:45:17:45:24 | global03 | test.cpp:43:17:43:24 | global03 | IR only |
|
||||
| test.cpp:46:3:46:7 | ... = ... | test.cpp:46:3:46:7 | ... = ... | AST only |
|
||||
| test.cpp:46:7:46:7 | x | test.cpp:43:7:43:24 | ... + ... | IR only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:51:25:51:25 | (unsigned int)... | test.cpp:51:25:51:25 | (unsigned int)... | AST only |
|
||||
| test.cpp:53:10:53:13 | (int)... | test.cpp:53:10:53:13 | (int)... | AST only |
|
||||
| test.cpp:53:10:53:13 | (int)... | test.cpp:56:21:56:24 | (int)... | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:55:5:55:15 | ... = ... | test.cpp:55:5:55:15 | ... = ... | AST only |
|
||||
| test.cpp:56:12:56:25 | (...) | test.cpp:56:12:56:25 | (...) | AST only |
|
||||
| test.cpp:56:12:56:43 | ... && ... | test.cpp:56:12:56:43 | ... && ... | AST only |
|
||||
| test.cpp:56:13:56:16 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
|
||||
| test.cpp:56:13:56:16 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
|
||||
| test.cpp:56:13:56:16 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
|
||||
| test.cpp:56:13:56:16 | * ... | test.cpp:56:31:56:34 | * ... | AST only |
|
||||
| test.cpp:56:13:56:16 | * ... | test.cpp:59:9:59:12 | * ... | AST only |
|
||||
| test.cpp:56:21:56:24 | (int)... | test.cpp:53:10:53:13 | (int)... | AST only |
|
||||
| test.cpp:56:21:56:24 | (int)... | test.cpp:56:21:56:24 | (int)... | AST only |
|
||||
| test.cpp:56:30:56:43 | (...) | test.cpp:56:30:56:43 | (...) | AST only |
|
||||
| test.cpp:56:31:56:34 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
|
||||
| test.cpp:56:31:56:34 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
|
||||
| test.cpp:56:31:56:34 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
|
||||
| test.cpp:56:31:56:34 | * ... | test.cpp:56:13:56:16 | * ... | AST only |
|
||||
| test.cpp:56:31:56:34 | * ... | test.cpp:59:9:59:12 | * ... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:56:47:56:51 | ... ++ | test.cpp:56:47:56:51 | ... ++ | AST only |
|
||||
| test.cpp:59:9:59:12 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
|
||||
| test.cpp:59:9:59:12 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
|
||||
| test.cpp:59:9:59:12 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
|
||||
| test.cpp:59:9:59:12 | * ... | test.cpp:56:13:56:16 | * ... | AST only |
|
||||
| test.cpp:59:9:59:12 | * ... | test.cpp:56:31:56:34 | * ... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:62:5:62:12 | ... ++ | test.cpp:62:5:62:12 | ... ++ | AST only |
|
||||
| test.cpp:77:20:77:28 | call to getAValue | test.cpp:79:7:79:7 | v | IR only |
|
||||
| test.cpp:77:20:77:30 | (signed short)... | test.cpp:77:20:77:30 | (signed short)... | AST only |
|
||||
| test.cpp:77:20:77:30 | (signed short)... | test.cpp:79:7:79:7 | v | AST only |
|
||||
| test.cpp:79:7:79:7 | (int)... | test.cpp:79:7:79:7 | (int)... | AST only |
|
||||
| test.cpp:79:7:79:7 | v | test.cpp:77:20:77:28 | call to getAValue | IR only |
|
||||
| test.cpp:79:7:79:7 | v | test.cpp:77:20:77:30 | (signed short)... | AST only |
|
||||
| test.cpp:79:11:79:20 | (int)... | test.cpp:79:11:79:20 | (int)... | AST only |
|
||||
| test.cpp:79:24:79:33 | (int)... | test.cpp:79:24:79:33 | (int)... | AST only |
|
||||
| test.cpp:80:5:80:19 | ... = ... | test.cpp:80:5:80:19 | ... = ... | AST only |
|
||||
| test.cpp:80:9:80:19 | (signed short)... | test.cpp:80:9:80:19 | (signed short)... | AST only |
|
||||
| test.cpp:88:3:88:20 | ... = ... | test.cpp:88:3:88:20 | ... = ... | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:88:12:88:12 | (void *)... | test.cpp:88:12:88:12 | (void *)... | AST only |
|
||||
| test.cpp:92:11:92:16 | ... = ... | test.cpp:92:15:92:16 | 10 | IR only |
|
||||
| test.cpp:92:11:92:16 | ... = ... | test.cpp:93:10:93:10 | x | IR only |
|
||||
| test.cpp:92:15:92:16 | 10 | test.cpp:92:11:92:16 | ... = ... | IR only |
|
||||
| test.cpp:92:15:92:16 | 10 | test.cpp:93:10:93:10 | x | IR only |
|
||||
| test.cpp:93:10:93:10 | x | test.cpp:92:11:92:16 | ... = ... | IR only |
|
||||
| test.cpp:93:10:93:10 | x | test.cpp:92:15:92:16 | 10 | IR only |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | test.cpp:105:11:105:12 | (Base *)... | AST only |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | test.cpp:106:14:106:35 | static_cast<Base *>... | AST only |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | test.cpp:107:11:107:12 | pb | AST only |
|
||||
| test.cpp:105:11:105:12 | pd | test.cpp:107:11:107:12 | pb | IR only |
|
||||
| test.cpp:106:14:106:35 | static_cast<Base *>... | test.cpp:105:11:105:12 | (Base *)... | AST only |
|
||||
| test.cpp:106:14:106:35 | static_cast<Base *>... | test.cpp:106:14:106:35 | static_cast<Base *>... | AST only |
|
||||
| test.cpp:106:14:106:35 | static_cast<Base *>... | test.cpp:107:11:107:12 | pb | AST only |
|
||||
| test.cpp:106:33:106:34 | pd | test.cpp:107:11:107:12 | pb | IR only |
|
||||
| test.cpp:107:11:107:12 | pb | test.cpp:105:11:105:12 | (Base *)... | AST only |
|
||||
| test.cpp:107:11:107:12 | pb | test.cpp:105:11:105:12 | pd | IR only |
|
||||
| test.cpp:107:11:107:12 | pb | test.cpp:106:14:106:35 | static_cast<Base *>... | AST only |
|
||||
| test.cpp:107:11:107:12 | pb | test.cpp:106:33:106:34 | pd | IR only |
|
||||
| test.cpp:113:3:113:5 | a | test.cpp:115:3:115:5 | a | IR only |
|
||||
| test.cpp:115:3:115:5 | a | test.cpp:113:3:113:5 | a | IR only |
|
||||
| test.cpp:125:15:125:15 | x | test.cpp:128:7:128:7 | x | AST only |
|
||||
| test.cpp:126:15:126:15 | x | test.cpp:128:7:128:7 | x | AST only |
|
||||
| test.cpp:128:3:128:11 | ... = ... | test.cpp:128:3:128:11 | ... = ... | AST only |
|
||||
| test.cpp:128:7:128:7 | x | test.cpp:125:15:125:15 | x | AST only |
|
||||
| test.cpp:128:7:128:7 | x | test.cpp:126:15:126:15 | x | AST only |
|
||||
| test.cpp:128:11:128:11 | n | test.cpp:129:15:129:15 | x | IR only |
|
||||
| test.cpp:129:15:129:15 | x | test.cpp:128:11:128:11 | n | IR only |
|
||||
| test.cpp:136:21:136:21 | x | test.cpp:137:21:137:21 | x | AST only |
|
||||
| test.cpp:136:21:136:21 | x | test.cpp:139:13:139:13 | x | AST only |
|
||||
| test.cpp:137:21:137:21 | x | test.cpp:136:21:136:21 | x | AST only |
|
||||
| test.cpp:137:21:137:21 | x | test.cpp:139:13:139:13 | x | AST only |
|
||||
| test.cpp:139:3:139:24 | ... = ... | test.cpp:139:3:139:24 | ... = ... | AST only |
|
||||
| test.cpp:139:13:139:13 | x | test.cpp:136:21:136:21 | x | AST only |
|
||||
| test.cpp:139:13:139:13 | x | test.cpp:137:21:137:21 | x | AST only |
|
||||
| test.cpp:144:15:144:15 | x | test.cpp:149:15:149:15 | x | IR only |
|
||||
| test.cpp:145:15:145:15 | y | test.cpp:147:7:147:7 | y | AST only |
|
||||
| test.cpp:147:3:147:18 | ... = ... | test.cpp:147:3:147:18 | ... = ... | AST only |
|
||||
| test.cpp:147:7:147:7 | y | test.cpp:145:15:145:15 | y | AST only |
|
||||
| test.cpp:149:15:149:15 | x | test.cpp:144:15:144:15 | x | IR only |
|
||||
| test.cpp:153:21:153:21 | x | test.cpp:154:21:154:21 | x | AST only |
|
||||
| test.cpp:154:21:154:21 | x | test.cpp:153:21:153:21 | x | AST only |
|
||||
| test.cpp:156:3:156:17 | ... = ... | test.cpp:156:3:156:17 | ... = ... | AST only |
|
||||
@@ -0,0 +1,15 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering as AST
|
||||
import semmle.code.cpp.ir.internal.ASTValueNumbering as IR
|
||||
import semmle.code.cpp.ir.IR
|
||||
|
||||
Expr ir(Expr e) { result = IR::globalValueNumber(e).getAnExpr() }
|
||||
|
||||
Expr ast(Expr e) { result = AST::globalValueNumber(e).getAnExpr() }
|
||||
|
||||
from Expr e, Expr evn, string note
|
||||
where
|
||||
evn = ast(e) and not evn = ir(e) and note = "AST only"
|
||||
or
|
||||
evn = ir(e) and not evn = ast(e) and note = "IR only"
|
||||
select e, evn, note
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.ValueNumbering
|
||||
import semmle.code.cpp.ir.IR
|
||||
|
||||
// Every non-void instruction should have exactly one GVN.
|
||||
// So this query should have zero results.
|
||||
from Instruction i
|
||||
where
|
||||
not i.getResultIRType() instanceof IRVoidType and
|
||||
count(valueNumber(i)) != 1
|
||||
select i, concat(ValueNumber g | g = valueNumber(i) | g.getKind(), ", ")
|
||||
Reference in New Issue
Block a user