Merge pull request #882 from jbj/ir-ConstantAnalysis-perf

C++: Speed up IR ConstantAnalysis
This commit is contained in:
Robert Marsh
2019-02-06 22:29:09 -08:00
committed by GitHub
9 changed files with 289 additions and 91 deletions

View File

@@ -1484,6 +1484,17 @@ class PhiInstruction extends Instruction {
override final MemoryAccessKind getResultMemoryAccess() {
result instanceof PhiMemoryAccess
}
/**
* Gets an instruction that defines the input to one of the operands of this
* instruction. It's possible for more than one operand to have the same
* defining instruction, so this predicate will have the same number of
* results as `getAnOperand()` or fewer.
*/
pragma[noinline]
final Instruction getAnOperandDefinitionInstruction() {
result = this.getAnOperand().(PhiOperand).getDefinitionInstruction()
}
}
/**
@@ -1492,7 +1503,7 @@ class PhiInstruction extends Instruction {
*
* A `ChiInstruction` is inserted immediately after an instruction that writes to memory. The
* `ChiInstruction` has two operands. The first operand, given by `getTotalOperand()`, represents
* the previous state of all of the memory that might be alised by the memory write. The second
* the previous state of all of the memory that might be aliased by the memory write. The second
* operand, given by `getPartialOperand()`, represents the memory that was actually modified by the
* memory write. The result of the `ChiInstruction` represents the same memory as
* `getTotalOperand()`, updated to include the changes due to the value that was actually stored by

View File

@@ -1,38 +1,49 @@
private import internal.ConstantAnalysisInternal
import semmle.code.cpp.ir.internal.IntegerConstant
private import semmle.code.cpp.ir.internal.IntegerPartial
private import IR
language[monotonicAggregates]
IntValue getConstantValue(Instruction instr) {
int getConstantValue(Instruction instr) {
result = instr.(IntegerConstantInstruction).getValue().toInt() or
exists(BinaryInstruction binInstr, IntValue left, IntValue right |
binInstr = instr and
left = getConstantValue(binInstr.getLeftOperand()) and
right = getConstantValue(binInstr.getRightOperand()) and
(
binInstr instanceof AddInstruction and result = add(left, right) or
binInstr instanceof SubInstruction and result = sub(left, right) or
binInstr instanceof MulInstruction and result = mul(left, right) or
binInstr instanceof DivInstruction and result = div(left, right) or
binInstr instanceof CompareEQInstruction and result = compareEQ(left, right) or
binInstr instanceof CompareNEInstruction and result = compareNE(left, right) or
binInstr instanceof CompareLTInstruction and result = compareLT(left, right) or
binInstr instanceof CompareGTInstruction and result = compareGT(left, right) or
binInstr instanceof CompareLEInstruction and result = compareLE(left, right) or
binInstr instanceof CompareGEInstruction and result = compareGE(left, right)
)
) or
exists(UnaryInstruction unaryInstr, IntValue src |
unaryInstr = instr and
src = getConstantValue(unaryInstr.getOperand()) and
(
unaryInstr instanceof NegateInstruction and result = neg(src)
)
) or
result = getBinaryInstructionValue(instr) or
result = neg(getConstantValue(instr.(NegateInstruction).getOperand())) or
result = getConstantValue(instr.(CopyInstruction).getSourceValue()) or
exists(PhiInstruction phi |
phi = instr and
result = max(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction())) and
result = min(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction()))
result = max(Instruction def | def = phi.getAnOperandDefinitionInstruction() | getConstantValueToPhi(def)) and
result = min(Instruction def | def = phi.getAnOperandDefinitionInstruction() | getConstantValueToPhi(def))
)
}
pragma[noinline]
int getConstantValueToPhi(Instruction def) {
exists(PhiInstruction phi |
result = getConstantValue(def) and
def = phi.getAnOperandDefinitionInstruction()
)
}
pragma[noinline]
private predicate binaryInstructionOperands(BinaryInstruction instr, int left, int right) {
left = getConstantValue(instr.getLeftOperand()) and
right = getConstantValue(instr.getRightOperand())
}
pragma[noinline]
private int getBinaryInstructionValue(BinaryInstruction instr) {
exists(int left, int right |
binaryInstructionOperands(instr, left, right) and
(
instr instanceof AddInstruction and result = add(left, right) or
instr instanceof SubInstruction and result = sub(left, right) or
instr instanceof MulInstruction and result = mul(left, right) or
instr instanceof DivInstruction and result = div(left, right) or
instr instanceof CompareEQInstruction and result = compareEQ(left, right) or
instr instanceof CompareNEInstruction and result = compareNE(left, right) or
instr instanceof CompareLTInstruction and result = compareLT(left, right) or
instr instanceof CompareGTInstruction and result = compareGT(left, right) or
instr instanceof CompareLEInstruction and result = compareLE(left, right) or
instr instanceof CompareGEInstruction and result = compareGE(left, right)
)
)
}

View File

@@ -1484,6 +1484,17 @@ class PhiInstruction extends Instruction {
override final MemoryAccessKind getResultMemoryAccess() {
result instanceof PhiMemoryAccess
}
/**
* Gets an instruction that defines the input to one of the operands of this
* instruction. It's possible for more than one operand to have the same
* defining instruction, so this predicate will have the same number of
* results as `getAnOperand()` or fewer.
*/
pragma[noinline]
final Instruction getAnOperandDefinitionInstruction() {
result = this.getAnOperand().(PhiOperand).getDefinitionInstruction()
}
}
/**
@@ -1492,7 +1503,7 @@ class PhiInstruction extends Instruction {
*
* A `ChiInstruction` is inserted immediately after an instruction that writes to memory. The
* `ChiInstruction` has two operands. The first operand, given by `getTotalOperand()`, represents
* the previous state of all of the memory that might be alised by the memory write. The second
* the previous state of all of the memory that might be aliased by the memory write. The second
* operand, given by `getPartialOperand()`, represents the memory that was actually modified by the
* memory write. The result of the `ChiInstruction` represents the same memory as
* `getTotalOperand()`, updated to include the changes due to the value that was actually stored by

View File

@@ -1,38 +1,49 @@
private import internal.ConstantAnalysisInternal
import semmle.code.cpp.ir.internal.IntegerConstant
private import semmle.code.cpp.ir.internal.IntegerPartial
private import IR
language[monotonicAggregates]
IntValue getConstantValue(Instruction instr) {
int getConstantValue(Instruction instr) {
result = instr.(IntegerConstantInstruction).getValue().toInt() or
exists(BinaryInstruction binInstr, IntValue left, IntValue right |
binInstr = instr and
left = getConstantValue(binInstr.getLeftOperand()) and
right = getConstantValue(binInstr.getRightOperand()) and
(
binInstr instanceof AddInstruction and result = add(left, right) or
binInstr instanceof SubInstruction and result = sub(left, right) or
binInstr instanceof MulInstruction and result = mul(left, right) or
binInstr instanceof DivInstruction and result = div(left, right) or
binInstr instanceof CompareEQInstruction and result = compareEQ(left, right) or
binInstr instanceof CompareNEInstruction and result = compareNE(left, right) or
binInstr instanceof CompareLTInstruction and result = compareLT(left, right) or
binInstr instanceof CompareGTInstruction and result = compareGT(left, right) or
binInstr instanceof CompareLEInstruction and result = compareLE(left, right) or
binInstr instanceof CompareGEInstruction and result = compareGE(left, right)
)
) or
exists(UnaryInstruction unaryInstr, IntValue src |
unaryInstr = instr and
src = getConstantValue(unaryInstr.getOperand()) and
(
unaryInstr instanceof NegateInstruction and result = neg(src)
)
) or
result = getBinaryInstructionValue(instr) or
result = neg(getConstantValue(instr.(NegateInstruction).getOperand())) or
result = getConstantValue(instr.(CopyInstruction).getSourceValue()) or
exists(PhiInstruction phi |
phi = instr and
result = max(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction())) and
result = min(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction()))
result = max(Instruction def | def = phi.getAnOperandDefinitionInstruction() | getConstantValueToPhi(def)) and
result = min(Instruction def | def = phi.getAnOperandDefinitionInstruction() | getConstantValueToPhi(def))
)
}
pragma[noinline]
int getConstantValueToPhi(Instruction def) {
exists(PhiInstruction phi |
result = getConstantValue(def) and
def = phi.getAnOperandDefinitionInstruction()
)
}
pragma[noinline]
private predicate binaryInstructionOperands(BinaryInstruction instr, int left, int right) {
left = getConstantValue(instr.getLeftOperand()) and
right = getConstantValue(instr.getRightOperand())
}
pragma[noinline]
private int getBinaryInstructionValue(BinaryInstruction instr) {
exists(int left, int right |
binaryInstructionOperands(instr, left, right) and
(
instr instanceof AddInstruction and result = add(left, right) or
instr instanceof SubInstruction and result = sub(left, right) or
instr instanceof MulInstruction and result = mul(left, right) or
instr instanceof DivInstruction and result = div(left, right) or
instr instanceof CompareEQInstruction and result = compareEQ(left, right) or
instr instanceof CompareNEInstruction and result = compareNE(left, right) or
instr instanceof CompareLTInstruction and result = compareLT(left, right) or
instr instanceof CompareGTInstruction and result = compareGT(left, right) or
instr instanceof CompareLEInstruction and result = compareLE(left, right) or
instr instanceof CompareGEInstruction and result = compareGE(left, right)
)
)
}

View File

@@ -1,11 +1,10 @@
private import ReachableBlockInternal
private import semmle.code.cpp.ir.internal.IntegerConstant
private import IR
private import ConstantAnalysis
predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) {
exists(int conditionValue |
conditionValue = getValue(getConstantValue(instr.(ConditionalBranchInstruction).getCondition())) and
conditionValue = getConstantValue(instr.(ConditionalBranchInstruction).getCondition()) and
if conditionValue = 0 then
kind instanceof TrueEdge
else

View File

@@ -1484,6 +1484,17 @@ class PhiInstruction extends Instruction {
override final MemoryAccessKind getResultMemoryAccess() {
result instanceof PhiMemoryAccess
}
/**
* Gets an instruction that defines the input to one of the operands of this
* instruction. It's possible for more than one operand to have the same
* defining instruction, so this predicate will have the same number of
* results as `getAnOperand()` or fewer.
*/
pragma[noinline]
final Instruction getAnOperandDefinitionInstruction() {
result = this.getAnOperand().(PhiOperand).getDefinitionInstruction()
}
}
/**
@@ -1492,7 +1503,7 @@ class PhiInstruction extends Instruction {
*
* A `ChiInstruction` is inserted immediately after an instruction that writes to memory. The
* `ChiInstruction` has two operands. The first operand, given by `getTotalOperand()`, represents
* the previous state of all of the memory that might be alised by the memory write. The second
* the previous state of all of the memory that might be aliased by the memory write. The second
* operand, given by `getPartialOperand()`, represents the memory that was actually modified by the
* memory write. The result of the `ChiInstruction` represents the same memory as
* `getTotalOperand()`, updated to include the changes due to the value that was actually stored by

View File

@@ -1,38 +1,49 @@
private import internal.ConstantAnalysisInternal
import semmle.code.cpp.ir.internal.IntegerConstant
private import semmle.code.cpp.ir.internal.IntegerPartial
private import IR
language[monotonicAggregates]
IntValue getConstantValue(Instruction instr) {
int getConstantValue(Instruction instr) {
result = instr.(IntegerConstantInstruction).getValue().toInt() or
exists(BinaryInstruction binInstr, IntValue left, IntValue right |
binInstr = instr and
left = getConstantValue(binInstr.getLeftOperand()) and
right = getConstantValue(binInstr.getRightOperand()) and
(
binInstr instanceof AddInstruction and result = add(left, right) or
binInstr instanceof SubInstruction and result = sub(left, right) or
binInstr instanceof MulInstruction and result = mul(left, right) or
binInstr instanceof DivInstruction and result = div(left, right) or
binInstr instanceof CompareEQInstruction and result = compareEQ(left, right) or
binInstr instanceof CompareNEInstruction and result = compareNE(left, right) or
binInstr instanceof CompareLTInstruction and result = compareLT(left, right) or
binInstr instanceof CompareGTInstruction and result = compareGT(left, right) or
binInstr instanceof CompareLEInstruction and result = compareLE(left, right) or
binInstr instanceof CompareGEInstruction and result = compareGE(left, right)
)
) or
exists(UnaryInstruction unaryInstr, IntValue src |
unaryInstr = instr and
src = getConstantValue(unaryInstr.getOperand()) and
(
unaryInstr instanceof NegateInstruction and result = neg(src)
)
) or
result = getBinaryInstructionValue(instr) or
result = neg(getConstantValue(instr.(NegateInstruction).getOperand())) or
result = getConstantValue(instr.(CopyInstruction).getSourceValue()) or
exists(PhiInstruction phi |
phi = instr and
result = max(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction())) and
result = min(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction()))
result = max(Instruction def | def = phi.getAnOperandDefinitionInstruction() | getConstantValueToPhi(def)) and
result = min(Instruction def | def = phi.getAnOperandDefinitionInstruction() | getConstantValueToPhi(def))
)
}
pragma[noinline]
int getConstantValueToPhi(Instruction def) {
exists(PhiInstruction phi |
result = getConstantValue(def) and
def = phi.getAnOperandDefinitionInstruction()
)
}
pragma[noinline]
private predicate binaryInstructionOperands(BinaryInstruction instr, int left, int right) {
left = getConstantValue(instr.getLeftOperand()) and
right = getConstantValue(instr.getRightOperand())
}
pragma[noinline]
private int getBinaryInstructionValue(BinaryInstruction instr) {
exists(int left, int right |
binaryInstructionOperands(instr, left, right) and
(
instr instanceof AddInstruction and result = add(left, right) or
instr instanceof SubInstruction and result = sub(left, right) or
instr instanceof MulInstruction and result = mul(left, right) or
instr instanceof DivInstruction and result = div(left, right) or
instr instanceof CompareEQInstruction and result = compareEQ(left, right) or
instr instanceof CompareNEInstruction and result = compareNE(left, right) or
instr instanceof CompareLTInstruction and result = compareLT(left, right) or
instr instanceof CompareGTInstruction and result = compareGT(left, right) or
instr instanceof CompareLEInstruction and result = compareLE(left, right) or
instr instanceof CompareGEInstruction and result = compareGE(left, right)
)
)
}

View File

@@ -1,11 +1,10 @@
private import ReachableBlockInternal
private import semmle.code.cpp.ir.internal.IntegerConstant
private import IR
private import ConstantAnalysis
predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) {
exists(int conditionValue |
conditionValue = getValue(getConstantValue(instr.(ConditionalBranchInstruction).getCondition())) and
conditionValue = getConstantValue(instr.(ConditionalBranchInstruction).getCondition()) and
if conditionValue = 0 then
kind instanceof TrueEdge
else

View File

@@ -0,0 +1,134 @@
/**
* Provides basic arithmetic operations that have no result if their result
* would overflow a 32-bit two's complement integer.
*/
/**
* Gets the value of the maximum representable integer.
*/
int maxValue() {
result = 2147483647
}
/**
* Gets the value of the minimum representable integer.
*/
int minValue() {
result = -2147483648
}
/**
* Holds if the value `f` is within the range of representable integers.
*/
pragma[inline]
bindingset[f]
private predicate isRepresentable(float f) {
(f >= minValue()) and (f <= maxValue())
}
/**
* Returns `a + b`. If the addition overflows, there is no result.
*/
bindingset[a, b]
int add(int a, int b) {
isRepresentable((float)a + (float)b) and
result = a + b
}
/**
* Returns `a - b`. If the subtraction overflows, there is no result.
*/
bindingset[a, b]
int sub(int a, int b) {
isRepresentable((float)a - (float)b) and
result = a - b
}
/**
* Returns `a * b`. If the multiplication overflows, there is no result. If
* either input is not given, and the other input is non-zero, there is no
* result.
*/
bindingset[a, b]
int mul(int a, int b) {
a = 0 and
result = 0
or
b = 0 and
result = 0
or
isRepresentable((float)a * (float)b) and
result = a * b
}
/**
* Returns `a / b`. If the division overflows, there is no result.
*/
bindingset[a, b]
int div(int a, int b) {
b != 0 and (a != minValue() or b != -1) and
result = a / b
}
/** Returns `a == b`. */
bindingset[a, b]
int compareEQ(int a, int b) {
if a = b then
result = 1
else
result = 0
}
/** Returns `a != b`. */
bindingset[a, b]
int compareNE(int a, int b) {
if a != b then
result = 1
else
result = 0
}
/** Returns `a < b`. */
bindingset[a, b]
int compareLT(int a, int b) {
if a < b then
result = 1
else
result = 0
}
/** Returns `a > b`. */
bindingset[a, b]
int compareGT(int a, int b) {
if a > b then
result = 1
else
result = 0
}
/** Returns `a <= b`. */
bindingset[a, b]
int compareLE(int a, int b) {
if a <= b then
result = 1
else
result = 0
}
/** Returns `a >= b`. */
bindingset[a, b]
int compareGE(int a, int b) {
if a >= b then
result = 1
else
result = 0
}
/**
* Returns `-a`. If the negation would overflow, there is no result.
*/
bindingset[a]
int neg(int a) {
a != minValue() and
result = -a
}