Commit 2dfb1ebee2

Andrew Kelley <superjoe30@gmail.com>
2017-05-27 05:31:38
const global values can reference each other
Before, if you did something like: ``` const hi1 = "hi"; const hi2 = hi1; ``` This would create the "hi" data twice in the built object. But since the value is const we don't have to duplicate the data, now we take advantage of this fact. closes #336
1 parent d6b0193
src/all_types.hpp
@@ -210,11 +210,15 @@ struct ConstFn {
     FnTableEntry *fn_entry;
 };
 
+struct ConstGlobalRefs {
+    LLVMValueRef llvm_value;
+    LLVMValueRef llvm_global;
+};
+
 struct ConstExprValue {
     TypeTableEntry *type;
     ConstValSpecial special;
-    LLVMValueRef llvm_value;
-    LLVMValueRef llvm_global;
+    ConstGlobalRefs *global_refs;
 
     union {
         // populated if special == ConstValSpecialStatic
@@ -527,6 +531,7 @@ enum CastOp {
     CastOpBoolToInt,
     CastOpResizeSlice,
     CastOpBytesToSlice,
+    CastOpNumLitToConcrete,
 };
 
 struct AstNodeFnCallExpr {
src/analyze.cpp
@@ -3457,7 +3457,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
 void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
     const_val->special = ConstValSpecialStatic;
     const_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str));
-    const_val->data.x_array.s_none.elements = allocate<ConstExprValue>(buf_len(str));
+    const_val->data.x_array.s_none.elements = create_const_vals(buf_len(str));
 
     for (size_t i = 0; i < buf_len(str); i += 1) {
         ConstExprValue *this_char = &const_val->data.x_array.s_none.elements[i];
@@ -3468,7 +3468,7 @@ void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
 }
 
 ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str) {
-    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    ConstExprValue *const_val = create_const_vals(1);
     init_const_str_lit(g, const_val, str);
     return const_val;
 }
@@ -3476,10 +3476,10 @@ ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str) {
 void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
     // first we build the underlying array
     size_t len_with_null = buf_len(str) + 1;
-    ConstExprValue *array_val = allocate<ConstExprValue>(1);
+    ConstExprValue *array_val = create_const_vals(1);
     array_val->special = ConstValSpecialStatic;
     array_val->type = get_array_type(g, g->builtin_types.entry_u8, len_with_null);
-    array_val->data.x_array.s_none.elements = allocate<ConstExprValue>(len_with_null);
+    array_val->data.x_array.s_none.elements = create_const_vals(len_with_null);
     for (size_t i = 0; i < buf_len(str); i += 1) {
         ConstExprValue *this_char = &array_val->data.x_array.s_none.elements[i];
         this_char->special = ConstValSpecialStatic;
@@ -3500,7 +3500,7 @@ void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
     const_val->data.x_ptr.data.base_array.is_cstr = true;
 }
 ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *str) {
-    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    ConstExprValue *const_val = create_const_vals(1);
     init_const_c_str_lit(g, const_val, str);
     return const_val;
 }
@@ -3513,7 +3513,7 @@ void init_const_unsigned_negative(ConstExprValue *const_val, TypeTableEntry *typ
 }
 
 ConstExprValue *create_const_unsigned_negative(TypeTableEntry *type, uint64_t x, bool negative) {
-    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    ConstExprValue *const_val = create_const_vals(1);
     init_const_unsigned_negative(const_val, type, x, negative);
     return const_val;
 }
@@ -3533,7 +3533,7 @@ void init_const_signed(ConstExprValue *const_val, TypeTableEntry *type, int64_t
 }
 
 ConstExprValue *create_const_signed(TypeTableEntry *type, int64_t x) {
-    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    ConstExprValue *const_val = create_const_vals(1);
     init_const_signed(const_val, type, x);
     return const_val;
 }
@@ -3545,7 +3545,7 @@ void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double va
 }
 
 ConstExprValue *create_const_float(TypeTableEntry *type, double value) {
-    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    ConstExprValue *const_val = create_const_vals(1);
     init_const_float(const_val, type, value);
     return const_val;
 }
@@ -3557,7 +3557,7 @@ void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, uint64
 }
 
 ConstExprValue *create_const_enum_tag(TypeTableEntry *type, uint64_t tag) {
-    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    ConstExprValue *const_val = create_const_vals(1);
     init_const_enum_tag(const_val, type, tag);
     return const_val;
 }
