Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 422b272

Browse files
alexmarkovCommit Queue
authored and
Commit Queue
committed
Essential CFG IR instructions
Issue: #61635 Change-Id: I7de7c4a3bd7008c03c81243c73a71c2018ab7c70 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/459382 Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Slava Egorov <vegorov@google.com>
1 parent 8210d84 commit 422b272

File tree

7 files changed

+2415
-0
lines changed

7 files changed

+2415
-0
lines changed

‎pkg/cfg/lib/ir/constant_value.dart‎

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:cfg/ir/instructions.dart';
6+
import 'package:cfg/ir/global_context.dart';
7+
import 'package:cfg/ir/types.dart';
8+
import 'package:cfg/utils/misc.dart';
9+
import 'package:kernel/ast.dart' as ast;
10+
import 'package:kernel/src/printer.dart' as ast_printer show AstPrinter;
11+
import 'package:kernel/type_environment.dart' show StaticTypeContext;
12+
13+
/// Represents an arbitrary constant value.
14+
///
15+
/// [ConstantValue] is a thin wrapper around [ast.Constant].
16+
/// Constants which do not have corresponding representation in AST
17+
/// (e.g. constant type arguments) have dedicated subclasses of
18+
/// [ast.AuxiliaryConstant].
19+
extension type ConstantValue(ast.Constant constant) {
20+
factory ConstantValue.fromInt(int value) =>
21+
ConstantValue(ast.IntConstant(value));
22+
factory ConstantValue.fromDouble(double value) =>
23+
ConstantValue(ast.DoubleConstant(value));
24+
factory ConstantValue.fromBool(bool value) =>
25+
ConstantValue(ast.BoolConstant(value));
26+
factory ConstantValue.fromNull() => ConstantValue(ast.NullConstant());
27+
factory ConstantValue.fromString(String value) =>
28+
ConstantValue(ast.StringConstant(value));
29+
30+
int get intValue => (constant as ast.IntConstant).value;
31+
double get doubleValue => (constant as ast.DoubleConstant).value;
32+
bool get boolValue => (constant as ast.BoolConstant).value;
33+
String get stringValue => (constant as ast.StringConstant).value;
34+
35+
bool get isInt => constant is ast.IntConstant;
36+
bool get isDouble => constant is ast.DoubleConstant;
37+
bool get isBool => constant is ast.BoolConstant;
38+
bool get isNull => constant is ast.NullConstant;
39+
bool get isString => constant is ast.StringConstant;
40+
41+
CType get type => switch (constant) {
42+
ast.IntConstant() => const IntType(),
43+
ast.DoubleConstant() => const DoubleType(),
44+
ast.BoolConstant() => const BoolType(),
45+
ast.NullConstant() => const NullType(),
46+
ast.StringConstant() => const StringType(),
47+
TypeArgumentsConstant() => const TypeArgumentsType(),
48+
_ => StaticType(
49+
constant.getType(GlobalContext.instance.staticTypeContextForConstants),
50+
),
51+
};
52+
53+
bool get isZero => switch (constant) {
54+
ast.IntConstant(:var value) => value == 0,
55+
ast.DoubleConstant(:var value) => value == 0.0,
56+
_ => false,
57+
};
58+
59+
bool get isNegative => switch (constant) {
60+
ast.IntConstant(:var value) => value < 0,
61+
ast.DoubleConstant(:var value) => value.isNegative,
62+
_ => false,
63+
};
64+
65+
String valueToString() => switch (constant) {
66+
ast.StringConstant(:var value) => '"${value}"',
67+
ast.PrimitiveConstant(:var value) => value.toString(),
68+
_ => constant.toString(),
69+
};
70+
}
71+
72+
/// Utility class to perform operations on constant values.
73+
///
74+
/// Methods of this class return `null` when constant folding
75+
/// cannot be performed (e.g. corresponding operation would
76+
/// throw an exception at runtime).
77+
class ConstantFolding {
78+
const ConstantFolding();
79+
80+
ConstantValue comparison(
81+
ComparisonOpcode op,
82+
ConstantValue left,
83+
ConstantValue right,
84+
) {
85+
final result = switch (op) {
86+
ComparisonOpcode.equal => left.constant == right.constant,
87+
ComparisonOpcode.notEqual => left.constant != right.constant,
88+
ComparisonOpcode.identical => left.constant == right.constant,
89+
ComparisonOpcode.notIdentical => left.constant != right.constant,
90+
ComparisonOpcode.intEqual => left.intValue == right.intValue,
91+
ComparisonOpcode.intNotEqual => left.intValue != right.intValue,
92+
ComparisonOpcode.intLess => left.intValue < right.intValue,
93+
ComparisonOpcode.intLessOrEqual => left.intValue <= right.intValue,
94+
ComparisonOpcode.intGreater => left.intValue > right.intValue,
95+
ComparisonOpcode.intGreaterOrEqual => left.intValue >= right.intValue,
96+
ComparisonOpcode.intTestIsZero => (left.intValue & right.intValue) == 0,
97+
ComparisonOpcode.intTestIsNotZero =>
98+
(left.intValue & right.intValue) != 0,
99+
ComparisonOpcode.doubleEqual => left.doubleValue == right.doubleValue,
100+
ComparisonOpcode.doubleNotEqual => left.doubleValue != right.doubleValue,
101+
ComparisonOpcode.doubleLess => left.doubleValue < right.doubleValue,
102+
ComparisonOpcode.doubleLessOrEqual =>
103+
left.doubleValue <= right.doubleValue,
104+
ComparisonOpcode.doubleGreater => left.doubleValue > right.doubleValue,
105+
ComparisonOpcode.doubleGreaterOrEqual =>
106+
left.doubleValue >= right.doubleValue,
107+
};
108+
return ConstantValue.fromBool(result);
109+
}
110+
111+
ConstantValue? binaryIntOp(
112+
BinaryIntOpcode op,
113+
ConstantValue left,
114+
ConstantValue right,
115+
) {
116+
final a = left.intValue;
117+
final b = right.intValue;
118+
switch (op) {
119+
case BinaryIntOpcode.add:
120+
return ConstantValue.fromInt(a + b);
121+
case BinaryIntOpcode.sub:
122+
return ConstantValue.fromInt(a - b);
123+
case BinaryIntOpcode.mul:
124+
return ConstantValue.fromInt(a * b);
125+
case BinaryIntOpcode.truncatingDiv:
126+
return (b != 0) ? ConstantValue.fromInt(a ~/ b) : null;
127+
case BinaryIntOpcode.mod:
128+
return (b != 0) ? ConstantValue.fromInt(a % b) : null;
129+
case BinaryIntOpcode.rem:
130+
return (b != 0) ? ConstantValue.fromInt(a.remainder(b)) : null;
131+
case BinaryIntOpcode.bitOr:
132+
return ConstantValue.fromInt(a | b);
133+
case BinaryIntOpcode.bitAnd:
134+
return ConstantValue.fromInt(a & b);
135+
case BinaryIntOpcode.bitXor:
136+
return ConstantValue.fromInt(a ^ b);
137+
case BinaryIntOpcode.shiftLeft:
138+
return (b >= 0) ? ConstantValue.fromInt(a << b) : null;
139+
case BinaryIntOpcode.shiftRight:
140+
return (b >= 0) ? ConstantValue.fromInt(a >> b) : null;
141+
case BinaryIntOpcode.unsignedShiftRight:
142+
return (b >= 0) ? ConstantValue.fromInt(a >>> b) : null;
143+
}
144+
}
145+
146+
ConstantValue? unaryIntOp(UnaryIntOpcode op, ConstantValue operand) {
147+
final x = operand.intValue;
148+
switch (op) {
149+
case UnaryIntOpcode.neg:
150+
return ConstantValue.fromInt(-x);
151+
case UnaryIntOpcode.bitNot:
152+
return ConstantValue.fromInt(~x);
153+
case UnaryIntOpcode.toDouble:
154+
return ConstantValue.fromDouble(x.toDouble());
155+
case UnaryIntOpcode.abs:
156+
return ConstantValue.fromInt(x.abs());
157+
case UnaryIntOpcode.sign:
158+
return ConstantValue.fromInt(x.sign);
159+
}
160+
}
161+
162+
ConstantValue? binaryDoubleOp(
163+
BinaryDoubleOpcode op,
164+
ConstantValue left,
165+
ConstantValue right,
166+
) {
167+
final a = left.doubleValue;
168+
final b = right.doubleValue;
169+
switch (op) {
170+
case BinaryDoubleOpcode.add:
171+
return ConstantValue.fromDouble(a + b);
172+
case BinaryDoubleOpcode.sub:
173+
return ConstantValue.fromDouble(a - b);
174+
case BinaryDoubleOpcode.mul:
175+
return ConstantValue.fromDouble(a * b);
176+
case BinaryDoubleOpcode.mod:
177+
return ConstantValue.fromDouble(a % b);
178+
case BinaryDoubleOpcode.rem:
179+
return ConstantValue.fromDouble(a.remainder(b));
180+
case BinaryDoubleOpcode.div:
181+
return ConstantValue.fromDouble(a / b);
182+
case BinaryDoubleOpcode.truncatingDiv:
183+
final doubleResult = a / b;
184+
return doubleResult.isFinite
185+
? ConstantValue.fromInt(doubleResult.truncate())
186+
: null;
187+
}
188+
}
189+
190+
ConstantValue? unaryDoubleOp(UnaryDoubleOpcode op, ConstantValue operand) {
191+
final x = operand.doubleValue;
192+
switch (op) {
193+
case UnaryDoubleOpcode.neg:
194+
return ConstantValue.fromDouble(-x);
195+
case UnaryDoubleOpcode.abs:
196+
return ConstantValue.fromDouble(x.abs());
197+
case UnaryDoubleOpcode.sign:
198+
return ConstantValue.fromDouble(x.sign);
199+
case UnaryDoubleOpcode.square:
200+
return ConstantValue.fromDouble(x * x);
201+
case UnaryDoubleOpcode.round:
202+
return x.isFinite ? ConstantValue.fromInt(x.round()) : null;
203+
case UnaryDoubleOpcode.floor:
204+
return x.isFinite ? ConstantValue.fromInt(x.floor()) : null;
205+
case UnaryDoubleOpcode.ceil:
206+
return x.isFinite ? ConstantValue.fromInt(x.ceil()) : null;
207+
case UnaryDoubleOpcode.truncate:
208+
return x.isFinite ? ConstantValue.fromInt(x.truncate()) : null;
209+
case UnaryDoubleOpcode.roundToDouble:
210+
return ConstantValue.fromDouble(x.roundToDouble());
211+
case UnaryDoubleOpcode.floorToDouble:
212+
return ConstantValue.fromDouble(x.floorToDouble());
213+
case UnaryDoubleOpcode.ceilToDouble:
214+
return ConstantValue.fromDouble(x.ceilToDouble());
215+
case UnaryDoubleOpcode.truncateToDouble:
216+
return ConstantValue.fromDouble(x.truncateToDouble());
217+
}
218+
}
219+
}
220+
221+
/// Constant type arguments.
222+
class TypeArgumentsConstant extends ast.AuxiliaryConstant {
223+
final List<ast.DartType> types;
224+
225+
TypeArgumentsConstant(this.types);
226+
227+
@override
228+
void visitChildren(ast.Visitor v) {
229+
ast.visitList(types, v);
230+
}
231+
232+
@override
233+
void toTextInternal(ast_printer.AstPrinter printer) {
234+
printer.writeTypeArguments(types);
235+
}
236+
237+
@override
238+
String toString() => toStringInternal();
239+
240+
@override
241+
int get hashCode => listHashCode(types);
242+
243+
@override
244+
bool operator ==(Object other) {
245+
return other is TypeArgumentsConstant &&
246+
listEquals(this.types, other.types);
247+
}
248+
249+
@override
250+
ast.DartType getType(StaticTypeContext context) => const ast.DynamicType();
251+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /