diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2015-12-14 23:10:18 -0700 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2015-12-14 23:10:18 -0700 |
| commit | 83b68c9f13c90dfbbd2735cde4ef570ac50476c0 (patch) | |
| tree | e662b59bea4462299688db4c103a6ea27fd35b25 | |
| parent | 52e19b4a9b6e6140bae3c20c6f1fef36dca20aa7 (diff) | |
| download | zig-83b68c9f13c90dfbbd2735cde4ef570ac50476c0.tar.gz zig-83b68c9f13c90dfbbd2735cde4ef570ac50476c0.zip | |
add global variable support
closes #12
| -rw-r--r-- | src/analyze.cpp | 67 | ||||
| -rw-r--r-- | src/analyze.hpp | 12 | ||||
| -rw-r--r-- | src/codegen.cpp | 40 | ||||
| -rw-r--r-- | std/std.zig | 6 |
4 files changed, 79 insertions, 46 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp index 288fadf42f..01325ae816 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -575,11 +575,11 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) { context->parent = parent; context->variable_table.init(8); - if (parent) { - context->fn_entry = parent->fn_entry; - } else if (node && node->type == NodeTypeFnDef) { + if (node && node->type == NodeTypeFnDef) { AstNode *fn_proto_node = node->data.fn_def.fn_proto; context->fn_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry; + } else if (parent) { + context->fn_entry = parent->fn_entry; } if (context->fn_entry) { @@ -589,16 +589,26 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) { return context; } -LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) { - while (true) { +static VariableTableEntry *find_local_variable(BlockContext *context, Buf *name) { + while (context && context->fn_entry) { auto entry = context->variable_table.maybe_get(name); if (entry != nullptr) return entry->value; context = context->parent; - if (context == nullptr) - return nullptr; } + return nullptr; +} + +VariableTableEntry *find_variable(BlockContext *context, Buf *name) { + while (context) { + auto entry = context->variable_table.maybe_get(name); + if (entry != nullptr) + return entry->value; + + context = context->parent; + } + return nullptr; } static void get_struct_field(TypeTableEntry *struct_type, Buf *name, TypeStructField **out_tsf, int *out_i) { @@ -728,14 +738,13 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i return return_type; } -static TypeTableEntry *analyze_variable_name(CodeGen *g, BlockContext *context, +static TypeTableEntry *analyze_variable_name(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node, Buf *variable_name) { - LocalVariableTableEntry *local_variable = find_local_variable(context, variable_name); - if (local_variable) { - return local_variable->type; + VariableTableEntry *var = find_variable(context, variable_name); + if (var) { + return var->type; } else { - // TODO: check global variables also add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); return g->builtin_types.entry_invalid; @@ -919,7 +928,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, TypeTableEntry *expected_rhs_type = nullptr; if (lhs_node->type == NodeTypeSymbol) { Buf *name = &lhs_node->data.symbol; - LocalVariableTableEntry *var = find_local_variable(context, name); + VariableTableEntry *var = find_variable(context, name); if (var) { if (var->is_const) { add_node_error(g, lhs_node, @@ -1065,8 +1074,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, zig_unreachable(); } -static TypeTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, BlockContext *context, - TypeTableEntry *expected_type, AstNode *node) +static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, + BlockContext *context, TypeTableEntry *expected_type, AstNode *node) { AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration; @@ -1102,20 +1111,21 @@ static TypeTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type; assert(type != nullptr); // should have been caught by the parser - LocalVariableTableEntry *existing_variable = find_local_variable(context, &variable_declaration->symbol); + VariableTableEntry *existing_variable = find_local_variable(context, &variable_declaration->symbol); if (existing_variable) { add_node_error(g, node, buf_sprintf("redeclaration of variable '%s'", buf_ptr(&variable_declaration->symbol))); } else { - LocalVariableTableEntry *variable_entry = allocate<LocalVariableTableEntry>(1); + VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); buf_init_from_buf(&variable_entry->name, &variable_declaration->symbol); variable_entry->type = type; variable_entry->is_const = variable_declaration->is_const; variable_entry->is_ptr = true; variable_entry->decl_node = node; context->variable_table.put(&variable_entry->name, variable_entry); + return variable_entry; } - return g->builtin_types.entry_void; + return nullptr; } static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, @@ -1200,7 +1210,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, break; } case NodeTypeVariableDeclaration: - return_type = analyze_variable_declaration(g, import, context, expected_type, node); + analyze_variable_declaration(g, import, context, expected_type, node); + return_type = g->builtin_types.entry_void; break; case NodeTypeGoto: { @@ -1220,7 +1231,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, { for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) { AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); - analyze_variable_name(g, context, node, &asm_output->variable_name); + analyze_variable_name(g, import, context, node, &asm_output->variable_name); } for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) { AsmInput *asm_input = node->data.asm_expr.input_list.at(i); @@ -1330,7 +1341,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, case NodeTypeSymbol: { - return_type = analyze_variable_name(g, context, node, &node->data.symbol); + return_type = analyze_variable_name(g, import, context, node, &node->data.symbol); break; } case NodeTypeCastExpr: @@ -1429,7 +1440,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, assert(fn_proto_node->type == NodeTypeFnProto); alloc_codegen_node(node); - BlockContext *context = new_block_context(node, nullptr); + BlockContext *context = new_block_context(node, import->block_context); node->codegen_node->data.fn_def_node.block_context = context; AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto; @@ -1442,14 +1453,14 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, assert(param_decl->type->type == NodeTypeType); TypeTableEntry *type = param_decl->type->codegen_node->data.type_node.entry; - LocalVariableTableEntry *variable_entry = allocate<LocalVariableTableEntry>(1); + VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); buf_init_from_buf(&variable_entry->name, ¶m_decl->name); variable_entry->type = type; variable_entry->is_const = true; variable_entry->decl_node = param_decl_node; variable_entry->arg_index = i; - LocalVariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name); + VariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name); if (!existing_entry) { // unique definition context->variable_table.put(&variable_entry->name, variable_entry); @@ -1505,8 +1516,12 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, // nothing to do break; case NodeTypeVariableDeclaration: - analyze_variable_declaration(g, import, import->block_context, nullptr, node); - break; + { + VariableTableEntry *var = analyze_variable_declaration(g, import, import->block_context, + nullptr, node); + g->global_vars.append(var); + break; + } case NodeTypeDirective: case NodeTypeParamDecl: case NodeTypeFnProto: diff --git a/src/analyze.hpp b/src/analyze.hpp index 7ad84ba915..8a262a2c0a 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -16,6 +16,7 @@ struct FnTableEntry; struct BlockContext; struct TypeTableEntry; +struct VariableTableEntry; struct TypeTableEntryPointer { TypeTableEntry *pointer_child; @@ -177,6 +178,7 @@ struct CodeGen { // The function prototypes this module includes. In the case of external declarations, // there will not be a corresponding fn_defs entry. ZigList<FnTableEntry *> fn_protos; + ZigList<VariableTableEntry *> global_vars; OutType out_type; FnTableEntry *cur_fn; @@ -192,7 +194,7 @@ struct CodeGen { ImportTableEntry *root_import; }; -struct LocalVariableTableEntry { +struct VariableTableEntry { Buf name; TypeTableEntry *type; LLVMValueRef value_ref; @@ -204,10 +206,10 @@ struct LocalVariableTableEntry { }; struct BlockContext { - AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or null for module scope + AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or NodeTypeRoot FnTableEntry *fn_entry; // null at the module scope BlockContext *parent; // null when this is the root - HashMap<Buf *, LocalVariableTableEntry *, buf_hash, buf_eql_buf> variable_table; + HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table; ZigList<AstNode *> cast_expr_alloca_list; LLVMZigDIScope *di_scope; }; @@ -234,7 +236,7 @@ struct ExprNode { }; struct AssignNode { - LocalVariableTableEntry *var_entry; + VariableTableEntry *var_entry; }; struct BlockNode { @@ -295,7 +297,7 @@ void semantic_analyze(CodeGen *g); void add_node_error(CodeGen *g, AstNode *node, Buf *msg); TypeTableEntry *new_type_table_entry(TypeTableEntryId id); TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); -LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name); +VariableTableEntry *find_variable(BlockContext *context, Buf *name); BlockContext *new_block_context(AstNode *node, BlockContext *parent); #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index 5593a689eb..6b1b3428ee 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -558,7 +558,7 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { LLVMValueRef target_ref; TypeTableEntry *op1_type; if (lhs_node->type == NodeTypeSymbol) { - LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context, + VariableTableEntry *var = find_variable(node->codegen_node->expr_node.block_context, &lhs_node->data.symbol); // semantic checking ensures no variables are constant @@ -807,7 +807,7 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) { buf_append_char(&constraint_buf, ','); } - LocalVariableTableEntry *variable = find_local_variable( + VariableTableEntry *variable = find_variable( node->codegen_node->expr_node.block_context, &asm_output->variable_name); assert(variable); @@ -851,7 +851,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { return gen_return_expr(g, node); case NodeTypeVariableDeclaration: { - LocalVariableTableEntry *variable = find_local_variable( + VariableTableEntry *variable = find_variable( node->codegen_node->expr_node.block_context, &node->data.variable_declaration.symbol); @@ -940,13 +940,14 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { } case NodeTypeSymbol: { - LocalVariableTableEntry *variable = find_local_variable( + VariableTableEntry *variable = find_variable( node->codegen_node->expr_node.block_context, &node->data.symbol); assert(variable); if (variable->type->id == TypeTableEntryIdVoid) { return nullptr; } else if (variable->is_ptr) { + assert(variable->value_ref); if (variable->type->id == TypeTableEntryIdArray) { return variable->value_ref; } else if (variable->type->id == TypeTableEntryIdStruct) { @@ -1035,9 +1036,25 @@ static LLVMAttribute to_llvm_fn_attr(FnAttrId attr_id) { static void do_code_gen(CodeGen *g) { assert(!g->errors.length); + // Generate module level variables + for (int i = 0; i < g->global_vars.length; i += 1) { + VariableTableEntry *var = g->global_vars.at(i); + + LLVMValueRef init_val = gen_expr(g, var->decl_node->data.variable_declaration.expr); + + // TODO if the global is exported, set external linkage + LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(init_val), ""); + LLVMSetLinkage(global_value, LLVMPrivateLinkage); + LLVMSetInitializer(global_value, init_val); + LLVMSetGlobalConstant(global_value, var->is_const); + LLVMSetUnnamedAddr(global_value, true); + + var->value_ref = global_value; + } + // Generate function prototypes - for (int i = 0; i < g->fn_protos.length; i += 1) { - FnTableEntry *fn_table_entry = g->fn_protos.at(i); + for (int fn_proto_i = 0; fn_proto_i < g->fn_protos.length; fn_proto_i += 1) { + FnTableEntry *fn_table_entry = g->fn_protos.at(fn_proto_i); AstNode *proto_node = fn_table_entry->proto_node; assert(proto_node->type == NodeTypeFnProto); @@ -1090,14 +1107,13 @@ static void do_code_gen(CodeGen *g) { AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; // Add debug info. - LLVMZigDIScope *fn_scope = LLVMZigFileToScope(import->di_file); unsigned line_number = fn_def_node->line + 1; unsigned scope_line = line_number; bool is_definition = true; unsigned flags = 0; bool is_optimized = g->build_type == CodeGenBuildTypeRelease; LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder, - fn_scope, buf_ptr(&fn_proto->name), "", import->di_file, line_number, + import->block_context->di_scope, buf_ptr(&fn_proto->name), "", import->di_file, line_number, create_di_function_type(g, fn_proto, import->di_file), fn_table_entry->internal_linkage, is_definition, scope_line, flags, is_optimized, fn); @@ -1123,7 +1139,7 @@ static void do_code_gen(CodeGen *g) { assert(param_decl->type == NodeTypeParamDecl); if (is_param_decl_type_void(g, param_decl)) continue; - LocalVariableTableEntry *parameter_variable = fn_def_node->codegen_node->data.fn_def_node.block_context->variable_table.get(¶m_decl->data.param_decl.name); + VariableTableEntry *parameter_variable = fn_def_node->codegen_node->data.fn_def_node.block_context->variable_table.get(¶m_decl->data.param_decl.name); parameter_variable->value_ref = params[non_void_index]; non_void_index += 1; } @@ -1135,7 +1151,7 @@ static void do_code_gen(CodeGen *g) { for (int bc_i = 0; bc_i < fn_table_entry->all_block_contexts.length; bc_i += 1) { BlockContext *block_context = fn_table_entry->all_block_contexts.at(bc_i); - if (block_context->parent) { + if (!block_context->di_scope) { LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder, block_context->parent->di_scope, import->di_file, @@ -1152,7 +1168,7 @@ static void do_code_gen(CodeGen *g) { if (!entry) break; - LocalVariableTableEntry *var = entry->value; + VariableTableEntry *var = entry->value; if (var->type->id == TypeTableEntryIdVoid) continue; @@ -1530,7 +1546,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *src_dirname, Buf *src import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname)); g->import_table.put(full_path, import_entry); - import_entry->block_context = new_block_context(nullptr, nullptr); + import_entry->block_context = new_block_context(import_entry->root, nullptr); import_entry->block_context->di_scope = LLVMZigFileToScope(import_entry->di_file); diff --git a/std/std.zig b/std/std.zig index 375eddc920..8b19628441 100644 --- a/std/std.zig +++ b/std/std.zig @@ -1,3 +1,6 @@ +const SYS_write : isize = 1; +const stdout_fileno : isize = 1; + fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize { var result : isize; asm volatile (" @@ -13,15 +16,12 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize { return result; } -// TODO constants for SYS_write and stdout_fileno pub fn write(fd: isize, buf: &const u8, count: usize) -> isize { - const SYS_write : isize = 1; return syscall3(SYS_write, fd, buf as isize, count as isize); } // TODO error handling // TODO handle buffering and flushing pub fn print_str(str : string) -> isize { - const stdout_fileno : isize = 1; return write(stdout_fileno, str.ptr, str.len); } |
