Skip to content

Commit 70c4473

Browse files
author
Dave Bartolomeo
authored
Merge pull request #8445 from dbartol/dbartol/ir-range/semantic-scratch
Sign, Modulus, and Range analysis for C++ using sharable semantic layer
2 parents a274af2 + e2396a5 commit 70c4473

29 files changed

+3785
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import SemanticExpr
2+
import SemanticBound
3+
import SemanticSSA
4+
import SemanticGuard
5+
import SemanticCFG
6+
import SemanticType
7+
import SemanticOpcode
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* Semantic wrapper around the language-specific bounds library.
3+
*/
4+
5+
private import SemanticExpr
6+
private import SemanticExprSpecific::SemanticExprConfig as Specific
7+
private import SemanticSSA
8+
9+
/**
10+
* A valid base for an expression bound.
11+
*
12+
* Can be either a variable (`SemSsaBound`) or zero (`SemZeroBound`).
13+
*/
14+
class SemBound instanceof Specific::Bound {
15+
final string toString() { result = super.toString() }
16+
17+
final SemExpr getExpr(int delta) { result = Specific::getBoundExpr(this, delta) }
18+
}
19+
20+
/**
21+
* A bound that is a constant zero.
22+
*/
23+
class SemZeroBound extends SemBound {
24+
SemZeroBound() { Specific::zeroBound(this) }
25+
}
26+
27+
/**
28+
* A bound that is an SSA definition.
29+
*/
30+
class SemSsaBound extends SemBound {
31+
/**
32+
* The variables whose value is used as the bound.
33+
*
34+
* Can be multi-valued in some implementations. If so, all variables will be equivalent.
35+
*/
36+
SemSsaVariable var;
37+
38+
SemSsaBound() { Specific::ssaBound(this, var) }
39+
40+
/** Gets a variable whose value is used as the bound. */
41+
final SemSsaVariable getAVariable() { result = var }
42+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Semantic interface to the control flow graph.
3+
*/
4+
5+
private import Semantic
6+
private import SemanticExprSpecific::SemanticExprConfig as Specific
7+
8+
/**
9+
* A basic block in the control-flow graph.
10+
*/
11+
class SemBasicBlock extends Specific::BasicBlock {
12+
/** Holds if this block (transitively) dominates `otherblock`. */
13+
final predicate bbDominates(SemBasicBlock otherBlock) { Specific::bbDominates(this, otherBlock) }
14+
15+
/** Holds if this block has dominance information. */
16+
final predicate hasDominanceInformation() { Specific::hasDominanceInformation(this) }
17+
18+
/** Gets an expression that is evaluated in this basic block. */
19+
final SemExpr getAnExpr() { result.getBasicBlock() = this }
20+
21+
final int getUniqueId() { result = Specific::getBasicBlockUniqueId(this) }
22+
}
Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
/**
2+
* Semantic interface for expressions.
3+
*/
4+
5+
private import Semantic
6+
private import SemanticExprSpecific::SemanticExprConfig as Specific
7+
8+
/**
9+
* An language-neutral expression.
10+
*
11+
* The expression computes a value of type `getSemType()`. The actual computation is determined by
12+
* the expression's opcode (`getOpcode()`).
13+
*/
14+
class SemExpr instanceof Specific::Expr {
15+
final string toString() { result = super.toString() }
16+
17+
final Specific::Location getLocation() { result = super.getLocation() }
18+
19+
Opcode getOpcode() { result instanceof Opcode::Unknown }
20+
21+
SemType getSemType() { result = Specific::getUnknownExprType(this) }
22+
23+
final SemBasicBlock getBasicBlock() { result = Specific::getExprBasicBlock(this) }
24+
}
25+
26+
/** An expression with an opcode other than `Unknown`. */
27+
abstract private class SemKnownExpr extends SemExpr {
28+
Opcode opcode;
29+
SemType type;
30+
31+
final override Opcode getOpcode() { result = opcode }
32+
33+
final override SemType getSemType() { result = type }
34+
}
35+
36+
/** An expression that returns a literal value. */
37+
class SemLiteralExpr extends SemKnownExpr {
38+
SemLiteralExpr() {
39+
Specific::integerLiteral(this, type, _) and opcode instanceof Opcode::Constant
40+
or
41+
Specific::largeIntegerLiteral(this, type, _) and opcode instanceof Opcode::Constant
42+
or
43+
Specific::booleanLiteral(this, type, _) and opcode instanceof Opcode::Constant
44+
or
45+
Specific::floatingPointLiteral(this, type, _) and opcode instanceof Opcode::Constant
46+
or
47+
Specific::nullLiteral(this, type) and opcode instanceof Opcode::Constant
48+
or
49+
Specific::stringLiteral(this, type, _) and opcode instanceof Opcode::StringConstant
50+
}
51+
}
52+
53+
/** An expression that returns a numeric literal value. */
54+
class SemNumericLiteralExpr extends SemLiteralExpr {
55+
SemNumericLiteralExpr() {
56+
Specific::integerLiteral(this, _, _)
57+
or
58+
Specific::largeIntegerLiteral(this, _, _)
59+
or
60+
Specific::floatingPointLiteral(this, _, _)
61+
}
62+
63+
/**
64+
* Gets an approximation of the value of the literal, as a `float`.
65+
*
66+
* If the value can be precisely represented as a `float`, the result will be exact. If the actual
67+
* value cannot be precisely represented (for example, it is an integer with more than 53
68+
* significant bits), then the result is an approximation.
69+
*/
70+
float getApproximateFloatValue() { none() }
71+
}
72+
73+
/** An expression that returns an integer literal value. */
74+
class SemIntegerLiteralExpr extends SemNumericLiteralExpr {
75+
SemIntegerLiteralExpr() {
76+
Specific::integerLiteral(this, _, _)
77+
or
78+
Specific::largeIntegerLiteral(this, _, _)
79+
}
80+
81+
/**
82+
* Gets the value of the literal, if it can be represented as an `int`.
83+
*
84+
* If the value is outside the range of an `int`, use `getApproximateFloatValue()` to get a value
85+
* that is equal to the actual integer value, within rounding error.
86+
*/
87+
final int getIntValue() { Specific::integerLiteral(this, _, result) }
88+
89+
final override float getApproximateFloatValue() {
90+
result = getIntValue()
91+
or
92+
Specific::largeIntegerLiteral(this, _, result)
93+
}
94+
}
95+
96+
/**
97+
* An expression that returns a floating-point literal value.
98+
*/
99+
class SemFloatingPointLiteralExpr extends SemNumericLiteralExpr {
100+
float value;
101+
102+
SemFloatingPointLiteralExpr() { Specific::floatingPointLiteral(this, _, value) }
103+
104+
final override float getApproximateFloatValue() { result = value }
105+
106+
/** Gets the value of the literal. */
107+
final float getFloatValue() { result = value }
108+
}
109+
110+
/**
111+
* An expression that consumes two operands.
112+
*/
113+
class SemBinaryExpr extends SemKnownExpr {
114+
SemExpr leftOperand;
115+
SemExpr rightOperand;
116+
117+
SemBinaryExpr() { Specific::binaryExpr(this, opcode, type, leftOperand, rightOperand) }
118+
119+
/** Gets the left operand. */
120+
final SemExpr getLeftOperand() { result = leftOperand }
121+
122+
/** Gets the right operand. */
123+
final SemExpr getRightOperand() { result = rightOperand }
124+
125+
/** Holds if `a` and `b` are the two operands, in either order. */
126+
final predicate hasOperands(SemExpr a, SemExpr b) {
127+
a = getLeftOperand() and b = getRightOperand()
128+
or
129+
a = getRightOperand() and b = getLeftOperand()
130+
}
131+
132+
/** Gets the two operands. */
133+
final SemExpr getAnOperand() { result = getLeftOperand() or result = getRightOperand() }
134+
}
135+
136+
/** An expression that performs and ordered comparison of two operands. */
137+
class SemRelationalExpr extends SemBinaryExpr {
138+
SemRelationalExpr() {
139+
opcode instanceof Opcode::CompareLT
140+
or
141+
opcode instanceof Opcode::CompareLE
142+
or
143+
opcode instanceof Opcode::CompareGT
144+
or
145+
opcode instanceof Opcode::CompareGE
146+
}
147+
148+
/**
149+
* Get the operand that will be less than the other operand if the result of the comparison is
150+
* `true`.
151+
*
152+
* For `x < y` or `x <= y`, this will return `x`.
153+
* For `x > y` or `x >= y`, this will return `y`.`
154+
*/
155+
final SemExpr getLesserOperand() {
156+
if opcode instanceof Opcode::CompareLT or opcode instanceof Opcode::CompareLE
157+
then result = getLeftOperand()
158+
else result = getRightOperand()
159+
}
160+
161+
/**
162+
* Get the operand that will be greater than the other operand if the result of the comparison is
163+
* `true`.
164+
*
165+
* For `x < y` or `x <= y`, this will return `y`.
166+
* For `x > y` or `x >= y`, this will return `x`.`
167+
*/
168+
final SemExpr getGreaterOperand() {
169+
if opcode instanceof Opcode::CompareGT or opcode instanceof Opcode::CompareGE
170+
then result = getLeftOperand()
171+
else result = getRightOperand()
172+
}
173+
174+
/** Holds if this comparison returns `false` if the two operands are equal. */
175+
final predicate isStrict() {
176+
opcode instanceof Opcode::CompareLT or opcode instanceof Opcode::CompareGT
177+
}
178+
}
179+
180+
class SemAddExpr extends SemBinaryExpr {
181+
SemAddExpr() { opcode instanceof Opcode::Add }
182+
}
183+
184+
class SemSubExpr extends SemBinaryExpr {
185+
SemSubExpr() { opcode instanceof Opcode::Sub }
186+
}
187+
188+
class SemMulExpr extends SemBinaryExpr {
189+
SemMulExpr() { opcode instanceof Opcode::Mul }
190+
}
191+
192+
class SemDivExpr extends SemBinaryExpr {
193+
SemDivExpr() { opcode instanceof Opcode::Div }
194+
}
195+
196+
class SemRemExpr extends SemBinaryExpr {
197+
SemRemExpr() { opcode instanceof Opcode::Rem }
198+
}
199+
200+
class SemShiftLeftExpr extends SemBinaryExpr {
201+
SemShiftLeftExpr() { opcode instanceof Opcode::ShiftLeft }
202+
}
203+
204+
class SemShiftRightExpr extends SemBinaryExpr {
205+
SemShiftRightExpr() { opcode instanceof Opcode::ShiftRight }
206+
}
207+
208+
class SemShiftRightUnsignedExpr extends SemBinaryExpr {
209+
SemShiftRightUnsignedExpr() { opcode instanceof Opcode::ShiftRightUnsigned }
210+
}
211+
212+
class SemBitAndExpr extends SemBinaryExpr {
213+
SemBitAndExpr() { opcode instanceof Opcode::BitAnd }
214+
}
215+
216+
class SemBitOrExpr extends SemBinaryExpr {
217+
SemBitOrExpr() { opcode instanceof Opcode::BitOr }
218+
}
219+
220+
class SemBitXorExpr extends SemBinaryExpr {
221+
SemBitXorExpr() { opcode instanceof Opcode::BitXor }
222+
}
223+
224+
class SemUnaryExpr extends SemKnownExpr {
225+
SemExpr operand;
226+
227+
SemUnaryExpr() { Specific::unaryExpr(this, opcode, type, operand) }
228+
229+
final SemExpr getOperand() { result = operand }
230+
}
231+
232+
class SemBoxExpr extends SemUnaryExpr {
233+
SemBoxExpr() { opcode instanceof Opcode::Box }
234+
}
235+
236+
class SemUnboxExpr extends SemUnaryExpr {
237+
SemUnboxExpr() { opcode instanceof Opcode::Unbox }
238+
}
239+
240+
class SemConvertExpr extends SemUnaryExpr {
241+
SemConvertExpr() { opcode instanceof Opcode::Convert }
242+
}
243+
244+
class SemCopyValueExpr extends SemUnaryExpr {
245+
SemCopyValueExpr() { opcode instanceof Opcode::CopyValue }
246+
}
247+
248+
class SemNegateExpr extends SemUnaryExpr {
249+
SemNegateExpr() { opcode instanceof Opcode::Negate }
250+
}
251+
252+
class SemBitComplementExpr extends SemUnaryExpr {
253+
SemBitComplementExpr() { opcode instanceof Opcode::BitComplement }
254+
}
255+
256+
class SemLogicalNotExpr extends SemUnaryExpr {
257+
SemLogicalNotExpr() { opcode instanceof Opcode::LogicalNot }
258+
}
259+
260+
class SemAddOneExpr extends SemUnaryExpr {
261+
SemAddOneExpr() { opcode instanceof Opcode::AddOne }
262+
}
263+
264+
class SemSubOneExpr extends SemUnaryExpr {
265+
SemSubOneExpr() { opcode instanceof Opcode::SubOne }
266+
}
267+
268+
private class SemNullaryExpr extends SemKnownExpr {
269+
SemNullaryExpr() { Specific::nullaryExpr(this, opcode, type) }
270+
}
271+
272+
class SemInitializeParameterExpr extends SemNullaryExpr {
273+
SemInitializeParameterExpr() { opcode instanceof Opcode::InitializeParameter }
274+
}
275+
276+
class SemLoadExpr extends SemNullaryExpr {
277+
SemLoadExpr() { opcode instanceof Opcode::Load }
278+
279+
final SemSsaVariable getDef() { result.getAUse() = this }
280+
}
281+
282+
class SemSsaLoadExpr extends SemLoadExpr {
283+
SemSsaLoadExpr() { exists(getDef()) }
284+
}
285+
286+
class SemNonSsaLoadExpr extends SemLoadExpr {
287+
SemNonSsaLoadExpr() { not exists(getDef()) }
288+
}
289+
290+
class SemStoreExpr extends SemUnaryExpr {
291+
SemStoreExpr() { opcode instanceof Opcode::Store }
292+
}
293+
294+
class SemConditionalExpr extends SemKnownExpr {
295+
SemExpr condition;
296+
SemExpr trueResult;
297+
SemExpr falseResult;
298+
299+
SemConditionalExpr() {
300+
opcode instanceof Opcode::Conditional and
301+
Specific::conditionalExpr(this, type, condition, trueResult, falseResult)
302+
}
303+
304+
final SemExpr getBranchExpr(boolean branch) {
305+
branch = true and result = trueResult
306+
or
307+
branch = false and result = falseResult
308+
}
309+
}

0 commit comments

Comments
 (0)