@@ -3569,7 +3569,7 @@ void init_const_bool(CodeGen *g, ConstExprValue *const_val, bool value) {
 }
 
 ConstExprValue *create_const_bool(CodeGen *g, bool value) {
-    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    ConstExprValue *const_val = create_const_vals(1);
     init_const_bool(g, const_val, value);
     return const_val;
 }
@@ -3580,7 +3580,7 @@ void init_const_runtime(ConstExprValue *const_val, TypeTableEntry *type) {
 }
 
 ConstExprValue *create_const_runtime(TypeTableEntry *type) {
-    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    ConstExprValue *const_val = create_const_vals(1);
     init_const_runtime(const_val, type);
     return const_val;
 }
@@ -3592,7 +3592,7 @@ void init_const_type(CodeGen *g, ConstExprValue *const_val, TypeTableEntry *type
 }
 
 ConstExprValue *create_const_type(CodeGen *g, TypeTableEntry *type_value) {
-    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    ConstExprValue *const_val = create_const_vals(1);
     init_const_type(g, const_val, type_value);
     return const_val;
 }
@@ -3604,14 +3604,14 @@ void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *arr
 
     const_val->special = ConstValSpecialStatic;
     const_val->type = get_slice_type(g, array_val->type->data.array.child_type, is_const);
-    const_val->data.x_struct.fields = allocate<ConstExprValue>(2);
+    const_val->data.x_struct.fields = create_const_vals(2);
 
     init_const_ptr_array(g, &const_val->data.x_struct.fields[slice_ptr_index], array_val, start, is_const);
     init_const_usize(g, &const_val->data.x_struct.fields[slice_len_index], len);
 }
 
 ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t start, size_t len, bool is_const) {
-    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    ConstExprValue *const_val = create_const_vals(1);
     init_const_slice(g, const_val, array_val, start, len, is_const);
     return const_val;
 }
@@ -3630,7 +3630,7 @@ void init_const_ptr_array(CodeGen *g, ConstExprValue *const_val, ConstExprValue
 }
 
 ConstExprValue *create_const_ptr_array(CodeGen *g, ConstExprValue *array_val, size_t elem_index, bool is_const) {
-    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    ConstExprValue *const_val = create_const_vals(1);
     init_const_ptr_array(g, const_val, array_val, elem_index, is_const);
     return const_val;
 }
@@ -3643,7 +3643,7 @@ void init_const_ptr_ref(CodeGen *g, ConstExprValue *const_val, ConstExprValue *p
 }
 
 ConstExprValue *create_const_ptr_ref(CodeGen *g, ConstExprValue *pointee_val, bool is_const) {
-    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    ConstExprValue *const_val = create_const_vals(1);
     init_const_ptr_ref(g, const_val, pointee_val, is_const);
     return const_val;
 }
@@ -3660,7 +3660,7 @@ void init_const_ptr_hard_coded_addr(CodeGen *g, ConstExprValue *const_val, TypeT
 ConstExprValue *create_const_ptr_hard_coded_addr(CodeGen *g, TypeTableEntry *pointee_type,
         size_t addr, bool is_const)
 {
-    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    ConstExprValue *const_val = create_const_vals(1);
     init_const_ptr_hard_coded_addr(g, const_val, pointee_type, addr, is_const);
     return const_val;
 }
@@ -3673,7 +3673,7 @@ void init_const_arg_tuple(CodeGen *g, ConstExprValue *const_val, size_t arg_inde
 }
 
 ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_t arg_index_end) {
-    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    ConstExprValue *const_val = create_const_vals(1);
     init_const_arg_tuple(g, const_val, arg_index_start, arg_index_end);
     return const_val;
 }
