exported global variables get emitted as external in LLVM

master
Andrew Kelley 2017-02-03 11:59:56 -05:00
parent 71d335e5cc
commit aae168550f
5 changed files with 40 additions and 20 deletions

View File

@ -1278,7 +1278,12 @@ struct CodeGen {
ConstExprValue const_void_val; ConstExprValue const_void_val;
}; };
// TODO after merging IR branch, we can probably delete some of these fields enum VarLinkage {
VarLinkageInternal,
VarLinkageExport,
VarLinkageExternal,
};
struct VariableTableEntry { struct VariableTableEntry {
Buf name; Buf name;
ConstExprValue value; ConstExprValue value;
@ -1297,7 +1302,7 @@ struct VariableTableEntry {
bool shadowable; bool shadowable;
size_t mem_slot_index; size_t mem_slot_index;
size_t ref_count; size_t ref_count;
bool is_extern; VarLinkage linkage;
}; };
struct ErrorTableEntry { struct ErrorTableEntry {

View File

@ -1913,6 +1913,20 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
AstNode *source_node = tld_var->base.source_node; 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; IrInstruction *init_value = nullptr;
TypeTableEntry *implicit_type = nullptr; TypeTableEntry *implicit_type = nullptr;
@ -1926,7 +1940,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
if (implicit_type->id == TypeTableEntryIdUnreachable) { if (implicit_type->id == TypeTableEntryIdUnreachable) {
add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable")); add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable"));
implicit_type = g->builtin_types.entry_invalid; 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 == TypeTableEntryIdNumLitFloat ||
implicit_type->id == TypeTableEntryIdNumLitInt)) 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; implicit_type = g->builtin_types.entry_invalid;
} }
assert(implicit_type->id == TypeTableEntryIdInvalid || init_value->value.special != ConstValSpecialRuntime); 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")); add_node_error(g, source_node, buf_sprintf("variables must be initialized"));
implicit_type = g->builtin_types.entry_invalid; 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); 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 = 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); g->global_vars.append(tld_var->var);
} }

View File

@ -955,7 +955,7 @@ static void ast_render_tld_var(AstRender *ar, Buf *name, TldVar *tld_var) {
VariableTableEntry *var = tld_var->var; VariableTableEntry *var = tld_var->var;
const char *visib_mod_str = visib_mod_string(tld_var->base.visib_mod); 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 *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)); fprintf(ar->f, "%s%s%s %s", visib_mod_str, extern_str, const_or_var, buf_ptr(name));
if (var->value.type->id == TypeTableEntryIdNumLitFloat || if (var->value.type->id == TypeTableEntryIdNumLitFloat ||

View File

@ -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(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) { static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
if (fn_table_entry->llvm_value) 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 // 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 // values are rendered with a type other than the one we expect
if (handle_is_ptr(instruction->value.type)) { 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); 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.llvm_global, ptr_type->type_ref, "");
} else if (instruction->value.type->id == TypeTableEntryIdPointer) { } 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); base_ptr = gen_const_ptr_array_recursive(g, parent_array, parent_array_index);
} else { } else {
render_const_val(g, array_const_val); 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; base_ptr = array_const_val->llvm_global;
} }
TypeTableEntry *usize = g->builtin_types.entry_usize; 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); return fn_llvm_value(g, const_val->data.x_fn);
case TypeTableEntryIdPointer: 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; size_t index = const_val->data.x_ptr.index;
ConstExprValue *base_ptr = const_val->data.x_ptr.base_ptr; ConstExprValue *base_ptr = const_val->data.x_ptr.base_ptr;
if (base_ptr) { if (base_ptr) {
if (index == SIZE_MAX) { if (index == SIZE_MAX) {
render_const_val(g, base_ptr); 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; ConstExprValue *other_val = base_ptr;
const_val->llvm_value = LLVMConstBitCast(other_val->llvm_global, const_val->type->type_ref); 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; return const_val->llvm_value;
} else { } else {
ConstExprValue *array_const_val = base_ptr; 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; TypeTableEntry *usize = g->builtin_types.entry_usize;
const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
const_val->type->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; return const_val->llvm_value;
} }
LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, index); 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); LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
const_val->llvm_value = ptr_val; const_val->llvm_value = ptr_val;
render_const_val_global(g, const_val); render_const_val_global(g, const_val, false);
return ptr_val; return ptr_val;
} }
} else { } else {
TypeTableEntry *usize = g->builtin_types.entry_usize; TypeTableEntry *usize = g->builtin_types.entry_usize;
const_val->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, index, false), const_val->type->type_ref); 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; 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); 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) { if (!const_val->llvm_global) {
LLVMTypeRef type_ref = const_val->llvm_value ? LLVMTypeOf(const_val->llvm_value) : const_val->type->type_ref; 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, ""); LLVMValueRef global_value = LLVMAddGlobal(g->module, type_ref, "");
LLVMSetLinkage(global_value, LLVMInternalLinkage); LLVMSetLinkage(global_value, is_export ? LLVMExternalLinkage : LLVMInternalLinkage);
LLVMSetGlobalConstant(global_value, true); LLVMSetGlobalConstant(global_value, true);
LLVMSetUnnamedAddr(global_value, true); LLVMSetUnnamedAddr(global_value, true);
@ -2827,15 +2827,16 @@ static void do_code_gen(CodeGen *g) {
assert(var->decl_node); assert(var->decl_node);
LLVMValueRef global_value; 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)); global_value = LLVMAddGlobal(g->module, var->value.type->type_ref, buf_ptr(&var->name));
// TODO debug info for the extern variable // TODO debug info for the extern variable
LLVMSetLinkage(global_value, LLVMExternalLinkage); LLVMSetLinkage(global_value, LLVMExternalLinkage);
} else { } else {
bool is_export = (var->linkage == VarLinkageExport);
render_const_val(g, &var->value); 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; global_value = var->value.llvm_global;
// TODO debug info for function pointers // TODO debug info for function pointers
if (var->gen_is_const && var->value.type->id != TypeTableEntryIdFn) { if (var->gen_is_const && var->value.type->id != TypeTableEntryIdFn) {

View File

@ -1090,7 +1090,7 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) {
if (is_extern) { if (is_extern) {
TldVar *tld_var = create_global_var(c, name, create_const_runtime(var_type), is_const); 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); add_global(c, &tld_var->base);
return; return;
} }