diff options
| author | yvt <i@yvt.jp> | 2020-05-15 18:28:58 +0900 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-07-24 13:33:17 -0700 |
| commit | d3ebd428650748e60db70dd2171cc044855814b1 (patch) | |
| tree | 877fd512be87b46adf73c8143d0c721e9d9849c0 /src/codegen.cpp | |
| parent | 3b26e508638e96997aff3d5ef2c42a917bf86cc8 (diff) | |
| download | zig-d3ebd428650748e60db70dd2171cc044855814b1.tar.gz zig-d3ebd428650748e60db70dd2171cc044855814b1.zip | |
Support taking extern pointers at comptime
This commit makes it possible to obtain pointers to `extern` variables
at comptime.
- `ir_get_var_ptr` employs several checks to determine if the given
variable is eligible for obtaining its pointer at comptime. This
commit alters these checks to consider `extern` variables, which have
runtime values, as eligible.
- After this change, it's now possible for `render_const_val` to be
called for `extern` variables. This commit modifies
`render_const_val` to suppress the value generation for `extern`
variables.
- `do_code_gen` now creates `ZigValue::llvm_global` of `extern`
variables before iterating through module-level variables so that
other module-level variables can refer to them.
This solution is incomplete since there are several cases still
failing:
- `global_var.array[n..m]`
- `&global_var.array[i]`
- `&global_var.inner_struct.value`
- `&global_array[i]`
Closes #5349
Diffstat (limited to 'src/codegen.cpp')
| -rw-r--r-- | src/codegen.cpp | 70 |
1 files changed, 50 insertions, 20 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp index 3f3d80d51d..246ecb4369 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7754,6 +7754,13 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n } static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name) { + if (const_val->special == ConstValSpecialRuntime) { + // `const_val` refers to an extern variable. Don't generate an `LLVMValueRef` for + // the variable. We shouldn't call `LLVMSetInitializer` on it either. + assert(const_val->llvm_global); + return; + } + if (!const_val->llvm_value) const_val->llvm_value = gen_const_val(g, const_val, name); @@ -7762,6 +7769,13 @@ static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name) } static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name) { + if (const_val->special == ConstValSpecialRuntime) { + // `const_val` refers to an extern variable. `llvm_global` should already + // have been created by an earlier codegen pass. + assert(const_val->llvm_global); + return; + } + if (!const_val->llvm_global) { LLVMTypeRef type_ref = const_val->llvm_value ? LLVMTypeOf(const_val->llvm_value) : get_llvm_type(g, const_val->type); @@ -7891,6 +7905,39 @@ static void do_code_gen(CodeGen *g) { generate_error_name_table(g); + // Create extern variables + for (size_t i = 0; i < g->global_vars.length; i += 1) { + TldVar *tld_var = g->global_vars.at(i); + ZigVar *var = tld_var->var; + + bool externally_initialized = var->decl_node->data.variable_declaration.expr == nullptr; + if (!externally_initialized) { + continue; + } + + assert(var->decl_node->data.variable_declaration.is_extern); + const char *symbol_name = var->name; + + LLVMValueRef global_value; + LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, symbol_name); + if (existing_llvm_var) { + global_value = LLVMConstBitCast(existing_llvm_var, + LLVMPointerType(get_llvm_type(g, var->var_type), 0)); + } else { + global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), symbol_name); + // TODO debug info for the extern variable + + LLVMSetLinkage(global_value, LLVMExternalLinkage); + maybe_import_dll(g, global_value, GlobalLinkageIdStrong); + LLVMSetAlignment(global_value, var->align_bytes); + LLVMSetGlobalConstant(global_value, var->gen_is_const); + set_global_tls(g, var, global_value); + } + + var->value_ref = global_value; + var->const_value->llvm_global = global_value; + } + // Generate module level variables for (size_t i = 0; i < g->global_vars.length; i += 1) { TldVar *tld_var = g->global_vars.at(i); @@ -7956,28 +8003,12 @@ static void do_code_gen(CodeGen *g) { linkage = global_export->linkage; } - LLVMValueRef global_value; bool externally_initialized = var->decl_node->data.variable_declaration.expr == nullptr; - if (externally_initialized) { - LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, symbol_name); - if (existing_llvm_var) { - global_value = LLVMConstBitCast(existing_llvm_var, - LLVMPointerType(get_llvm_type(g, var->var_type), 0)); - } else { - global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), symbol_name); - // TODO debug info for the extern variable - - LLVMSetLinkage(global_value, to_llvm_linkage(linkage)); - maybe_import_dll(g, global_value, GlobalLinkageIdStrong); - LLVMSetAlignment(global_value, var->align_bytes); - LLVMSetGlobalConstant(global_value, var->gen_is_const); - set_global_tls(g, var, global_value); - } - } else { + if (!externally_initialized) { bool exported = (linkage != GlobalLinkageIdInternal); render_const_val(g, var->const_value, symbol_name); render_const_val_global(g, var->const_value, symbol_name); - global_value = var->const_value->llvm_global; + LLVMValueRef global_value = var->const_value->llvm_global; if (exported) { LLVMSetLinkage(global_value, to_llvm_linkage(linkage)); @@ -7997,10 +8028,9 @@ static void do_code_gen(CodeGen *g) { LLVMSetGlobalConstant(global_value, var->gen_is_const); set_global_tls(g, var, global_value); + var->value_ref = global_value; } - var->value_ref = global_value; - for (size_t export_i = 1; export_i < var->export_list.length; export_i += 1) { GlobalExport *global_export = &var->export_list.items[export_i]; LLVMAddAlias(g->module, LLVMTypeOf(var->value_ref), var->value_ref, buf_ptr(&global_export->name)); |
