Skip to content

Commit f12ebe8

Browse files
committed
Revert "C++: Replace SkippableInstruction with local flow steps."
This reverts commit 258d041. This change caused a ~20% performance regression.
1 parent 84f1b11 commit f12ebe8

File tree

2 files changed

+66
-51
lines changed

2 files changed

+66
-51
lines changed

cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,24 @@ private class ArrayToPointerConvertInstruction extends ConvertInstruction {
346346
}
347347
}
348348

349+
/**
350+
* These two predicates look like copy-paste from the two predicates with the same name in DataFlowUtil,
351+
* but crucially they only skip past `CopyValueInstruction`s. This is because we use a special case of
352+
* a `ConvertInstruction` to detect some read steps from arrays that undergoes array-to-pointer
353+
* conversion.
354+
*/
355+
private Instruction skipOneCopyValueInstructionRec(CopyValueInstruction copy) {
356+
copy.getUnary() = result and not result instanceof CopyValueInstruction
357+
or
358+
result = skipOneCopyValueInstructionRec(copy.getUnary())
359+
}
360+
361+
private Instruction skipCopyValueInstructions(Operand op) {
362+
not result instanceof CopyValueInstruction and result = op.getDef()
363+
or
364+
result = skipOneCopyValueInstructionRec(op.getDef())
365+
}
366+
349367
private class InexactLoadOperand extends LoadOperand {
350368
InexactLoadOperand() { this.isDefinitionInexact() }
351369
}

cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll

Lines changed: 48 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -185,15 +185,54 @@ class OperandNode extends Node, TOperandNode {
185185
override string toString() { result = this.getOperand().toString() }
186186
}
187187

188+
/** An abstract class that defines conversion-like instructions. */
189+
abstract private class SkippableInstruction extends Instruction {
190+
abstract Instruction getSourceInstruction();
191+
}
192+
193+
/**
194+
* Gets the instruction that is propaged through a non-empty sequence of conversion-like instructions.
195+
*/
196+
private Instruction skipSkippableInstructionsRec(SkippableInstruction skip) {
197+
result = skip.getSourceInstruction() and not result instanceof SkippableInstruction
198+
or
199+
result = skipSkippableInstructionsRec(skip.getSourceInstruction())
200+
}
201+
202+
/**
203+
* Gets the instruction that is propagated through a (possibly empty) sequence of conversion-like
204+
* instructions.
205+
*/
206+
private Instruction skipSkippableInstructions(Instruction instr) {
207+
result = instr and not result instanceof SkippableInstruction
208+
or
209+
result = skipSkippableInstructionsRec(instr)
210+
}
211+
212+
private class SkippableCopyValueInstruction extends SkippableInstruction, CopyValueInstruction {
213+
override Instruction getSourceInstruction() { result = this.getSourceValue() }
214+
}
215+
216+
private class SkippableConvertInstruction extends SkippableInstruction, ConvertInstruction {
217+
override Instruction getSourceInstruction() { result = this.getUnary() }
218+
}
219+
220+
private class SkippableCheckedConvertInstruction extends SkippableInstruction,
221+
CheckedConvertOrNullInstruction {
222+
override Instruction getSourceInstruction() { result = this.getUnary() }
223+
}
224+
225+
private class SkippableInheritanceConversionInstruction extends SkippableInstruction,
226+
InheritanceConversionInstruction {
227+
override Instruction getSourceInstruction() { result = this.getUnary() }
228+
}
229+
188230
/**
189231
* INTERNAL: do not use. Gets the `FieldNode` corresponding to `instr`, if
190232
* `instr` is an instruction that propagates an address of a `FieldAddressInstruction`.
191233
*/
192234
FieldNode getFieldNodeForFieldInstruction(Instruction instr) {
193-
result.getFieldInstruction() =
194-
any(FieldAddressInstruction fai |
195-
longestRegisterInstructionOperandLocalFlowStep(instructionNode(fai), instructionNode(instr))
196-
)
235+
result.getFieldInstruction() = skipSkippableInstructions(instr)
197236
}
198237

199238
/**
@@ -584,11 +623,6 @@ class VariableNode extends Node, TVariableNode {
584623
*/
585624
InstructionNode instructionNode(Instruction instr) { result.getInstruction() = instr }
586625

587-
/**
588-
* Gets the node corresponding to `operand`.
589-
*/
590-
OperandNode operandNode(Operand operand) { result.getOperand() = operand }
591-
592626
/**
593627
* DEPRECATED: use `definitionByReferenceNodeFromArgument` instead.
594628
*
@@ -706,47 +740,6 @@ private predicate flowIntoReadNode(Node nodeFrom, FieldNode nodeTo) {
706740
)
707741
}
708742

709-
/** Holds if `node` holds an `Instruction` or `Operand` that has a register result. */
710-
private predicate hasRegisterResult(Node node) {
711-
node.asOperand() instanceof RegisterOperand
712-
or
713-
exists(Instruction i | i = node.asInstruction() and not i.hasMemoryResult())
714-
}
715-
716-
/**
717-
* Holds if there is a `Instruction` or `Operand` flow step from `nodeFrom` to `nodeTo` and both
718-
* `nodeFrom` and `nodeTo` wraps register results.
719-
*/
720-
private predicate registerInstructionOperandLocalFlowStep(Node nodeFrom, Node nodeTo) {
721-
hasRegisterResult(nodeFrom) and
722-
hasRegisterResult(nodeTo) and
723-
instructionOperandLocalFlowStep(nodeFrom, nodeTo)
724-
}
725-
726-
/**
727-
* INTERNAL: do not use.
728-
* Holds if `nodeFrom` has no incoming local `Operand` or `Instruction` register flow and `nodeFrom` can
729-
* reach `nodeTo` using only local `Instruction` or `Operand` register flow steps.
730-
*/
731-
bindingset[nodeTo]
732-
private predicate longestRegisterInstructionOperandLocalFlowStep(Node nodeFrom, Node nodeTo) {
733-
registerInstructionOperandLocalFlowStep*(nodeFrom, nodeTo) and
734-
not registerInstructionOperandLocalFlowStep(_, nodeFrom)
735-
}
736-
737-
/**
738-
* INTERNAL: do not use.
739-
* Holds if `nodeFrom` is an operand and `nodeTo` is an instruction node that uses this operand, or
740-
* if `nodeFrom` is an instruction and `nodeTo` is an operand that refers to this instruction.
741-
*/
742-
private predicate instructionOperandLocalFlowStep(Node nodeFrom, Node nodeTo) {
743-
// Operand -> Instruction flow
744-
simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction())
745-
or
746-
// Instruction -> Operand flow
747-
simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand())
748-
}
749-
750743
/**
751744
* INTERNAL: do not use.
752745
*
@@ -755,7 +748,11 @@ private predicate instructionOperandLocalFlowStep(Node nodeFrom, Node nodeTo) {
755748
*/
756749
cached
757750
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
758-
instructionOperandLocalFlowStep(nodeFrom, nodeTo)
751+
// Operand -> Instruction flow
752+
simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction())
753+
or
754+
// Instruction -> Operand flow
755+
simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand())
759756
or
760757
flowIntoReadNode(nodeFrom, nodeTo)
761758
or

0 commit comments

Comments
 (0)