@@ -3689,7 +3689,7 @@ void init_const_undefined(CodeGen *g, ConstExprValue *const_val) {
 
         const_val->special = ConstValSpecialStatic;
         size_t field_count = wanted_type->data.structure.src_field_count;
-        const_val->data.x_struct.fields = allocate<ConstExprValue>(field_count);
+        const_val->data.x_struct.fields = create_const_vals(field_count);
         for (size_t i = 0; i < field_count; i += 1) {
             ConstExprValue *field_val = &const_val->data.x_struct.fields[i];
             field_val->type = wanted_type->data.structure.fields[i].type_entry;
@@ -3707,6 +3707,15 @@ void init_const_undefined(CodeGen *g, ConstExprValue *const_val) {
     }
 }
 
+ConstExprValue *create_const_vals(size_t count) {
+    ConstGlobalRefs *global_refs = allocate<ConstGlobalRefs>(count);
+    ConstExprValue *vals = allocate<ConstExprValue>(count);
+    for (size_t i = 0; i < count; i += 1) {
+        vals[i].global_refs = &global_refs[i];
+    }
+    return vals;
+}
+
 void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry) {
     if (type_entry->id == TypeTableEntryIdStruct) {
         if (!type_entry->data.structure.complete)
@@ -3788,16 +3797,24 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
                         return false;
                     return true;
                 case ConstPtrSpecialBaseArray:
-                    if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val)
+                    if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val &&
+                        a->data.x_ptr.data.base_array.array_val->global_refs !=
+                        b->data.x_ptr.data.base_array.array_val->global_refs)
+                    {
                         return false;
+                    }
                     if (a->data.x_ptr.data.base_array.elem_index != b->data.x_ptr.data.base_array.elem_index)
                         return false;
                     if (a->data.x_ptr.data.base_array.is_cstr != b->data.x_ptr.data.base_array.is_cstr)
                         return false;
                     return true;
                 case ConstPtrSpecialBaseStruct:
-                    if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val)
+                    if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val &&
+                        a->data.x_ptr.data.base_struct.struct_val->global_refs !=
+                        b->data.x_ptr.data.base_struct.struct_val->global_refs)
+                    {
                         return false;
+                    }
                     if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index)
                         return false;
                     return true;
@@ -4293,7 +4310,7 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) {
     if (const_val->data.x_array.special == ConstArraySpecialUndef) {
         const_val->data.x_array.special = ConstArraySpecialNone;
         size_t elem_count = const_val->type->data.array.len;
-        const_val->data.x_array.s_none.elements = allocate<ConstExprValue>(elem_count);
+        const_val->data.x_array.s_none.elements = create_const_vals(elem_count);
         for (size_t i = 0; i < elem_count; i += 1) {
             ConstExprValue *element_val = &const_val->data.x_array.s_none.elements[i];
             element_val->type = const_val->type->data.array.child_type;
src/analyze.hpp
@@ -153,6 +153,8 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_
 
 void init_const_undefined(CodeGen *g, ConstExprValue *const_val);
 
+ConstExprValue *create_const_vals(size_t count);
+
 TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits);
 ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value);
 FnTableEntry *get_extern_panic_fn(CodeGen *g);
src/codegen.cpp
@@ -682,8 +682,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
 
 static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
     ConstExprValue *val = &g->panic_msg_vals[msg_id];
-    if (val->llvm_global)
-        return val->llvm_global;
+    if (val->global_refs->llvm_global)
+        return val->global_refs->llvm_global;
 
     Buf *buf_msg = panic_msg_buf(msg_id);
     ConstExprValue *array_val = create_const_str_lit(g, buf_msg);
@@ -692,8 +692,8 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
     render_const_val_global(g, val, "");
     render_const_val(g, val);
 
-    assert(val->llvm_global);
-    return val->llvm_global;
+    assert(val->global_refs->llvm_global);
+    return val->global_refs->llvm_global;
 }
 
 static void gen_panic_raw(CodeGen *g, LLVMValueRef msg_ptr, LLVMValueRef msg_len) {
@@ -1086,11 +1086,11 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
         if (handle_is_ptr(instruction->value.type)) {
             render_const_val_global(g, &instruction->value, "");
             TypeTableEntry *ptr_type = get_pointer_to_type(g, instruction->value.type, true);
-            instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value.llvm_global, ptr_type->type_ref, "");
+            instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value.global_refs->llvm_global, ptr_type->type_ref, "");
         } else if (instruction->value.type->id == TypeTableEntryIdPointer) {
-            instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value.llvm_value, instruction->value.type->type_ref, "");
+            instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value.global_refs->llvm_value, instruction->value.type->type_ref, "");
         } else {
-            instruction->llvm_value = instruction->value.llvm_value;
+            instruction->llvm_value = instruction->value.global_refs->llvm_value;
         }
         assert(instruction->llvm_value);
     }
