authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-14 23:10:18-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-14 23:10:18-07:00
log83b68c9f13c90dfbbd2735cde4ef570ac50476c0
treee662b59bea4462299688db4c103a6ea27fd35b25
parent52e19b4a9b6e6140bae3c20c6f1fef36dca20aa7

add global variable support

closes #12

4 files changed, 79 insertions(+), 46 deletions(-)

src/analyze.cpp+41-26
......@@ -575,11 +575,11 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
575575 context->parent = parent;
576576 context->variable_table.init(8);
577577
578 if (parent) {
579 context->fn_entry = parent->fn_entry;
580 } else if (node && node->type == NodeTypeFnDef) {
578 if (node && node->type == NodeTypeFnDef) {
581579 AstNode *fn_proto_node = node->data.fn_def.fn_proto;
582580 context->fn_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry;
581 } else if (parent) {
582 context->fn_entry = parent->fn_entry;
583583 }
584584
585585 if (context->fn_entry) {
......@@ -589,16 +589,26 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
589589 return context;
590590}
591591
592LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {
593 while (true) {
592static VariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {
593 while (context && context->fn_entry) {
594594 auto entry = context->variable_table.maybe_get(name);
595595 if (entry != nullptr)
596596 return entry->value;
597597
598598 context = context->parent;
599 if (context == nullptr)
600 return nullptr;
601599 }
600 return nullptr;
601}
602
603VariableTableEntry *find_variable(BlockContext *context, Buf *name) {
604 while (context) {
605 auto entry = context->variable_table.maybe_get(name);
606 if (entry != nullptr)
607 return entry->value;
608
609 context = context->parent;
610 }
611 return nullptr;
602612}
603613
604614static 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
728738 return return_type;
729739}
730740
731static TypeTableEntry *analyze_variable_name(CodeGen *g, BlockContext *context,
741static TypeTableEntry *analyze_variable_name(CodeGen *g, ImportTableEntry *import, BlockContext *context,
732742 AstNode *node, Buf *variable_name)
733743{
734 LocalVariableTableEntry *local_variable = find_local_variable(context, variable_name);
735 if (local_variable) {
736 return local_variable->type;
744 VariableTableEntry *var = find_variable(context, variable_name);
745 if (var) {
746 return var->type;
737747 } else {
738 // TODO: check global variables also
739748 add_node_error(g, node,
740749 buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
741750 return g->builtin_types.entry_invalid;
......@@ -919,7 +928,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
919928 TypeTableEntry *expected_rhs_type = nullptr;
920929 if (lhs_node->type == NodeTypeSymbol) {
921930 Buf *name = &lhs_node->data.symbol;
922 LocalVariableTableEntry *var = find_local_variable(context, name);
931 VariableTableEntry *var = find_variable(context, name);
923932 if (var) {
924933 if (var->is_const) {
925934 add_node_error(g, lhs_node,
......@@ -1065,8 +1074,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
10651074 zig_unreachable();
10661075}
10671076
1068static TypeTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1069 TypeTableEntry *expected_type, AstNode *node)
1077static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import,
1078 BlockContext *context, TypeTableEntry *expected_type, AstNode *node)
10701079{
10711080 AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;
10721081
......@@ -1102,20 +1111,21 @@ static TypeTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry
11021111 TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type;
11031112 assert(type != nullptr); // should have been caught by the parser
11041113
1105 LocalVariableTableEntry *existing_variable = find_local_variable(context, &variable_declaration->symbol);
1114 VariableTableEntry *existing_variable = find_local_variable(context, &variable_declaration->symbol);
11061115 if (existing_variable) {
11071116 add_node_error(g, node,
11081117 buf_sprintf("redeclaration of variable '%s'", buf_ptr(&variable_declaration->symbol)));
11091118 } else {
1110 LocalVariableTableEntry *variable_entry = allocate<LocalVariableTableEntry>(1);
1119 VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
11111120 buf_init_from_buf(&variable_entry->name, &variable_declaration->symbol);
11121121 variable_entry->type = type;
11131122 variable_entry->is_const = variable_declaration->is_const;
11141123 variable_entry->is_ptr = true;
11151124 variable_entry->decl_node = node;
11161125 context->variable_table.put(&variable_entry->name, variable_entry);
1126 return variable_entry;
11171127 }
1118 return g->builtin_types.entry_void;
1128 return nullptr;
11191129}
11201130
11211131static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
......@@ -1200,7 +1210,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
12001210 break;
12011211 }
12021212 case NodeTypeVariableDeclaration:
1203 return_type = analyze_variable_declaration(g, import, context, expected_type, node);
1213 analyze_variable_declaration(g, import, context, expected_type, node);
1214 return_type = g->builtin_types.entry_void;
12041215 break;
12051216 case NodeTypeGoto:
12061217 {
......@@ -1220,7 +1231,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
12201231 {
12211232 for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) {
12221233 AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
1223 analyze_variable_name(g, context, node, &asm_output->variable_name);
1234 analyze_variable_name(g, import, context, node, &asm_output->variable_name);
12241235 }
12251236 for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) {
12261237 AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
......@@ -1330,7 +1341,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
13301341
13311342 case NodeTypeSymbol:
13321343 {
1333 return_type = analyze_variable_name(g, context, node, &node->data.symbol);
1344 return_type = analyze_variable_name(g, import, context, node, &node->data.symbol);
13341345 break;
13351346 }
13361347 case NodeTypeCastExpr:
......@@ -1429,7 +1440,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
14291440 assert(fn_proto_node->type == NodeTypeFnProto);
14301441
14311442 alloc_codegen_node(node);
1432 BlockContext *context = new_block_context(node, nullptr);
1443 BlockContext *context = new_block_context(node, import->block_context);
14331444 node->codegen_node->data.fn_def_node.block_context = context;
14341445
14351446 AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto;
......@@ -1442,14 +1453,14 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
14421453 assert(param_decl->type->type == NodeTypeType);
14431454 TypeTableEntry *type = param_decl->type->codegen_node->data.type_node.entry;
14441455
1445 LocalVariableTableEntry *variable_entry = allocate<LocalVariableTableEntry>(1);
1456 VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
14461457 buf_init_from_buf(&variable_entry->name, &param_decl->name);
14471458 variable_entry->type = type;
14481459 variable_entry->is_const = true;
14491460 variable_entry->decl_node = param_decl_node;
14501461 variable_entry->arg_index = i;
14511462
1452 LocalVariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name);
1463 VariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name);
14531464 if (!existing_entry) {
14541465 // unique definition
14551466 context->variable_table.put(&variable_entry->name, variable_entry);
......@@ -1505,8 +1516,12 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
15051516 // nothing to do
15061517 break;
15071518 case NodeTypeVariableDeclaration:
1508 analyze_variable_declaration(g, import, import->block_context, nullptr, node);
1509 break;
1519 {
1520 VariableTableEntry *var = analyze_variable_declaration(g, import, import->block_context,
1521 nullptr, node);
1522 g->global_vars.append(var);
1523 break;
1524 }
15101525 case NodeTypeDirective:
15111526 case NodeTypeParamDecl:
15121527 case NodeTypeFnProto:
src/analyze.hpp+7-5
......@@ -16,6 +16,7 @@
1616struct FnTableEntry;
1717struct BlockContext;
1818struct TypeTableEntry;
19struct VariableTableEntry;
1920
2021struct TypeTableEntryPointer {
2122 TypeTableEntry *pointer_child;
......@@ -177,6 +178,7 @@ struct CodeGen {
177178 // The function prototypes this module includes. In the case of external declarations,
178179 // there will not be a corresponding fn_defs entry.
179180 ZigList<FnTableEntry *> fn_protos;
181 ZigList<VariableTableEntry *> global_vars;
180182
181183 OutType out_type;
182184 FnTableEntry *cur_fn;
......@@ -192,7 +194,7 @@ struct CodeGen {
192194 ImportTableEntry *root_import;
193195};
194196
195struct LocalVariableTableEntry {
197struct VariableTableEntry {
196198 Buf name;
197199 TypeTableEntry *type;
198200 LLVMValueRef value_ref;
......@@ -204,10 +206,10 @@ struct LocalVariableTableEntry {
204206};
205207
206208struct BlockContext {
207 AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or null for module scope
209 AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or NodeTypeRoot
208210 FnTableEntry *fn_entry; // null at the module scope
209211 BlockContext *parent; // null when this is the root
210 HashMap<Buf *, LocalVariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
212 HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
211213 ZigList<AstNode *> cast_expr_alloca_list;
212214 LLVMZigDIScope *di_scope;
213215};
......@@ -234,7 +236,7 @@ struct ExprNode {
234236};
235237
236238struct AssignNode {
237 LocalVariableTableEntry *var_entry;
239 VariableTableEntry *var_entry;
238240};
239241
240242struct BlockNode {
......@@ -295,7 +297,7 @@ void semantic_analyze(CodeGen *g);
295297void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
296298TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
297299TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
298LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name);
300VariableTableEntry *find_variable(BlockContext *context, Buf *name);
299301BlockContext *new_block_context(AstNode *node, BlockContext *parent);
300302
301303#endif
src/codegen.cpp+28-12
......@@ -558,7 +558,7 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
558558 LLVMValueRef target_ref;
559559 TypeTableEntry *op1_type;
560560 if (lhs_node->type == NodeTypeSymbol) {
561 LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context,
561 VariableTableEntry *var = find_variable(node->codegen_node->expr_node.block_context,
562562 &lhs_node->data.symbol);
563563
564564 // semantic checking ensures no variables are constant
......@@ -807,7 +807,7 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
807807 buf_append_char(&constraint_buf, ',');
808808 }
809809
810 LocalVariableTableEntry *variable = find_local_variable(
810 VariableTableEntry *variable = find_variable(
811811 node->codegen_node->expr_node.block_context,
812812 &asm_output->variable_name);
813813 assert(variable);
......@@ -851,7 +851,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
851851 return gen_return_expr(g, node);
852852 case NodeTypeVariableDeclaration:
853853 {
854 LocalVariableTableEntry *variable = find_local_variable(
854 VariableTableEntry *variable = find_variable(
855855 node->codegen_node->expr_node.block_context,
856856 &node->data.variable_declaration.symbol);
857857
......@@ -940,13 +940,14 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
940940 }
941941 case NodeTypeSymbol:
942942 {
943 LocalVariableTableEntry *variable = find_local_variable(
943 VariableTableEntry *variable = find_variable(
944944 node->codegen_node->expr_node.block_context,
945945 &node->data.symbol);
946946 assert(variable);
947947 if (variable->type->id == TypeTableEntryIdVoid) {
948948 return nullptr;
949949 } else if (variable->is_ptr) {
950 assert(variable->value_ref);
950951 if (variable->type->id == TypeTableEntryIdArray) {
951952 return variable->value_ref;
952953 } else if (variable->type->id == TypeTableEntryIdStruct) {
......@@ -1035,9 +1036,25 @@ static LLVMAttribute to_llvm_fn_attr(FnAttrId attr_id) {
10351036static void do_code_gen(CodeGen *g) {
10361037 assert(!g->errors.length);
10371038
1039 // Generate module level variables
1040 for (int i = 0; i < g->global_vars.length; i += 1) {
1041 VariableTableEntry *var = g->global_vars.at(i);
1042
1043 LLVMValueRef init_val = gen_expr(g, var->decl_node->data.variable_declaration.expr);
1044
1045 // TODO if the global is exported, set external linkage
1046 LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(init_val), "");
1047 LLVMSetLinkage(global_value, LLVMPrivateLinkage);
1048 LLVMSetInitializer(global_value, init_val);
1049 LLVMSetGlobalConstant(global_value, var->is_const);
1050 LLVMSetUnnamedAddr(global_value, true);
1051
1052 var->value_ref = global_value;
1053 }
1054
10381055 // Generate function prototypes
1039 for (int i = 0; i < g->fn_protos.length; i += 1) {
1040 FnTableEntry *fn_table_entry = g->fn_protos.at(i);
1056 for (int fn_proto_i = 0; fn_proto_i < g->fn_protos.length; fn_proto_i += 1) {
1057 FnTableEntry *fn_table_entry = g->fn_protos.at(fn_proto_i);
10411058
10421059 AstNode *proto_node = fn_table_entry->proto_node;
10431060 assert(proto_node->type == NodeTypeFnProto);
......@@ -1090,14 +1107,13 @@ static void do_code_gen(CodeGen *g) {
10901107 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
10911108
10921109 // Add debug info.
1093 LLVMZigDIScope *fn_scope = LLVMZigFileToScope(import->di_file);
10941110 unsigned line_number = fn_def_node->line + 1;
10951111 unsigned scope_line = line_number;
10961112 bool is_definition = true;
10971113 unsigned flags = 0;
10981114 bool is_optimized = g->build_type == CodeGenBuildTypeRelease;
10991115 LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder,
1100 fn_scope, buf_ptr(&fn_proto->name), "", import->di_file, line_number,
1116 import->block_context->di_scope, buf_ptr(&fn_proto->name), "", import->di_file, line_number,
11011117 create_di_function_type(g, fn_proto, import->di_file), fn_table_entry->internal_linkage,
11021118 is_definition, scope_line, flags, is_optimized, fn);
11031119
......@@ -1123,7 +1139,7 @@ static void do_code_gen(CodeGen *g) {
11231139 assert(param_decl->type == NodeTypeParamDecl);
11241140 if (is_param_decl_type_void(g, param_decl))
11251141 continue;
1126 LocalVariableTableEntry *parameter_variable = fn_def_node->codegen_node->data.fn_def_node.block_context->variable_table.get(&param_decl->data.param_decl.name);
1142 VariableTableEntry *parameter_variable = fn_def_node->codegen_node->data.fn_def_node.block_context->variable_table.get(&param_decl->data.param_decl.name);
11271143 parameter_variable->value_ref = params[non_void_index];
11281144 non_void_index += 1;
11291145 }
......@@ -1135,7 +1151,7 @@ static void do_code_gen(CodeGen *g) {
11351151 for (int bc_i = 0; bc_i < fn_table_entry->all_block_contexts.length; bc_i += 1) {
11361152 BlockContext *block_context = fn_table_entry->all_block_contexts.at(bc_i);
11371153
1138 if (block_context->parent) {
1154 if (!block_context->di_scope) {
11391155 LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder,
11401156 block_context->parent->di_scope,
11411157 import->di_file,
......@@ -1152,7 +1168,7 @@ static void do_code_gen(CodeGen *g) {
11521168 if (!entry)
11531169 break;
11541170
1155 LocalVariableTableEntry *var = entry->value;
1171 VariableTableEntry *var = entry->value;
11561172 if (var->type->id == TypeTableEntryIdVoid)
11571173 continue;
11581174
......@@ -1530,7 +1546,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *src_dirname, Buf *src
15301546 import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));
15311547 g->import_table.put(full_path, import_entry);
15321548
1533 import_entry->block_context = new_block_context(nullptr, nullptr);
1549 import_entry->block_context = new_block_context(import_entry->root, nullptr);
15341550 import_entry->block_context->di_scope = LLVMZigFileToScope(import_entry->di_file);
15351551
15361552
std/std.zig+3-3
......@@ -1,3 +1,6 @@
1const SYS_write : isize = 1;
2const stdout_fileno : isize = 1;
3
14fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
25 var result : isize;
36 asm volatile ("
......@@ -13,15 +16,12 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
1316 return result;
1417}
1518
16// TODO constants for SYS_write and stdout_fileno
1719pub fn write(fd: isize, buf: &const u8, count: usize) -> isize {
18 const SYS_write : isize = 1;
1920 return syscall3(SYS_write, fd, buf as isize, count as isize);
2021}
2122
2223// TODO error handling
2324// TODO handle buffering and flushing
2425pub fn print_str(str : string) -> isize {
25 const stdout_fileno : isize = 1;
2626 return write(stdout_fileno, str.ptr, str.len);
2727}