Commit aae168550f

Andrew Kelley <superjoe30@gmail.com>
2017-02-03 17:59:56
exported global variables get emitted as external in LLVM
1 parent 71d335e
src/all_types.hpp
@@ -1278,7 +1278,12 @@ struct CodeGen {
     ConstExprValue const_void_val;
 };
 
-// TODO after merging IR branch, we can probably delete some of these fields
+enum VarLinkage {
+    VarLinkageInternal,
+    VarLinkageExport,
+    VarLinkageExternal,
+};
+
 struct VariableTableEntry {
     Buf name;
     ConstExprValue value;
@@ -1297,7 +1302,7 @@ struct VariableTableEntry {
     bool shadowable;
     size_t mem_slot_index;
     size_t ref_count;
-    bool is_extern;
+    VarLinkage linkage;
 };
 
 struct ErrorTableEntry {
src/analyze.cpp
@@ -1913,6 +1913,20 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
 
     AstNode *source_node = tld_var->base.source_node;
 
+    if (is_export && is_extern) {
+        add_node_error(g, source_node, buf_sprintf("variable is both export and extern"));
+    }
+
+    VarLinkage linkage;
+    if (is_export) {
+        linkage = VarLinkageExport;
+    } else if (is_extern) {
+        linkage = VarLinkageExternal;
+    } else {
+        linkage = VarLinkageInternal;
+    }
+
+
     IrInstruction *init_value = nullptr;
 
     TypeTableEntry *implicit_type = nullptr;
@@ -1926,7 +1940,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
         if (implicit_type->id == TypeTableEntryIdUnreachable) {
             add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable"));
             implicit_type = g->builtin_types.entry_invalid;
-        } else if ((!is_const || is_export) &&
+        } else if ((!is_const || linkage == VarLinkageExternal) &&
                 (implicit_type->id == TypeTableEntryIdNumLitFloat ||
                 implicit_type->id == TypeTableEntryIdNumLitInt))
         {
@@ -1940,7 +1954,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
             implicit_type = g->builtin_types.entry_invalid;
         }
         assert(implicit_type->id == TypeTableEntryIdInvalid || init_value->value.special != ConstValSpecialRuntime);
-    } else if (!is_extern) {
+    } else if (linkage != VarLinkageExternal) {
         add_node_error(g, source_node, buf_sprintf("variables must be initialized"));
         implicit_type = g->builtin_types.entry_invalid;
     }
@@ -1951,7 +1965,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
     ConstExprValue *init_val = init_value ? &init_value->value : create_const_runtime(type);
 
     tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol, is_const, init_val);
-    tld_var->var->is_extern = is_extern;
+    tld_var->var->linkage = linkage;
 
     g->global_vars.append(tld_var->var);
 }
src/ast_render.cpp
@@ -955,7 +955,7 @@ static void ast_render_tld_var(AstRender *ar, Buf *name, TldVar *tld_var) {
     VariableTableEntry *var = tld_var->var;
     const char *visib_mod_str = visib_mod_string(tld_var->base.visib_mod);
     const char *const_or_var = const_or_var_string(var->src_is_const);
-    const char *extern_str = extern_string(var->is_extern);
+    const char *extern_str = extern_string(var->linkage == VarLinkageExternal);
     fprintf(ar->f, "%s%s%s %s", visib_mod_str, extern_str, const_or_var, buf_ptr(name));
 
     if (var->value.type->id == TypeTableEntryIdNumLitFloat ||
src/codegen.cpp
@@ -226,7 +226,7 @@ void codegen_set_rdynamic(CodeGen *g, bool rdynamic) {
 }
 
 static void render_const_val(CodeGen *g, ConstExprValue *const_val);
-static void render_const_val_global(CodeGen *g, ConstExprValue *const_val);
+static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, bool is_export);
 
 static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
     if (fn_table_entry->llvm_value)
@@ -681,7 +681,7 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
         // we might have to do some pointer casting here due to the way union
         // values are rendered with a type other than the one we expect
         if (handle_is_ptr(instruction->value.type)) {
-            render_const_val_global(g, &instruction->value);
+            render_const_val_global(g, &instruction->value, false);
             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, "");
         } else if (instruction->value.type->id == TypeTableEntryIdPointer) {
@@ -2414,7 +2414,7 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar
         base_ptr = gen_const_ptr_array_recursive(g, parent_array, parent_array_index);
     } else {
         render_const_val(g, array_const_val);
-        render_const_val_global(g, array_const_val);
+        render_const_val_global(g, array_const_val, false);
         base_ptr = array_const_val->llvm_global;
     }
     TypeTableEntry *usize = g->builtin_types.entry_usize;