@@ -1535,6 +1535,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
 
     switch (cast_instruction->cast_op) {
         case CastOpNoCast:
+        case CastOpNumLitToConcrete:
             zig_unreachable();
         case CastOpNoop:
             return expr_val;
@@ -3197,7 +3198,7 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent
         case ConstParentIdNone:
             render_const_val(g, val);
             render_const_val_global(g, val, "");
-            return val->llvm_global;
+            return val->global_refs->llvm_global;
         case ConstParentIdStruct:
             return gen_const_ptr_struct_recursive(g, parent->data.p_struct.struct_val,
                     parent->data.p_struct.field_index);
@@ -3506,9 +3507,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
                             render_const_val(g, pointee);
                             render_const_val_global(g, pointee, "");
                             ConstExprValue *other_val = pointee;
-                            const_val->llvm_value = LLVMConstBitCast(other_val->llvm_global, const_val->type->type_ref);
+                            const_val->global_refs->llvm_value = LLVMConstBitCast(other_val->global_refs->llvm_global, const_val->type->type_ref);
                             render_const_val_global(g, const_val, "");
-                            return const_val->llvm_value;
+                            return const_val->global_refs->llvm_value;
                         }
                     case ConstPtrSpecialBaseArray:
                         {
@@ -3518,15 +3519,15 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
                             if (array_const_val->type->zero_bits) {
                                 // make this a null pointer
                                 TypeTableEntry *usize = g->builtin_types.entry_usize;
-                                const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
+                                const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
                                         const_val->type->type_ref);
                                 render_const_val_global(g, const_val, "");
-                                return const_val->llvm_value;
+                                return const_val->global_refs->llvm_value;
                             }
                             LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val,
                                     elem_index);
                             LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
-                            const_val->llvm_value = ptr_val;
+                            const_val->global_refs->llvm_value = ptr_val;
                             render_const_val_global(g, const_val, "");
                             return ptr_val;
                         }
@@ -3537,10 +3538,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
                             if (struct_const_val->type->zero_bits) {
                                 // make this a null pointer
                                 TypeTableEntry *usize = g->builtin_types.entry_usize;
-                                const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
+                                const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
                                         const_val->type->type_ref);
                                 render_const_val_global(g, const_val, "");
-                                return const_val->llvm_value;
+                                return const_val->global_refs->llvm_value;
                             }
                             size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index;
                             size_t gen_field_index =
@@ -3548,7 +3549,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
                             LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val,
                                     gen_field_index);
                             LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
-                            const_val->llvm_value = ptr_val;
+                            const_val->global_refs->llvm_value = ptr_val;
                             render_const_val_global(g, const_val, "");
                             return ptr_val;
                         }
@@ -3556,10 +3557,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
                         {
                             uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr;
                             TypeTableEntry *usize = g->builtin_types.entry_usize;
-                            const_val->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, addr_value, false),
+                            const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, addr_value, false),
                                     const_val->type->type_ref);
                             render_const_val_global(g, const_val, "");
-                            return const_val->llvm_value;
+                            return const_val->global_refs->llvm_value;
                         }
                 }
             }
