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()) + ) + ) +}