Commit aa89fd3b3e
Changed files (7)
src/all_types.hpp
@@ -65,7 +65,6 @@ struct ConstExprValue {
bool ok; // true if constant expression evalution worked
bool depends_on_compile_var;
bool undef;
- bool deep_const;
union {
BigNum x_bignum;
@@ -961,6 +960,7 @@ struct TypeTableEntry {
LLVMZigDIType *di_type;
bool zero_bits;
+ bool deep_const;
union {
TypeTableEntryPointer pointer;
src/analyze.cpp
@@ -207,6 +207,7 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
static TypeTableEntry *get_generic_fn_type(CodeGen *g, AstNode *decl_node) {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdGenericFn);
buf_init_from_str(&entry->name, "(generic function)");
+ entry->deep_const = true;
entry->zero_bits = true;
entry->data.generic_fn.decl_node = decl_node;
return entry;
@@ -220,6 +221,8 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
} else {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer);
+ entry->deep_const = is_const && child_type->deep_const;
+
const char *const_str = is_const ? "const " : "";
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name));
@@ -261,6 +264,8 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
assert(child_type->type_ref);
assert(child_type->di_type);
+ entry->deep_const = child_type->deep_const;
+
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
@@ -344,6 +349,8 @@ static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
entry->data.error.child_type = child_type;
+ entry->deep_const = child_type->deep_const;
+
if (!type_has_bits(child_type)) {
entry->type_ref = g->err_tag_type->type_ref;
entry->di_type = g->err_tag_type->di_type;
@@ -415,6 +422,7 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray);
entry->type_ref = LLVMArrayType(child_type->type_ref, array_size);
entry->zero_bits = (array_size == 0) || child_type->zero_bits;
+ entry->deep_const = child_type->deep_const;
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "[%" PRIu64 "]%s", array_size, buf_ptr(&child_type->name));
@@ -465,6 +473,8 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c
TypeTableEntry *var_peer = get_slice_type(g, child_type, false);
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
+ entry->deep_const = child_type->deep_const;
+
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "[]const %s", buf_ptr(&child_type->name));
@@ -550,6 +560,7 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *
buf_init_from_str(&entry->name, name);
+ entry->deep_const = child_type->deep_const;
entry->type_ref = child_type->type_ref;
entry->di_type = child_type->di_type;
entry->zero_bits = child_type->zero_bits;
@@ -573,6 +584,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
}
TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
+ fn_type->deep_const = true;
fn_type->data.fn.fn_type_id = *fn_type_id;
if (fn_type_id->param_info == &fn_type_id->prealloc_param_info[0]) {
fn_type->data.fn.fn_type_id.param_info = &fn_type->data.fn.fn_type_id.prealloc_param_info[0];
@@ -1038,6 +1050,8 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
assert(enum_type->di_type);
+ enum_type->deep_const = true;
+
uint32_t field_count = decl_node->data.struct_decl.fields.length;
enum_type->data.enumeration.field_count = field_count;
@@ -1065,6 +1079,10 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
type_enum_field->type_entry = field_type;
type_enum_field->value = i;
+ if (!field_type->deep_const) {
+ enum_type->deep_const = false;
+ }
+
di_enumerators[i] = LLVMZigCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i);
@@ -1225,6 +1243,8 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
assert(struct_type->di_type);
+ struct_type->deep_const = true;
+
int field_count = decl_node->data.struct_decl.fields.length;
struct_type->data.structure.src_field_count = field_count;
@@ -1248,6 +1268,10 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
type_struct_field->src_index = i;
type_struct_field->gen_index = -1;
+ if (!field_type->deep_const) {
+ struct_type->deep_const = false;
+ }
+
if (field_type->id == TypeTableEntryIdStruct) {
resolve_struct_type(g, import, field_type);
} else if (field_type->id == TypeTableEntryIdEnum) {
@@ -2486,7 +2510,6 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i
static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node) {
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
- expr->const_val.deep_const = true;
return g->builtin_types.entry_void;
}
@@ -2494,7 +2517,6 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node,
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_type = type;
- expr->const_val.deep_const = true;
return g->builtin_types.entry_type;
}
@@ -2509,7 +2531,6 @@ static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, F
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_fn = fn;
- expr->const_val.deep_const = true;
return fn->type_entry;
}
@@ -2519,7 +2540,6 @@ static TypeTableEntry *resolve_expr_const_val_as_generic_fn(CodeGen *g, AstNode
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_type = type_entry;
- expr->const_val.deep_const = true;
return type_entry;
}
@@ -2527,7 +2547,6 @@ static TypeTableEntry *resolve_expr_const_val_as_err(CodeGen *g, AstNode *node,
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_err.err = err;
- expr->const_val.deep_const = true;
return g->builtin_types.entry_pure_error;
}
@@ -2538,7 +2557,6 @@ static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node,
expr->const_val.ok = true;
expr->const_val.depends_on_compile_var = depends_on_compile_var;
expr->const_val.data.x_bool = value;
- expr->const_val.deep_const = true;
return g->builtin_types.entry_bool;
}
@@ -2546,7 +2564,6 @@ static TypeTableEntry *resolve_expr_const_val_as_null(CodeGen *g, AstNode *node,
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_maybe = nullptr;
- expr->const_val.deep_const = true;
return type;
}
@@ -2557,14 +2574,12 @@ static TypeTableEntry *resolve_expr_const_val_as_non_null(CodeGen *g, AstNode *n
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_maybe = other_val;
- expr->const_val.deep_const = other_val->deep_const;
return type;
}
static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNode *node, Buf *str) {
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
- expr->const_val.deep_const = true;
int len_with_null = buf_len(str) + 1;
expr->const_val.data.x_ptr.ptr = allocate<ConstExprValue*>(len_with_null);
@@ -2574,14 +2589,12 @@ static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNod
for (int i = 0; i < buf_len(str); i += 1) {
ConstExprValue *this_char = &all_chars[i];
this_char->ok = true;
- this_char->deep_const = true;
bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]);
expr->const_val.data.x_ptr.ptr[i] = this_char;
}
ConstExprValue *null_char = &all_chars[len_with_null - 1];
null_char->ok = true;
- null_char->deep_const = true;
bignum_init_unsigned(&null_char->data.x_bignum, 0);
expr->const_val.data.x_ptr.ptr[len_with_null - 1] = null_char;
@@ -2591,14 +2604,12 @@ static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNod
static TypeTableEntry *resolve_expr_const_val_as_string_lit(CodeGen *g, AstNode *node, Buf *str) {
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
- expr->const_val.deep_const = true;
expr->const_val.data.x_array.fields = allocate<ConstExprValue*>(buf_len(str));
ConstExprValue *all_chars = allocate<ConstExprValue>(buf_len(str));
for (int i = 0; i < buf_len(str); i += 1) {
ConstExprValue *this_char = &all_chars[i];
this_char->ok = true;
- this_char->deep_const = true;
bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]);
expr->const_val.data.x_array.fields[i] = this_char;
}
@@ -2611,7 +2622,6 @@ static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, As
{
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
- expr->const_val.deep_const = true;
bignum_init_unsigned(&expr->const_val.data.x_bignum, x);
@@ -2623,7 +2633,6 @@ static TypeTableEntry *resolve_expr_const_val_as_float_num_lit(CodeGen *g, AstNo
{
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
- expr->const_val.deep_const = true;
bignum_init_float(&expr->const_val.data.x_bignum, x);
@@ -2639,7 +2648,6 @@ static TypeTableEntry *resolve_expr_const_val_as_bignum_op(CodeGen *g, AstNode *
ConstExprValue *op2_val = &get_resolved_expr(op2)->const_val;
const_val->ok = true;
- const_val->deep_const = true;
if (bignum_fn(&const_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum)) {
add_node_error(g, node,
@@ -2713,12 +2721,7 @@ static bool var_is_pure(VariableTableEntry *var, TypeTableEntry *var_type, Block
// variable was declared in the current function, so it's OK.
return true;
}
- if (!var->is_const) {
- return false;
- }
-
- ConstExprValue *const_val = &get_resolved_expr(var->val_node)->const_val;
- return const_val->deep_const;
+ return var->is_const && var->type->deep_const;
}
static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
@@ -3714,17 +3717,6 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import,
node, then_node, else_node, cond_is_const, cond_bool_val);
}
-static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type) {
- assert(int_type->id == TypeTableEntryIdInt);
-
- for (int i = 0; i < CIntTypeCount; i += 1) {
- if (int_type == g->builtin_types.entry_c_int[i]) {
- return true;
- }
- }
- return false;
-}
-
static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node, const char *err_format, bool is_max)
{
@@ -3733,67 +3725,15 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
AstNode *type_node = node->data.fn_call_expr.params.at(0);
TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
+
if (type_entry->id == TypeTableEntryIdInvalid) {
return g->builtin_types.entry_invalid;
- } else if (type_entry->id == TypeTableEntryIdInt) {
- ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
- const_val->ok = true;
- const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry);
- if (is_max) {
- if (type_entry->data.integral.is_signed) {
- int64_t val;
- if (type_entry->data.integral.bit_count == 64) {
- val = INT64_MAX;
- } else if (type_entry->data.integral.bit_count == 32) {
- val = INT32_MAX;
- } else if (type_entry->data.integral.bit_count == 16) {
- val = INT16_MAX;
- } else if (type_entry->data.integral.bit_count == 8) {
- val = INT8_MAX;
- } else {
- zig_unreachable();
- }
- bignum_init_signed(&const_val->data.x_bignum, val);
- } else {
- uint64_t val;
- if (type_entry->data.integral.bit_count == 64) {
- val = UINT64_MAX;
- } else if (type_entry->data.integral.bit_count == 32) {
- val = UINT32_MAX;
- } else if (type_entry->data.integral.bit_count == 16) {
- val = UINT16_MAX;
- } else if (type_entry->data.integral.bit_count == 8) {
- val = UINT8_MAX;
- } else {
- zig_unreachable();
- }
- bignum_init_unsigned(&const_val->data.x_bignum, val);
- }
- } else {
- if (type_entry->data.integral.is_signed) {
- int64_t val;
- if (type_entry->data.integral.bit_count == 64) {
- val = INT64_MIN;
- } else if (type_entry->data.integral.bit_count == 32) {
- val = INT32_MIN;
- } else if (type_entry->data.integral.bit_count == 16) {
- val = INT16_MIN;
- } else if (type_entry->data.integral.bit_count == 8) {
- val = INT8_MIN;
- } else {
- zig_unreachable();
- }
- bignum_init_signed(&const_val->data.x_bignum, val);
- } else {
- bignum_init_unsigned(&const_val->data.x_bignum, 0);
- }
- }
- return type_entry;
- } else if (type_entry->id == TypeTableEntryIdFloat) {
- zig_panic("TODO analyze_min_max_value float");
+ } else if (type_entry->id == TypeTableEntryIdInt ||
+ type_entry->id == TypeTableEntryIdFloat ||
+ type_entry->id == TypeTableEntryIdBool)
+ {
+ eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max);
return type_entry;
- } else if (type_entry->id == TypeTableEntryIdBool) {
- return resolve_expr_const_val_as_bool(g, node, is_max, false);
} else {
add_node_error(g, node,
buf_sprintf(err_format, buf_ptr(&type_entry->name)));
@@ -3810,7 +3750,8 @@ static TypeTableEntry *resolve_cast(CodeGen *g, BlockContext *context, AstNode *
TypeTableEntry *other_type = get_resolved_expr(expr_node)->type_entry;
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
if (other_val->ok) {
- eval_const_expr_implicit_cast(node->data.fn_call_expr.cast_op, other_val, other_type, const_val);
+ eval_const_expr_implicit_cast(node->data.fn_call_expr.cast_op, other_val, other_type,
+ const_val, wanted_type);
}
if (need_alloca) {
@@ -4238,8 +4179,6 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
}
case BuiltinFnIdMemcpy:
{
- mark_impure_fn(context);
-
AstNode *dest_node = node->data.fn_call_expr.params.at(0);
AstNode *src_node = node->data.fn_call_expr.params.at(1);
AstNode *len_node = node->data.fn_call_expr.params.at(2);
@@ -4278,8 +4217,6 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
}
case BuiltinFnIdMemset:
{
- mark_impure_fn(context);
-
AstNode *dest_node = node->data.fn_call_expr.params.at(0);
AstNode *char_node = node->data.fn_call_expr.params.at(1);
AstNode *len_node = node->data.fn_call_expr.params.at(2);
@@ -4601,6 +4538,8 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
// calling an impure fn is impure
mark_impure_fn(context);
}
+ } else {
+ mark_impure_fn(context);
}
if (handle_is_ptr(return_type)) {
@@ -5602,6 +5541,10 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
param_decl_node->data.param_decl.variable = var;
var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index;
+
+ if (!type->deep_const) {
+ fn_table_entry->is_pure = false;
+ }
}
TypeTableEntry *expected_type = fn_type->data.fn.fn_type_id.return_type;
src/bignum.cpp
@@ -71,6 +71,11 @@ bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed) {
}
}
+void bignum_truncate(BigNum *bn, int bit_count) {
+ assert(bn->kind == BigNumKindInt);
+ bn->data.x_uint &= (1LL << bit_count) - 1;
+}
+
uint64_t bignum_to_twos_complement(BigNum *bn) {
assert(bn->kind == BigNumKindInt);
src/bignum.hpp
@@ -47,6 +47,8 @@ void bignum_negate(BigNum *dest, BigNum *op);
void bignum_cast_to_float(BigNum *dest, BigNum *op);
void bignum_cast_to_int(BigNum *dest, BigNum *op);
+void bignum_truncate(BigNum *dest, int bit_count);
+
// returns the result of the comparison
bool bignum_cmp_eq(BigNum *op1, BigNum *op2);
bool bignum_cmp_neq(BigNum *op1, BigNum *op2);
src/codegen.cpp
@@ -3463,23 +3463,27 @@ static void define_builtin_types(CodeGen *g) {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNamespace);
buf_init_from_str(&entry->name, "(namespace)");
entry->zero_bits = true;
+ entry->deep_const = true;
g->builtin_types.entry_namespace = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitFloat);
buf_init_from_str(&entry->name, "(float literal)");
entry->zero_bits = true;
+ entry->deep_const = true;
g->builtin_types.entry_num_lit_float = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitInt);
buf_init_from_str(&entry->name, "(integer literal)");
entry->zero_bits = true;
+ entry->deep_const = true;
g->builtin_types.entry_num_lit_int = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUndefLit);
buf_init_from_str(&entry->name, "(undefined)");
+ entry->deep_const = true;
g->builtin_types.entry_undef = entry;
}
@@ -3489,6 +3493,7 @@ static void define_builtin_types(CodeGen *g) {
for (;;) {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->type_ref = LLVMIntType(size_in_bits);
+ entry->deep_const = true;
const char u_or_i = is_signed ? 'i' : 'u';
buf_resize(&entry->name, 0);
@@ -3534,6 +3539,7 @@ static void define_builtin_types(CodeGen *g) {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->type_ref = LLVMIntType(size_in_bits);
+ entry->deep_const = true;
buf_init_from_str(&entry->name, info->name);
@@ -3553,6 +3559,7 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool);
entry->type_ref = LLVMInt1Type();
+ entry->deep_const = true;
buf_init_from_str(&entry->name, "bool");
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
@@ -3565,6 +3572,7 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
+ entry->deep_const = true;
entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
buf_init_from_str(&entry->name, "isize");
entry->data.integral.is_signed = true;
@@ -3581,6 +3589,7 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
+ entry->deep_const = true;
entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
buf_init_from_str(&entry->name, "usize");
entry->data.integral.is_signed = false;
@@ -3597,6 +3606,7 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
+ entry->deep_const = true;
entry->type_ref = LLVMFloatType();
buf_init_from_str(&entry->name, "f32");
entry->data.floating.bit_count = 32;
@@ -3612,6 +3622,7 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
+ entry->deep_const = true;
entry->type_ref = LLVMDoubleType();
buf_init_from_str(&entry->name, "f64");
entry->data.floating.bit_count = 64;
@@ -3627,6 +3638,7 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
+ entry->deep_const = true;
entry->type_ref = LLVMX86FP80Type();
buf_init_from_str(&entry->name, "c_long_double");
entry->data.floating.bit_count = 80;
@@ -3642,6 +3654,7 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid);
+ entry->deep_const = true;
entry->type_ref = LLVMVoidType();
entry->zero_bits = true;
buf_init_from_str(&entry->name, "void");
@@ -3654,6 +3667,7 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUnreachable);
+ entry->deep_const = true;
entry->type_ref = LLVMVoidType();
entry->zero_bits = true;
buf_init_from_str(&entry->name, "unreachable");
@@ -3663,6 +3677,7 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMetaType);
+ entry->deep_const = true;
buf_init_from_str(&entry->name, "type");
entry->zero_bits = true;
g->builtin_types.entry_type = entry;
@@ -3685,6 +3700,7 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError);
+ entry->deep_const = true;
buf_init_from_str(&entry->name, "error");
// TODO allow overriding this type and keep track of max value and emit an
@@ -3700,6 +3716,7 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
+ entry->deep_const = true;
entry->zero_bits = true; // only allowed at compile time
buf_init_from_str(&entry->name, "@OS");
uint32_t field_count = target_os_count();
@@ -3725,6 +3742,7 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
+ entry->deep_const = true;
entry->zero_bits = true; // only allowed at compile time
buf_init_from_str(&entry->name, "@Arch");
uint32_t field_count = target_arch_count();
@@ -3756,6 +3774,7 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
+ entry->deep_const = true;
entry->zero_bits = true; // only allowed at compile time
buf_init_from_str(&entry->name, "@Environ");
uint32_t field_count = target_environ_count();
src/eval.cpp
@@ -360,7 +360,7 @@ static bool eval_if_bool_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val
void eval_const_expr_implicit_cast(CastOp cast_op,
ConstExprValue *other_val, TypeTableEntry *other_type,
- ConstExprValue *const_val)
+ ConstExprValue *const_val, TypeTableEntry *new_type)
{
const_val->depends_on_compile_var = other_val->depends_on_compile_var;
const_val->undef = other_val->undef;
@@ -371,9 +371,30 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
zig_unreachable();
case CastOpNoop:
case CastOpWidenOrShorten:
- case CastOpPointerReinterpret:
*const_val = *other_val;
break;
+ case CastOpPointerReinterpret:
+ {
+ TypeTableEntry *other_child_type = other_type->data.pointer.child_type;
+ TypeTableEntry *new_child_type = new_type->data.pointer.child_type;
+
+ if ((other_child_type->id == TypeTableEntryIdInt ||
+ other_child_type->id == TypeTableEntryIdFloat) &&
+ (new_child_type->id == TypeTableEntryIdInt ||
+ new_child_type->id == TypeTableEntryIdFloat))
+ {
+ ConstExprValue **ptr_val = allocate<ConstExprValue*>(1);
+ *ptr_val = other_val->data.x_ptr.ptr[0];
+ const_val->data.x_ptr.ptr = ptr_val;
+ const_val->data.x_ptr.len = 1;
+ const_val->ok = true;
+ const_val->undef = other_val->undef;
+ const_val->depends_on_compile_var = other_val->depends_on_compile_var;
+ } else {
+ zig_panic("TODO");
+ }
+ break;
+ }
case CastOpPtrToInt:
case CastOpIntToPtr:
// can't do it
@@ -435,20 +456,184 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
}
}
+static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type) {
+ assert(int_type->id == TypeTableEntryIdInt);
+
+ for (int i = 0; i < CIntTypeCount; i += 1) {
+ if (int_type == g->builtin_types.entry_c_int[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max) {
+ if (type_entry->id == TypeTableEntryIdInt) {
+ const_val->ok = true;
+ const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry);
+ if (is_max) {
+ if (type_entry->data.integral.is_signed) {
+ int64_t val;
+ if (type_entry->data.integral.bit_count == 64) {
+ val = INT64_MAX;
+ } else if (type_entry->data.integral.bit_count == 32) {
+ val = INT32_MAX;
+ } else if (type_entry->data.integral.bit_count == 16) {
+ val = INT16_MAX;
+ } else if (type_entry->data.integral.bit_count == 8) {
+ val = INT8_MAX;
+ } else {
+ zig_unreachable();
+ }
+ bignum_init_signed(&const_val->data.x_bignum, val);
+ } else {
+ uint64_t val;
+ if (type_entry->data.integral.bit_count == 64) {
+ val = UINT64_MAX;
+ } else if (type_entry->data.integral.bit_count == 32) {
+ val = UINT32_MAX;
+ } else if (type_entry->data.integral.bit_count == 16) {
+ val = UINT16_MAX;
+ } else if (type_entry->data.integral.bit_count == 8) {
+ val = UINT8_MAX;
+ } else {
+ zig_unreachable();
+ }
+ bignum_init_unsigned(&const_val->data.x_bignum, val);
+ }
+ } else {
+ if (type_entry->data.integral.is_signed) {
+ int64_t val;
+ if (type_entry->data.integral.bit_count == 64) {
+ val = INT64_MIN;
+ } else if (type_entry->data.integral.bit_count == 32) {
+ val = INT32_MIN;
+ } else if (type_entry->data.integral.bit_count == 16) {
+ val = INT16_MIN;
+ } else if (type_entry->data.integral.bit_count == 8) {
+ val = INT8_MIN;
+ } else {
+ zig_unreachable();
+ }
+ bignum_init_signed(&const_val->data.x_bignum, val);
+ } else {
+ bignum_init_unsigned(&const_val->data.x_bignum, 0);
+ }
+ }
+ } else if (type_entry->id == TypeTableEntryIdFloat) {
+ zig_panic("TODO analyze_min_max_value float");
+ } else if (type_entry->id == TypeTableEntryIdBool) {
+ const_val->ok = true;
+ const_val->data.x_bool = is_max;
+ } else {
+ zig_unreachable();
+ }
+}
+
+static bool eval_min_max(EvalFn *ef, AstNode *node, ConstExprValue *out_val, bool is_max) {
+ assert(node->type == NodeTypeFnCallExpr);
+ AstNode *type_node = node->data.fn_call_expr.params.at(0);
+ TypeTableEntry *type_entry = resolve_expr_type(type_node);
+ eval_min_max_value(ef->root->codegen, type_entry, out_val, is_max);
+ return false;
+}
+
+static bool eval_fn_with_overflow(EvalFn *ef, AstNode *node, ConstExprValue *out_val,
+ bool (*bignum_fn)(BigNum *dest, BigNum *op1, BigNum *op2))
+{
+ assert(node->type == NodeTypeFnCallExpr);
+
+ AstNode *type_node = node->data.fn_call_expr.params.at(0);
+ TypeTableEntry *int_type = resolve_expr_type(type_node);
+ assert(int_type->id == TypeTableEntryIdInt);
+
+ AstNode *op1_node = node->data.fn_call_expr.params.at(1);
+ AstNode *op2_node = node->data.fn_call_expr.params.at(2);
+ AstNode *result_node = node->data.fn_call_expr.params.at(3);
+
+ ConstExprValue op1_val = {0};
+ if (eval_expr(ef, op1_node, &op1_val)) return true;
+
+ ConstExprValue op2_val = {0};
+ if (eval_expr(ef, op2_node, &op2_val)) return true;
+
+ ConstExprValue result_ptr_val = {0};
+ if (eval_expr(ef, result_node, &result_ptr_val)) return true;
+
+ ConstExprValue *result_val = result_ptr_val.data.x_ptr.ptr[0];
+
+ out_val->ok = true;
+ bool overflow = bignum_fn(&result_val->data.x_bignum, &op1_val.data.x_bignum, &op2_val.data.x_bignum);
+
+ overflow = overflow || !bignum_fits_in_bits(&result_val->data.x_bignum,
+ int_type->data.integral.bit_count, int_type->data.integral.is_signed);
+
+ out_val->data.x_bool = overflow;
+
+ if (overflow) {
+ bignum_truncate(&result_val->data.x_bignum, int_type->data.integral.bit_count);
+ }
+
+ return false;
+}
+
+static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
+ assert(node->type == NodeTypeFnCallExpr);
+
+ BuiltinFnEntry *builtin_fn = node->data.fn_call_expr.builtin_fn;
+ switch (builtin_fn->id) {
+ case BuiltinFnIdMaxValue:
+ return eval_min_max(ef, node, out_val, true);
+ case BuiltinFnIdMinValue:
+ return eval_min_max(ef, node, out_val, false);
+ case BuiltinFnIdMulWithOverflow:
+ return eval_fn_with_overflow(ef, node, out_val, bignum_mul);
+ case BuiltinFnIdAddWithOverflow:
+ return eval_fn_with_overflow(ef, node, out_val, bignum_add);
+ case BuiltinFnIdSubWithOverflow:
+ return eval_fn_with_overflow(ef, node, out_val, bignum_sub);
+ case BuiltinFnIdMemcpy:
+ case BuiltinFnIdMemset:
+ case BuiltinFnIdSizeof:
+ case BuiltinFnIdAlignof:
+ case BuiltinFnIdMemberCount:
+ case BuiltinFnIdTypeof:
+ case BuiltinFnIdCInclude:
+ case BuiltinFnIdCDefine:
+ case BuiltinFnIdCUndef:
+ case BuiltinFnIdCompileVar:
+ case BuiltinFnIdConstEval:
+ case BuiltinFnIdCtz:
+ case BuiltinFnIdClz:
+ case BuiltinFnIdImport:
+ case BuiltinFnIdCImport:
+ case BuiltinFnIdErrName:
+ zig_panic("TODO");
+ case BuiltinFnIdBreakpoint:
+ case BuiltinFnIdInvalid:
+ zig_unreachable();
+ }
+
+ return false;
+}
+
static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
assert(node->type == NodeTypeFnCallExpr);
+ AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
CastOp cast_op = node->data.fn_call_expr.cast_op;
if (node->data.fn_call_expr.is_builtin) {
- zig_panic("TODO");
+ return eval_fn_call_builtin(ef, node, out_val);
} else if (cast_op != CastOpNoCast) {
- AstNode *expr_node = node->data.fn_call_expr.params.at(0);
- Expr *expr = get_resolved_expr(expr_node);
- eval_const_expr_implicit_cast(cast_op, &expr->const_val, expr->type_entry, out_val);
+ TypeTableEntry *new_type = resolve_expr_type(fn_ref_expr);
+ AstNode *param_node = node->data.fn_call_expr.params.at(0);
+ TypeTableEntry *old_type = get_resolved_expr(param_node)->type_entry;
+ ConstExprValue param_val = {0};
+ if (eval_expr(ef, param_node, ¶m_val)) return true;
+ eval_const_expr_implicit_cast(cast_op, ¶m_val, old_type, out_val, new_type);
return false;
}
- AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
if (node->data.fn_call_expr.enum_type) {
zig_panic("TODO");
}
@@ -503,7 +688,12 @@ static bool eval_field_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *ou
zig_panic("TODO");
}
} else if (struct_type->id == TypeTableEntryIdMetaType) {
- zig_panic("TODO");
+ TypeTableEntry *child_type = resolve_expr_type(struct_expr);
+ if (child_type->id == TypeTableEntryIdPureError) {
+ *out_val = get_resolved_expr(node)->const_val;
+ } else {
+ zig_panic("TODO");
+ }
} else if (struct_type->id == TypeTableEntryIdNamespace) {
zig_panic("TODO");
} else {
@@ -630,7 +820,6 @@ static bool eval_bool_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *ou
assert(node->type == NodeTypeBoolLiteral);
out_val->ok = true;
- out_val->deep_const = true;
out_val->data.x_bool = node->data.bool_literal.value;
return false;
@@ -640,20 +829,38 @@ static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_v
assert(node->type == NodeTypePrefixOpExpr);
PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op;
+ AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
ConstExprValue expr_val = {0};
- if (eval_expr(ef, node->data.prefix_op_expr.primary_expr, &expr_val)) return true;
+ if (eval_expr(ef, expr_node, &expr_val)) return true;
+
+ TypeTableEntry *expr_type = get_resolved_expr(expr_node)->type_entry;
switch (prefix_op) {
case PrefixOpBoolNot:
*out_val = expr_val;
out_val->data.x_bool = !out_val->data.x_bool;
break;
- case PrefixOpBinNot:
- case PrefixOpNegation:
+ case PrefixOpDereference:
+ assert(expr_type->id == TypeTableEntryIdPointer);
+ *out_val = *expr_val.data.x_ptr.ptr[0];
+ break;
case PrefixOpAddressOf:
case PrefixOpConstAddressOf:
- case PrefixOpDereference:
+ {
+ ConstExprValue *child_val = allocate<ConstExprValue>(1);
+ *child_val = expr_val;
+
+ ConstExprValue **ptr_val = allocate<ConstExprValue*>(1);
+ *ptr_val = child_val;
+
+ out_val->data.x_ptr.ptr = ptr_val;
+ out_val->data.x_ptr.len = 1;
+ out_val->ok = true;
+ break;
+ }
+ case PrefixOpBinNot:
+ case PrefixOpNegation:
case PrefixOpMaybe:
case PrefixOpError:
case PrefixOpUnwrapError:
@@ -666,6 +873,48 @@ static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_v
return false;
}
+static bool eval_var_decl_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
+ assert(node->type == NodeTypeVariableDeclaration);
+
+ assert(node->data.variable_declaration.expr);
+
+ EvalScope *my_scope = ef->scope_stack.at(ef->scope_stack.length - 1);
+
+ my_scope->vars.add_one();
+ EvalVar *var = &my_scope->vars.last();
+ var->name = &node->data.variable_declaration.symbol;
+
+ if (eval_expr(ef, node->data.variable_declaration.expr, &var->value)) return true;
+
+ out_val->ok = true;
+
+ return false;
+}
+
+static bool eval_number_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
+ assert(node->type == NodeTypeNumberLiteral);
+ assert(!node->data.number_literal.overflow);
+
+ out_val->ok = true;
+ if (node->data.number_literal.kind == NumLitUInt) {
+ bignum_init_unsigned(&out_val->data.x_bignum, node->data.number_literal.data.x_uint);
+ } else if (node->data.number_literal.kind == NumLitFloat) {
+ bignum_init_float(&out_val->data.x_bignum, node->data.number_literal.data.x_float);
+ } else {
+ zig_unreachable();
+ }
+
+ return false;
+}
+
+static bool eval_char_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
+ assert(node->type == NodeTypeCharLiteral);
+
+ out_val->ok = true;
+ bignum_init_unsigned(&out_val->data.x_bignum, node->data.char_literal.value);
+
+ return false;
+}
static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
if (ef->root->branches_used > ef->root->branch_quota) {
@@ -697,6 +946,12 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
return eval_bool_literal_expr(ef, node, out);
case NodeTypePrefixOpExpr:
return eval_prefix_op_expr(ef, node, out);
+ case NodeTypeVariableDeclaration:
+ return eval_var_decl_expr(ef, node, out);
+ case NodeTypeNumberLiteral:
+ return eval_number_literal_expr(ef, node, out);
+ case NodeTypeCharLiteral:
+ return eval_char_literal_expr(ef, node, out);
case NodeTypeRoot:
case NodeTypeFnProto:
case NodeTypeFnDef:
@@ -704,13 +959,10 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
case NodeTypeParamDecl:
case NodeTypeDirective:
case NodeTypeDefer:
- case NodeTypeVariableDeclaration:
case NodeTypeTypeDecl:
case NodeTypeErrorValueDecl:
case NodeTypeUnwrapErrorExpr:
- case NodeTypeNumberLiteral:
case NodeTypeStringLiteral:
- case NodeTypeCharLiteral:
case NodeTypeSliceExpr:
case NodeTypeUse:
case NodeTypeNullLiteral:
src/eval.hpp
@@ -19,6 +19,8 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
void eval_const_expr_implicit_cast(CastOp cast_op,
ConstExprValue *other_val, TypeTableEntry *other_type,
- ConstExprValue *const_val);
+ ConstExprValue *const_val, TypeTableEntry *new_type);
+
+void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max);
#endif