Skip to content

Commit 9e0c82e

Browse files
authored
Merge pull request #10039 from rdmarsh2/rdmarsh2/cpp/sem-range-analysis-perf
C++: Fix missing bounds and performance issues in semantic range analysis
2 parents 9232b28 + 818bdcf commit 9e0c82e

File tree

5 files changed

+97
-35
lines changed

5 files changed

+97
-35
lines changed

cpp/ql/lib/experimental/semmle/code/cpp/semantic/SemanticExprSpecific.qll

Lines changed: 72 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -119,27 +119,67 @@ module SemanticExprConfig {
119119
result = block.getDisplayIndex()
120120
}
121121

122-
class SsaVariable instanceof IR::Instruction {
123-
SsaVariable() { super.hasMemoryResult() }
122+
newtype TSsaVariable =
123+
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
124+
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() }
124125

125-
final string toString() { result = super.toString() }
126+
class SsaVariable extends TSsaVariable {
127+
string toString() { none() }
126128

127-
final Location getLocation() { result = super.getLocation() }
129+
Location getLocation() { none() }
130+
131+
IR::Instruction asInstruction() { none() }
132+
133+
IR::Operand asOperand() { none() }
128134
}
129135

130-
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) { v = sourceExpr }
136+
class SsaInstructionVariable extends SsaVariable, TSsaInstruction {
137+
IR::Instruction instr;
138+
139+
SsaInstructionVariable() { this = TSsaInstruction(instr) }
140+
141+
final override string toString() { result = instr.toString() }
142+
143+
final override Location getLocation() { result = instr.getLocation() }
131144

132-
predicate phi(SsaVariable v) { v instanceof IR::PhiInstruction }
145+
final override IR::Instruction asInstruction() { result = instr }
146+
}
147+
148+
class SsaOperand extends SsaVariable, TSsaOperand {
149+
IR::Operand op;
150+
151+
SsaOperand() { this = TSsaOperand(op) }
152+
153+
final override string toString() { result = op.toString() }
154+
155+
final override Location getLocation() { result = op.getLocation() }
156+
157+
final override IR::Operand asOperand() { result = op }
158+
}
133159

134-
SsaVariable getAPhiInput(SsaVariable v) { result = v.(IR::PhiInstruction).getAnInput() }
160+
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) { v.asInstruction() = sourceExpr }
135161

136-
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v }
162+
predicate phi(SsaVariable v) { v.asInstruction() instanceof IR::PhiInstruction }
163+
164+
SsaVariable getAPhiInput(SsaVariable v) {
165+
exists(IR::PhiInstruction instr |
166+
result.asInstruction() = instr.getAnInput()
167+
or
168+
result.asOperand() = instr.getAnInputOperand()
169+
)
170+
}
171+
172+
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
137173

138174
SemType getSsaVariableType(SsaVariable v) {
139-
result = getSemanticType(v.(IR::Instruction).getResultIRType())
175+
result = getSemanticType(v.asInstruction().getResultIRType())
140176
}
141177

142-
BasicBlock getSsaVariableBasicBlock(SsaVariable v) { result = v.(IR::Instruction).getBlock() }
178+
BasicBlock getSsaVariableBasicBlock(SsaVariable v) {
179+
result = v.asInstruction().getBlock()
180+
or
181+
result = v.asOperand().getUse().getBlock()
182+
}
143183