@@ -2562,16 +2562,16 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
             return fn_llvm_value(g, const_val->data.x_fn);
         case TypeTableEntryIdPointer:
             {
-                render_const_val_global(g, const_val);
+                render_const_val_global(g, const_val, false);
                 size_t index = const_val->data.x_ptr.index;
                 ConstExprValue *base_ptr = const_val->data.x_ptr.base_ptr;
                 if (base_ptr) {
                     if (index == SIZE_MAX) {
                         render_const_val(g, base_ptr);
-                        render_const_val_global(g, base_ptr);
+                        render_const_val_global(g, base_ptr, false);
                         ConstExprValue *other_val = base_ptr;
                         const_val->llvm_value = LLVMConstBitCast(other_val->llvm_global, const_val->type->type_ref);
-                        render_const_val_global(g, const_val);
+                        render_const_val_global(g, const_val, false);
                         return const_val->llvm_value;
                     } else {
                         ConstExprValue *array_const_val = base_ptr;
@@ -2581,19 +2581,19 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
                             TypeTableEntry *usize = g->builtin_types.entry_usize;
                             const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
                                     const_val->type->type_ref);
-                            render_const_val_global(g, const_val);
+                            render_const_val_global(g, const_val, false);
                             return const_val->llvm_value;
                         }
                         LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, index);
                         LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
                         const_val->llvm_value = ptr_val;
-                        render_const_val_global(g, const_val);
+                        render_const_val_global(g, const_val, false);
                         return ptr_val;
                     }
                 } else {
                     TypeTableEntry *usize = g->builtin_types.entry_usize;
                     const_val->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, index, false), const_val->type->type_ref);
-                    render_const_val_global(g, const_val);
+                    render_const_val_global(g, const_val, false);
                     return const_val->llvm_value;
                 }
             }
@@ -2648,11 +2648,11 @@ static void render_const_val(CodeGen *g, ConstExprValue *const_val) {
         LLVMSetInitializer(const_val->llvm_global, const_val->llvm_value);
 }
 
-static void render_const_val_global(CodeGen *g, ConstExprValue *const_val) {
+static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, bool is_export) {
     if (!const_val->llvm_global) {
         LLVMTypeRef type_ref = const_val->llvm_value ? LLVMTypeOf(const_val->llvm_value) : const_val->type->type_ref;
         LLVMValueRef global_value = LLVMAddGlobal(g->module, type_ref, "");
-        LLVMSetLinkage(global_value, LLVMInternalLinkage);
+        LLVMSetLinkage(global_value, is_export ? LLVMExternalLinkage : LLVMInternalLinkage);
         LLVMSetGlobalConstant(global_value, true);
         LLVMSetUnnamedAddr(global_value, true);
 
@@ -2827,15 +2827,16 @@ static void do_code_gen(CodeGen *g) {
         assert(var->decl_node);
 
         LLVMValueRef global_value;
-        if (var->is_extern) {
+        if (var->linkage == VarLinkageExternal) {
             global_value = LLVMAddGlobal(g->module, var->value.type->type_ref, buf_ptr(&var->name));
 
             // TODO debug info for the extern variable
 
             LLVMSetLinkage(global_value, LLVMExternalLinkage);
         } else {
+            bool is_export = (var->linkage == VarLinkageExport);
             render_const_val(g, &var->value);
-            render_const_val_global(g, &var->value);
+            render_const_val_global(g, &var->value, is_export);
             global_value = var->value.llvm_global;
             // TODO debug info for function pointers
             if (var->gen_is_const && var->value.type->id != TypeTableEntryIdFn) {
src/parseh.cpp
@@ -1090,7 +1090,7 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) {
 
     if (is_extern) {
         TldVar *tld_var = create_global_var(c, name, create_const_runtime(var_type), is_const);
-        tld_var->var->is_extern = true;
+        tld_var->var->linkage = VarLinkageExternal;
         add_global(c, &tld_var->base);
         return;
     }