mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge pull request #882 from jbj/ir-ConstantAnalysis-perf
C++: Speed up IR ConstantAnalysis
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
134
cpp/ql/src/semmle/code/cpp/ir/internal/IntegerPartial.qll
Normal file
134
cpp/ql/src/semmle/code/cpp/ir/internal/IntegerPartial.qll
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user