| author | |
| committer | |
| log | 83b68c9f13c90dfbbd2735cde4ef570ac50476c0 |
| tree | e662b59bea4462299688db4c103a6ea27fd35b25 |
| parent | 52e19b4a9b6e6140bae3c20c6f1fef36dca20aa7 |
closes #124 files changed, 79 insertions(+), 46 deletions(-)
src/analyze.cpp+41-26| ... | @@ -575,11 +575,11 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) { | ... | @@ -575,11 +575,11 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) { |
| 575 | context->parent = parent; | 575 | context->parent = parent; |
| 576 | context->variable_table.init(8); | 576 | context->variable_table.init(8); |
| 577 | 577 | ||
| 578 | if (parent) { | 578 | if (node && node->type == NodeTypeFnDef) { |
| 579 | context->fn_entry = parent->fn_entry; | ||
| 580 | } else if (node && node->type == NodeTypeFnDef) { | ||
| 581 | AstNode *fn_proto_node = node->data.fn_def.fn_proto; | 579 | AstNode *fn_proto_node = node->data.fn_def.fn_proto; |
| 582 | context->fn_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry; | 580 | 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; | ||
| 583 | } | 583 | } |
| 584 | 584 | ||
| 585 | if (context->fn_entry) { | 585 | if (context->fn_entry) { |
| ... | @@ -589,16 +589,26 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) { | ... | @@ -589,16 +589,26 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) { |
| 589 | return context; | 589 | return context; |
| 590 | } | 590 | } |
| 591 | 591 | ||
| 592 | LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) { | 592 | static VariableTableEntry *find_local_variable(BlockContext *context, Buf *name) { |
| 593 | while (true) { | 593 | while (context && context->fn_entry) { |
| 594 | auto entry = context->variable_table.maybe_get(name); | 594 | auto entry = context->variable_table.maybe_get(name); |
| 595 | if (entry != nullptr) | 595 | if (entry != nullptr) |
| 596 | return entry->value; | 596 | return entry->value; |
| 597 | 597 | ||
| 598 | context = context->parent; | 598 | context = context->parent; |
| 599 | if (context == nullptr) | ||
| 600 | return nullptr; | ||
| 601 | } | 599 | } |
| 600 | return nullptr; | ||
| 601 | } | ||
| 602 | |||
| 603 | VariableTableEntry *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; | ||
| 602 | } | 612 | } |
| 603 | 613 | ||
| 604 | static void get_struct_field(TypeTableEntry *struct_type, Buf *name, TypeStructField **out_tsf, int *out_i) { | 614 | 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 | ... | @@ -728,14 +738,13 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i |
| 728 | return return_type; | 738 | return return_type; |
| 729 | } | 739 | } |
| 730 | 740 | ||
| 731 | static TypeTableEntry *analyze_variable_name(CodeGen *g, BlockContext *context, | 741 | static TypeTableEntry *analyze_variable_name(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 732 | AstNode *node, Buf *variable_name) | 742 | AstNode *node, Buf *variable_name) |
| 733 | { | 743 | { |
| 734 | LocalVariableTableEntry *local_variable = find_local_variable(context, variable_name); | 744 | VariableTableEntry *var = find_variable(context, variable_name); |
| 735 | if (local_variable) { | 745 | if (var) { |
| 736 | return local_variable->type; | 746 | return var->type; |
| 737 | } else { | 747 | } else { |
| 738 | // TODO: check global variables also | ||
| 739 | add_node_error(g, node, | 748 | add_node_error(g, node, |
| 740 | buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); | 749 | buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); |
| 741 | return g->builtin_types.entry_invalid; | 750 | return g->builtin_types.entry_invalid; |
| ... | @@ -919,7 +928,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -919,7 +928,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 919 | TypeTableEntry *expected_rhs_type = nullptr; | 928 | TypeTableEntry *expected_rhs_type = nullptr; |
| 920 | if (lhs_node->type == NodeTypeSymbol) { | 929 | if (lhs_node->type == NodeTypeSymbol) { |
| 921 | Buf *name = &lhs_node->data.symbol; | 930 | Buf *name = &lhs_node->data.symbol; |
| 922 | LocalVariableTableEntry *var = find_local_variable(context, name); | 931 | VariableTableEntry *var = find_variable(context, name); |
| 923 | if (var) { | 932 | if (var) { |
| 924 | if (var->is_const) { | 933 | if (var->is_const) { |
| 925 | add_node_error(g, lhs_node, | 934 | add_node_error(g, lhs_node, |
| ... | @@ -1065,8 +1074,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -1065,8 +1074,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 1065 | zig_unreachable(); | 1074 | zig_unreachable(); |
| 1066 | } | 1075 | } |
| 1067 | 1076 | ||
| 1068 | static TypeTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 1077 | static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, |
| 1069 | TypeTableEntry *expected_type, AstNode *node) | 1078 | BlockContext *context, TypeTableEntry *expected_type, AstNode *node) |
| 1070 | { | 1079 | { |
| 1071 | AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration; | 1080 | AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration; |
| 1072 | 1081 | ||
| ... | @@ -1102,20 +1111,21 @@ static TypeTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry | ... | @@ -1102,20 +1111,21 @@ static TypeTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry |
| 1102 | TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type; | 1111 | TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type; |
| 1103 | assert(type != nullptr); // should have been caught by the parser | 1112 | assert(type != nullptr); // should have been caught by the parser |
| 1104 | 1113 | ||
| 1105 | LocalVariableTableEntry *existing_variable = find_local_variable(context, &variable_declaration->symbol); | 1114 | VariableTableEntry *existing_variable = find_local_variable(context, &variable_declaration->symbol); |
| 1106 | if (existing_variable) { | 1115 | if (existing_variable) { |
| 1107 | add_node_error(g, node, | 1116 | add_node_error(g, node, |
| 1108 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(&variable_declaration->symbol))); | 1117 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(&variable_declaration->symbol))); |
| 1109 | } else { | 1118 | } else { |
| 1110 | LocalVariableTableEntry *variable_entry = allocate<LocalVariableTableEntry>(1); | 1119 | VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); |
| 1111 | buf_init_from_buf(&variable_entry->name, &variable_declaration->symbol); | 1120 | buf_init_from_buf(&variable_entry->name, &variable_declaration->symbol); |
| 1112 | variable_entry->type = type; | 1121 | variable_entry->type = type; |
| 1113 | variable_entry->is_const = variable_declaration->is_const; | 1122 | variable_entry->is_const = variable_declaration->is_const; |
| 1114 | variable_entry->is_ptr = true; | 1123 | variable_entry->is_ptr = true; |
| 1115 | variable_entry->decl_node = node; | 1124 | variable_entry->decl_node = node; |
| 1116 | context->variable_table.put(&variable_entry->name, variable_entry); | 1125 | context->variable_table.put(&variable_entry->name, variable_entry); |
| 1126 | return variable_entry; | ||
| 1117 | } | 1127 | } |
| 1118 | return g->builtin_types.entry_void; | 1128 | return nullptr; |
| 1119 | } | 1129 | } |
| 1120 | 1130 | ||
| 1121 | static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 1131 | static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| ... | @@ -1200,7 +1210,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -1200,7 +1210,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1200 | break; | 1210 | break; |
| 1201 | } | 1211 | } |
| 1202 | case NodeTypeVariableDeclaration: | 1212 | 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; | ||
| 1204 | break; | 1215 | break; |
| 1205 | case NodeTypeGoto: | 1216 | case NodeTypeGoto: |
| 1206 | { | 1217 | { |
| ... | @@ -1220,7 +1231,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -1220,7 +1231,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1220 | { | 1231 | { |
| 1221 | for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) { | 1232 | for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) { |
| 1222 | AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); | 1233 | 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); |
| 1224 | } | 1235 | } |
| 1225 | for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) { | 1236 | for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) { |
| 1226 | AsmInput *asm_input = node->data.asm_expr.input_list.at(i); | 1237 | AsmInput *asm_input = node->data.asm_expr.input_list.at(i); |
| ... | @@ -1330,7 +1341,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -1330,7 +1341,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1330 | 1341 | ||
| 1331 | case NodeTypeSymbol: | 1342 | case NodeTypeSymbol: |
| 1332 | { | 1343 | { |
| 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); |
| 1334 | break; | 1345 | break; |
| 1335 | } | 1346 | } |
| 1336 | case NodeTypeCastExpr: | 1347 | case NodeTypeCastExpr: |
| ... | @@ -1429,7 +1440,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, | ... | @@ -1429,7 +1440,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 1429 | assert(fn_proto_node->type == NodeTypeFnProto); | 1440 | assert(fn_proto_node->type == NodeTypeFnProto); |
| 1430 | 1441 | ||
| 1431 | alloc_codegen_node(node); | 1442 | alloc_codegen_node(node); |
| 1432 | BlockContext *context = new_block_context(node, nullptr); | 1443 | BlockContext *context = new_block_context(node, import->block_context); |
| 1433 | node->codegen_node->data.fn_def_node.block_context = context; | 1444 | node->codegen_node->data.fn_def_node.block_context = context; |
| 1434 | 1445 | ||
| 1435 | AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto; | 1446 | AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto; |
| ... | @@ -1442,14 +1453,14 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, | ... | @@ -1442,14 +1453,14 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 1442 | assert(param_decl->type->type == NodeTypeType); | 1453 | assert(param_decl->type->type == NodeTypeType); |
| 1443 | TypeTableEntry *type = param_decl->type->codegen_node->data.type_node.entry; | 1454 | TypeTableEntry *type = param_decl->type->codegen_node->data.type_node.entry; |
| 1444 | 1455 | ||
| 1445 | LocalVariableTableEntry *variable_entry = allocate<LocalVariableTableEntry>(1); | 1456 | VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); |
| 1446 | buf_init_from_buf(&variable_entry->name, &param_decl->name); | 1457 | buf_init_from_buf(&variable_entry->name, &param_decl->name); |
| 1447 | variable_entry->type = type; | 1458 | variable_entry->type = type; |
| 1448 | variable_entry->is_const = true; | 1459 | variable_entry->is_const = true; |
| 1449 | variable_entry->decl_node = param_decl_node; | 1460 | variable_entry->decl_node = param_decl_node; |
| 1450 | variable_entry->arg_index = i; | 1461 | variable_entry->arg_index = i; |
| 1451 | 1462 | ||
| 1452 | LocalVariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name); | 1463 | VariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name); |
| 1453 | if (!existing_entry) { | 1464 | if (!existing_entry) { |
| 1454 | // unique definition | 1465 | // unique definition |
| 1455 | context->variable_table.put(&variable_entry->name, variable_entry); | 1466 | context->variable_table.put(&variable_entry->name, variable_entry); |
| ... | @@ -1505,8 +1516,12 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, | ... | @@ -1505,8 +1516,12 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 1505 | // nothing to do | 1516 | // nothing to do |
| 1506 | break; | 1517 | break; |
| 1507 | case NodeTypeVariableDeclaration: | 1518 | case NodeTypeVariableDeclaration: |
| 1508 | analyze_variable_declaration(g, import, import->block_context, nullptr, node); | 1519 | { |
| 1509 | break; | 1520 | VariableTableEntry *var = analyze_variable_declaration(g, import, import->block_context, |
| 1521 | nullptr, node); | ||
| 1522 | g->global_vars.append(var); | ||
| 1523 | break; | ||
| 1524 | } | ||
| 1510 | case NodeTypeDirective: | 1525 | case NodeTypeDirective: |
| 1511 | case NodeTypeParamDecl: | 1526 | case NodeTypeParamDecl: |
| 1512 | case NodeTypeFnProto: | 1527 | case NodeTypeFnProto: |
src/analyze.hpp+7-5| ... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
| 16 | struct FnTableEntry; | 16 | struct FnTableEntry; |
| 17 | struct BlockContext; | 17 | struct BlockContext; |
| 18 | struct TypeTableEntry; | 18 | struct TypeTableEntry; |
| 19 | struct VariableTableEntry; | ||
| 19 | 20 | ||
| 20 | struct TypeTableEntryPointer { | 21 | struct TypeTableEntryPointer { |
| 21 | TypeTableEntry *pointer_child; | 22 | TypeTableEntry *pointer_child; |
| ... | @@ -177,6 +178,7 @@ struct CodeGen { | ... | @@ -177,6 +178,7 @@ struct CodeGen { |
| 177 | // The function prototypes this module includes. In the case of external declarations, | 178 | // The function prototypes this module includes. In the case of external declarations, |
| 178 | // there will not be a corresponding fn_defs entry. | 179 | // there will not be a corresponding fn_defs entry. |
| 179 | ZigList<FnTableEntry *> fn_protos; | 180 | ZigList<FnTableEntry *> fn_protos; |
| 181 | ZigList<VariableTableEntry *> global_vars; | ||
| 180 | 182 | ||
| 181 | OutType out_type; | 183 | OutType out_type; |
| 182 | FnTableEntry *cur_fn; | 184 | FnTableEntry *cur_fn; |
| ... | @@ -192,7 +194,7 @@ struct CodeGen { | ... | @@ -192,7 +194,7 @@ struct CodeGen { |
| 192 | ImportTableEntry *root_import; | 194 | ImportTableEntry *root_import; |
| 193 | }; | 195 | }; |
| 194 | 196 | ||
| 195 | struct LocalVariableTableEntry { | 197 | struct VariableTableEntry { |
| 196 | Buf name; | 198 | Buf name; |
| 197 | TypeTableEntry *type; | 199 | TypeTableEntry *type; |
| 198 | LLVMValueRef value_ref; | 200 | LLVMValueRef value_ref; |
| ... | @@ -204,10 +206,10 @@ struct LocalVariableTableEntry { | ... | @@ -204,10 +206,10 @@ struct LocalVariableTableEntry { |
| 204 | }; | 206 | }; |
| 205 | 207 | ||
| 206 | struct BlockContext { | 208 | struct BlockContext { |
| 207 | AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or null for module scope | 209 | AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or NodeTypeRoot |
| 208 | FnTableEntry *fn_entry; // null at the module scope | 210 | FnTableEntry *fn_entry; // null at the module scope |
| 209 | BlockContext *parent; // null when this is the root | 211 | 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; |
| 211 | ZigList<AstNode *> cast_expr_alloca_list; | 213 | ZigList<AstNode *> cast_expr_alloca_list; |
| 212 | LLVMZigDIScope *di_scope; | 214 | LLVMZigDIScope *di_scope; |
| 213 | }; | 215 | }; |
| ... | @@ -234,7 +236,7 @@ struct ExprNode { | ... | @@ -234,7 +236,7 @@ struct ExprNode { |
| 234 | }; | 236 | }; |
| 235 | 237 | ||
| 236 | struct AssignNode { | 238 | struct AssignNode { |
| 237 | LocalVariableTableEntry *var_entry; | 239 | VariableTableEntry *var_entry; |
| 238 | }; | 240 | }; |
| 239 | 241 | ||
| 240 | struct BlockNode { | 242 | struct BlockNode { |
| ... | @@ -295,7 +297,7 @@ void semantic_analyze(CodeGen *g); | ... | @@ -295,7 +297,7 @@ void semantic_analyze(CodeGen *g); |
| 295 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg); | 297 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg); |
| 296 | TypeTableEntry *new_type_table_entry(TypeTableEntryId id); | 298 | TypeTableEntry *new_type_table_entry(TypeTableEntryId id); |
| 297 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); | 299 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); |
| 298 | LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name); | 300 | VariableTableEntry *find_variable(BlockContext *context, Buf *name); |
| 299 | BlockContext *new_block_context(AstNode *node, BlockContext *parent); | 301 | BlockContext *new_block_context(AstNode *node, BlockContext *parent); |
| 300 | 302 | ||
| 301 | #endif | 303 | #endif |
src/codegen.cpp+28-12| ... | @@ -558,7 +558,7 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { | ... | @@ -558,7 +558,7 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { |
| 558 | LLVMValueRef target_ref; | 558 | LLVMValueRef target_ref; |
| 559 | TypeTableEntry *op1_type; | 559 | TypeTableEntry *op1_type; |
| 560 | if (lhs_node->type == NodeTypeSymbol) { | 560 | 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, |
| 562 | &lhs_node->data.symbol); | 562 | &lhs_node->data.symbol); |
| 563 | 563 | ||
| 564 | // semantic checking ensures no variables are constant | 564 | // semantic checking ensures no variables are constant |
| ... | @@ -807,7 +807,7 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) { | ... | @@ -807,7 +807,7 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) { |
| 807 | buf_append_char(&constraint_buf, ','); | 807 | buf_append_char(&constraint_buf, ','); |
| 808 | } | 808 | } |
| 809 | 809 | ||
| 810 | LocalVariableTableEntry *variable = find_local_variable( | 810 | VariableTableEntry *variable = find_variable( |
| 811 | node->codegen_node->expr_node.block_context, | 811 | node->codegen_node->expr_node.block_context, |
| 812 | &asm_output->variable_name); | 812 | &asm_output->variable_name); |
| 813 | assert(variable); | 813 | assert(variable); |
| ... | @@ -851,7 +851,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { | ... | @@ -851,7 +851,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 851 | return gen_return_expr(g, node); | 851 | return gen_return_expr(g, node); |
| 852 | case NodeTypeVariableDeclaration: | 852 | case NodeTypeVariableDeclaration: |
| 853 | { | 853 | { |
| 854 | LocalVariableTableEntry *variable = find_local_variable( | 854 | VariableTableEntry *variable = find_variable( |
| 855 | node->codegen_node->expr_node.block_context, | 855 | node->codegen_node->expr_node.block_context, |
| 856 | &node->data.variable_declaration.symbol); | 856 | &node->data.variable_declaration.symbol); |
| 857 | 857 | ||
| ... | @@ -940,13 +940,14 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { | ... | @@ -940,13 +940,14 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 940 | } | 940 | } |
| 941 | case NodeTypeSymbol: | 941 | case NodeTypeSymbol: |
| 942 | { | 942 | { |
| 943 | LocalVariableTableEntry *variable = find_local_variable( | 943 | VariableTableEntry *variable = find_variable( |
| 944 | node->codegen_node->expr_node.block_context, | 944 | node->codegen_node->expr_node.block_context, |
| 945 | &node->data.symbol); | 945 | &node->data.symbol); |
| 946 | assert(variable); | 946 | assert(variable); |
| 947 | if (variable->type->id == TypeTableEntryIdVoid) { | 947 | if (variable->type->id == TypeTableEntryIdVoid) { |
| 948 | return nullptr; | 948 | return nullptr; |
| 949 | } else if (variable->is_ptr) { | 949 | } else if (variable->is_ptr) { |
| 950 | assert(variable->value_ref); | ||
| 950 | if (variable->type->id == TypeTableEntryIdArray) { | 951 | if (variable->type->id == TypeTableEntryIdArray) { |
| 951 | return variable->value_ref; | 952 | return variable->value_ref; |
| 952 | } else if (variable->type->id == TypeTableEntryIdStruct) { | 953 | } else if (variable->type->id == TypeTableEntryIdStruct) { |
| ... | @@ -1035,9 +1036,25 @@ static LLVMAttribute to_llvm_fn_attr(FnAttrId attr_id) { | ... | @@ -1035,9 +1036,25 @@ static LLVMAttribute to_llvm_fn_attr(FnAttrId attr_id) { |
| 1035 | static void do_code_gen(CodeGen *g) { | 1036 | static void do_code_gen(CodeGen *g) { |
| 1036 | assert(!g->errors.length); | 1037 | assert(!g->errors.length); |
| 1037 | 1038 | ||
| 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 | |||
| 1038 | // Generate function prototypes | 1055 | // Generate function prototypes |
| 1039 | for (int i = 0; i < g->fn_protos.length; i += 1) { | 1056 | for (int fn_proto_i = 0; fn_proto_i < g->fn_protos.length; fn_proto_i += 1) { |
| 1040 | FnTableEntry *fn_table_entry = g->fn_protos.at(i); | 1057 | FnTableEntry *fn_table_entry = g->fn_protos.at(fn_proto_i); |
| 1041 | 1058 | ||
| 1042 | AstNode *proto_node = fn_table_entry->proto_node; | 1059 | AstNode *proto_node = fn_table_entry->proto_node; |
| 1043 | assert(proto_node->type == NodeTypeFnProto); | 1060 | assert(proto_node->type == NodeTypeFnProto); |
| ... | @@ -1090,14 +1107,13 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -1090,14 +1107,13 @@ static void do_code_gen(CodeGen *g) { |
| 1090 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; | 1107 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| 1091 | 1108 | ||
| 1092 | // Add debug info. | 1109 | // Add debug info. |
| 1093 | LLVMZigDIScope *fn_scope = LLVMZigFileToScope(import->di_file); | ||
| 1094 | unsigned line_number = fn_def_node->line + 1; | 1110 | unsigned line_number = fn_def_node->line + 1; |
| 1095 | unsigned scope_line = line_number; | 1111 | unsigned scope_line = line_number; |
| 1096 | bool is_definition = true; | 1112 | bool is_definition = true; |
| 1097 | unsigned flags = 0; | 1113 | unsigned flags = 0; |
| 1098 | bool is_optimized = g->build_type == CodeGenBuildTypeRelease; | 1114 | bool is_optimized = g->build_type == CodeGenBuildTypeRelease; |
| 1099 | LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder, | 1115 | 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, |
| 1101 | create_di_function_type(g, fn_proto, import->di_file), fn_table_entry->internal_linkage, | 1117 | create_di_function_type(g, fn_proto, import->di_file), fn_table_entry->internal_linkage, |
| 1102 | is_definition, scope_line, flags, is_optimized, fn); | 1118 | is_definition, scope_line, flags, is_optimized, fn); |
| 1103 | 1119 | ||
| ... | @@ -1123,7 +1139,7 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -1123,7 +1139,7 @@ static void do_code_gen(CodeGen *g) { |
| 1123 | assert(param_decl->type == NodeTypeParamDecl); | 1139 | assert(param_decl->type == NodeTypeParamDecl); |
| 1124 | if (is_param_decl_type_void(g, param_decl)) | 1140 | if (is_param_decl_type_void(g, param_decl)) |
| 1125 | continue; | 1141 | 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); |
| 1127 | parameter_variable->value_ref = params[non_void_index]; | 1143 | parameter_variable->value_ref = params[non_void_index]; |
| 1128 | non_void_index += 1; | 1144 | non_void_index += 1; |
| 1129 | } | 1145 | } |
| ... | @@ -1135,7 +1151,7 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -1135,7 +1151,7 @@ static void do_code_gen(CodeGen *g) { |
| 1135 | for (int bc_i = 0; bc_i < fn_table_entry->all_block_contexts.length; bc_i += 1) { | 1151 | for (int bc_i = 0; bc_i < fn_table_entry->all_block_contexts.length; bc_i += 1) { |
| 1136 | BlockContext *block_context = fn_table_entry->all_block_contexts.at(bc_i); | 1152 | BlockContext *block_context = fn_table_entry->all_block_contexts.at(bc_i); |
| 1137 | 1153 | ||
| 1138 | if (block_context->parent) { | 1154 | if (!block_context->di_scope) { |
| 1139 | LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder, | 1155 | LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder, |
| 1140 | block_context->parent->di_scope, | 1156 | block_context->parent->di_scope, |
| 1141 | import->di_file, | 1157 | import->di_file, |
| ... | @@ -1152,7 +1168,7 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -1152,7 +1168,7 @@ static void do_code_gen(CodeGen *g) { |
| 1152 | if (!entry) | 1168 | if (!entry) |
| 1153 | break; | 1169 | break; |
| 1154 | 1170 | ||
| 1155 | LocalVariableTableEntry *var = entry->value; | 1171 | VariableTableEntry *var = entry->value; |
| 1156 | if (var->type->id == TypeTableEntryIdVoid) | 1172 | if (var->type->id == TypeTableEntryIdVoid) |
| 1157 | continue; | 1173 | continue; |
| 1158 | 1174 | ||
| ... | @@ -1530,7 +1546,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *src_dirname, Buf *src | ... | @@ -1530,7 +1546,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *src_dirname, Buf *src |
| 1530 | import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname)); | 1546 | import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname)); |
| 1531 | g->import_table.put(full_path, import_entry); | 1547 | g->import_table.put(full_path, import_entry); |
| 1532 | 1548 | ||
| 1533 | import_entry->block_context = new_block_context(nullptr, nullptr); | 1549 | import_entry->block_context = new_block_context(import_entry->root, nullptr); |
| 1534 | import_entry->block_context->di_scope = LLVMZigFileToScope(import_entry->di_file); | 1550 | import_entry->block_context->di_scope = LLVMZigFileToScope(import_entry->di_file); |
| 1535 | 1551 | ||
| 1536 | 1552 |
std/std.zig+3-3| ... | @@ -1,3 +1,6 @@ | ... | @@ -1,3 +1,6 @@ |
| 1 | const SYS_write : isize = 1; | ||
| 2 | const stdout_fileno : isize = 1; | ||
| 3 | |||
| 1 | fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize { | 4 | fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize { |
| 2 | var result : isize; | 5 | var result : isize; |
| 3 | asm volatile (" | 6 | asm volatile (" |
| ... | @@ -13,15 +16,12 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize { | ... | @@ -13,15 +16,12 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize { |
| 13 | return result; | 16 | return result; |
| 14 | } | 17 | } |
| 15 | 18 | ||
| 16 | // TODO constants for SYS_write and stdout_fileno | ||
| 17 | pub fn write(fd: isize, buf: &const u8, count: usize) -> isize { | 19 | pub fn write(fd: isize, buf: &const u8, count: usize) -> isize { |
| 18 | const SYS_write : isize = 1; | ||
| 19 | return syscall3(SYS_write, fd, buf as isize, count as isize); | 20 | return syscall3(SYS_write, fd, buf as isize, count as isize); |
| 20 | } | 21 | } |
| 21 | 22 | ||
| 22 | // TODO error handling | 23 | // TODO error handling |
| 23 | // TODO handle buffering and flushing | 24 | // TODO handle buffering and flushing |
| 24 | pub fn print_str(str : string) -> isize { | 25 | pub fn print_str(str : string) -> isize { |
| 25 | const stdout_fileno : isize = 1; | ||
| 26 | return write(stdout_fileno, str.ptr, str.len); | 26 | return write(stdout_fileno, str.ptr, str.len); |
| 27 | } | 27 | } |