@@ -3608,27 +3609,32 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
 }
 
 static void render_const_val(CodeGen *g, ConstExprValue *const_val) {
-    if (!const_val->llvm_value)
-        const_val->llvm_value = gen_const_val(g, const_val);
+    if (!const_val->global_refs)
+        const_val->global_refs = allocate<ConstGlobalRefs>(1);
+    if (!const_val->global_refs->llvm_value)
+        const_val->global_refs->llvm_value = gen_const_val(g, const_val);
 
-    if (const_val->llvm_global)
-        LLVMSetInitializer(const_val->llvm_global, const_val->llvm_value);
+    if (const_val->global_refs->llvm_global)
+        LLVMSetInitializer(const_val->global_refs->llvm_global, const_val->global_refs->llvm_value);
 }
 
 static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const char *name) {
-    if (!const_val->llvm_global) {
-        LLVMTypeRef type_ref = const_val->llvm_value ? LLVMTypeOf(const_val->llvm_value) : const_val->type->type_ref;
+    if (!const_val->global_refs)
+        const_val->global_refs = allocate<ConstGlobalRefs>(1);
+
+    if (!const_val->global_refs->llvm_global) {
+        LLVMTypeRef type_ref = const_val->global_refs->llvm_value ? LLVMTypeOf(const_val->global_refs->llvm_value) : const_val->type->type_ref;
         LLVMValueRef global_value = LLVMAddGlobal(g->module, type_ref, name);
         LLVMSetLinkage(global_value, LLVMInternalLinkage);
         LLVMSetGlobalConstant(global_value, true);
         LLVMSetUnnamedAddr(global_value, true);
         LLVMSetAlignment(global_value, get_type_alignment(g, const_val->type));
 
-        const_val->llvm_global = global_value;
+        const_val->global_refs->llvm_global = global_value;
     }
 
-    if (const_val->llvm_value)
-        LLVMSetInitializer(const_val->llvm_global, const_val->llvm_value);
+    if (const_val->global_refs->llvm_value)
+        LLVMSetInitializer(const_val->global_refs->llvm_global, const_val->global_refs->llvm_value);
 }
 
 static void delete_unused_builtin_fns(CodeGen *g) {
@@ -3849,7 +3855,7 @@ static void do_code_gen(CodeGen *g) {
             bool exported = (var->linkage == VarLinkageExport);
             render_const_val(g, var->value);
             render_const_val_global(g, var->value, buf_ptr(get_mangled_name(g, &var->name, exported)));
-            global_value = var->value->llvm_global;
+            global_value = var->value->global_refs->llvm_global;
 
             if (exported) {
                 LLVMSetLinkage(global_value, LLVMExternalLinkage);
@@ -3862,7 +3868,7 @@ static void do_code_gen(CodeGen *g) {
 
             // TODO debug info for function pointers
             if (var->gen_is_const && var->value->type->id != TypeTableEntryIdFn) {
-                gen_global_var(g, var, var->value->llvm_value, var->value->type);
+                gen_global_var(g, var, var->value->global_refs->llvm_value, var->value->type);
             }
         }
 
@@ -4737,9 +4743,18 @@ static void init(CodeGen *g) {
 
     g->invalid_instruction = allocate<IrInstruction>(1);
     g->invalid_instruction->value.type = g->builtin_types.entry_invalid;
+    g->invalid_instruction->value.global_refs = allocate<ConstGlobalRefs>(1);
 
     g->const_void_val.special = ConstValSpecialStatic;
     g->const_void_val.type = g->builtin_types.entry_void;
+    g->const_void_val.global_refs = allocate<ConstGlobalRefs>(1);
+
+    {
+        ConstGlobalRefs *global_refs = allocate<ConstGlobalRefs>(PanicMsgIdCount);
+        for (size_t i = 0; i < PanicMsgIdCount; i += 1) {
+            g->panic_msg_vals[i].global_refs = &global_refs[i];
+        }
+    }
 
     define_builtin_fns(g);
     define_builtin_compile_vars(g);
@@ -4826,10 +4841,10 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
     TypeTableEntry *field_types[] = { str_type, fn_type, };
     TypeTableEntry *struct_type = get_struct_type(g, "ZigTestFn", field_names, field_types, 2);
 
-    ConstExprValue *test_fn_array = allocate<ConstExprValue>(1);
+    ConstExprValue *test_fn_array = create_const_vals(1);
     test_fn_array->type = get_array_type(g, struct_type, g->test_fns.length);
     test_fn_array->special = ConstValSpecialStatic;
-    test_fn_array->data.x_array.s_none.elements = allocate<ConstExprValue>(g->test_fns.length);
+    test_fn_array->data.x_array.s_none.elements = create_const_vals(g->test_fns.length);
 
     for (size_t i = 0; i < g->test_fns.length; i += 1) {
         FnTableEntry *test_fn_entry = g->test_fns.at(i);
@@ -4840,7 +4855,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
         this_val->data.x_struct.parent.id = ConstParentIdArray;
         this_val->data.x_struct.parent.data.p_array.array_val = test_fn_array;
         this_val->data.x_struct.parent.data.p_array.elem_index = i;
-        this_val->data.x_struct.fields = allocate<ConstExprValue>(2);
+        this_val->data.x_struct.fields = create_const_vals(2);
 
         ConstExprValue *name_field = &this_val->data.x_struct.fields[0];
         ConstExprValue *name_array_val = create_const_str_lit(g, &test_fn_entry->symbol_name);
src/ir.cpp
@@ -553,6 +553,7 @@ static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_no
     special_instruction->base.source_node = source_node;
     special_instruction->base.debug_id = exec_next_debug_id(irb->exec);
     special_instruction->base.owner_bb = irb->current_basic_block;
+    special_instruction->base.value.global_refs = allocate<ConstGlobalRefs>(1);
     return special_instruction;
 }
 
@@ -3210,7 +3211,7 @@ static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Sco
     variable_entry->mem_slot_index = SIZE_MAX;
     variable_entry->is_comptime = is_comptime;
     variable_entry->src_arg_index = SIZE_MAX;
-    variable_entry->value = allocate<ConstExprValue>(1);
+    variable_entry->value = create_const_vals(1);
 
     if (name) {
         buf_init_from_buf(&variable_entry->name, name);
@@ -6565,6 +6566,14 @@ static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, TypeTableE
     }
 }
 
+static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs) {
+    ConstGlobalRefs *global_refs = dest->global_refs;
+    *dest = *src;
+    if (!same_global_refs) {
+        dest->global_refs = global_refs;
+    }
+}
+
 static void eval_const_expr_implicit_cast(CastOp cast_op,
         ConstExprValue *other_val, TypeTableEntry *other_type,
         ConstExprValue *const_val, TypeTableEntry *new_type)
@@ -6576,7 +6585,13 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
         case CastOpNoCast:
             zig_unreachable();
         case CastOpNoop:
-            *const_val = *other_val;
+            {
+                copy_const_val(const_val, other_val, other_val->special == ConstValSpecialStatic);
+                const_val->type = new_type;
+                break;
+            }
+        case CastOpNumLitToConcrete:
+            const_val->data.x_bignum = other_val->data.x_bignum;
             const_val->type = new_type;
             break;
         case CastOpResizeSlice:
@@ -7188,7 +7203,7 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction
         }
         IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
                 source_instr->source_node, wanted_type);
-        result->value = *val;
+        result->value.data.x_bignum = val->data.x_bignum;
         result->value.type = wanted_type;
         return result;
     }
