Skip to content

Commit cc4de28

Browse files
committed
compiler: improve Value handling and expression evaluator
AST values: * add `getValue()` type methods for literal expr nodes, returning a `Value` * add `Value.castAs()` type method * add `ValueKind.Error` for invalid result and evaluation errors * add `Value` factories for unsigned, signed, float, boolean and error Simplify ctv_analyser: * remove hard coded strings in `Limits` array * dispatch to more `getValue()` handlers * improve conversion checker: refine arithmetic operations * use expression evaluator from ast_evaluator for Ctv expressions Expression/Function evaluator: * add statement evaluator * move generator/c/c_generator_pure_call.c2 to ast/ast_evaluator.c2 * add function address to evaluate some external function calls * support indirect pure functions calls including recursive and external Improve C generator: * add `Generator.need_const_expr`, used for static intializers * add `Generator.emitConstExpr()` to force pure function calls evaluation * simplify initializer generation * pass Diags object for code generation errors
1 parent 2e0e65b commit cc4de28

26 files changed

+1159
-613
lines changed

analyser/conversion_checker_expr.c2

Lines changed: 37 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,17 @@ type ExprWidth struct {
2323
bool is_signed;
2424
}
2525

26-
fn ExprWidth ExprWidth.mergeSmaller(ExprWidth* w1, ExprWidth* w2) {
26+
fn ExprWidth ExprWidth.mergeSmaller(ExprWidth w1, ExprWidth w2) {
2727
ExprWidth result;
28-
if (w2.width < w1.width) result.width = w2.width;
29-
else result.width = w1.width;
30-
result.is_signed = w1.is_signed || w2.is_signed;
28+
result.width = (w1.width < w2.width) ? w1.width : w2.width;
29+
result.is_signed = w1.is_signed | w2.is_signed;
3130
return result;
3231
}
3332

34-
fn ExprWidth ExprWidth.mergeWider(ExprWidth* w1, ExprWidth* w2) {
33+
fn ExprWidth ExprWidth.mergeWider(ExprWidth w1, ExprWidth w2) {
3534
ExprWidth result;
36-
if (w2.width > w1.width) result.width = w2.width;
37-
else result.width = w1.width;
38-
result.is_signed = w1.is_signed || w2.is_signed;
35+
result.width = (w1.width > w2.width) ? w1.width : w2.width;
36+
result.is_signed = w1.is_signed | w2.is_signed;
3937
return result;
4038
}
4139

@@ -44,13 +42,8 @@ fn ExprWidth getExprWidth(const Expr* e) {
4442

4543
if (e.isCtv()) {
4644
Value v = ctv_analyser.get_value(e);
47-
if (v.isNegative()) {
48-
result.width = v.getWidth();
49-
result.is_signed = true;
50-
} else {
51-
result.width = v.getWidth();
52-
result.is_signed = false;
53-
}
45+
result.width = v.getWidth();
46+
result.is_signed = v.isNegative();
5447
return result;
5548
}
5649

@@ -63,26 +56,13 @@ fn ExprWidth getExprWidth(const Expr* e) {
6356
case Nil:
6457
break;
6558
case Identifier:
66-
QualType qt = e.getType();
67-
qt = qt.getCanonicalType();
68-
if (qt.isBuiltin()) {
69-
BuiltinType* bi = qt.getBuiltin();
70-
result.width = cast<u8>(bi.getWidth());
71-
result.is_signed = bi.isSigned();
72-
} else {
73-
// pointer or something
74-
result.width = cast<u8>(ast.getWordSize() * 8);
75-
result.is_signed = true;
76-
}
77-
return result;
59+
return getTypeWidth(e.getType());
7860
case Type:
7961
break;
8062
case Call:
8163
return getTypeWidth(e.getType());
8264
case InitList:
83-
break;
8465
case FieldDesignatedInit:
85-
break;
8666
case ArrayDesignatedInit:
8767
break;
8868
case BinaryOperator:
@@ -92,27 +72,19 @@ fn ExprWidth getExprWidth(const Expr* e) {
9272
case ConditionalOperator:
9373
return getCondOpWidth(cast<ConditionalOperator*>(e));
9474
case Builtin:
75+
// TODO ToContainer -> width = 64
9576
break;
9677
case ArraySubscript:
78+
// TODO BitOffset -> specific width
9779
case Member:
98-
QualType qt = e.getType();
99-
qt = qt.getCanonicalType();
100-
if (qt.isPointer()) {
101-
result.width = 64; // TODO or 32
102-
result.is_signed = false;
103-
return result;
104-
}
105-
assert(qt.isBuiltin());
106-
BuiltinType* bi = qt.getBuiltin();
107-
result.width = cast<u8>(bi.getWidth());
108-
result.is_signed = bi.isSigned();
109-
return result;
80+
return getTypeWidth(e.getType());
11081
case Paren:
11182
const ParenExpr* p = cast<ParenExpr*>(e);
11283
return getExprWidth(p.getInner());
11384
case BitOffset:
11485
break;
11586
case ExplicitCast:
87+
// TODO: explicit cast may reduce signed values
11688
QualType qt = e.getType();
11789
qt = qt.getCanonicalType();
11890
assert(qt.isBuiltin());
@@ -127,7 +99,7 @@ fn ExprWidth getExprWidth(const Expr* e) {
12799
RangeExpr* b = cast<RangeExpr*>(e);
128100
ExprWidth lhs = getExprWidth(b.getLHS());
129101
ExprWidth rhs = getExprWidth(b.getRHS());
130-
return ExprWidth.mergeWider(&lhs, &rhs);
102+
return ExprWidth.mergeWider(lhs, rhs);
131103
}
132104

133105
e.dump();
@@ -138,7 +110,7 @@ fn ExprWidth getExprWidth(const Expr* e) {
138110
fn ExprWidth getCondOpWidth(const ConditionalOperator* c) {
139111
ExprWidth lhs = getExprWidth(c.getLHS());
140112
ExprWidth rhs = getExprWidth(c.getRHS());
141-
return ExprWidth.mergeWider(&lhs, &rhs);
113+
return ExprWidth.mergeWider(lhs, rhs);
142114
}
143115

144116
fn ExprWidth getUnaryOpWidth(const UnaryOperator* u) {
@@ -183,37 +155,36 @@ fn ExprWidth getBinOpWidth(const BinaryOperator* b) {
183155
case Multiply:
184156
break;
185157
case Divide:
186-
break;
158+
return getExprWidth(b.getLHS());
187159
case Remainder:
188-
// TODO special
189-
break;
160+
return getExprWidth(b.getRHS());
190161
case Add:
191-
break;
192162
case Subtract:
193163
break;
194164
case ShiftLeft:
195-
break;
165+
ExprWidth result = getExprWidth(b.getLHS());
166+
if (result.width < 31) { result.width = 31; result.is_signed = true; }
167+
return result;
196168
case ShiftRight:
197-
break;
169+
return getExprWidth(b.getLHS());
198170
case LessThan:
199171
case GreaterThan:
200172
case LessEqual:
201173
case GreaterEqual:
202174
case Equal:
203175
case NotEqual:
204-
ExprWidth result = { 1, 0 }
176+
ExprWidth result = { .width = 1, .is_signed = false }
205177
return result;
206178
case And:
207179
ExprWidth l = getExprWidth(b.getLHS());
208180
ExprWidth r = getExprWidth(b.getRHS());
209-
return ExprWidth.mergeSmaller(&l, &r);
181+
return ExprWidth.mergeSmaller(l, r);
210182
case Xor:
211-
break;
212183
case Or:
213184
break;
214185
case LAnd:
215186
case LOr:
216-
ExprWidth result = { 1, 0 }
187+
ExprWidth result = { .width = 1, .is_signed = false }
217188
return result;
218189
case Assign:
219190
case MulAssign:
@@ -226,25 +197,29 @@ fn ExprWidth getBinOpWidth(const BinaryOperator* b) {
226197
case AndAssign:
227198
case XorAssign:
228199
case OrAssign:
200+
// TODO: refine this
229201
return getExprWidth(b.getLHS());
230202
}
231203

232204
ExprWidth lhs = getExprWidth(b.getLHS());
233205
ExprWidth rhs = getExprWidth(b.getRHS());
234-
return ExprWidth.mergeWider(&lhs, &rhs);
206+
return ExprWidth.mergeWider(lhs, rhs);
235207
}
236208

237209
fn ExprWidth getTypeWidth(QualType qt) {
238-
if (qt.isPointer()) {
239-
// TODO or 32
240-
ExprWidth result = { .width = 64, .is_signed = false }
210+
qt = qt.getCanonicalType();
211+
if (qt.isEnum()) {
212+
EnumType* et = qt.getEnumType();
213+
qt = et.getImplType();
214+
}
215+
if (qt.isBuiltin()) {
216+
const BuiltinType* bi = qt.getBuiltin();
217+
ExprWidth result = { .width = cast<u8>(bi.getWidth()), .is_signed = bi.isSigned() }
241218
return result;
242219
}
243-
assert(qt.isBuiltin());
244-
const BuiltinType* bi = qt.getBuiltin();
245-
ExprWidth result;
246-
result.width = cast<u8>(bi.getWidth());
247-
result.is_signed = bi.isSigned();
220+
// pointer or something
221+
// TODO or 32
222+
ExprWidth result = { .width = cast<u8>(ast.getWordSize() * 8), .is_signed = false }
248223
return result;
249224
}
250225

0 commit comments

Comments
 (0)