Skip to content

Commit a0917ae

Browse files
committed
C++: Remove IR re-evaluation.
1 parent 2dc2607 commit a0917ae

4 files changed

Lines changed: 145 additions & 77 deletions

File tree

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ExprNodes.qll

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ private import semmle.code.cpp.ir.IR
77
private import DataFlowUtil
88
private import DataFlowPrivate
99
private import DataFlowNodes
10-
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
11-
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
10+
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
1211

1312
cached
1413
private module Cached {
@@ -74,17 +73,9 @@ private module Cached {
7473
// a result for `getConvertedResultExpression`. We remap this here so that
7574
// this `ConvertInstruction` maps to the result of the expression that
7675
// represents the extent.
77-
exists(TranslatedNonConstantAllocationSize tas |
78-
result = tas.getExtent().getExpr() and
79-
instr = tas.getInstruction(AllocationExtentConvertTag())
80-
)
76+
result = IRConstruction::Raw::getAllocationExtentConvertExpr(instr)
8177
or
82-
// There's no instruction that returns `ParenthesisExpr`, but some queries
83-
// expect this
84-
exists(TranslatedTransparentConversion ttc |
85-
result = ttc.getExpr().(ParenthesisExpr) and
86-
instr = ttc.getResult()
87-
)
78+
result = IRConstruction::Raw::getTransparentConversionParenthesisExpr(instr)
8879
or
8980
// Certain expressions generate `CopyValueInstruction`s only when they
9081
// are needed. Examples of this include crement operations and compound
@@ -113,10 +104,10 @@ private module Cached {
113104
// needed, and in that case the only value that will propagate forward in
114105
// the program is the value that's been updated. So in those cases we just
115106
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
116-
exists(TranslatedCoreExpr tco |
117-
tco.getInstruction(_) = instr and
118-
tco.producesExprResult() and
119-
result = asDefinitionImpl0(instr)
107+
exists(StoreInstruction store |
108+
store = instr and
109+
IRConstruction::Raw::instructionProducesExprResult(store) and
110+
result = asDefinitionImpl0(store)
120111
)
121112
or
122113
// IR construction breaks an array aggregate literal `{1, 2, 3}` into a
@@ -146,18 +137,9 @@ private module Cached {
146137
// For an expression such as `i += 2` we pretend that the generated
147138
// `StoreInstruction` contains the result of the expression even though
148139
// this isn't totally aligned with the C/C++ standard.
149-
exists(TranslatedAssignOperation tao |
150-
store = tao.getInstruction(AssignmentStoreTag()) and
151-
result = tao.getExpr()
152-
)
140+
result = IRConstruction::Raw::getAssignOperationStoreExpr(store)
153141
or
154-
// Similarly for `i++` and `++i` we pretend that the generated
155-
// `StoreInstruction` contains the result of the expression even though
156-
// this isn't totally aligned with the C/C++ standard.
157-
exists(TranslatedCrementOperation tco |
158-
store = tco.getInstruction(CrementStoreTag()) and
159-
result = tco.getExpr()
160-
)
142+
result = IRConstruction::Raw::getCrementOperationStoreExpr(store)
161143
}
162144

163145
/**
@@ -167,11 +149,7 @@ private module Cached {
167149
*/
168150
private predicate excludeAsDefinitionResult(StoreInstruction store) {
169151
// Exclude the store to the temporary generated by a ternary expression.
170-
exists(TranslatedConditionalExpr tce |
171-
store = tce.getInstruction(ConditionValueFalseStoreTag())
172-
or
173-
store = tce.getInstruction(ConditionValueTrueStoreTag())
174-
)
152+
IRConstruction::Raw::isConditionalExprTempStore(store)
175153
}
176154

177155
/**

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImpl.qll

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ private import semmle.code.cpp.models.interfaces.PartialFlow as PartialFlow
1010
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as FIO
1111
private import semmle.code.cpp.ir.internal.IRCppLanguage
1212
private import semmle.code.cpp.ir.dataflow.internal.ModelUtil
13-
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedInitialization
13+
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
1414
private import DataFlowPrivate
1515
private import DataFlowNodes
1616
import SsaImplCommon
@@ -439,10 +439,7 @@ private predicate sourceVariableHasBaseAndIndex(SourceVariable v, BaseSourceVari
439439
* initialize `v`.
440440
*/
441441
private Instruction getInitializationTargetAddress(IRVariable v) {
442-
exists(TranslatedVariableInitialization init |
443-
init.getIRVariable() = v and
444-
result = init.getTargetAddress()
445-
)
442+
result = IRConstruction::Raw::getInitializationTargetAddress(v)
446443
}
447444

448445
/** An initial definition of an SSA variable address. */

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -10,42 +10,6 @@ private import DataFlowPrivate
1010
private import TypeFlow
1111
private import semmle.code.cpp.ir.ValueNumbering
1212

13-
/**
14-
* Holds if `operand` is an operand that is not used by the dataflow library.
15-
* Ignored operands are not recognized as uses by SSA, and they don't have a
16-
* corresponding `(Indirect)OperandNode`.
17-
*/
18-
predicate ignoreOperand(Operand operand) {
19-
operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand() or
20-
operand = any(Instruction instr | ignoreInstruction(instr)).getAUse() or
21-
operand instanceof MemoryOperand
22-
}
23-
24-
/**
25-
* Holds if `instr` is an instruction that is not used by the dataflow library.
26-
* Ignored instructions are not recognized as reads/writes by SSA, and they
27-
* don't have a corresponding `(Indirect)InstructionNode`.
28-
*/
29-
predicate ignoreInstruction(Instruction instr) {
30-
DataFlowImplCommon::forceCachingInSameStage() and
31-
(
32-
instr instanceof CallSideEffectInstruction or
33-
instr instanceof CallReadSideEffectInstruction or
34-
instr instanceof ExitFunctionInstruction or
35-
instr instanceof EnterFunctionInstruction or
36-
instr instanceof WriteSideEffectInstruction or
37-
instr instanceof PhiInstruction or
38-
instr instanceof ReadSideEffectInstruction or
39-
instr instanceof ChiInstruction or
40-
instr instanceof InitializeIndirectionInstruction or
41-
instr instanceof AliasedDefinitionInstruction or
42-
instr instanceof AliasedUseInstruction or
43-
instr instanceof InitializeNonLocalInstruction or
44-
instr instanceof ReturnIndirectionInstruction or
45-
instr instanceof UninitializedGroupInstruction
46-
)
47-
}
48-
4913
/**
5014
* Gets the C++ type of `this` in the member function `f`.
5115
* The result is a glvalue if `isGLValue` is true, and
@@ -328,10 +292,6 @@ predicate isWrite(Node0Impl value, Operand address, boolean certain) {
328292
)
329293
}
330294

331-
predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
332-
any(Indirection ind).isAdditionalConversionFlow(opFrom, instrTo)
333-
}
334-
335295
newtype TBaseSourceVariable =
336296
// Each IR variable gets its own source variable
337297
TBaseIRVariable(IRVariable var) or
@@ -553,6 +513,49 @@ private class BaseCallInstruction extends BaseSourceVariableInstruction, CallIns
553513

554514
cached
555515
private module Cached {
516+
/**
517+
* Holds if `operand` is an operand that is not used by the dataflow library.
518+
* Ignored operands are not recognized as uses by SSA, and they don't have a
519+
* corresponding `(Indirect)OperandNode`.
520+
*/
521+
cached
522+
predicate ignoreOperand(Operand operand) {
523+
operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand() or
524+
operand = any(Instruction instr | ignoreInstruction(instr)).getAUse() or
525+
operand instanceof MemoryOperand
526+
}
527+
528+
/**
529+
* Holds if `instr` is an instruction that is not used by the dataflow library.
530+
* Ignored instructions are not recognized as reads/writes by SSA, and they
531+
* don't have a corresponding `(Indirect)InstructionNode`.
532+
*/
533+
cached
534+
predicate ignoreInstruction(Instruction instr) {
535+
DataFlowImplCommon::forceCachingInSameStage() and
536+
(
537+
instr instanceof CallSideEffectInstruction or
538+
instr instanceof CallReadSideEffectInstruction or
539+
instr instanceof ExitFunctionInstruction or
540+
instr instanceof EnterFunctionInstruction or
541+
instr instanceof WriteSideEffectInstruction or
542+
instr instanceof PhiInstruction or
543+
instr instanceof ReadSideEffectInstruction or
544+
instr instanceof ChiInstruction or
545+
instr instanceof InitializeIndirectionInstruction or
546+
instr instanceof AliasedDefinitionInstruction or
547+
instr instanceof AliasedUseInstruction or
548+
instr instanceof InitializeNonLocalInstruction or
549+
instr instanceof ReturnIndirectionInstruction or
550+
instr instanceof UninitializedGroupInstruction
551+
)
552+
}
553+
554+
cached
555+
predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
556+
any(Indirection ind).isAdditionalConversionFlow(opFrom, instrTo)
557+
}
558+
556559
/**
557560
* Gets the C++ type of the instruction `i`.
558561
*

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ private import TranslatedCall
1515
private import TranslatedStmt
1616
private import TranslatedFunction
1717
private import TranslatedGlobalVar
18+
private import TranslatedInitialization
1819

1920
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
2021
instruction = TRawInstruction(result, _)
@@ -194,6 +195,95 @@ module Raw {
194195
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
195196
result = getInstructionConvertedResultExpression(instruction).getUnconverted()
196197
}
198+
199+
/**
200+
* Gets the expression associated with an allocation extent conversion instruction.
201+
* This maps the intermediate `ConvertInstruction` for `new[]` extents back to
202+
* the extent expression.
203+
*/
204+
cached
205+
Expr getAllocationExtentConvertExpr(Instruction instr) {
206+
exists(TranslatedNonConstantAllocationSize tas |
207+
instr = tas.getInstruction(AllocationExtentConvertTag()) and
208+
result = tas.getExtent().getExpr()
209+
)
210+
}
211+
212+
/**
213+
* Gets the `ParenthesisExpr` associated with a transparent conversion instruction,
214+
* if any.
215+
*/
216+
cached
217+
ParenthesisExpr getTransparentConversionParenthesisExpr(Instruction instr) {
218+
exists(TranslatedTransparentConversion ttc |
219+
result = ttc.getExpr() and
220+
instr = ttc.getResult()
221+
)
222+
}
223+
224+
/**
225+
* Holds if `instr` belongs to a `TranslatedCoreExpr` that produces an
226+
* expression result. This indicates that the instruction represents a
227+
* definition whose result should be mapped back to the expression.
228+
*/
229+
cached
230+
predicate instructionProducesExprResult(Instruction instr) {
231+
exists(TranslatedCoreExpr tco |
232+
tco.getInstruction(_) = instr and
233+
tco.producesExprResult()
234+
)
235+
}
236+
237+
/**
238+
* Gets the expression for an assignment operation store instruction.
239+
* Maps `StoreInstruction`s generated by compound assignment operations
240+
* (e.g., `x += 2`) back to the assignment expression.
241+
*/
242+
cached
243+
Expr getAssignOperationStoreExpr(StoreInstruction store) {
244+
exists(TranslatedAssignOperation tao |
245+
store = tao.getInstruction(AssignmentStoreTag()) and
246+
result = tao.getExpr()
247+
)
248+
}
249+
250+
/**
251+
* Gets the expression for a crement operation store instruction.
252+
* Maps `StoreInstruction`s generated by crement operations
253+
* (e.g., `x++`, `++x`) back to the crement expression.
254+
*/
255+
cached
256+
Expr getCrementOperationStoreExpr(StoreInstruction store) {
257+
exists(TranslatedCrementOperation tco |
258+
store = tco.getInstruction(CrementStoreTag()) and
259+
result = tco.getExpr()
260+
)
261+
}
262+
263+
/**
264+
* Holds if `store` is a temporary store generated by a conditional (ternary)
265+
* expression. Such stores should be excluded from `asDefinition()` results.
266+
*/
267+
cached
268+
predicate isConditionalExprTempStore(StoreInstruction store) {
269+
exists(TranslatedConditionalExpr tce |
270+
store = tce.getInstruction(ConditionValueFalseStoreTag())
271+
or
272+
store = tce.getInstruction(ConditionValueTrueStoreTag())
273+
)
274+
}
275+
276+
/**
277+
* Gets the instruction that computes the address used to initialize
278+
* the IR variable `v`.
279+
*/
280+
cached
281+
Instruction getInitializationTargetAddress(IRVariable v) {
282+
exists(TranslatedVariableInitialization init |
283+
init.getIRVariable() = v and
284+
result = init.getTargetAddress()
285+
)
286+
}
197287
}
198288

199289
class TStageInstruction = TRawInstruction or TRawUnreachedInstruction;

0 commit comments

Comments
 (0)