@@ -7613,7 +7628,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
                 (actual_type->id == TypeTableEntryIdNumLitInt &&
                  wanted_type->id == TypeTableEntryIdInt))
             {
-                op = CastOpNoop;
+                op = CastOpNumLitToConcrete;
             } else if (wanted_type->id == TypeTableEntryIdInt) {
                 op = CastOpFloatToInt;
             } else if (wanted_type->id == TypeTableEntryIdFloat) {
@@ -7741,7 +7756,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
                 if (pointee->special != ConstValSpecialRuntime) {
                     IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
                         source_instruction->source_node, child_type);
-                    result->value = *pointee;
+                    copy_const_val(&result->value, pointee, ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst);
                     return result;
                 }
             }
@@ -8584,7 +8599,7 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
 
         result_type = get_pointer_to_type(ira->codegen, child_type, true);
 
-        out_array_val = allocate<ConstExprValue>(1);
+        out_array_val = create_const_vals(1);
         out_array_val->special = ConstValSpecialStatic;
         out_array_val->type = get_array_type(ira->codegen, child_type, new_len);
         out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
@@ -8592,7 +8607,7 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
         out_val->data.x_ptr.data.base_array.array_val = out_array_val;
         out_val->data.x_ptr.data.base_array.elem_index = 0;
     }
-    out_array_val->data.x_array.s_none.elements = allocate<ConstExprValue>(new_len);
+    out_array_val->data.x_array.s_none.elements = create_const_vals(new_len);
 
     expand_undef_array(ira->codegen, op1_array_val);
 
@@ -8648,7 +8663,7 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp
     ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
 
     uint64_t new_array_len = array_len.data.x_uint;
-    out_val->data.x_array.s_none.elements = allocate<ConstExprValue>(new_array_len);
+    out_val->data.x_array.s_none.elements = create_const_vals(new_array_len);
 
     expand_undef_array(ira->codegen, array_val);
 
