Commit 21fc5a6402

Andrew Kelley <superjoe30@gmail.com>
2016-01-23 04:36:08
un-special case constant global strings
1 parent 1158bc3
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<Buf *> lib_search_paths;
 
     // reminder: hash tables must be initialized before use
-    HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;
     HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table;
     HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;
     HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> 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;
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<ConstExprValue*>(len_with_null);
+    expr->const_val.data.x_ptr.len = len_with_null;
+
+    ConstExprValue *all_chars = allocate<ConstExprValue>(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<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;
+        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<ConstExprValue>(2);
+                ConstExprValue *ptr_field = &all_fields[0];
+                ConstExprValue *len_field = &all_fields[1];
+
+                const_val->data.x_struct.fields = allocate<ConstExprValue*>(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;
src/codegen.cpp
@@ -19,7 +19,6 @@
 
 CodeGen *codegen_create(Buf *root_source_dir) {
     CodeGen *g = allocate<CodeGen>(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<LLVMValueRef>(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<LLVMValueRef>(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);