Commit aa89fd3b3e

Andrew Kelley <superjoe30@gmail.com>
2016-04-12 07:41:26
eval: ability to eval more things
1 parent fa60548
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, &param_val)) return true;
+        eval_const_expr_implicit_cast(cast_op, &param_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