@@ -9139,7 +9154,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
         GenericFnTypeId *generic_id = allocate<GenericFnTypeId>(1);
         generic_id->fn_entry = fn_entry;
         generic_id->param_count = 0;
-        generic_id->params = allocate<ConstExprValue>(new_fn_arg_count);
+        generic_id->params = create_const_vals(new_fn_arg_count);
         size_t next_proto_i = 0;
 
         if (first_arg_ptr) {
@@ -9451,7 +9466,7 @@ static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp
         ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value);
         if (pointee->type == child_type) {
             ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);
-            *out_val = *pointee;
+            copy_const_val(out_val, pointee, value->value.data.x_ptr.mut == ConstPtrMutComptimeConst);
             return child_type;
         }
     }
@@ -10118,7 +10133,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
 
             // TODO instead of allocating this every time, put it in the tld value and we can reference
             // the same one every time
-            ConstExprValue *const_val = allocate<ConstExprValue>(1);
+            ConstExprValue *const_val = create_const_vals(1);
             const_val->special = ConstValSpecialStatic;
             const_val->type = fn_entry->type_entry;
             const_val->data.x_fn.fn_entry = fn_entry;
@@ -10162,7 +10177,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
         }
     } else if (container_type->id == TypeTableEntryIdArray) {
         if (buf_eql_str(field_name, "len")) {
-            ConstExprValue *len_val = allocate<ConstExprValue>(1);
+            ConstExprValue *len_val = create_const_vals(1);
             init_const_usize(ira->codegen, len_val, container_type->data.array.len);
 
             TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
@@ -10185,7 +10200,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
         ConstExprValue *child_val = const_ptr_pointee(ira->codegen, container_ptr_val);
 
         if (buf_eql_str(field_name, "len")) {
-            ConstExprValue *len_val = allocate<ConstExprValue>(1);
+            ConstExprValue *len_val = create_const_vals(1);
             size_t len = child_val->data.x_arg_tuple.end_index - child_val->data.x_arg_tuple.start_index;
             init_const_usize(ira->codegen, len_val, len);
 
@@ -10258,7 +10273,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
         } else if (child_type->id == TypeTableEntryIdPureError) {
             auto err_table_entry = ira->codegen->error_table.maybe_get(field_name);
             if (err_table_entry) {
-                ConstExprValue *const_val = allocate<ConstExprValue>(1);
+                ConstExprValue *const_val = create_const_vals(1);
                 const_val->special = ConstValSpecialStatic;
                 const_val->type = child_type;
                 const_val->data.x_pure_err = err_table_entry->value;
@@ -11346,7 +11361,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
         case TypeTableEntryIdPureError:
             if (pointee_val) {
                 ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);
-                *out_val = *pointee_val;
+                copy_const_val(out_val, pointee_val, true);
                 out_val->type = target_type;
                 return target_type;
             }
@@ -11583,7 +11598,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
     ConstExprValue const_val = {};
     const_val.special = ConstValSpecialStatic;
     const_val.type = container_type;
-    const_val.data.x_struct.fields = allocate<ConstExprValue>(actual_field_count);
+    const_val.data.x_struct.fields = create_const_vals(actual_field_count);
     for (size_t i = 0; i < instr_field_count; i += 1) {
         IrInstructionContainerInitFieldsField *field = &fields[i];
 
@@ -11624,7 +11639,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
                 if (!field_val)
                     return ira->codegen->builtin_types.entry_invalid;
 
-                const_val.data.x_struct.fields[field_index] = *field_val;
+                copy_const_val(&const_val.data.x_struct.fields[field_index], field_val, true);
             } else {
                 first_non_const_instruction = casted_field_value;
                 const_val.special = ConstValSpecialRuntime;
@@ -11698,7 +11713,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
             ConstExprValue const_val = {};
             const_val.special = ConstValSpecialStatic;
             const_val.type = fixed_size_array_type;
-            const_val.data.x_array.s_none.elements = allocate<ConstExprValue>(elem_count);
+            const_val.data.x_array.s_none.elements = create_const_vals(elem_count);
 
             bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope);
 
@@ -11723,7 +11738,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
                         if (!elem_val)
                             return ira->codegen->builtin_types.entry_invalid;
 
-                        const_val.data.x_array.s_none.elements[i] = *elem_val;
+                        copy_const_val(&const_val.data.x_array.s_none.elements[i], elem_val, true);
                     } else {
                         first_non_const_instruction = casted_arg;
                         const_val.special = ConstValSpecialRuntime;
@@ -11950,7 +11965,7 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc
             err->cached_error_name_val = create_const_slice(ira->codegen, array_val, 0, buf_len(&err->name), true);
         }
         ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
-        *out_val = *err->cached_error_name_val;
+        copy_const_val(out_val, err->cached_error_name_val, true);
         return str_type;
     }
 
@@ -12133,7 +12148,7 @@ static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstru
         type_entry->cached_const_name_val = create_const_str_lit(ira->codegen, &type_entry->name);
     }
     ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
