Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 09321ee

Browse files
author
Robert Marsh
committed
C++: refactor escape analysis for performance
1 parent 6f76c13 commit 09321ee

2 files changed

Lines changed: 118 additions & 108 deletions

File tree

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll

Lines changed: 59 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import cpp
33
private import InputIR
44
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
55

6+
private import semmle.code.cpp.models.interfaces.Alias
7+
68
private class IntValue = Ints::IntValue;
79

810
/**
@@ -60,8 +62,18 @@ predicate operandIsConsumedWithoutEscaping(Operand operand) {
6062
// Converting an address to a `bool` does not escape the address.
6163
instr.(ConvertInstruction).getResultType() instanceof BoolType
6264
)
63-
)
65+
) or
66+
// Some standard function arguments never escape
67+
isNeverEscapesArgument(operand)
68+
}
69+
70+
predicate operandEscapesDomain(Operand operand) {
71+
not operandIsConsumedWithoutEscaping(operand) and
72+
not operandIsPropagated(operand, _) and
73+
not isArgumentForParameter(_, operand, _) and
74+
not isOnlyEscapesViaReturnArgument(operand)
6475
}
76+
6577
/**
6678
* If the result of instruction `instr` is an integer constant, returns the
6779
* value of that constant. Otherwise, returns unknown.
@@ -133,58 +145,32 @@ predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
133145
// offset of the field.
134146
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
135147
// A copy propagates the source value.
136-
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
137-
)
138-
)
139-
}
140-
141-
/**
142-
* Holds if any address held in operand number `tag` of instruction `instr`
143-
* escapes outside the domain of the analysis.
144-
*/
145-
predicate operandEscapes(Operand operand) {
146-
// Conservatively assume that the address escapes unless one of the following
147-
// holds:
148-
not (
149-
// The operand is used in a way that does not escape the instruction
150-
operandIsConsumedWithoutEscaping(operand) or
151-
// The address is propagated to the result of the instruction, but that
152-
// result does not itself escape.
153-
operandIsPropagated(operand, _) and not resultEscapes(operand.getUseInstruction())
154-
or
155-
// The operand is used in a function call from which the operand does not escape
156-
exists(CallInstruction ci, Instruction init |
157-
ci = operand.getUseInstruction() and
158-
isArgumentForParameter(ci, operand, init) and
159-
not resultEscapesNonReturn(init) and
160-
(
161-
not resultReturned(init)
162-
or
163-
not resultEscapes(operand.getUseInstruction())
164-
)
148+
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0 or
149+
// Some functions are known to propagate an argument
150+
isAlwaysReturnedArgument(operand) and bitOffset = 0
165151
)
166152
)
167153
}
168154

169155
predicate operandEscapesNonReturn(Operand operand) {
170-
// Conservatively assume that the address escapes unless one of the following
171-
// holds:
172-
not (
173-
// The operand is used in a way that does not escape the instruction
174-
operandIsConsumedWithoutEscaping(operand) or
175-
// The address is propagated to the result of the instruction, but that
176-
// result does not itself escape.
177-
operandIsPropagated(operand, _) and
178-
not resultEscapesNonReturn(operand.getUseInstruction())
179-
or
180-
// The operand is used in a function call from which the operand does not escape
181-
exists(CallInstruction ci, Instruction init |
182-
isArgumentForParameter(ci, operand, init) and
183-
not resultEscapesNonReturn(init) and
184-
not resultEscapesNonReturn(ci)
185-
) or
186-
operand.getUseInstruction() instanceof ReturnValueInstruction
156+
// The address is propagated to the result of the instruction, and that result itself is returned
157+
operandIsPropagated(operand, _) and resultEscapesNonReturn(operand.getUseInstruction())
158+
or
159+
// The operand is used in a function call which returns it, and the return value is then returned
160+
exists(CallInstruction ci, Instruction init |
161+
ci = operand.getUseInstruction() and
162+
isArgumentForParameter(ci, operand, init) and
163+
(
164+
resultReturned(init) and
165+
resultEscapesNonReturn(ci)
166+
or
167+
resultEscapesNonReturn(init)
168+
)
187169
)
170+
or
171+
isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUseInstruction())
172+
or
173+
operandEscapesDomain(operand)
188174
}
189175

190176

