diff --git a/config/identical-files.json b/config/identical-files.json index 29601d195103..0799aa2521c9 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -205,6 +205,13 @@ "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 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", + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll" + ], "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", 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 79e5a2b6713b..f5c2f2972794 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. @@ -15,45 +14,6 @@ class ValueNumberPropertyProvider extends IRPropertyProvider { } } -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 - TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) } - /** * The value number assigned to a particular set of instructions that produce equivalent results. */ @@ -86,234 +46,13 @@ class ValueNumber extends TValueNumber { 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`. - */ -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, 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 - 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 -} - -/** - * 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 - // The value number of a copy is just the value number of its source value. - result = valueNumber(instr.(CongruentCopyInstruction).getSourceValue()) - ) - ) -} 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..8482a5e4b143 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,3 @@ +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 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..2bef4cb94f31 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,264 @@ -import semmle.code.cpp.ir.implementation.aliased_ssa.IR as IR +private import ValueNumberingImports + +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/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 79e5a2b6713b..f5c2f2972794 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. @@ -15,45 +14,6 @@ class ValueNumberPropertyProvider extends IRPropertyProvider { } } -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 - TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) } - /** * The value number assigned to a particular set of instructions that produce equivalent results. */ @@ -86,234 +46,13 @@ class ValueNumber extends TValueNumber { 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`. - */ -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, 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 - 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 -} - -/** - * 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 - // The value number of a copy is just the value number of its source value. - result = valueNumber(instr.(CongruentCopyInstruction).getSourceValue()) - ) - ) -} 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..17e8fe3a1251 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,3 @@ +import semmle.code.cpp.ir.implementation.raw.IR import semmle.code.cpp.ir.internal.Overlap import semmle.code.cpp.ir.internal.IRCppLanguage as Language 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..2bef4cb94f31 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,264 @@ -import semmle.code.cpp.ir.implementation.raw.IR as IR +private import ValueNumberingImports + +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/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 79e5a2b6713b..f5c2f2972794 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. @@ -15,45 +14,6 @@ class ValueNumberPropertyProvider extends IRPropertyProvider { } } -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 - TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) } - /** * The value number assigned to a particular set of instructions that produce equivalent results. */ @@ -86,234 +46,13 @@ class ValueNumber extends TValueNumber { 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`. - */ -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, 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 - 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 -} - -/** - * 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 - // The value number of a copy is just the value number of its source value. - result = valueNumber(instr.(CongruentCopyInstruction).getSourceValue()) - ) - ) -} 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..5b1b94d499b5 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,3 @@ +import semmle.code.cpp.ir.implementation.unaliased_ssa.IR import semmle.code.cpp.ir.internal.Overlap import semmle.code.cpp.ir.internal.IRCppLanguage as Language 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..2bef4cb94f31 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,264 @@ -import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR +private import ValueNumberingImports + +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/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..7a09f47ac5d0 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/ASTValueNumbering.qll @@ -0,0 +1,74 @@ +/** + * 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 { + private Instruction getAnInstruction() { this = tvalueNumber(result) } + + final string toString() { result = "GVN" } + + final Location getLocation() { + result = rank[1](Location l | + l = getAnExpr().getLocation() + | + l + order by + l.getFile().getAbsolutePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(), + l.getEndColumn() + ) + } + + /** Gets an expression that has this GVN. */ + Expr getAnExpr() { result = getAnInstruction().getConvertedResultExpression() } +} + +/** Gets the global value number of expression `e`. */ +GVN globalValueNumber(Expr e) { e = result.getAnExpr() } 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 79e5a2b6713b..f5c2f2972794 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. @@ -15,45 +14,6 @@ class ValueNumberPropertyProvider extends IRPropertyProvider { } } -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 - TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) } - /** * The value number assigned to a particular set of instructions that produce equivalent results. */ @@ -86,234 +46,13 @@ class ValueNumber extends TValueNumber { 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`. - */ -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, 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 - 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 -} - -/** - * 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 - // The value number of a copy is just the value number of its source value. - result = valueNumber(instr.(CongruentCopyInstruction).getSourceValue()) - ) - ) -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll index 555cb581d375..f0aee625ba9a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll @@ -1 +1,3 @@ +import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language import semmle.code.csharp.ir.internal.Overlap +import semmle.code.csharp.ir.implementation.raw.IR 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..2bef4cb94f31 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,264 @@ -import semmle.code.csharp.ir.implementation.raw.IR as IR -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import ValueNumberingImports + +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 79e5a2b6713b..f5c2f2972794 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. @@ -15,45 +14,6 @@ class ValueNumberPropertyProvider extends IRPropertyProvider { } } -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 - TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) } - /** * The value number assigned to a particular set of instructions that produce equivalent results. */ @@ -86,234 +46,13 @@ class ValueNumber extends TValueNumber { 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`. - */ -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, 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 - 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 -} - -/** - * 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 - // The value number of a copy is just the value number of its source value. - result = valueNumber(instr.(CongruentCopyInstruction).getSourceValue()) - ) - ) -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll index 555cb581d375..f0aee625ba9a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll @@ -1 +1,3 @@ +import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language import semmle.code.csharp.ir.internal.Overlap +import semmle.code.csharp.ir.implementation.raw.IR 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..2bef4cb94f31 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,264 @@ -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as IR -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import ValueNumberingImports + +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()) + ) + ) +}