-    *out_val = *type_entry->cached_const_name_val;
+    copy_const_val(out_val, type_entry->cached_const_name_val, true);
     return out_val->type;
 }
 
@@ -12809,7 +12824,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
         }
 
         ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
-        out_val->data.x_struct.fields = allocate<ConstExprValue>(2);
+        out_val->data.x_struct.fields = create_const_vals(2);
 
         ConstExprValue *ptr_val = &out_val->data.x_struct.fields[slice_ptr_index];
 
@@ -13370,7 +13385,7 @@ static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruc
             return ira->codegen->builtin_types.entry_invalid;
 
         ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
-        *out_val = *val;
+        copy_const_val(out_val, val, false);
         out_val->type = dest_type;
         return dest_type;
     }
@@ -13696,7 +13711,7 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl
     ira->new_irb.exec = new_exec;
 
     ira->exec_context.mem_slot_count = ira->old_irb.exec->mem_slot_count;
-    ira->exec_context.mem_slot_list = allocate<ConstExprValue>(ira->exec_context.mem_slot_count);
+    ira->exec_context.mem_slot_list = create_const_vals(ira->exec_context.mem_slot_count);
 
     IrBasicBlock *old_entry_bb = ira->old_irb.exec->basic_block_list.at(0);
     IrBasicBlock *new_entry_bb = ir_get_new_bb(ira, old_entry_bb, nullptr);
test/cases/eval.zig
@@ -332,3 +332,13 @@ test "compile-time downcast when the bits fit" {
         assert(byte == 255);
     }
 }
+
+const hi1 = "hi";
+const hi2 = hi1;
+test "const global shares pointer with other same one" {
+    assertEqualPtrs(&hi1[0], &hi2[0]);
+    comptime assert(&hi1[0] == &hi2[0]);
+}
+fn assertEqualPtrs(ptr1: &const u8, ptr2: &const u8) {
+    assert(ptr1 == ptr2);
+}
test/cases/var_args.zig
@@ -65,3 +65,17 @@ test "array of var args functions" {
     assert(foos[0]());
     assert(!foos[1]());
 }
+
+
+test "pass array and slice of same array to var args should have same pointers" {
+    const array = "hi";
+    const slice: []const u8 = array;
+    return assertSlicePtrsEql(array, slice);
+}
+
+fn assertSlicePtrsEql(args: ...) {
+    const s1 = ([]const u8)(args[0]);
+    const s2 = args[1];
+    assert(s1.ptr == s2.ptr);
+}
+
test/tests.zig
@@ -591,8 +591,7 @@ pub const CompileErrorContext = struct {
         tc.addSourceFile(".tmp_source.zig", source);
         comptime var arg_i = 0;
         inline while (arg_i < expected_lines.len) : (arg_i += 1) {
-            // TODO mem.dupe is because of issue #336
-            tc.addExpectedError(%%mem.dupe(self.b.allocator, u8, expected_lines[arg_i]));
+            tc.addExpectedError(expected_lines[arg_i]);
         }
         return tc;
     }
@@ -854,8 +853,7 @@ pub const ParseHContext = struct {
         tc.addSourceFile("source.h", source);
         comptime var arg_i = 0;
         inline while (arg_i < expected_lines.len) : (arg_i += 1) {
-            // TODO mem.dupe is because of issue #336
-            tc.addExpectedError(%%mem.dupe(self.b.allocator, u8, expected_lines[arg_i]));
+            tc.addExpectedError(expected_lines[arg_i]);
         }
         return tc;
     }