@@ -202,6 +188,8 @@ predicate operandReturned(Operand operand) {
202188
or
203189
// The address is returned
204190
operand.getUseInstruction() instanceof ReturnValueInstruction
191+
or
192+
isOnlyEscapesViaReturnArgument(operand) and resultReturned(operand.getUseInstruction())
205193
}
206194

207195
predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instruction init) {
@@ -215,7 +203,29 @@ predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instructio
215203
init.getEnclosingFunction() = f and
216204
operand instanceof ThisArgumentOperand
217205
) and
218-
not f.isVirtual()
206+
not f.isVirtual() and
207+
not f instanceof AliasFunction
208+
)
209+
}
210+
211+
predicate isAlwaysReturnedArgument(Operand operand) {
212+
exists(AliasFunction f |
213+
f = operand.getUseInstruction().(CallInstruction).getStaticCallTarget() and
214+
f.parameterIsAlwaysReturned(operand.(PositionalArgumentOperand).getIndex())
215+
)
216+
}
217+
218+
predicate isOnlyEscapesViaReturnArgument(Operand operand) {
219+
exists(AliasFunction f |
220+
f = operand.getUseInstruction().(CallInstruction).getStaticCallTarget() and
221+
f.parameterEscapesOnlyViaReturn(operand.(PositionalArgumentOperand).getIndex())
222+
)
223+
}
224+
225+
predicate isNeverEscapesArgument(Operand operand) {
226+
exists(AliasFunction f |
227+
f = operand.getUseInstruction().(CallInstruction).getStaticCallTarget() and
228+
f.parameterNeverEscapes(operand.(PositionalArgumentOperand).getIndex())
219229
)
220230
}
221231

