| author | |
| committer | |
| log | 21fc5a6402c527675900397ea60f107730985f1c |
| tree | 6b94e455082ed74aa0c4da45c0e6f6124b13b60c |
| parent | 1158bc3eadd8127301f96ecb9bcbb04cf04156b8 |
3 files changed, 120 insertions(+), 41 deletions(-)
src/all_types.hpp+12-2| ... | ... | @@ -49,6 +49,16 @@ struct ConstStructValue { |
| 49 | 49 | ConstExprValue **fields; |
| 50 | 50 | }; |
| 51 | 51 | |
| 52 | struct ConstArrayValue { | |
| 53 | ConstExprValue **fields; | |
| 54 | }; | |
| 55 | ||
| 56 | struct ConstPtrValue { | |
| 57 | ConstExprValue **ptr; | |
| 58 | // len should almost always be 1. exceptions include C strings | |
| 59 | uint64_t len; | |
| 60 | }; | |
| 61 | ||
| 52 | 62 | struct ConstExprValue { |
| 53 | 63 | bool ok; // true if constant expression evalution worked |
| 54 | 64 | bool depends_on_compile_var; |
| ... | ... | @@ -61,6 +71,8 @@ struct ConstExprValue { |
| 61 | 71 | ConstExprValue *x_maybe; |
| 62 | 72 | ConstEnumValue x_enum; |
| 63 | 73 | ConstStructValue x_struct; |
| 74 | ConstArrayValue x_array; | |
| 75 | ConstPtrValue x_ptr; | |
| 64 | 76 | } data; |
| 65 | 77 | }; |
| 66 | 78 | |
| ... | ... | @@ -900,7 +912,6 @@ struct CodeGen { |
| 900 | 912 | ZigList<Buf *> lib_search_paths; |
| 901 | 913 | |
| 902 | 914 | // reminder: hash tables must be initialized before use |
| 903 | HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table; | |
| 904 | 915 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table; |
| 905 | 916 | HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table; |
| 906 | 917 | HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table; |
| ... | ... | @@ -924,7 +935,6 @@ struct CodeGen { |
| 924 | 935 | TypeTableEntry *entry_usize; |
| 925 | 936 | TypeTableEntry *entry_f32; |
| 926 | 937 | TypeTableEntry *entry_f64; |
| 927 | TypeTableEntry *entry_c_string_literal; | |
| 928 | 938 | TypeTableEntry *entry_void; |
| 929 | 939 | TypeTableEntry *entry_unreachable; |
| 930 | 940 | TypeTableEntry *entry_type; |
src/analyze.cpp+73-8| ... | ... | @@ -1795,6 +1795,46 @@ static TypeTableEntry *resolve_expr_const_val_as_null(CodeGen *g, AstNode *node, |
| 1795 | 1795 | return type; |
| 1796 | 1796 | } |
| 1797 | 1797 | |
| 1798 | static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNode *node, Buf *str) { | |
| 1799 | Expr *expr = get_resolved_expr(node); | |
| 1800 | expr->const_val.ok = true; | |
| 1801 | ||
| 1802 | int len_with_null = buf_len(str) + 1; | |
| 1803 | expr->const_val.data.x_ptr.ptr = allocate<ConstExprValue*>(len_with_null); | |
| 1804 | expr->const_val.data.x_ptr.len = len_with_null; | |
| 1805 | ||
| 1806 | ConstExprValue *all_chars = allocate<ConstExprValue>(len_with_null); | |
| 1807 | for (int i = 0; i < buf_len(str); i += 1) { | |
| 1808 | ConstExprValue *this_char = &all_chars[i]; | |
| 1809 | this_char->ok = true; | |
| 1810 | bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]); | |
| 1811 | expr->const_val.data.x_ptr.ptr[i] = this_char; | |
| 1812 | } | |
| 1813 | ||
| 1814 | ConstExprValue *null_char = &all_chars[len_with_null - 1]; | |
| 1815 | null_char->ok = true; | |
| 1816 | bignum_init_unsigned(&null_char->data.x_bignum, 0); | |
| 1817 | expr->const_val.data.x_ptr.ptr[len_with_null - 1] = null_char; | |
| 1818 | ||
| 1819 | return get_pointer_to_type(g, g->builtin_types.entry_u8, true); | |
| 1820 | } | |
| 1821 | ||
| 1822 | static TypeTableEntry *resolve_expr_const_val_as_string_lit(CodeGen *g, AstNode *node, Buf *str) { | |
| 1823 | Expr *expr = get_resolved_expr(node); | |
| 1824 | expr->const_val.ok = true; | |
| 1825 | expr->const_val.data.x_array.fields = allocate<ConstExprValue*>(buf_len(str)); | |
| 1826 | ||
| 1827 | ConstExprValue *all_chars = allocate<ConstExprValue>(buf_len(str)); | |
| 1828 | for (int i = 0; i < buf_len(str); i += 1) { | |
| 1829 | ConstExprValue *this_char = &all_chars[i]; | |
| 1830 | this_char->ok = true; | |
| 1831 | bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]); | |
| 1832 | expr->const_val.data.x_array.fields[i] = this_char; | |
| 1833 | } | |
| 1834 | return get_array_type(g, g->builtin_types.entry_u8, buf_len(str)); | |
| 1835 | } | |
| 1836 | ||
| 1837 | ||
| 1798 | 1838 | static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node, |
| 1799 | 1839 | TypeTableEntry *expected_type, uint64_t x) |
| 1800 | 1840 | { |
| ... | ... | @@ -2737,8 +2777,28 @@ static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *ex |
| 2737 | 2777 | *const_val = *other_val; |
| 2738 | 2778 | break; |
| 2739 | 2779 | case CastOpToUnknownSizeArray: |
| 2740 | zig_panic("TODO CastOpToUnknownSizeArray"); | |
| 2741 | break; | |
| 2780 | { | |
| 2781 | TypeTableEntry *other_type = get_resolved_expr(expr_node)->type_entry; | |
| 2782 | assert(other_type->id == TypeTableEntryIdArray); | |
| 2783 | ||
| 2784 | ConstExprValue *all_fields = allocate<ConstExprValue>(2); | |
| 2785 | ConstExprValue *ptr_field = &all_fields[0]; | |
| 2786 | ConstExprValue *len_field = &all_fields[1]; | |
| 2787 | ||
| 2788 | const_val->data.x_struct.fields = allocate<ConstExprValue*>(2); | |
| 2789 | const_val->data.x_struct.fields[0] = ptr_field; | |
| 2790 | const_val->data.x_struct.fields[1] = len_field; | |
| 2791 | ||
| 2792 | ptr_field->ok = true; | |
| 2793 | ptr_field->data.x_ptr.ptr = other_val->data.x_array.fields; | |
| 2794 | ptr_field->data.x_ptr.len = other_type->data.array.len; | |
| 2795 | ||
| 2796 | len_field->ok = true; | |
| 2797 | bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len); | |
| 2798 | ||
| 2799 | const_val->ok = true; | |
| 2800 | break; | |
| 2801 | } | |
| 2742 | 2802 | case CastOpMaybeWrap: |
| 2743 | 2803 | const_val->data.x_maybe = other_val; |
| 2744 | 2804 | const_val->ok = true; |
| ... | ... | @@ -3422,6 +3482,16 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, |
| 3422 | 3482 | return g->builtin_types.entry_unreachable; |
| 3423 | 3483 | } |
| 3424 | 3484 | |
| 3485 | static TypeTableEntry *analyze_string_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | |
| 3486 | TypeTableEntry *expected_type, AstNode *node) | |
| 3487 | { | |
| 3488 | if (node->data.string_literal.c) { | |
| 3489 | return resolve_expr_const_val_as_c_string_lit(g, node, &node->data.string_literal.buf); | |
| 3490 | } else { | |
| 3491 | return resolve_expr_const_val_as_string_lit(g, node, &node->data.string_literal.buf); | |
| 3492 | } | |
| 3493 | } | |
| 3494 | ||
| 3425 | 3495 | // When you call analyze_expression, the node you pass might no longer be the child node |
| 3426 | 3496 | // you thought it was due to implicit casting rewriting the AST. |
| 3427 | 3497 | static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| ... | ... | @@ -3544,12 +3614,7 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 3544 | 3614 | return_type = analyze_error_literal_expr(g, import, context, expected_type, node); |
| 3545 | 3615 | break; |
| 3546 | 3616 | case NodeTypeStringLiteral: |
| 3547 | if (node->data.string_literal.c) { | |
| 3548 | return_type = g->builtin_types.entry_c_string_literal; | |
| 3549 | } else { | |
| 3550 | return_type = get_array_type(g, g->builtin_types.entry_u8, | |
| 3551 | buf_len(&node->data.string_literal.buf)); | |
| 3552 | } | |
| 3617 | return_type = analyze_string_literal_expr(g, import, context, expected_type, node); | |
| 3553 | 3618 | break; |
| 3554 | 3619 | case NodeTypeCharLiteral: |
| 3555 | 3620 | return_type = g->builtin_types.entry_u8; |
src/codegen.cpp+35-31| ... | ... | @@ -19,7 +19,6 @@ |
| 19 | 19 | |
| 20 | 20 | CodeGen *codegen_create(Buf *root_source_dir) { |
| 21 | 21 | CodeGen *g = allocate<CodeGen>(1); |
| 22 | g->str_table.init(32); | |
| 23 | 22 | g->link_table.init(32); |
| 24 | 23 | g->import_table.init(32); |
| 25 | 24 | g->builtin_fn_table.init(32); |
| ... | ... | @@ -92,22 +91,6 @@ static void add_debug_source_node(CodeGen *g, AstNode *node) { |
| 92 | 91 | g->cur_block_context->di_scope); |
| 93 | 92 | } |
| 94 | 93 | |
| 95 | static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) { | |
| 96 | auto entry = g->str_table.maybe_get(str); | |
| 97 | if (entry) { | |
| 98 | return entry->value; | |
| 99 | } | |
| 100 | LLVMValueRef text = LLVMConstString(buf_ptr(str), buf_len(str), !c); | |
| 101 | LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(text), ""); | |
| 102 | LLVMSetLinkage(global_value, LLVMPrivateLinkage); | |
| 103 | LLVMSetInitializer(global_value, text); | |
| 104 | LLVMSetGlobalConstant(global_value, true); | |
| 105 | LLVMSetUnnamedAddr(global_value, true); | |
| 106 | g->str_table.put(str, global_value); | |
| 107 | ||
| 108 | return global_value; | |
| 109 | } | |
| 110 | ||
| 111 | 94 | static TypeTableEntry *get_expr_type(AstNode *node) { |
| 112 | 95 | return get_resolved_expr(node)->type_entry; |
| 113 | 96 | } |
| ... | ... | @@ -1993,17 +1976,6 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 1993 | 1976 | return gen_asm_expr(g, node); |
| 1994 | 1977 | case NodeTypeErrorLiteral: |
| 1995 | 1978 | return gen_error_literal(g, node); |
| 1996 | case NodeTypeStringLiteral: | |
| 1997 | { | |
| 1998 | Buf *str = &node->data.string_literal.buf; | |
| 1999 | LLVMValueRef str_val = find_or_create_string(g, str, node->data.string_literal.c); | |
| 2000 | LLVMValueRef indices[] = { | |
| 2001 | LLVMConstNull(g->builtin_types.entry_isize->type_ref), | |
| 2002 | LLVMConstNull(g->builtin_types.entry_isize->type_ref), | |
| 2003 | }; | |
| 2004 | LLVMValueRef ptr_val = LLVMBuildInBoundsGEP(g->builder, str_val, indices, 2, ""); | |
| 2005 | return ptr_val; | |
| 2006 | } | |
| 2007 | 1979 | case NodeTypeCharLiteral: |
| 2008 | 1980 | return LLVMConstInt(LLVMInt8Type(), node->data.char_literal.value, false); |
| 2009 | 1981 | case NodeTypeSymbol: |
| ... | ... | @@ -2035,6 +2007,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 2035 | 2007 | return gen_switch_expr(g, node); |
| 2036 | 2008 | case NodeTypeNumberLiteral: |
| 2037 | 2009 | case NodeTypeBoolLiteral: |
| 2010 | case NodeTypeStringLiteral: | |
| 2038 | 2011 | // caught by constant expression eval codegen |
| 2039 | 2012 | zig_unreachable(); |
| 2040 | 2013 | case NodeTypeRoot: |
| ... | ... | @@ -2117,7 +2090,14 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE |
| 2117 | 2090 | } |
| 2118 | 2091 | return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count); |
| 2119 | 2092 | } else if (type_entry->id == TypeTableEntryIdArray) { |
| 2120 | zig_panic("TODO"); | |
| 2093 | TypeTableEntry *child_type = type_entry->data.array.child_type; | |
| 2094 | uint64_t len = type_entry->data.array.len; | |
| 2095 | LLVMValueRef *values = allocate<LLVMValueRef>(len); | |
| 2096 | for (int i = 0; i < len; i += 1) { | |
| 2097 | ConstExprValue *field_value = const_val->data.x_array.fields[i]; | |
| 2098 | values[i] = gen_const_val(g, child_type, field_value); | |
| 2099 | } | |
| 2100 | return LLVMConstArray(child_type->type_ref, values, len); | |
| 2121 | 2101 | } else if (type_entry->id == TypeTableEntryIdEnum) { |
| 2122 | 2102 | LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref; |
| 2123 | 2103 | LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, const_val->data.x_enum.tag, false); |
| ... | ... | @@ -2135,6 +2115,32 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE |
| 2135 | 2115 | } |
| 2136 | 2116 | } else if (type_entry->id == TypeTableEntryIdFn) { |
| 2137 | 2117 | return const_val->data.x_fn->fn_value; |
| 2118 | } else if (type_entry->id == TypeTableEntryIdPointer) { | |
| 2119 | TypeTableEntry *child_type = type_entry->data.pointer.child_type; | |
| 2120 | int len = const_val->data.x_ptr.len; | |
| 2121 | LLVMValueRef target_val; | |
| 2122 | if (len == 1) { | |
| 2123 | target_val = gen_const_val(g, child_type, const_val->data.x_ptr.ptr[0]); | |
| 2124 | } else if (len > 1) { | |
| 2125 | LLVMValueRef *values = allocate<LLVMValueRef>(len); | |
| 2126 | for (int i = 0; i < len; i += 1) { | |
| 2127 | values[i] = gen_const_val(g, child_type, const_val->data.x_ptr.ptr[i]); | |
| 2128 | } | |
| 2129 | target_val = LLVMConstArray(child_type->type_ref, values, len); | |
| 2130 | } else { | |
| 2131 | zig_unreachable(); | |
| 2132 | } | |
| 2133 | LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(target_val), ""); | |
| 2134 | LLVMSetInitializer(global_value, target_val); | |
| 2135 | LLVMSetLinkage(global_value, LLVMPrivateLinkage); | |
| 2136 | LLVMSetGlobalConstant(global_value, type_entry->data.pointer.is_const); | |
| 2137 | LLVMSetUnnamedAddr(global_value, true); | |
| 2138 | ||
| 2139 | if (len > 1) { | |
| 2140 | return LLVMConstBitCast(global_value, type_entry->type_ref); | |
| 2141 | } else { | |
| 2142 | return global_value; | |
| 2143 | } | |
| 2138 | 2144 | } else { |
| 2139 | 2145 | zig_unreachable(); |
| 2140 | 2146 | } |
| ... | ... | @@ -2532,8 +2538,6 @@ static void define_builtin_types(CodeGen *g) { |
| 2532 | 2538 | g->primitive_type_table.put(&entry->name, entry); |
| 2533 | 2539 | } |
| 2534 | 2540 | |
| 2535 | g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, get_int_type(g, false, 8), true); | |
| 2536 | ||
| 2537 | 2541 | g->builtin_types.entry_u8 = get_int_type(g, false, 8); |
| 2538 | 2542 | g->builtin_types.entry_u16 = get_int_type(g, false, 16); |
| 2539 | 2543 | g->builtin_types.entry_u32 = get_int_type(g, false, 32); |