diff --git a/src/all_types.hpp b/src/all_types.hpp index 655b0a4b6..45669ed43 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -49,6 +49,16 @@ struct ConstStructValue { ConstExprValue **fields; }; +struct ConstArrayValue { + ConstExprValue **fields; +}; + +struct ConstPtrValue { + ConstExprValue **ptr; + // len should almost always be 1. exceptions include C strings + uint64_t len; +}; + struct ConstExprValue { bool ok; // true if constant expression evalution worked bool depends_on_compile_var; @@ -61,6 +71,8 @@ struct ConstExprValue { ConstExprValue *x_maybe; ConstEnumValue x_enum; ConstStructValue x_struct; + ConstArrayValue x_array; + ConstPtrValue x_ptr; } data; }; @@ -900,7 +912,6 @@ struct CodeGen { ZigList lib_search_paths; // reminder: hash tables must be initialized before use - HashMap str_table; HashMap link_table; HashMap import_table; HashMap builtin_fn_table; @@ -924,7 +935,6 @@ struct CodeGen { TypeTableEntry *entry_usize; TypeTableEntry *entry_f32; TypeTableEntry *entry_f64; - TypeTableEntry *entry_c_string_literal; TypeTableEntry *entry_void; TypeTableEntry *entry_unreachable; TypeTableEntry *entry_type; diff --git a/src/analyze.cpp b/src/analyze.cpp index 5d79256fa..56eb138a6 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1795,6 +1795,46 @@ static TypeTableEntry *resolve_expr_const_val_as_null(CodeGen *g, AstNode *node, 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; + + int len_with_null = buf_len(str) + 1; + expr->const_val.data.x_ptr.ptr = allocate(len_with_null); + expr->const_val.data.x_ptr.len = len_with_null; + + ConstExprValue *all_chars = allocate(len_with_null); + for (int i = 0; i < buf_len(str); i += 1) { + ConstExprValue *this_char = &all_chars[i]; + this_char->ok = 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; + bignum_init_unsigned(&null_char->data.x_bignum, 0); + expr->const_val.data.x_ptr.ptr[len_with_null - 1] = null_char; + + return get_pointer_to_type(g, g->builtin_types.entry_u8, true); +} + +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.data.x_array.fields = allocate(buf_len(str)); + + ConstExprValue *all_chars = allocate(buf_len(str)); + for (int i = 0; i < buf_len(str); i += 1) { + ConstExprValue *this_char = &all_chars[i]; + this_char->ok = true; + bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]); + expr->const_val.data.x_array.fields[i] = this_char; + } + return get_array_type(g, g->builtin_types.entry_u8, buf_len(str)); +} + + static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node, TypeTableEntry *expected_type, uint64_t x) { @@ -2737,8 +2777,28 @@ static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *ex *const_val = *other_val; break; case CastOpToUnknownSizeArray: - zig_panic("TODO CastOpToUnknownSizeArray"); - break; + { + TypeTableEntry *other_type = get_resolved_expr(expr_node)->type_entry; + assert(other_type->id == TypeTableEntryIdArray); + + ConstExprValue *all_fields = allocate(2); + ConstExprValue *ptr_field = &all_fields[0]; + ConstExprValue *len_field = &all_fields[1]; + + const_val->data.x_struct.fields = allocate(2); + const_val->data.x_struct.fields[0] = ptr_field; + const_val->data.x_struct.fields[1] = len_field; + + ptr_field->ok = true; + ptr_field->data.x_ptr.ptr = other_val->data.x_array.fields; + ptr_field->data.x_ptr.len = other_type->data.array.len; + + len_field->ok = true; + bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len); + + const_val->ok = true; + break; + } case CastOpMaybeWrap: const_val->data.x_maybe = other_val; const_val->ok = true; @@ -3422,6 +3482,16 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, return g->builtin_types.entry_unreachable; } +static TypeTableEntry *analyze_string_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, + TypeTableEntry *expected_type, AstNode *node) +{ + if (node->data.string_literal.c) { + return resolve_expr_const_val_as_c_string_lit(g, node, &node->data.string_literal.buf); + } else { + return resolve_expr_const_val_as_string_lit(g, node, &node->data.string_literal.buf); + } +} + // When you call analyze_expression, the node you pass might no longer be the child node // you thought it was due to implicit casting rewriting the AST. static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, @@ -3544,12 +3614,7 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, return_type = analyze_error_literal_expr(g, import, context, expected_type, node); break; case NodeTypeStringLiteral: - if (node->data.string_literal.c) { - return_type = g->builtin_types.entry_c_string_literal; - } else { - return_type = get_array_type(g, g->builtin_types.entry_u8, - buf_len(&node->data.string_literal.buf)); - } + return_type = analyze_string_literal_expr(g, import, context, expected_type, node); break; case NodeTypeCharLiteral: return_type = g->builtin_types.entry_u8; diff --git a/src/codegen.cpp b/src/codegen.cpp index 28bf7c50c..467740e94 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -19,7 +19,6 @@ CodeGen *codegen_create(Buf *root_source_dir) { CodeGen *g = allocate(1); - g->str_table.init(32); g->link_table.init(32); g->import_table.init(32); g->builtin_fn_table.init(32); @@ -92,22 +91,6 @@ static void add_debug_source_node(CodeGen *g, AstNode *node) { g->cur_block_context->di_scope); } -static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) { - auto entry = g->str_table.maybe_get(str); - if (entry) { - return entry->value; - } - LLVMValueRef text = LLVMConstString(buf_ptr(str), buf_len(str), !c); - LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(text), ""); - LLVMSetLinkage(global_value, LLVMPrivateLinkage); - LLVMSetInitializer(global_value, text); - LLVMSetGlobalConstant(global_value, true); - LLVMSetUnnamedAddr(global_value, true); - g->str_table.put(str, global_value); - - return global_value; -} - static TypeTableEntry *get_expr_type(AstNode *node) { return get_resolved_expr(node)->type_entry; } @@ -1993,17 +1976,6 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { return gen_asm_expr(g, node); case NodeTypeErrorLiteral: return gen_error_literal(g, node); - case NodeTypeStringLiteral: - { - Buf *str = &node->data.string_literal.buf; - LLVMValueRef str_val = find_or_create_string(g, str, node->data.string_literal.c); - LLVMValueRef indices[] = { - LLVMConstNull(g->builtin_types.entry_isize->type_ref), - LLVMConstNull(g->builtin_types.entry_isize->type_ref), - }; - LLVMValueRef ptr_val = LLVMBuildInBoundsGEP(g->builder, str_val, indices, 2, ""); - return ptr_val; - } case NodeTypeCharLiteral: return LLVMConstInt(LLVMInt8Type(), node->data.char_literal.value, false); case NodeTypeSymbol: @@ -2035,6 +2007,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { return gen_switch_expr(g, node); case NodeTypeNumberLiteral: case NodeTypeBoolLiteral: + case NodeTypeStringLiteral: // caught by constant expression eval codegen zig_unreachable(); case NodeTypeRoot: @@ -2117,7 +2090,14 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE } return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count); } else if (type_entry->id == TypeTableEntryIdArray) { - zig_panic("TODO"); + TypeTableEntry *child_type = type_entry->data.array.child_type; + uint64_t len = type_entry->data.array.len; + LLVMValueRef *values = allocate(len); + for (int i = 0; i < len; i += 1) { + ConstExprValue *field_value = const_val->data.x_array.fields[i]; + values[i] = gen_const_val(g, child_type, field_value); + } + return LLVMConstArray(child_type->type_ref, values, len); } else if (type_entry->id == TypeTableEntryIdEnum) { LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref; 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 } } else if (type_entry->id == TypeTableEntryIdFn) { return const_val->data.x_fn->fn_value; + } else if (type_entry->id == TypeTableEntryIdPointer) { + TypeTableEntry *child_type = type_entry->data.pointer.child_type; + int len = const_val->data.x_ptr.len; + LLVMValueRef target_val; + if (len == 1) { + target_val = gen_const_val(g, child_type, const_val->data.x_ptr.ptr[0]); + } else if (len > 1) { + LLVMValueRef *values = allocate(len); + for (int i = 0; i < len; i += 1) { + values[i] = gen_const_val(g, child_type, const_val->data.x_ptr.ptr[i]); + } + target_val = LLVMConstArray(child_type->type_ref, values, len); + } else { + zig_unreachable(); + } + LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(target_val), ""); + LLVMSetInitializer(global_value, target_val); + LLVMSetLinkage(global_value, LLVMPrivateLinkage); + LLVMSetGlobalConstant(global_value, type_entry->data.pointer.is_const); + LLVMSetUnnamedAddr(global_value, true); + + if (len > 1) { + return LLVMConstBitCast(global_value, type_entry->type_ref); + } else { + return global_value; + } } else { zig_unreachable(); } @@ -2532,8 +2538,6 @@ static void define_builtin_types(CodeGen *g) { g->primitive_type_table.put(&entry->name, entry); } - g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, get_int_type(g, false, 8), true); - g->builtin_types.entry_u8 = get_int_type(g, false, 8); g->builtin_types.entry_u16 = get_int_type(g, false, 16); g->builtin_types.entry_u32 = get_int_type(g, false, 32);