C++ IR: Don't propagate GVN through non-exact Copy

The `ValueNumbering` library is supposed to propagate value numberings
through a `CopyInstruction` only when it's _congruent_, meaning it must
have exact overlap with its source. A `CopyInstruction` can be a
`LoadInstruction`, a `StoreInstruction`, or a `CopyValueInstruction`.
The latter is also a `UnaryInstruction`, and the value numbering rule
for `UnaryInstruction` applied to it as well.

This meant that value numbering would propagate even through a
non-congruent `CopyValueInstruction`. That's semantically wrong but
probably only an issue in very rare circumstances, and it should get
corrected when we change the definition of `getUnary` to require
congruence.

What's worse is the performance implications. It meant that the value
numbering IPA witness could take two different paths through every
`CopyValueInstruction`. If multiple `CopyValueInstruction`s were
chained, this would lead to an exponential number of variable numbers
for the same `Instruction`, and we would run out of time and space
while performing value numbering.

This fixes the performance of `ValueNumbering.qll` on
https://github.com/asterisk/asterisk, although this project might also
require a separate change for fixing an infinite loop in the IR constant
analysis.
This commit is contained in:
Jonas Jensen
2019-07-08 15:23:59 +02:00
parent 46d779248d
commit da13dc6442
3 changed files with 6 additions and 3 deletions

View File

@@ -124,7 +124,7 @@ private predicate numberableInstruction(Instruction instr) {
instr instanceof StringConstantInstruction or
instr instanceof FieldAddressInstruction or
instr instanceof BinaryInstruction or
instr instanceof UnaryInstruction or
(instr instanceof UnaryInstruction and not instr instanceof CopyInstruction) or
instr instanceof PointerArithmeticInstruction or
instr instanceof CongruentCopyInstruction
}
@@ -191,6 +191,7 @@ private predicate unaryValueNumber(UnaryInstruction instr, IRFunction irFunc, Op
Type type, ValueNumber operand) {
instr.getEnclosingIRFunction() = irFunc and
(not instr instanceof InheritanceConversionInstruction) and
(not instr instanceof CopyInstruction) and
instr.getOpcode() = opcode and
instr.getResultType() = type and
valueNumber(instr.getUnary()) = operand

View File

@@ -124,7 +124,7 @@ private predicate numberableInstruction(Instruction instr) {
instr instanceof StringConstantInstruction or
instr instanceof FieldAddressInstruction or
instr instanceof BinaryInstruction or
instr instanceof UnaryInstruction or
(instr instanceof UnaryInstruction and not instr instanceof CopyInstruction) or
instr instanceof PointerArithmeticInstruction or
instr instanceof CongruentCopyInstruction
}
@@ -191,6 +191,7 @@ private predicate unaryValueNumber(UnaryInstruction instr, IRFunction irFunc, Op
Type type, ValueNumber operand) {
instr.getEnclosingIRFunction() = irFunc and
(not instr instanceof InheritanceConversionInstruction) and
(not instr instanceof CopyInstruction) and
instr.getOpcode() = opcode and
instr.getResultType() = type and
valueNumber(instr.getUnary()) = operand

View File

@@ -124,7 +124,7 @@ private predicate numberableInstruction(Instruction instr) {
instr instanceof StringConstantInstruction or
instr instanceof FieldAddressInstruction or
instr instanceof BinaryInstruction or
instr instanceof UnaryInstruction or
(instr instanceof UnaryInstruction and not instr instanceof CopyInstruction) or
instr instanceof PointerArithmeticInstruction or
instr instanceof CongruentCopyInstruction
}
@@ -191,6 +191,7 @@ private predicate unaryValueNumber(UnaryInstruction instr, IRFunction irFunc, Op
Type type, ValueNumber operand) {
instr.getEnclosingIRFunction() = irFunc and
(not instr instanceof InheritanceConversionInstruction) and
(not instr instanceof CopyInstruction) and
instr.getOpcode() = opcode and
instr.getResultType() = type and
valueNumber(instr.getUnary()) = operand