diff --git a/config/identical-files.json b/config/identical-files.json
index c93a2b28ae6f..0f40aa45a957 100644
--- a/config/identical-files.json
+++ b/config/identical-files.json
@@ -222,7 +222,12 @@
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll"
],
- "IR ValueNumber": [
+ "C++ IR ValueNumberInternal": [
+ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll",
+ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll",
+ "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll"
+ ],
+ "C++ IR ValueNumber": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll",
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll
index ec6d786a684a..1575609fb2fd 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll
@@ -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 string getDebugString() { result = strictconcat(getAnInstruction().getResultId(), ", ") }
- final Language::Location getLocation() { result = getExampleInstruction().getLocation() }
+ 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) }
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingImports.qll
index 0282f6887f15..a5f4cfbf32d5 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingImports.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingImports.qll
@@ -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
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll
index d55844c04712..9e5e74012cd5 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll
@@ -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())
+ )
+ )
+}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll
index ec6d786a684a..1575609fb2fd 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll
@@ -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 string getDebugString() { result = strictconcat(getAnInstruction().getResultId(), ", ") }
- final Language::Location getLocation() { result = getExampleInstruction().getLocation() }
+ 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) }
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll
index 0282f6887f15..a5f4cfbf32d5 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll
@@ -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
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll
index 3b28a05290c4..9e5e74012cd5 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll
@@ -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())
+ )
+ )
+}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll
index ec6d786a684a..1575609fb2fd 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll
@@ -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 string getDebugString() { result = strictconcat(getAnInstruction().getResultId(), ", ") }
- final Language::Location getLocation() { result = getExampleInstruction().getLocation() }
+ 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) }
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll
index 0282f6887f15..a5f4cfbf32d5 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll
@@ -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
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll
index 9b4f813a10bd..9e5e74012cd5 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll
@@ -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())
+ )
+ )
+}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/ASTValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/ASTValueNumbering.qll
new file mode 100644
index 000000000000..e3f64f29db1f
--- /dev/null
+++ b/cpp/ql/src/semmle/code/cpp/ir/internal/ASTValueNumbering.qll
@@ -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() }
diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected
new file mode 100644
index 000000000000..cd44eb8572b7
--- /dev/null
+++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.expected
@@ -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... | 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... | test.cpp:105:11:105:12 | (Base *)... | AST only |
+| test.cpp:106:14:106:35 | static_cast... | test.cpp:106:14:106:35 | static_cast... | AST only |
+| test.cpp:106:14:106:35 | static_cast... | 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... | 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 |
diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.ql b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.ql
new file mode 100644
index 000000000000..317c3d975565
--- /dev/null
+++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/diff_ir_expr.ql
@@ -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
diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected
index ad702554776d..10366d1f6bbd 100644
--- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected
+++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected
@@ -11,19 +11,19 @@ test.cpp:
# 1| mu1_5(unknown) = UnmodeledDefinition :
# 1| valnum = unique
# 1| r1_6(glval) = VariableAddress[p0] :
-# 1| valnum = r1_6
+# 1| valnum = r1_6, r5_1, r6_1
# 1| m1_7(int) = InitializeParameter[p0] : &:r1_6
-# 1| valnum = m1_7
+# 1| valnum = m1_7, r5_2, r6_2
# 1| r1_8(glval) = VariableAddress[p1] :
-# 1| valnum = r1_8
+# 1| valnum = r1_8, r5_3, r6_3
# 1| m1_9(int) = InitializeParameter[p1] : &:r1_8
-# 1| valnum = m1_9
+# 1| valnum = m1_9, r5_4, r6_4
# 2| r2_1(glval) = VariableAddress[x] :
-# 2| valnum = r2_1
+# 2| valnum = r2_1, r5_6, r6_6, r7_1
# 2| m2_2(int) = Uninitialized[x] : &:r2_1
# 2| valnum = unique
# 2| r2_3(glval) = VariableAddress[y] :
-# 2| valnum = r2_3
+# 2| valnum = r2_3, r7_3
# 2| m2_4(int) = Uninitialized[y] : &:r2_3
# 2| valnum = unique
# 3| r3_1(glval) = VariableAddress[b] :
@@ -31,41 +31,41 @@ test.cpp:
# 3| m3_2(unsigned char) = Uninitialized[b] : &:r3_1
# 3| valnum = unique
# 5| r5_1(glval) = VariableAddress[p0] :
-# 5| valnum = r1_6
+# 5| valnum = r1_6, r5_1, r6_1
# 5| r5_2(int) = Load : &:r5_1, m1_7
-# 5| valnum = m1_7
+# 5| valnum = m1_7, r5_2, r6_2
# 5| r5_3(glval) = VariableAddress[p1] :
-# 5| valnum = r1_8
+# 5| valnum = r1_8, r5_3, r6_3
# 5| r5_4(int) = Load : &:r5_3, m1_9
-# 5| valnum = m1_9
+# 5| valnum = m1_9, r5_4, r6_4
# 5| r5_5(int) = Add : r5_2, r5_4
-# 5| valnum = r5_5
+# 5| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2
# 5| r5_6(glval) = VariableAddress[x] :
-# 5| valnum = r2_1
+# 5| valnum = r2_1, r5_6, r6_6, r7_1
# 5| m5_7(int) = Store : &:r5_6, r5_5
-# 5| valnum = r5_5
+# 5| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2
# 6| r6_1(glval) = VariableAddress[p0] :
-# 6| valnum = r1_6
+# 6| valnum = r1_6, r5_1, r6_1
# 6| r6_2(int) = Load : &:r6_1, m1_7
-# 6| valnum = m1_7
+# 6| valnum = m1_7, r5_2, r6_2
# 6| r6_3(glval) = VariableAddress[p1] :
-# 6| valnum = r1_8
+# 6| valnum = r1_8, r5_3, r6_3
# 6| r6_4(int) = Load : &:r6_3, m1_9
-# 6| valnum = m1_9
+# 6| valnum = m1_9, r5_4, r6_4
# 6| r6_5(int) = Add : r6_2, r6_4
-# 6| valnum = r5_5
+# 6| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2
# 6| r6_6(glval) = VariableAddress[x] :
-# 6| valnum = r2_1
+# 6| valnum = r2_1, r5_6, r6_6, r7_1
# 6| m6_7(int) = Store : &:r6_6, r6_5
-# 6| valnum = r5_5
+# 6| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2
# 7| r7_1(glval) = VariableAddress[x] :
-# 7| valnum = r2_1
+# 7| valnum = r2_1, r5_6, r6_6, r7_1
# 7| r7_2(int) = Load : &:r7_1, m6_7
-# 7| valnum = r5_5
+# 7| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2
# 7| r7_3(glval) = VariableAddress[y] :
-# 7| valnum = r2_3
+# 7| valnum = r2_3, r7_3
# 7| m7_4(int) = Store : &:r7_3, r7_2
-# 7| valnum = r5_5
+# 7| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2
# 8| v8_1(void) = NoOp :
# 1| r1_10(glval) = VariableAddress[#return] :
# 1| valnum = unique
@@ -86,19 +86,19 @@ test.cpp:
# 12| mu12_5(unknown) = UnmodeledDefinition :
# 12| valnum = unique
# 12| r12_6(glval) = VariableAddress[p0] :
-# 12| valnum = r12_6
+# 12| valnum = r12_6, r16_1, r17_1
# 12| m12_7(int) = InitializeParameter[p0] : &:r12_6
-# 12| valnum = m12_7
+# 12| valnum = m12_7, r16_2, r17_2
# 12| r12_8(glval) = VariableAddress[p1] :
-# 12| valnum = r12_8
+# 12| valnum = r12_8, r16_3, r17_3
# 12| m12_9(int) = InitializeParameter[p1] : &:r12_8
-# 12| valnum = m12_9
+# 12| valnum = m12_9, r16_4, r17_4
# 13| r13_1(glval) = VariableAddress[x] :
-# 13| valnum = r13_1
+# 13| valnum = r13_1, r16_9, r17_9, r18_1
# 13| m13_2(int) = Uninitialized[x] : &:r13_1
# 13| valnum = unique
# 13| r13_3(glval) = VariableAddress[y] :
-# 13| valnum = r13_3
+# 13| valnum = r13_3, r18_3
# 13| m13_4(int) = Uninitialized[y] : &:r13_3
# 13| valnum = unique
# 14| r14_1(glval) = VariableAddress[b] :
@@ -106,53 +106,53 @@ test.cpp:
# 14| m14_2(unsigned char) = Uninitialized[b] : &:r14_1
# 14| valnum = unique
# 16| r16_1(glval) = VariableAddress[p0] :
-# 16| valnum = r12_6
+# 16| valnum = r12_6, r16_1, r17_1
# 16| r16_2(int) = Load : &:r16_1, m12_7
-# 16| valnum = m12_7
+# 16| valnum = m12_7, r16_2, r17_2
# 16| r16_3(glval) = VariableAddress[p1] :
-# 16| valnum = r12_8
+# 16| valnum = r12_8, r16_3, r17_3
# 16| r16_4(int) = Load : &:r16_3, m12_9
-# 16| valnum = m12_9
+# 16| valnum = m12_9, r16_4, r17_4
# 16| r16_5(int) = Add : r16_2, r16_4
-# 16| valnum = r16_5
+# 16| valnum = r16_5, r17_5
# 16| r16_6(glval) = VariableAddress[global01] :
-# 16| valnum = r16_6
+# 16| valnum = r16_6, r17_6
# 16| r16_7(int) = Load : &:r16_6, ~m12_3
-# 16| valnum = r16_7
+# 16| valnum = r16_7, r17_7
# 16| r16_8(int) = Add : r16_5, r16_7
-# 16| valnum = r16_8
+# 16| valnum = m16_10, m17_10, m18_4, r16_8, r17_8, r18_2
# 16| r16_9(glval) = VariableAddress[x] :
-# 16| valnum = r13_1
+# 16| valnum = r13_1, r16_9, r17_9, r18_1
# 16| m16_10(int) = Store : &:r16_9, r16_8
-# 16| valnum = r16_8
+# 16| valnum = m16_10, m17_10, m18_4, r16_8, r17_8, r18_2
# 17| r17_1(glval) = VariableAddress[p0] :
-# 17| valnum = r12_6
+# 17| valnum = r12_6, r16_1, r17_1
# 17| r17_2(int) = Load : &:r17_1, m12_7
-# 17| valnum = m12_7
+# 17| valnum = m12_7, r16_2, r17_2
# 17| r17_3(glval) = VariableAddress[p1] :
-# 17| valnum = r12_8
+# 17| valnum = r12_8, r16_3, r17_3
# 17| r17_4(int) = Load : &:r17_3, m12_9
-# 17| valnum = m12_9
+# 17| valnum = m12_9, r16_4, r17_4
# 17| r17_5(int) = Add : r17_2, r17_4
-# 17| valnum = r16_5
+# 17| valnum = r16_5, r17_5
# 17| r17_6(glval) = VariableAddress[global01] :
-# 17| valnum = r16_6
+# 17| valnum = r16_6, r17_6
# 17| r17_7(int) = Load : &:r17_6, ~m12_3
-# 17| valnum = r16_7
+# 17| valnum = r16_7, r17_7
# 17| r17_8(int) = Add : r17_5, r17_7
-# 17| valnum = r16_8
+# 17| valnum = m16_10, m17_10, m18_4, r16_8, r17_8, r18_2
# 17| r17_9(glval) = VariableAddress[x] :
-# 17| valnum = r13_1
+# 17| valnum = r13_1, r16_9, r17_9, r18_1
# 17| m17_10(int) = Store : &:r17_9, r17_8
-# 17| valnum = r16_8
+# 17| valnum = m16_10, m17_10, m18_4, r16_8, r17_8, r18_2
# 18| r18_1(glval) = VariableAddress[x] :
-# 18| valnum = r13_1
+# 18| valnum = r13_1, r16_9, r17_9, r18_1
# 18| r18_2(int) = Load : &:r18_1, m17_10
-# 18| valnum = r16_8
+# 18| valnum = m16_10, m17_10, m18_4, r16_8, r17_8, r18_2
# 18| r18_3(glval) = VariableAddress[y] :
-# 18| valnum = r13_3
+# 18| valnum = r13_3, r18_3
# 18| m18_4(int) = Store : &:r18_3, r18_2
-# 18| valnum = r16_8
+# 18| valnum = m16_10, m17_10, m18_4, r16_8, r17_8, r18_2
# 19| v19_1(void) = NoOp :
# 12| r12_10(glval) = VariableAddress[#return] :
# 12| valnum = unique
@@ -173,19 +173,19 @@ test.cpp:
# 25| mu25_5(unknown) = UnmodeledDefinition :
# 25| valnum = unique
# 25| r25_6(glval) = VariableAddress[p0] :
-# 25| valnum = r25_6
+# 25| valnum = r25_6, r29_1, r31_1
# 25| m25_7(int) = InitializeParameter[p0] : &:r25_6
-# 25| valnum = m25_7
+# 25| valnum = m25_7, r29_2, r31_2
# 25| r25_8(glval) = VariableAddress[p1] :
-# 25| valnum = r25_8
+# 25| valnum = r25_8, r29_3, r31_3
# 25| m25_9(int) = InitializeParameter[p1] : &:r25_8
-# 25| valnum = m25_9
+# 25| valnum = m25_9, r29_4, r31_4
# 26| r26_1(glval) = VariableAddress[x] :
-# 26| valnum = r26_1
+# 26| valnum = r26_1, r29_9, r31_9, r32_1
# 26| m26_2(int) = Uninitialized[x] : &:r26_1
# 26| valnum = unique
# 26| r26_3(glval) = VariableAddress[y] :
-# 26| valnum = r26_3
+# 26| valnum = r26_3, r32_3
# 26| m26_4(int) = Uninitialized[y] : &:r26_3
# 26| valnum = unique
# 27| r27_1(glval) = VariableAddress[b] :
@@ -193,25 +193,25 @@ test.cpp:
# 27| m27_2(unsigned char) = Uninitialized[b] : &:r27_1
# 27| valnum = unique
# 29| r29_1(glval) = VariableAddress[p0] :
-# 29| valnum = r25_6
+# 29| valnum = r25_6, r29_1, r31_1
# 29| r29_2(int) = Load : &:r29_1, m25_7
-# 29| valnum = m25_7
+# 29| valnum = m25_7, r29_2, r31_2
# 29| r29_3(glval) = VariableAddress[p1] :
-# 29| valnum = r25_8
+# 29| valnum = r25_8, r29_3, r31_3
# 29| r29_4(int) = Load : &:r29_3, m25_9
-# 29| valnum = m25_9
+# 29| valnum = m25_9, r29_4, r31_4
# 29| r29_5(int) = Add : r29_2, r29_4
-# 29| valnum = r29_5
+# 29| valnum = r29_5, r31_5
# 29| r29_6(glval) = VariableAddress[global02] :
-# 29| valnum = r29_6
+# 29| valnum = r29_6, r31_6
# 29| r29_7(int) = Load : &:r29_6, ~m25_3
# 29| valnum = unique
# 29| r29_8(int) = Add : r29_5, r29_7
-# 29| valnum = r29_8
+# 29| valnum = m29_10, r29_8
# 29| r29_9(glval) = VariableAddress[x] :
-# 29| valnum = r26_1
+# 29| valnum = r26_1, r29_9, r31_9, r32_1
# 29| m29_10(int) = Store : &:r29_9, r29_8
-# 29| valnum = r29_8
+# 29| valnum = m29_10, r29_8
# 30| r30_1(glval) = FunctionAddress[change_global02] :
# 30| valnum = unique
# 30| v30_2(void) = Call : func:r30_1
@@ -220,33 +220,33 @@ test.cpp:
# 30| m30_4(unknown) = Chi : total:m25_4, partial:m30_3
# 30| valnum = unique
# 31| r31_1(glval) = VariableAddress[p0] :
-# 31| valnum = r25_6
+# 31| valnum = r25_6, r29_1, r31_1
# 31| r31_2(int) = Load : &:r31_1, m25_7
-# 31| valnum = m25_7
+# 31| valnum = m25_7, r29_2, r31_2
# 31| r31_3(glval) = VariableAddress[p1] :
-# 31| valnum = r25_8
+# 31| valnum = r25_8, r29_3, r31_3
# 31| r31_4(int) = Load : &:r31_3, m25_9
-# 31| valnum = m25_9
+# 31| valnum = m25_9, r29_4, r31_4
# 31| r31_5(int) = Add : r31_2, r31_4
-# 31| valnum = r29_5
+# 31| valnum = r29_5, r31_5
# 31| r31_6(glval) = VariableAddress[global02] :
-# 31| valnum = r29_6
+# 31| valnum = r29_6, r31_6
# 31| r31_7(int) = Load : &:r31_6, ~m30_4
# 31| valnum = unique
# 31| r31_8(int) = Add : r31_5, r31_7
-# 31| valnum = r31_8
+# 31| valnum = m31_10, m32_4, r31_8, r32_2
# 31| r31_9(glval) = VariableAddress[x] :
-# 31| valnum = r26_1
+# 31| valnum = r26_1, r29_9, r31_9, r32_1
# 31| m31_10(int) = Store : &:r31_9, r31_8
-# 31| valnum = r31_8
+# 31| valnum = m31_10, m32_4, r31_8, r32_2
# 32| r32_1(glval) = VariableAddress[x] :
-# 32| valnum = r26_1
+# 32| valnum = r26_1, r29_9, r31_9, r32_1
# 32| r32_2(int) = Load : &:r32_1, m31_10
-# 32| valnum = r31_8
+# 32| valnum = m31_10, m32_4, r31_8, r32_2
# 32| r32_3(glval) = VariableAddress[y] :
-# 32| valnum = r26_3
+# 32| valnum = r26_3, r32_3
# 32| m32_4(int) = Store : &:r32_3, r32_2
-# 32| valnum = r31_8
+# 32| valnum = m31_10, m32_4, r31_8, r32_2
# 33| v33_1(void) = NoOp :
# 25| r25_10(glval) = VariableAddress[#return] :
# 25| valnum = unique
@@ -267,27 +267,27 @@ test.cpp:
# 39| mu39_5(unknown) = UnmodeledDefinition :
# 39| valnum = unique
# 39| r39_6(glval) = VariableAddress[p0] :
-# 39| valnum = r39_6
+# 39| valnum = r39_6, r43_1, r45_1
# 39| m39_7(int) = InitializeParameter[p0] : &:r39_6
-# 39| valnum = m39_7
+# 39| valnum = m39_7, r43_2, r45_2
# 39| r39_8(glval) = VariableAddress[p1] :
-# 39| valnum = r39_8
+# 39| valnum = r39_8, r43_3, r45_3
# 39| m39_9(int) = InitializeParameter[p1] : &:r39_8
-# 39| valnum = m39_9
+# 39| valnum = m39_9, r43_4, r45_4
# 39| r39_10(glval) = VariableAddress[p2] :
-# 39| valnum = r39_10
+# 39| valnum = r39_10, r44_2
# 39| m39_11(int *) = InitializeParameter[p2] : &:r39_10
-# 39| valnum = m39_11
+# 39| valnum = m39_11, r39_12, r44_3, r44_4
# 39| r39_12(int *) = Load : &:r39_10, m39_11
-# 39| valnum = m39_11
+# 39| valnum = m39_11, r39_12, r44_3, r44_4
# 39| m39_13(unknown) = InitializeIndirection[p2] : &:r39_12
# 39| valnum = unique
# 40| r40_1(glval) = VariableAddress[x] :
-# 40| valnum = r40_1
+# 40| valnum = r40_1, r43_9, r45_9, r46_1
# 40| m40_2(int) = Uninitialized[x] : &:r40_1
# 40| valnum = unique
# 40| r40_3(glval) = VariableAddress[y] :
-# 40| valnum = r40_3
+# 40| valnum = r40_3, r46_3
# 40| m40_4(int) = Uninitialized[y] : &:r40_3
# 40| valnum = unique
# 41| r41_1(glval) = VariableAddress[b] :
@@ -295,65 +295,65 @@ test.cpp:
# 41| m41_2(unsigned char) = Uninitialized[b] : &:r41_1
# 41| valnum = unique
# 43| r43_1(glval) = VariableAddress[p0] :
-# 43| valnum = r39_6
+# 43| valnum = r39_6, r43_1, r45_1
# 43| r43_2(int) = Load : &:r43_1, m39_7
-# 43| valnum = m39_7
+# 43| valnum = m39_7, r43_2, r45_2
# 43| r43_3(glval) = VariableAddress[p1] :
-# 43| valnum = r39_8
+# 43| valnum = r39_8, r43_3, r45_3
# 43| r43_4(int) = Load : &:r43_3, m39_9
-# 43| valnum = m39_9
+# 43| valnum = m39_9, r43_4, r45_4
# 43| r43_5(int) = Add : r43_2, r43_4
-# 43| valnum = r43_5
+# 43| valnum = r43_5, r45_5
# 43| r43_6(glval) = VariableAddress[global03] :
-# 43| valnum = r43_6
+# 43| valnum = r43_6, r45_6
# 43| r43_7(int) = Load : &:r43_6, ~m39_3
-# 43| valnum = r43_7
+# 43| valnum = r43_7, r45_7
# 43| r43_8(int) = Add : r43_5, r43_7
-# 43| valnum = r43_8
+# 43| valnum = m43_10, m45_10, m46_4, r43_8, r45_8, r46_2
# 43| r43_9(glval) = VariableAddress[x] :
-# 43| valnum = r40_1
+# 43| valnum = r40_1, r43_9, r45_9, r46_1
# 43| m43_10(int) = Store : &:r43_9, r43_8
-# 43| valnum = r43_8
+# 43| valnum = m43_10, m45_10, m46_4, r43_8, r45_8, r46_2
# 44| r44_1(int) = Constant[0] :
-# 44| valnum = r44_1
+# 44| valnum = m44_5, r44_1
# 44| r44_2(glval) = VariableAddress[p2] :
-# 44| valnum = r39_10
+# 44| valnum = r39_10, r44_2
# 44| r44_3(int *) = Load : &:r44_2, m39_11
-# 44| valnum = m39_11
+# 44| valnum = m39_11, r39_12, r44_3, r44_4
# 44| r44_4(glval) = CopyValue : r44_3
-# 44| valnum = m39_11
+# 44| valnum = m39_11, r39_12, r44_3, r44_4
# 44| m44_5(int) = Store : &:r44_4, r44_1
-# 44| valnum = r44_1
+# 44| valnum = m44_5, r44_1
# 44| m44_6(unknown) = Chi : total:m39_13, partial:m44_5
# 44| valnum = unique
# 45| r45_1(glval) = VariableAddress[p0] :
-# 45| valnum = r39_6
+# 45| valnum = r39_6, r43_1, r45_1
# 45| r45_2(int) = Load : &:r45_1, m39_7
-# 45| valnum = m39_7
+# 45| valnum = m39_7, r43_2, r45_2
# 45| r45_3(glval) = VariableAddress[p1] :
-# 45| valnum = r39_8
+# 45| valnum = r39_8, r43_3, r45_3
# 45| r45_4(int) = Load : &:r45_3, m39_9
-# 45| valnum = m39_9
+# 45| valnum = m39_9, r43_4, r45_4
# 45| r45_5(int) = Add : r45_2, r45_4
-# 45| valnum = r43_5
+# 45| valnum = r43_5, r45_5
# 45| r45_6(glval) = VariableAddress[global03] :
-# 45| valnum = r43_6
+# 45| valnum = r43_6, r45_6
# 45| r45_7(int) = Load : &:r45_6, ~m39_3
-# 45| valnum = r43_7
+# 45| valnum = r43_7, r45_7
# 45| r45_8(int) = Add : r45_5, r45_7
-# 45| valnum = r43_8
+# 45| valnum = m43_10, m45_10, m46_4, r43_8, r45_8, r46_2
# 45| r45_9(glval) = VariableAddress[x] :
-# 45| valnum = r40_1
+# 45| valnum = r40_1, r43_9, r45_9, r46_1
# 45| m45_10(int) = Store : &:r45_9, r45_8
-# 45| valnum = r43_8
+# 45| valnum = m43_10, m45_10, m46_4, r43_8, r45_8, r46_2
# 46| r46_1(glval) = VariableAddress[x] :
-# 46| valnum = r40_1
+# 46| valnum = r40_1, r43_9, r45_9, r46_1
# 46| r46_2(int) = Load : &:r46_1, m45_10
-# 46| valnum = r43_8
+# 46| valnum = m43_10, m45_10, m46_4, r43_8, r45_8, r46_2
# 46| r46_3(glval) = VariableAddress[y] :
-# 46| valnum = r40_3
+# 46| valnum = r40_3, r46_3
# 46| m46_4(int) = Store : &:r46_3, r46_2
-# 46| valnum = r43_8
+# 46| valnum = m43_10, m45_10, m46_4, r43_8, r45_8, r46_2
# 47| v47_1(void) = NoOp :
# 39| v39_14(void) = ReturnIndirection : &:r39_12, ~m44_6
# 39| r39_15(glval) = VariableAddress[#return] :
@@ -375,46 +375,46 @@ test.cpp:
# 49| mu49_5(unknown) = UnmodeledDefinition :
# 49| valnum = unique
# 49| r49_6(glval) = VariableAddress[str] :
-# 49| valnum = r49_6
+# 49| valnum = r49_6, r53_2, r56_6
# 49| m49_7(char *) = InitializeParameter[str] : &:r49_6
-# 49| valnum = m49_7
+# 49| valnum = m49_7, r49_8, r53_3, r56_7
# 49| r49_8(char *) = Load : &:r49_6, m49_7
-# 49| valnum = m49_7
+# 49| valnum = m49_7, r49_8, r53_3, r56_7
# 49| m49_9(unknown) = InitializeIndirection[str] : &:r49_8
# 49| valnum = unique
# 49| r49_10(glval) = VariableAddress[chars] :
-# 49| valnum = r49_10
+# 49| valnum = r49_10, r55_1
# 49| m49_11(char *) = InitializeParameter[chars] : &:r49_10
-# 49| valnum = m49_11
+# 49| valnum = m49_11, m55_4, r49_12, r55_2
# 49| r49_12(char *) = Load : &:r49_10, m49_11
-# 49| valnum = m49_11
+# 49| valnum = m49_11, m55_4, r49_12, r55_2
# 49| m49_13(unknown) = InitializeIndirection[chars] : &:r49_12
# 49| valnum = unique
# 50| r50_1(glval) = VariableAddress[ptr] :
-# 50| valnum = r50_1
+# 50| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1
# 50| m50_2(char *) = Uninitialized[ptr] : &:r50_1
# 50| valnum = unique
# 51| r51_1(glval) = VariableAddress[result] :
-# 51| valnum = r51_1
+# 51| valnum = r51_1, r62_1, r65_2
# 51| r51_2(unsigned int) = Constant[0] :
-# 51| valnum = r51_2
+# 51| valnum = m51_3, r51_2
# 51| m51_3(unsigned int) = Store : &:r51_1, r51_2
-# 51| valnum = r51_2
+# 51| valnum = m51_3, r51_2
#-----| Goto -> Block 1
# 53| Block 1
# 53| m53_1(unsigned int) = Phi : from 0:m51_3, from 8:m62_5
-# 53| valnum = m53_1
+# 53| valnum = m53_1, m65_4, r62_2, r65_3
# 53| r53_2(glval) = VariableAddress[str] :
-# 53| valnum = r49_6
+# 53| valnum = r49_6, r53_2, r56_6
# 53| r53_3(char *) = Load : &:r53_2, m49_7
-# 53| valnum = m49_7
+# 53| valnum = m49_7, r49_8, r53_3, r56_7
# 53| r53_4(char) = Load : &:r53_3, ~m49_9
-# 53| valnum = r53_4
+# 53| valnum = r53_4, r56_8
# 53| r53_5(int) = Convert : r53_4
-# 53| valnum = r53_5
+# 53| valnum = r53_5, r56_9
# 53| r53_6(int) = Constant[0] :
-# 53| valnum = r53_6
+# 53| valnum = r53_6, r56_16, r59_5
# 53| r53_7(bool) = CompareNE : r53_5, r53_6
# 53| valnum = unique
# 53| v53_8(void) = ConditionalBranch : r53_7
@@ -423,34 +423,34 @@ test.cpp:
# 55| Block 2
# 55| r55_1(glval) = VariableAddress[chars] :
-# 55| valnum = r49_10
+# 55| valnum = r49_10, r55_1
# 55| r55_2(char *) = Load : &:r55_1, m49_11
-# 55| valnum = m49_11
+# 55| valnum = m49_11, m55_4, r49_12, r55_2
# 55| r55_3(glval) = VariableAddress[ptr] :
-# 55| valnum = r50_1
+# 55| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1
# 55| m55_4(char *) = Store : &:r55_3, r55_2
-# 55| valnum = m49_11
+# 55| valnum = m49_11, m55_4, r49_12, r55_2
#-----| Goto -> Block 3
# 56| Block 3
# 56| m56_1(decltype(nullptr)) = Phi : from 2:m55_4, from 5:m56_23
-# 56| valnum = m56_1
+# 56| valnum = m56_1, r56_13, r56_20, r56_3, r59_2
# 56| r56_2(glval) = VariableAddress[ptr] :
-# 56| valnum = r50_1
+# 56| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1
# 56| r56_3(char *) = Load : &:r56_2, m56_1
-# 56| valnum = m56_1
+# 56| valnum = m56_1, r56_13, r56_20, r56_3, r59_2
# 56| r56_4(char) = Load : &:r56_3, ~m49_4
# 56| valnum = unique
# 56| r56_5(int) = Convert : r56_4
# 56| valnum = unique
# 56| r56_6(glval) = VariableAddress[str] :
-# 56| valnum = r49_6
+# 56| valnum = r49_6, r53_2, r56_6
# 56| r56_7(char *) = Load : &:r56_6, m49_7
-# 56| valnum = m49_7
+# 56| valnum = m49_7, r49_8, r53_3, r56_7
# 56| r56_8(char) = Load : &:r56_7, ~m49_9
-# 56| valnum = r53_4
+# 56| valnum = r53_4, r56_8
# 56| r56_9(int) = Convert : r56_8
-# 56| valnum = r53_5
+# 56| valnum = r53_5, r56_9
# 56| r56_10(bool) = CompareNE : r56_5, r56_9
# 56| valnum = unique
# 56| v56_11(void) = ConditionalBranch : r56_10
@@ -459,15 +459,15 @@ test.cpp:
# 56| Block 4
# 56| r56_12(glval) = VariableAddress[ptr] :
-# 56| valnum = r50_1
+# 56| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1
# 56| r56_13(char *) = Load : &:r56_12, m56_1
-# 56| valnum = m56_1
+# 56| valnum = m56_1, r56_13, r56_20, r56_3, r59_2
# 56| r56_14(char) = Load : &:r56_13, ~m49_4
# 56| valnum = unique
# 56| r56_15(int) = Convert : r56_14
# 56| valnum = unique
# 56| r56_16(int) = Constant[0] :
-# 56| valnum = r53_6
+# 56| valnum = r53_6, r56_16, r59_5
# 56| r56_17(bool) = CompareNE : r56_15, r56_16
# 56| valnum = unique
# 56| v56_18(void) = ConditionalBranch : r56_17
@@ -476,28 +476,28 @@ test.cpp:
# 56| Block 5
# 56| r56_19(glval) = VariableAddress[ptr] :
-# 56| valnum = r50_1
+# 56| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1
# 56| r56_20(char *) = Load : &:r56_19, m56_1
-# 56| valnum = m56_1
+# 56| valnum = m56_1, r56_13, r56_20, r56_3, r59_2
# 56| r56_21(int) = Constant[1] :
# 56| valnum = unique
# 56| r56_22(char *) = PointerAdd[1] : r56_20, r56_21
-# 56| valnum = r56_22
+# 56| valnum = m56_23, r56_22
# 56| m56_23(char *) = Store : &:r56_19, r56_22
-# 56| valnum = r56_22
+# 56| valnum = m56_23, r56_22
#-----| Goto (back edge) -> Block 3
# 59| Block 6
# 59| r59_1(glval) = VariableAddress[ptr] :
-# 59| valnum = r50_1
+# 59| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1
# 59| r59_2(char *) = Load : &:r59_1, m56_1
-# 59| valnum = m56_1
+# 59| valnum = m56_1, r56_13, r56_20, r56_3, r59_2
# 59| r59_3(char) = Load : &:r59_2, ~m49_4
# 59| valnum = unique
# 59| r59_4(int) = Convert : r59_3
# 59| valnum = unique
# 59| r59_5(int) = Constant[0] :
-# 59| valnum = r53_6
+# 59| valnum = r53_6, r56_16, r59_5
# 59| r59_6(bool) = CompareEQ : r59_4, r59_5
# 59| valnum = unique
# 59| v59_7(void) = ConditionalBranch : r59_6
@@ -510,31 +510,31 @@ test.cpp:
# 62| Block 8
# 62| r62_1(glval) = VariableAddress[result] :
-# 62| valnum = r51_1
+# 62| valnum = r51_1, r62_1, r65_2
# 62| r62_2(unsigned int) = Load : &:r62_1, m53_1
-# 62| valnum = m53_1
+# 62| valnum = m53_1, m65_4, r62_2, r65_3
# 62| r62_3(unsigned int) = Constant[1] :
# 62| valnum = unique
# 62| r62_4(unsigned int) = Add : r62_2, r62_3
-# 62| valnum = r62_4
+# 62| valnum = m62_5, r62_4
# 62| m62_5(unsigned int) = Store : &:r62_1, r62_4
-# 62| valnum = r62_4
+# 62| valnum = m62_5, r62_4
#-----| Goto (back edge) -> Block 1
# 63| Block 9
# 63| v63_1(void) = NoOp :
# 65| r65_1(glval) = VariableAddress[#return] :
-# 65| valnum = r65_1
+# 65| valnum = r49_16, r65_1
# 65| r65_2(glval) = VariableAddress[result] :
-# 65| valnum = r51_1
+# 65| valnum = r51_1, r62_1, r65_2
# 65| r65_3(unsigned int) = Load : &:r65_2, m53_1
-# 65| valnum = m53_1
+# 65| valnum = m53_1, m65_4, r62_2, r65_3
# 65| m65_4(unsigned int) = Store : &:r65_1, r65_3
-# 65| valnum = m53_1
+# 65| valnum = m53_1, m65_4, r62_2, r65_3
# 49| v49_14(void) = ReturnIndirection : &:r49_8, m49_9
# 49| v49_15(void) = ReturnIndirection : &:r49_12, m49_13
# 49| r49_16(glval) = VariableAddress[#return] :
-# 49| valnum = r65_1
+# 49| valnum = r49_16, r65_1
# 49| v49_17(void) = ReturnValue : &:r49_16, m65_4
# 49| v49_18(void) = UnmodeledUse : mu*
# 49| v49_19(void) = AliasedUse : m49_3
@@ -552,15 +552,15 @@ test.cpp:
# 75| mu75_5(unknown) = UnmodeledDefinition :
# 75| valnum = unique
# 75| r75_6(glval) = VariableAddress[vals] :
-# 75| valnum = r75_6
+# 75| valnum = r75_6, r79_4, r79_9
# 75| m75_7(two_values *) = InitializeParameter[vals] : &:r75_6
-# 75| valnum = m75_7
+# 75| valnum = m75_7, r75_8, r79_10, r79_5
# 75| r75_8(two_values *) = Load : &:r75_6, m75_7
-# 75| valnum = m75_7
+# 75| valnum = m75_7, r75_8, r79_10, r79_5
# 75| m75_9(unknown) = InitializeIndirection[vals] : &:r75_8
# 75| valnum = unique
# 77| r77_1(glval) = VariableAddress[v] :
-# 77| valnum = r77_1
+# 77| valnum = r77_1, r79_1, r80_6
# 77| r77_2(glval) = FunctionAddress[getAValue] :
# 77| valnum = unique
# 77| r77_3(int) = Call : func:r77_2
@@ -570,19 +570,19 @@ test.cpp:
# 77| m77_5(unknown) = Chi : total:m75_4, partial:m77_4
# 77| valnum = unique
# 77| r77_6(signed short) = Convert : r77_3
-# 77| valnum = r77_6
+# 77| valnum = m77_7, r77_6, r79_2
# 77| m77_7(signed short) = Store : &:r77_1, r77_6
-# 77| valnum = r77_6
+# 77| valnum = m77_7, r77_6, r79_2
# 79| r79_1(glval) = VariableAddress[v] :
-# 79| valnum = r77_1
+# 79| valnum = r77_1, r79_1, r80_6
# 79| r79_2(signed short) = Load : &:r79_1, m77_7
-# 79| valnum = r77_6
+# 79| valnum = m77_7, r77_6, r79_2
# 79| r79_3(int) = Convert : r79_2
# 79| valnum = unique
# 79| r79_4(glval) = VariableAddress[vals] :
-# 79| valnum = r75_6
+# 79| valnum = r75_6, r79_4, r79_9
# 79| r79_5(two_values *) = Load : &:r79_4, m75_7
-# 79| valnum = m75_7
+# 79| valnum = m75_7, r75_8, r79_10, r79_5
# 79| r79_6(glval) = FieldAddress[val1] : r79_5
# 79| valnum = unique
# 79| r79_7(signed short) = Load : &:r79_6, ~m75_9
@@ -590,9 +590,9 @@ test.cpp:
# 79| r79_8(int) = Convert : r79_7
# 79| valnum = unique
# 79| r79_9(glval) = VariableAddress[vals] :
-# 79| valnum = r75_6
+# 79| valnum = r75_6, r79_4, r79_9
# 79| r79_10(two_values *) = Load : &:r79_9, m75_7
-# 79| valnum = m75_7
+# 79| valnum = m75_7, r75_8, r79_10, r79_5
# 79| r79_11(glval) = FieldAddress[val2] : r79_10
# 79| valnum = unique
# 79| r79_12(signed short) = Load : &:r79_11, ~m75_9
@@ -617,11 +617,11 @@ test.cpp:
# 80| m80_4(unknown) = Chi : total:m77_5, partial:m80_3
# 80| valnum = unique
# 80| r80_5(signed short) = Convert : r80_2
-# 80| valnum = r80_5
+# 80| valnum = m80_7, r80_5
# 80| r80_6(glval) = VariableAddress[v] :
-# 80| valnum = r77_1
+# 80| valnum = r77_1, r79_1, r80_6
# 80| m80_7(signed short) = Store : &:r80_6, r80_5
-# 80| valnum = r80_5
+# 80| valnum = m80_7, r80_5
#-----| Goto -> Block 2
# 82| Block 2
@@ -646,29 +646,29 @@ test.cpp:
# 84| mu84_5(unknown) = UnmodeledDefinition :
# 84| valnum = unique
# 84| r84_6(glval) = VariableAddress[x] :
-# 84| valnum = r84_6
+# 84| valnum = r84_6, r88_11
# 84| m84_7(int) = InitializeParameter[x] : &:r84_6
-# 84| valnum = m84_7
+# 84| valnum = m84_7, m88_14, r88_12
# 84| r84_8(glval) = VariableAddress[y] :
-# 84| valnum = r84_8
+# 84| valnum = r84_8, r88_15
# 84| m84_9(int) = InitializeParameter[y] : &:r84_8
-# 84| valnum = m84_9
+# 84| valnum = m84_9, m88_18, r88_16
# 84| r84_10(glval) = VariableAddress[p] :
-# 84| valnum = r84_10
+# 84| valnum = r84_10, r88_1
# 84| m84_11(void *) = InitializeParameter[p] : &:r84_10
-# 84| valnum = m84_11
+# 84| valnum = m84_11, r84_12, r88_2
# 84| r84_12(void *) = Load : &:r84_10, m84_11
-# 84| valnum = m84_11
+# 84| valnum = m84_11, r84_12, r88_2
# 84| m84_13(unknown) = InitializeIndirection[p] : &:r84_12
# 84| valnum = unique
# 86| r86_1(glval) = VariableAddress[v] :
-# 86| valnum = r86_1
+# 86| valnum = r86_1, r88_9
# 86| m86_2(int) = Uninitialized[v] : &:r86_1
# 86| valnum = unique
# 88| r88_1(glval) = VariableAddress[p] :
-# 88| valnum = r84_10
+# 88| valnum = r84_10, r88_1
# 88| r88_2(void *) = Load : &:r88_1, m84_11
-# 88| valnum = m84_11
+# 88| valnum = m84_11, r84_12, r88_2
# 88| r88_3(void *) = Constant[0] :
# 88| valnum = unique
# 88| r88_4(bool) = CompareNE : r88_2, r88_3
@@ -679,15 +679,15 @@ test.cpp:
# 88| Block 1
# 88| m88_6(int) = Phi : from 2:m88_14, from 3:m88_18
-# 88| valnum = m88_6
+# 88| valnum = m88_10, m88_6, r88_8
# 88| r88_7(glval) = VariableAddress[#temp88:7] :
-# 88| valnum = r88_7
+# 88| valnum = r88_13, r88_17, r88_7
# 88| r88_8(int) = Load : &:r88_7, m88_6
-# 88| valnum = m88_6
+# 88| valnum = m88_10, m88_6, r88_8
# 88| r88_9(glval) = VariableAddress[v] :
-# 88| valnum = r86_1
+# 88| valnum = r86_1, r88_9
# 88| m88_10(int) = Store : &:r88_9, r88_8
-# 88| valnum = m88_6
+# 88| valnum = m88_10, m88_6, r88_8
# 89| v89_1(void) = NoOp :
# 84| v84_14(void) = ReturnIndirection : &:r84_12, m84_13
# 84| v84_15(void) = ReturnVoid :
@@ -697,24 +697,24 @@ test.cpp:
# 88| Block 2
# 88| r88_11(glval) = VariableAddress[x] :
-# 88| valnum = r84_6
+# 88| valnum = r84_6, r88_11
# 88| r88_12(int) = Load : &:r88_11, m84_7
-# 88| valnum = m84_7
+# 88| valnum = m84_7, m88_14, r88_12
# 88| r88_13(glval) = VariableAddress[#temp88:7] :
-# 88| valnum = r88_7
+# 88| valnum = r88_13, r88_17, r88_7
# 88| m88_14(int) = Store : &:r88_13, r88_12
-# 88| valnum = m84_7
+# 88| valnum = m84_7, m88_14, r88_12
#-----| Goto -> Block 1
# 88| Block 3
# 88| r88_15(glval) = VariableAddress[y] :
-# 88| valnum = r84_8
+# 88| valnum = r84_8, r88_15
# 88| r88_16(int) = Load : &:r88_15, m84_9
-# 88| valnum = m84_9
+# 88| valnum = m84_9, m88_18, r88_16
# 88| r88_17(glval) = VariableAddress[#temp88:7] :
-# 88| valnum = r88_7
+# 88| valnum = r88_13, r88_17, r88_7
# 88| m88_18(int) = Store : &:r88_17, r88_16
-# 88| valnum = m84_9
+# 88| valnum = m84_9, m88_18, r88_16
#-----| Goto -> Block 1
# 91| int regression_test00()
@@ -729,27 +729,27 @@ test.cpp:
# 91| mu91_5(unknown) = UnmodeledDefinition :
# 91| valnum = unique
# 92| r92_1(glval) = VariableAddress[x] :
-# 92| valnum = r92_1
+# 92| valnum = r92_1, r92_3, r93_2
# 92| r92_2(int) = Constant[10] :
-# 92| valnum = r92_2
+# 92| valnum = m92_4, m92_6, m93_4, r92_2, r92_5, r93_3
# 92| r92_3(glval) = VariableAddress[x] :
-# 92| valnum = r92_1
+# 92| valnum = r92_1, r92_3, r93_2
# 92| m92_4(int) = Store : &:r92_3, r92_2
-# 92| valnum = r92_2
+# 92| valnum = m92_4, m92_6, m93_4, r92_2, r92_5, r93_3
# 92| r92_5(int) = CopyValue : r92_2
-# 92| valnum = r92_2
+# 92| valnum = m92_4, m92_6, m93_4, r92_2, r92_5, r93_3
# 92| m92_6(int) = Store : &:r92_1, r92_5
-# 92| valnum = r92_2
+# 92| valnum = m92_4, m92_6, m93_4, r92_2, r92_5, r93_3
# 93| r93_1(glval) = VariableAddress[#return] :
-# 93| valnum = r93_1
+# 93| valnum = r91_6, r93_1
# 93| r93_2(glval) = VariableAddress[x] :
-# 93| valnum = r92_1
+# 93| valnum = r92_1, r92_3, r93_2
# 93| r93_3(int) = Load : &:r93_2, m92_6
-# 93| valnum = r92_2
+# 93| valnum = m92_4, m92_6, m93_4, r92_2, r92_5, r93_3
# 93| m93_4(int) = Store : &:r93_1, r93_3
-# 93| valnum = r92_2
+# 93| valnum = m92_4, m92_6, m93_4, r92_2, r92_5, r93_3
# 91| r91_6(glval) = VariableAddress[#return] :
-# 91| valnum = r93_1
+# 91| valnum = r91_6, r93_1
# 91| v91_7(void) = ReturnValue : &:r91_6, m93_4
# 91| v91_8(void) = UnmodeledUse : mu*
# 91| v91_9(void) = AliasedUse : m91_3
@@ -767,60 +767,60 @@ test.cpp:
# 104| mu104_5(unknown) = UnmodeledDefinition :
# 104| valnum = unique
# 104| r104_6(glval) = VariableAddress[pd] :
-# 104| valnum = r104_6
+# 104| valnum = r104_6, r105_2, r106_2
# 104| m104_7(Derived *) = InitializeParameter[pd] : &:r104_6
-# 104| valnum = m104_7
+# 104| valnum = m104_7, r104_8, r105_3, r106_3
# 104| r104_8(Derived *) = Load : &:r104_6, m104_7
-# 104| valnum = m104_7
+# 104| valnum = m104_7, r104_8, r105_3, r106_3
# 104| m104_9(unknown) = InitializeIndirection[pd] : &:r104_8
# 104| valnum = unique
# 105| r105_1(glval) = VariableAddress[x] :
# 105| valnum = unique
# 105| r105_2(glval) = VariableAddress[pd] :
-# 105| valnum = r104_6
+# 105| valnum = r104_6, r105_2, r106_2
# 105| r105_3(Derived *) = Load : &:r105_2, m104_7
-# 105| valnum = m104_7
+# 105| valnum = m104_7, r104_8, r105_3, r106_3
# 105| r105_4(Base *) = ConvertToNonVirtualBase[Derived : Base] : r105_3
-# 105| valnum = r105_4
+# 105| valnum = m106_5, r105_4, r106_4, r107_3
# 105| r105_5(glval) = FieldAddress[b] : r105_4
-# 105| valnum = r105_5
+# 105| valnum = r105_5, r107_4
# 105| r105_6(int) = Load : &:r105_5, ~m104_9
-# 105| valnum = r105_6
+# 105| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3
# 105| m105_7(int) = Store : &:r105_1, r105_6
-# 105| valnum = r105_6
+# 105| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3
# 106| r106_1(glval) = VariableAddress[pb] :
-# 106| valnum = r106_1
+# 106| valnum = r106_1, r107_2
# 106| r106_2(glval) = VariableAddress[pd] :
-# 106| valnum = r104_6
+# 106| valnum = r104_6, r105_2, r106_2
# 106| r106_3(Derived *) = Load : &:r106_2, m104_7
-# 106| valnum = m104_7
+# 106| valnum = m104_7, r104_8, r105_3, r106_3
# 106| r106_4(Base *) = ConvertToNonVirtualBase[Derived : Base] : r106_3
-# 106| valnum = r105_4
+# 106| valnum = m106_5, r105_4, r106_4, r107_3
# 106| m106_5(Base *) = Store : &:r106_1, r106_4
-# 106| valnum = r105_4
+# 106| valnum = m106_5, r105_4, r106_4, r107_3
# 107| r107_1(glval) = VariableAddress[y] :
-# 107| valnum = r107_1
+# 107| valnum = r107_1, r109_2
# 107| r107_2(glval) = VariableAddress[pb] :
-# 107| valnum = r106_1
+# 107| valnum = r106_1, r107_2
# 107| r107_3(Base *) = Load : &:r107_2, m106_5
-# 107| valnum = r105_4
+# 107| valnum = m106_5, r105_4, r106_4, r107_3
# 107| r107_4(glval) = FieldAddress[b] : r107_3
-# 107| valnum = r105_5
+# 107| valnum = r105_5, r107_4
# 107| r107_5(int) = Load : &:r107_4, ~m104_9
-# 107| valnum = r105_6
+# 107| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3
# 107| m107_6(int) = Store : &:r107_1, r107_5
-# 107| valnum = r105_6
+# 107| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3
# 109| r109_1(glval) = VariableAddress[#return] :
-# 109| valnum = r109_1
+# 109| valnum = r104_11, r109_1
# 109| r109_2(glval) = VariableAddress[y] :
-# 109| valnum = r107_1
+# 109| valnum = r107_1, r109_2
# 109| r109_3(int) = Load : &:r109_2, m107_6
-# 109| valnum = r105_6
+# 109| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3
# 109| m109_4(int) = Store : &:r109_1, r109_3
-# 109| valnum = r105_6
+# 109| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3
# 104| v104_10(void) = ReturnIndirection : &:r104_8, m104_9
# 104| r104_11(glval) = VariableAddress[#return] :
-# 104| valnum = r109_1
+# 104| valnum = r104_11, r109_1
# 104| v104_12(void) = ReturnValue : &:r104_11, m109_4
# 104| v104_13(void) = UnmodeledUse : mu*
# 104| v104_14(void) = AliasedUse : m104_3
@@ -838,11 +838,11 @@ test.cpp:
# 112| mu112_5(unknown) = UnmodeledDefinition :
# 112| valnum = unique
# 113| r113_1(glval) = StringConstant["a"] :
-# 113| valnum = r113_1
+# 113| valnum = r113_1, r115_1
# 114| r114_1(glval) = StringConstant["b"] :
# 114| valnum = unique
# 115| r115_1(glval) = StringConstant["a"] :
-# 115| valnum = r113_1
+# 115| valnum = r113_1, r115_1
# 116| r116_1(glval) = StringConstant["c"] :
# 116| valnum = unique
# 117| v117_1(void) = NoOp :
@@ -863,67 +863,67 @@ test.cpp:
# 124| mu124_5(unknown) = UnmodeledDefinition :
# 124| valnum = unique
# 124| r124_6(glval) = VariableAddress[pa] :
-# 124| valnum = r124_6
+# 124| valnum = r124_6, r125_2, r126_2, r128_3, r129_2
# 124| m124_7(A *) = InitializeParameter[pa] : &:r124_6
-# 124| valnum = m124_7
+# 124| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3
# 124| r124_8(A *) = Load : &:r124_6, m124_7
-# 124| valnum = m124_7
+# 124| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3
# 124| m124_9(unknown) = InitializeIndirection[pa] : &:r124_8
# 124| valnum = unique
# 124| r124_10(glval) = VariableAddress[n] :
-# 124| valnum = r124_10
+# 124| valnum = r124_10, r128_1
# 124| m124_11(int) = InitializeParameter[n] : &:r124_10
-# 124| valnum = m124_11
+# 124| valnum = m124_11, m128_6, m129_6, r128_2, r129_5
# 125| r125_1(glval) = VariableAddress[b] :
# 125| valnum = unique
# 125| r125_2(glval) = VariableAddress[pa] :
-# 125| valnum = r124_6
+# 125| valnum = r124_6, r125_2, r126_2, r128_3, r129_2
# 125| r125_3(A *) = Load : &:r125_2, m124_7
-# 125| valnum = m124_7
+# 125| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3
# 125| r125_4(glval) = FieldAddress[x] : r125_3
-# 125| valnum = r125_4
+# 125| valnum = r125_4, r126_4, r128_5, r129_4
# 125| r125_5(int) = Load : &:r125_4, ~m124_9
-# 125| valnum = r125_5
+# 125| valnum = m125_6, m126_6, r125_5, r126_5
# 125| m125_6(int) = Store : &:r125_1, r125_5
-# 125| valnum = r125_5
+# 125| valnum = m125_6, m126_6, r125_5, r126_5
# 126| r126_1(glval) = VariableAddress[c] :
# 126| valnum = unique
# 126| r126_2(glval) = VariableAddress[pa] :
-# 126| valnum = r124_6
+# 126| valnum = r124_6, r125_2, r126_2, r128_3, r129_2
# 126| r126_3(A *) = Load : &:r126_2, m124_7
-# 126| valnum = m124_7
+# 126| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3
# 126| r126_4(glval) = FieldAddress[x] : r126_3
-# 126| valnum = r125_4
+# 126| valnum = r125_4, r126_4, r128_5, r129_4
# 126| r126_5(int) = Load : &:r126_4, ~m124_9
-# 126| valnum = r125_5
+# 126| valnum = m125_6, m126_6, r125_5, r126_5
# 126| m126_6(int) = Store : &:r126_1, r126_5
-# 126| valnum = r125_5
+# 126| valnum = m125_6, m126_6, r125_5, r126_5
# 128| r128_1(glval) = VariableAddress[n] :
-# 128| valnum = r124_10
+# 128| valnum = r124_10, r128_1
# 128| r128_2(int) = Load : &:r128_1, m124_11
-# 128| valnum = m124_11
+# 128| valnum = m124_11, m128_6, m129_6, r128_2, r129_5
# 128| r128_3(glval) = VariableAddress[pa] :
-# 128| valnum = r124_6
+# 128| valnum = r124_6, r125_2, r126_2, r128_3, r129_2
# 128| r128_4(A *) = Load : &:r128_3, m124_7
-# 128| valnum = m124_7
+# 128| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3
# 128| r128_5(glval) = FieldAddress[x] : r128_4
-# 128| valnum = r125_4
+# 128| valnum = r125_4, r126_4, r128_5, r129_4
# 128| m128_6(int) = Store : &:r128_5, r128_2
-# 128| valnum = m124_11
+# 128| valnum = m124_11, m128_6, m129_6, r128_2, r129_5
# 128| m128_7(unknown) = Chi : total:m124_9, partial:m128_6
# 128| valnum = unique
# 129| r129_1(glval) = VariableAddress[d] :
# 129| valnum = unique
# 129| r129_2(glval) = VariableAddress[pa] :
-# 129| valnum = r124_6
+# 129| valnum = r124_6, r125_2, r126_2, r128_3, r129_2
# 129| r129_3(A *) = Load : &:r129_2, m124_7
-# 129| valnum = m124_7
+# 129| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3
# 129| r129_4(glval) = FieldAddress[x] : r129_3
-# 129| valnum = r125_4
+# 129| valnum = r125_4, r126_4, r128_5, r129_4
# 129| r129_5(int) = Load : &:r129_4, m128_6
-# 129| valnum = m124_11
+# 129| valnum = m124_11, m128_6, m129_6, r128_2, r129_5
# 129| m129_6(int) = Store : &:r129_1, r129_5
-# 129| valnum = m124_11
+# 129| valnum = m124_11, m128_6, m129_6, r128_2, r129_5
# 130| v130_1(void) = NoOp :
# 124| v124_12(void) = ReturnIndirection : &:r124_8, ~m128_7
# 124| v124_13(void) = ReturnVoid :
@@ -945,53 +945,53 @@ test.cpp:
# 136| r136_1(glval) = VariableAddress[b] :
# 136| valnum = unique
# 136| r136_2(glval) = VariableAddress[global_a] :
-# 136| valnum = r136_2
+# 136| valnum = r136_2, r137_2, r139_3, r140_2
# 136| r136_3(A *) = Load : &:r136_2, ~m135_3
-# 136| valnum = r136_3
+# 136| valnum = r136_3, r137_3, r139_4
# 136| r136_4(glval) = FieldAddress[x] : r136_3
-# 136| valnum = r136_4
+# 136| valnum = r136_4, r137_4, r139_5
# 136| r136_5(int) = Load : &:r136_4, ~m135_4
-# 136| valnum = r136_5
+# 136| valnum = m136_6, r136_5
# 136| m136_6(int) = Store : &:r136_1, r136_5
-# 136| valnum = r136_5
+# 136| valnum = m136_6, r136_5
# 137| r137_1(glval) = VariableAddress[c] :
# 137| valnum = unique
# 137| r137_2(glval) = VariableAddress[global_a] :
-# 137| valnum = r136_2
+# 137| valnum = r136_2, r137_2, r139_3, r140_2
# 137| r137_3(A *) = Load : &:r137_2, ~m135_3
-# 137| valnum = r136_3
+# 137| valnum = r136_3, r137_3, r139_4
# 137| r137_4(glval) = FieldAddress[x] : r137_3
-# 137| valnum = r136_4
+# 137| valnum = r136_4, r137_4, r139_5
# 137| r137_5(int) = Load : &:r137_4, ~m135_4
-# 137| valnum = r137_5
+# 137| valnum = m137_6, r137_5
# 137| m137_6(int) = Store : &:r137_1, r137_5
-# 137| valnum = r137_5
+# 137| valnum = m137_6, r137_5
# 139| r139_1(glval) = VariableAddress[global_n] :
# 139| valnum = unique
# 139| r139_2(int) = Load : &:r139_1, ~m135_3
-# 139| valnum = r139_2
+# 139| valnum = m139_6, r139_2
# 139| r139_3(glval) = VariableAddress[global_a] :
-# 139| valnum = r136_2
+# 139| valnum = r136_2, r137_2, r139_3, r140_2
# 139| r139_4(A *) = Load : &:r139_3, ~m135_3
-# 139| valnum = r136_3
+# 139| valnum = r136_3, r137_3, r139_4
# 139| r139_5(glval) = FieldAddress[x] : r139_4
-# 139| valnum = r136_4
+# 139| valnum = r136_4, r137_4, r139_5
# 139| m139_6(int) = Store : &:r139_5, r139_2
-# 139| valnum = r139_2
+# 139| valnum = m139_6, r139_2
# 139| m139_7(unknown) = Chi : total:m135_4, partial:m139_6
# 139| valnum = unique
# 140| r140_1(glval) = VariableAddress[d] :
# 140| valnum = unique
# 140| r140_2(glval) = VariableAddress[global_a] :
-# 140| valnum = r136_2
+# 140| valnum = r136_2, r137_2, r139_3, r140_2
# 140| r140_3(A *) = Load : &:r140_2, ~m139_7
# 140| valnum = unique
# 140| r140_4(glval) = FieldAddress[x] : r140_3
# 140| valnum = unique
# 140| r140_5(int) = Load : &:r140_4, ~m139_7
-# 140| valnum = r140_5
+# 140| valnum = m140_6, r140_5
# 140| m140_6(int) = Store : &:r140_1, r140_5
-# 140| valnum = r140_5
+# 140| valnum = m140_6, r140_5
# 141| v141_1(void) = NoOp :
# 135| v135_6(void) = ReturnVoid :
# 135| v135_7(void) = UnmodeledUse : mu*
@@ -1010,63 +1010,63 @@ test.cpp:
# 143| mu143_5(unknown) = UnmodeledDefinition :
# 143| valnum = unique
# 143| r143_6(glval) = VariableAddress[pa] :
-# 143| valnum = r143_6
+# 143| valnum = r143_6, r144_2, r145_2, r147_3, r149_2
# 143| m143_7(A *) = InitializeParameter[pa] : &:r143_6
-# 143| valnum = m143_7
+# 143| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3
# 143| r143_8(A *) = Load : &:r143_6, m143_7
-# 143| valnum = m143_7
+# 143| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3
# 143| m143_9(unknown) = InitializeIndirection[pa] : &:r143_8
# 143| valnum = unique
# 144| r144_1(glval) = VariableAddress[b] :
# 144| valnum = unique
# 144| r144_2(glval) = VariableAddress[pa] :
-# 144| valnum = r143_6
+# 144| valnum = r143_6, r144_2, r145_2, r147_3, r149_2
# 144| r144_3(A *) = Load : &:r144_2, m143_7
-# 144| valnum = m143_7
+# 144| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3
# 144| r144_4(glval) = FieldAddress[x] : r144_3
-# 144| valnum = r144_4
+# 144| valnum = r144_4, r149_4
# 144| r144_5(int) = Load : &:r144_4, ~m143_9
-# 144| valnum = r144_5
+# 144| valnum = m144_6, m149_6, r144_5, r149_5
# 144| m144_6(int) = Store : &:r144_1, r144_5
-# 144| valnum = r144_5
+# 144| valnum = m144_6, m149_6, r144_5, r149_5
# 145| r145_1(glval) = VariableAddress[c] :
# 145| valnum = unique
# 145| r145_2(glval) = VariableAddress[pa] :
-# 145| valnum = r143_6
+# 145| valnum = r143_6, r144_2, r145_2, r147_3, r149_2
# 145| r145_3(A *) = Load : &:r145_2, m143_7
-# 145| valnum = m143_7
+# 145| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3
# 145| r145_4(glval) = FieldAddress[y] : r145_3
-# 145| valnum = r145_4
+# 145| valnum = r145_4, r147_5
# 145| r145_5(int) = Load : &:r145_4, ~m143_9
-# 145| valnum = r145_5
+# 145| valnum = m145_6, r145_5
# 145| m145_6(int) = Store : &:r145_1, r145_5
-# 145| valnum = r145_5
+# 145| valnum = m145_6, r145_5
# 147| r147_1(glval) = VariableAddress[global_n] :
# 147| valnum = unique
# 147| r147_2(int) = Load : &:r147_1, ~m143_3
-# 147| valnum = r147_2
+# 147| valnum = m147_6, r147_2
# 147| r147_3(glval) = VariableAddress[pa] :
-# 147| valnum = r143_6
+# 147| valnum = r143_6, r144_2, r145_2, r147_3, r149_2
# 147| r147_4(A *) = Load : &:r147_3, m143_7
-# 147| valnum = m143_7
+# 147| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3
# 147| r147_5(glval) = FieldAddress[y] : r147_4
-# 147| valnum = r145_4
+# 147| valnum = r145_4, r147_5
# 147| m147_6(int) = Store : &:r147_5, r147_2
-# 147| valnum = r147_2
+# 147| valnum = m147_6, r147_2
# 147| m147_7(unknown) = Chi : total:m143_9, partial:m147_6
# 147| valnum = unique
# 149| r149_1(glval) = VariableAddress[d] :
# 149| valnum = unique
# 149| r149_2(glval) = VariableAddress[pa] :
-# 149| valnum = r143_6
+# 149| valnum = r143_6, r144_2, r145_2, r147_3, r149_2
# 149| r149_3(A *) = Load : &:r149_2, m143_7
-# 149| valnum = m143_7
+# 149| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3
# 149| r149_4(glval) = FieldAddress[x] : r149_3
-# 149| valnum = r144_4
+# 149| valnum = r144_4, r149_4
# 149| r149_5(int) = Load : &:r149_4, ~m143_9
-# 149| valnum = r144_5
+# 149| valnum = m144_6, m149_6, r144_5, r149_5
# 149| m149_6(int) = Store : &:r149_1, r149_5
-# 149| valnum = r144_5
+# 149| valnum = m144_6, m149_6, r144_5, r149_5
# 150| v150_1(void) = NoOp :
# 143| v143_10(void) = ReturnIndirection : &:r143_8, ~m147_7
# 143| v143_11(void) = ReturnVoid :
@@ -1086,59 +1086,59 @@ test.cpp:
# 152| mu152_5(unknown) = UnmodeledDefinition :
# 152| valnum = unique
# 152| r152_6(glval) = VariableAddress[n] :
-# 152| valnum = r152_6
+# 152| valnum = r152_6, r156_1
# 152| m152_7(int) = InitializeParameter[n] : &:r152_6
-# 152| valnum = m152_7
+# 152| valnum = m152_7, m156_6, r156_2
# 153| r153_1(glval) = VariableAddress[b] :
# 153| valnum = unique
# 153| r153_2(glval) = VariableAddress[global_a] :
-# 153| valnum = r153_2
+# 153| valnum = r153_2, r154_2, r156_3, r158_2
# 153| r153_3(A *) = Load : &:r153_2, ~m152_3
-# 153| valnum = r153_3
+# 153| valnum = r153_3, r154_3, r156_4
# 153| r153_4(glval) = FieldAddress[x] : r153_3
-# 153| valnum = r153_4
+# 153| valnum = r153_4, r154_4
# 153| r153_5(int) = Load : &:r153_4, ~m152_4
-# 153| valnum = r153_5
+# 153| valnum = m153_6, r153_5
# 153| m153_6(int) = Store : &:r153_1, r153_5
-# 153| valnum = r153_5
+# 153| valnum = m153_6, r153_5
# 154| r154_1(glval) = VariableAddress[c] :
# 154| valnum = unique
# 154| r154_2(glval) = VariableAddress[global_a] :
-# 154| valnum = r153_2
+# 154| valnum = r153_2, r154_2, r156_3, r158_2
# 154| r154_3(A *) = Load : &:r154_2, ~m152_3
-# 154| valnum = r153_3
+# 154| valnum = r153_3, r154_3, r156_4
# 154| r154_4(glval) = FieldAddress[x] : r154_3
-# 154| valnum = r153_4
+# 154| valnum = r153_4, r154_4
# 154| r154_5(int) = Load : &:r154_4, ~m152_4
-# 154| valnum = r154_5
+# 154| valnum = m154_6, r154_5
# 154| m154_6(int) = Store : &:r154_1, r154_5
-# 154| valnum = r154_5
+# 154| valnum = m154_6, r154_5
# 156| r156_1(glval) = VariableAddress[n] :
-# 156| valnum = r152_6
+# 156| valnum = r152_6, r156_1
# 156| r156_2(int) = Load : &:r156_1, m152_7
-# 156| valnum = m152_7
+# 156| valnum = m152_7, m156_6, r156_2
# 156| r156_3(glval) = VariableAddress[global_a] :
-# 156| valnum = r153_2
+# 156| valnum = r153_2, r154_2, r156_3, r158_2
# 156| r156_4(A *) = Load : &:r156_3, ~m152_3
-# 156| valnum = r153_3
+# 156| valnum = r153_3, r154_3, r156_4
# 156| r156_5(glval) = FieldAddress[y] : r156_4
# 156| valnum = unique
# 156| m156_6(int) = Store : &:r156_5, r156_2
-# 156| valnum = m152_7
+# 156| valnum = m152_7, m156_6, r156_2
# 156| m156_7(unknown) = Chi : total:m152_4, partial:m156_6
# 156| valnum = unique
# 158| r158_1(glval) = VariableAddress[d] :
# 158| valnum = unique
# 158| r158_2(glval) = VariableAddress[global_a] :
-# 158| valnum = r153_2
+# 158| valnum = r153_2, r154_2, r156_3, r158_2
# 158| r158_3(A *) = Load : &:r158_2, ~m156_7
# 158| valnum = unique
# 158| r158_4(glval) = FieldAddress[x] : r158_3
# 158| valnum = unique
# 158| r158_5(int) = Load : &:r158_4, ~m156_7
-# 158| valnum = r158_5
+# 158| valnum = m158_6, r158_5
# 158| m158_6(int) = Store : &:r158_1, r158_5
-# 158| valnum = r158_5
+# 158| valnum = m158_6, r158_5
# 159| v159_1(void) = NoOp :
# 152| v152_8(void) = ReturnVoid :
# 152| v152_9(void) = UnmodeledUse : mu*
diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_uniqueness.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_uniqueness.expected
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_uniqueness.ql b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_uniqueness.ql
new file mode 100644
index 000000000000..7e5eeb74093f
--- /dev/null
+++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_uniqueness.ql
@@ -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(), ", ")
diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll
index ec6d786a684a..1575609fb2fd 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll
@@ -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 string getDebugString() { result = strictconcat(getAnInstruction().getResultId(), ", ") }
- final Language::Location getLocation() { result = getExampleInstruction().getLocation() }
+ 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) }
diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll
index e25693a02070..9408469a8673 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll
@@ -1,2 +1,275 @@
-import semmle.code.csharp.ir.implementation.raw.IR as IR
+private import ValueNumberingImports
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
+import semmle.code.csharp.ir.implementation.raw.IR
+private import semmle.code.csharp.Location
+
+class UnknownLocation = EmptyLocation;
+
+class UnknownDefaultLocation = EmptyLocation;
+
+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, 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, Language::Class baseClass, Language::Class derivedClass,
+ TValueNumber operand
+ ) {
+ inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, 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`.
+ */
+private class CongruentCopyInstruction extends CopyInstruction {
+ CongruentCopyInstruction() {
+ this.getSourceValueOperand().getDefinitionOverlap() instanceof MustExactlyOverlap
+ }
+}
+
+/**
+ * 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
+}
+
+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
+ 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
+}
+
+/**
+ * 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 `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
+ // The value number of a copy is just the value number of its source value.
+ result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
+ )
+ )
+}
diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll
index ec6d786a684a..1575609fb2fd 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll
@@ -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 string getDebugString() { result = strictconcat(getAnInstruction().getResultId(), ", ") }
- final Language::Location getLocation() { result = getExampleInstruction().getLocation() }
+ 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) }
diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll
index 9e4a85dd8edd..fc0177a2e2c1 100644
--- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll
+++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll
@@ -1,2 +1,309 @@
-import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as IR
+private import ValueNumberingImports
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
+import semmle.code.csharp.ir.implementation.unaliased_ssa.IR
+private import semmle.code.csharp.Location
+
+class UnknownLocation = EmptyLocation;
+
+class UnknownDefaultLocation = EmptyLocation;
+
+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, 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, Language::Class baseClass, Language::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
+ 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())
+ )
+ )
+}