@@ -227,12 +237,7 @@ predicate resultReturned(Instruction instr) {
227237
* Holds if any address held in the result of instruction `instr` escapes
228238
* outside the domain of the analysis.
229239
*/
230-
predicate resultEscapes(Instruction instr) {
231-
// The result escapes if it has at least one use that escapes.
232-
operandEscapes(instr.getAUse())
233-
}
234-
235-
predicate resultEscapesNonReturn(Instruction instr) {
240+
predicate resultEscapesNonReturn(Instruction instr) {
236241
// The result escapes if it has at least one use that escapes.
237242
operandEscapesNonReturn(instr.getAUse())
238243
}

cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll

Lines changed: 59 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import cpp
33
private import InputIR
44
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
55

6+
private import semmle.code.cpp.models.interfaces.Alias
7+
68
private class IntValue = Ints::IntValue;
79

810
/**
@@ -60,8 +62,18 @@ predicate operandIsConsumedWithoutEscaping(Operand operand) {
6062
// Converting an address to a `bool` does not escape the address.
6163
instr.(ConvertInstruction).getResultType() instanceof BoolType
6264
)
63-
)
65+
) or
66+
// Some standard function arguments never escape
67+
isNeverEscapesArgument(operand)
68+
}
69+
70+
predicate operandEscapesDomain(Operand operand) {
71+
not operandIsConsumedWithoutEscaping(operand) and
72+
not operandIsPropagated(operand, _) and
73+
not isArgumentForParameter(_, operand, _) and
74+
not isOnlyEscapesViaReturnArgument(operand)
6475
}
76+
6577
/**
6678
* If the result of instruction `instr` is an integer constant, returns the
6779
* value of that constant. Otherwise, returns unknown.
@@ -133,58 +145,32 @@ predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
133145
// offset of the field.
134146
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
135147
// A copy propagates the source value.
136-
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
137-
)
138-
)
139-
}
140-
141-
/**
142-
* Holds if any address held in operand number `tag` of instruction `instr`
143-
* escapes outside the domain of the analysis.
144-
*/
145-
predicate operandEscapes(Operand operand) {
146-
// Conservatively assume that the address escapes unless one of the following
147-
// holds:
148-
not (
149-
// The operand is used in a way that does not escape the instruction
150-
operandIsConsumedWithoutEscaping(operand) or
151-
// The address is propagated to the result of the instruction, but that
152-
// result does not itself escape.
153-
operandIsPropagated(operand, _) and not resultEscapes(operand.getUseInstruction())
154-
or
155-
// The operand is used in a function call from which the operand does not escape
156-
exists(CallInstruction ci, Instruction init |
157-
ci = operand.getUseInstruction() and
158-
isArgumentForParameter(ci, operand, init) and
159-
not resultEscapesNonReturn(init) and
160-
(
161-
not resultReturned(init)
162-
or
163-
not resultEscapes(operand.getUseInstruction())
164-
)
148+
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0 or
149+
// Some functions are known to propagate an argument
150+
isAlwaysReturnedArgument(operand) and bitOffset = 0
165151
)
166152
)
167153
}
168154

169155
predicate operandEscapesNonReturn(Operand operand) {
170-
// Conservatively assume that the address escapes unless one of the following
171-
// holds:
172-
not (
173-
// The operand is used in a way that does not escape the instruction
174-
operandIsConsumedWithoutEscaping(operand) or
175-
// The address is propagated to the result of the instruction, but that
176-
// result does not itself escape.
177-
operandIsPropagated(operand, _) and
178-
not resultEscapesNonReturn(operand.getUseInstruction())
179-
or
180-
// The operand is used in a function call from which the operand does not escape
181-
exists(CallInstruction ci, Instruction init |
182-
isArgumentForParameter(ci, operand, init) and
183-
not resultEscapesNonReturn(init) and
184-
not resultEscapesNonReturn(ci)
185-
) or
186-
operand.getUseInstruction() instanceof ReturnValueInstruction
156+
// The address is propagated to the result of the instruction, and that result itself is returned
157+
operandIsPropagated(operand, _) and resultEscapesNonReturn(operand.getUseInstruction())
158+
or
159+
// The operand is used in a function call which returns it, and the return value is then returned
160+
exists(CallInstruction ci, Instruction init |
161+
ci = operand.getUseInstruction() and
162+
isArgumentForParameter(ci, operand, init) and
163+
(
164+
resultReturned(init) and
165+
resultEscapesNonReturn(ci)
166+
or
167+
resultEscapesNonReturn(init)
168+
)
187169
)
170+
or
171+
isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUseInstruction())
172+
or
173+
operandEscapesDomain(operand)
188174
}
189175

190176

@@ -202,6 +188,8 @@ predicate operandReturned(Operand operand) {
202188
or
203189
// The address is returned
204190
operand.getUseInstruction() instanceof ReturnValueInstruction
191+
or
192+
isOnlyEscapesViaReturnArgument(operand) and resultReturned(operand.getUseInstruction())
205193
}
206194

207195
predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instruction init) {
@@ -215,7 +203,29 @@ predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instructio
215203
init.getEnclosingFunction() = f and
216204
operand instanceof ThisArgumentOperand
217205
) and
218-
not f.isVirtual()
206+
not f.isVirtual() and
207+
not f instanceof AliasFunction
208+
)
209+
}
210+
211+
predicate isAlwaysReturnedArgument(Operand operand) {
212+
exists(AliasFunction f |
213+
f = operand.getUseInstruction().(CallInstruction).getStaticCallTarget() and
214+
f.parameterIsAlwaysReturned(operand.(PositionalArgumentOperand).getIndex())
215+
)
216+
}
217+
218+
predicate isOnlyEscapesViaReturnArgument(Operand operand) {
219+
exists(AliasFunction f |
220+
f = operand.getUseInstruction().(CallInstruction).getStaticCallTarget() and
221+
f.parameterEscapesOnlyViaReturn(operand.(PositionalArgumentOperand).getIndex())
222+
)
223+
}
224+
225+
predicate isNeverEscapesArgument(Operand operand) {
226+
exists(AliasFunction f |
227+
f = operand.getUseInstruction().(CallInstruction).getStaticCallTarget() and
228+
f.parameterNeverEscapes(operand.(PositionalArgumentOperand).getIndex())
219229
)
220230
}
221231

@@ -227,12 +237,7 @@ predicate resultReturned(Instruction instr) {
227237
* Holds if any address held in the result of instruction `instr` escapes
228238
* outside the domain of the analysis.
229239
*/
230-
predicate resultEscapes(Instruction instr) {
231-
// The result escapes if it has at least one use that escapes.
232-
operandEscapes(instr.getAUse())
233-
}
234-
235-
predicate resultEscapesNonReturn(Instruction instr) {
240+
predicate resultEscapesNonReturn(Instruction instr) {
236241
// The result escapes if it has at least one use that escapes.
237242
operandEscapesNonReturn(instr.getAUse())
238243
}

0 commit comments

Comments
 (0)