144184
private newtype TReadPosition =
145185
TReadPositionBlock(IR::IRBlock block) or
@@ -169,7 +209,9 @@ module SemanticExprConfig {
169209

170210
final override predicate hasRead(SsaVariable v) {
171211
exists(IR::Operand operand |
172-
operand.getDef() = v and not operand instanceof IR::PhiInputOperand
212+
operand.getDef() = v.asInstruction() and
213+
not operand instanceof IR::PhiInputOperand and
214+
operand.getUse().getBlock() = block
173215
)
174216
}
175217
}
@@ -186,7 +228,7 @@ module SemanticExprConfig {
186228

187229
final override predicate hasRead(SsaVariable v) {
188230
exists(IR::PhiInputOperand operand |
189-
operand.getDef() = v and
231+
operand.getDef() = v.asInstruction() and
190232
operand.getPredecessorBlock() = pred and
191233
operand.getUse().getBlock() = succ
192234
)
@@ -205,17 +247,16 @@ module SemanticExprConfig {
205247
exists(IR::PhiInputOperand operand |
206248
pos = TReadPositionPhiInputEdge(operand.getPredecessorBlock(), operand.getUse().getBlock())
207249
|
208-
phi = operand.getUse() and input = operand.getDef()
250+
phi.asInstruction() = operand.getUse() and
251+
(
252+
input.asInstruction() = operand.getDef()
253+
or
254+
input.asOperand() = operand
255+
)
209256
)
210257
}
211258

212259
class Bound instanceof IRBound::Bound {
213-
Bound() {
214-
this instanceof IRBound::ZeroBound
215-
or
216-
this.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction() instanceof SsaVariable
217-
}
218-
219260
string toString() { result = super.toString() }
220261

221262
final Location getLocation() { result = super.getLocation() }
@@ -228,21 +269,21 @@ module SemanticExprConfig {
228269

229270
override string toString() {
230271
result =
231-
min(SsaVariable instr |
232-
instr = bound.getValueNumber().getAnInstruction()
272+
min(SsaVariable v |
273+
v.asInstruction() = bound.getValueNumber().getAnInstruction()
233274
|
234-
instr
275+
v
235276
order by
236-
instr.(IR::Instruction).getBlock().getDisplayIndex(),
237-
instr.(IR::Instruction).getDisplayIndexInBlock()
277+
v.asInstruction().getBlock().getDisplayIndex(),
278+
v.asInstruction().getDisplayIndexInBlock()
238279
).toString()
239280
}
240281
}
241282

242283
predicate zeroBound(Bound bound) { bound instanceof IRBound::ZeroBound }
243284

244285
predicate ssaBound(Bound bound, SsaVariable v) {
245-
v = bound.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction()
286+
v.asInstruction() = bound.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction()
246287
}
247288

248289
Expr getBoundExpr(Bound bound, int delta) {
@@ -284,9 +325,13 @@ SemBasicBlock getSemanticBasicBlock(IR::IRBlock block) { result = block }
284325

285326
IR::IRBlock getCppBasicBlock(SemBasicBlock block) { block = result }
286327

287-
SemSsaVariable getSemanticSsaVariable(IR::Instruction instr) { result = instr }
328+
SemSsaVariable getSemanticSsaVariable(IR::Instruction instr) {
329+
result.(SemanticExprConfig::SsaVariable).asInstruction() = instr
330+
}
288331

289-
IR::Instruction getCppSsaVariableInstruction(SemSsaVariable v) { v = result }
332+
IR::Instruction getCppSsaVariableInstruction(SemSsaVariable var) {
333+
var.(SemanticExprConfig::SsaVariable).asInstruction() = result
334+
}
290335

291336
SemBound getSemanticBound(IRBound::Bound bound) { result = bound }
292337

cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/ModulusAnalysis.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ private predicate phiModulusInit(SemSsaPhiNode phi, SemBound b, int val, int mod
160160
/**
161161
* Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
162162
*/
163+
pragma[nomagic]
163164
private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int mod, int rix) {
164165
rix = 0 and
165166
phiModulusInit(phi, b, val, mod)
@@ -169,7 +170,7 @@ private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int
169170
val = remainder(v1, mod)
170171
|
171172
exists(int v2, int m2 |
172-
rankedPhiInput(phi, inp, edge, rix) and
173+
rankedPhiInput(pragma[only_bind_out](phi), inp, edge, rix) and
173174
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
174175
ssaModulus(inp, edge, b, v2, m2) and
175176
mod = m1.gcd(m2).gcd(v1 - v2)

cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,10 @@ private class ConvertOrBoxExpr extends SemUnaryExpr {
342342
* A cast that can be ignored for the purpose of range analysis.
343343
*/
344344
private class SafeCastExpr extends ConvertOrBoxExpr {
345-
SafeCastExpr() { conversionCannotOverflow(getTrackedType(getOperand()), getTrackedType(this)) }
345+
SafeCastExpr() {
346+
conversionCannotOverflow(getTrackedType(pragma[only_bind_into](getOperand())),
347+
getTrackedType(this))
348+
}
346349
}
347350

348351
/**

cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/SignAnalysisCommon.qll

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,12 @@ private class BinarySignExpr extends FlowSignExpr {
189189
BinarySignExpr() { binary = this }
190190

191191
override Sign getSignRestriction() {
192-
result =
193-
semExprSign(binary.getLeftOperand())
194-
.applyBinaryOp(semExprSign(binary.getRightOperand()), binary.getOpcode())
192+
exists(SemExpr left, SemExpr right |
193+
binaryExprOperands(binary, left, right) and
194+
result =
195+
semExprSign(pragma[only_bind_out](left))
196+
.applyBinaryOp(semExprSign(pragma[only_bind_out](right)), binary.getOpcode())
197+
)
195198
or
196199
exists(SemDivExpr div | div = binary |
197200
result = semExprSign(div.getLeftOperand()) and
@@ -201,6 +204,10 @@ private class BinarySignExpr extends FlowSignExpr {
201204
}
202205
}
203206

207+
private predicate binaryExprOperands(SemBinaryExpr binary, SemExpr left, SemExpr right) {
208+
binary.getLeftOperand() = left and binary.getRightOperand() = right
209+
}
210+
204211
/**
205212
* A `Convert`, `Box`, or `Unbox` expression.
206213
*/
@@ -221,7 +228,7 @@ private class UnarySignExpr extends FlowSignExpr {
221228
UnarySignExpr() { unary = this and not this instanceof SemCastExpr }
222229

223230
override Sign getSignRestriction() {
224-
result = semExprSign(unary.getOperand()).applyUnaryOp(unary.getOpcode())
231+
result = semExprSign(pragma[only_bind_out](unary.getOperand())).applyUnaryOp(unary.getOpcode())
225232
}
226233
}
227234

cpp/ql/test/library-tests/ir/range-analysis/RangeAnalysis.ql

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import cpp
22
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
33
import experimental.semmle.code.cpp.semantic.Semantic
4+
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
45
import semmle.code.cpp.ir.IR as IR
56
import TestUtilities.InlineExpectationsTest
67

@@ -37,8 +38,13 @@ private string getBoundString(SemBound b, int delta) {
3738
b instanceof SemZeroBound and result = delta.toString()
3839
or
3940
result =
40-
strictconcat(b.(SemSsaBound).getAVariable().(IR::Instruction).getAst().toString(), ":") +
41-
getOffsetString(delta)
41+
strictconcat(b.(SemSsaBound)
42+
.getAVariable()
43+
.(SemanticExprConfig::SsaVariable)
44+
.asInstruction()
45+
.getAst()
46+
.toString(), ":"
47+
) + getOffsetString(delta)
4248
}
4349

4450
private string getARangeString(SemExpr e) {

0 commit comments

Comments
 (0)