authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-10-29 19:14:48-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-10-29 19:14:48-04:00
logafc5507b6469c9963db8e00efc5648f8e682cf02
tree4474b3bc4f036dfbfa29ecceb338b54b7de06926
parent8e2804efa1d23696a476ab3f88c6b9852370cf8b

ir: ability to modify global vars


5 files changed, 188 insertions(+), 72 deletions(-)

src/analyze.cpp+129-8
......@@ -49,6 +49,9 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte
4949static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);
5050static void resolve_use_decl(CodeGen *g, AstNode *node);
5151static void preview_use_decl(CodeGen *g, AstNode *node);
52static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, ImportTableEntry *import,
53 BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const,
54 AstNode *val_node);
5255
5356AstNode *first_executing_node(AstNode *node) {
5457 switch (node->type) {
......@@ -1677,6 +1680,129 @@ static void preview_error_value_decl(CodeGen *g, AstNode *node) {
16771680 node->data.error_value_decl.top_level_decl.resolution = TldResolutionOk;
16781681}
16791682
1683TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry) {
1684 TypeTableEntry *underlying_type = get_underlying_type(type_entry);
1685 switch (underlying_type->id) {
1686 case TypeTableEntryIdTypeDecl:
1687 zig_unreachable();
1688 case TypeTableEntryIdInvalid:
1689 return g->builtin_types.entry_invalid;
1690 case TypeTableEntryIdUnreachable:
1691 case TypeTableEntryIdVar:
1692 case TypeTableEntryIdNumLitFloat:
1693 case TypeTableEntryIdNumLitInt:
1694 case TypeTableEntryIdUndefLit:
1695 case TypeTableEntryIdNullLit:
1696 case TypeTableEntryIdBlock:
1697 add_node_error(g, source_node, buf_sprintf("variable of type '%s' not allowed",
1698 buf_ptr(&underlying_type->name)));
1699 return g->builtin_types.entry_invalid;
1700 case TypeTableEntryIdNamespace:
1701 case TypeTableEntryIdMetaType:
1702 case TypeTableEntryIdVoid:
1703 case TypeTableEntryIdBool:
1704 case TypeTableEntryIdInt:
1705 case TypeTableEntryIdFloat:
1706 case TypeTableEntryIdPointer:
1707 case TypeTableEntryIdArray:
1708 case TypeTableEntryIdStruct:
1709 case TypeTableEntryIdMaybe:
1710 case TypeTableEntryIdErrorUnion:
1711 case TypeTableEntryIdPureError:
1712 case TypeTableEntryIdEnum:
1713 case TypeTableEntryIdUnion:
1714 case TypeTableEntryIdFn:
1715 case TypeTableEntryIdGenericFn:
1716 return type_entry;
1717 }
1718 zig_unreachable();
1719}
1720
1721static void resolve_var_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
1722 assert(node->type == NodeTypeVariableDeclaration);
1723
1724 AstNodeVariableDeclaration *var_decl = &node->data.variable_declaration;
1725 BlockContext *scope = node->block_context;
1726 bool is_const = var_decl->is_const;
1727 bool is_export = (var_decl->top_level_decl.visib_mod == VisibModExport);
1728 bool is_extern = var_decl->is_extern;
1729
1730 assert(!scope->fn_entry);
1731
1732 TypeTableEntry *explicit_type = nullptr;
1733 if (var_decl->type) {
1734 TypeTableEntry *proposed_type = analyze_type_expr(g, import, scope, var_decl->type);
1735 explicit_type = validate_var_type(g, var_decl->type, proposed_type);
1736 }
1737
1738 TypeTableEntry *implicit_type = nullptr;
1739 if (explicit_type && explicit_type->id == TypeTableEntryIdInvalid) {
1740 implicit_type = explicit_type;
1741 } else if (var_decl->expr) {
1742 IrExecutable ir_executable = {0};
1743 IrExecutable analyzed_executable = {0};
1744 IrInstruction *result = ir_gen(g, var_decl->expr, scope, &ir_executable);
1745 if (result == g->invalid_instruction) {
1746 // ignore the poison value
1747 implicit_type = g->builtin_types.entry_invalid;
1748 } else {
1749 if (g->verbose) {
1750 fprintf(stderr, "var %s = {\n", buf_ptr(var_decl->symbol));
1751 ir_print(stderr, &ir_executable, 4);
1752 fprintf(stderr, "}\n");
1753 }
1754 implicit_type = ir_analyze(g, &ir_executable, &analyzed_executable,
1755 explicit_type, var_decl->type);
1756 if (g->verbose) {
1757 fprintf(stderr, "var %s = { // (analyzed)\n", buf_ptr(var_decl->symbol));
1758 ir_print(stderr, &analyzed_executable, 4);
1759 fprintf(stderr, "}\n");
1760 }
1761
1762 if (implicit_type->id == TypeTableEntryIdUnreachable) {
1763 add_node_error(g, node,
1764 buf_sprintf("variable initialization is unreachable"));
1765 implicit_type = g->builtin_types.entry_invalid;
1766 } else if ((!is_const || is_export) &&
1767 (implicit_type->id == TypeTableEntryIdNumLitFloat ||
1768 implicit_type->id == TypeTableEntryIdNumLitInt))
1769 {
1770 add_node_error(g, node, buf_sprintf("unable to infer variable type"));
1771 implicit_type = g->builtin_types.entry_invalid;
1772 } else if (implicit_type->id == TypeTableEntryIdMetaType && !is_const) {
1773 add_node_error(g, node, buf_sprintf("variable of type 'type' must be constant"));
1774 implicit_type = g->builtin_types.entry_invalid;
1775 }
1776 if (implicit_type->id != TypeTableEntryIdInvalid) {
1777 Expr *expr = get_resolved_expr(var_decl->expr);
1778 IrInstruction *result = ir_exec_const_result(&analyzed_executable);
1779 if (result) {
1780 assert(result->static_value.ok);
1781 expr->const_val = result->static_value;
1782 expr->type_entry = result->type_entry;
1783 } else {
1784 add_node_error(g, first_executing_node(var_decl->expr),
1785 buf_sprintf("global variable initializer requires constant expression"));
1786 implicit_type = g->builtin_types.entry_invalid;
1787 }
1788 }
1789 }
1790 } else if (!is_extern) {
1791 add_node_error(g, node, buf_sprintf("variables must be initialized"));
1792 implicit_type = g->builtin_types.entry_invalid;
1793 }
1794
1795 TypeTableEntry *type = explicit_type ? explicit_type : implicit_type;
1796 assert(type != nullptr); // should have been caught by the parser
1797
1798 VariableTableEntry *var = add_local_var(g, node, import, scope,
1799 var_decl->symbol, type, is_const, var_decl->expr);
1800
1801 var_decl->variable = var;
1802
1803 g->global_vars.append(var);
1804}
1805
16801806void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) {
16811807 TopLevelDecl *tld = get_as_top_level_decl(node);
16821808 if (tld->resolution != TldResolutionUnresolved) {
......@@ -1705,14 +1831,8 @@ void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) {
17051831 resolve_struct_decl(g, import, node);
17061832 break;
17071833 case NodeTypeVariableDeclaration:
1708 {
1709 AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;
1710 VariableTableEntry *var = analyze_variable_declaration_raw(g, import, node->block_context,
1711 node, variable_declaration, false, node, false);
1712
1713 g->global_vars.append(var);
1714 break;
1715 }
1834 resolve_var_decl(g, import, node);
1835 break;
17161836 case NodeTypeTypeDecl:
17171837 {
17181838 AstNode *type_node = node->data.type_decl.child_type;
......@@ -3566,6 +3686,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
35663686}
35673687
35683688// Set name to nullptr to make the variable anonymous (not visible to programmer).
3689// TODO merge with definition of add_local_var in ir.cpp
35693690static VariableTableEntry *add_local_var_shadowable(CodeGen *g, AstNode *source_node, ImportTableEntry *import,
35703691 BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node,
35713692 bool shadowable)
src/analyze.hpp+1
......@@ -58,5 +58,6 @@ void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only);
5858TopLevelDecl *get_as_top_level_decl(AstNode *node);
5959void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node);
6060bool type_is_codegen_pointer(TypeTableEntry *type);
61TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry);
6162
6263#endif
src/codegen.cpp+1-1
......@@ -2885,7 +2885,7 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn
28852885 VariableTableEntry *var = instruction->var;
28862886 if (type_has_bits(var->type)) {
28872887 assert(var->value_ref);
2888 return get_handle_value(g, var->value_ref, var->type);
2888 return var->value_ref;
28892889 } else {
28902890 return nullptr;
28912891 }
src/ir.cpp+55-63
......@@ -617,39 +617,38 @@ static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) {
617617 irb->current_basic_block = basic_block;
618618}
619619
620// Set name to nullptr to make the variable anonymous (not visible to programmer).
621static VariableTableEntry *ir_add_local_var(IrBuilder *irb, AstNode *node, Buf *name,
620static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, Buf *name,
622621 bool is_const, bool is_shadowable)
623622{
624623 VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
625624 variable_entry->block_context = node->block_context;
626625 variable_entry->import = node->owner;
627626 variable_entry->shadowable = is_shadowable;
628 variable_entry->mem_slot_index = exec_next_mem_slot(irb->exec);
627 variable_entry->mem_slot_index = SIZE_MAX;
629628
630629 if (name) {
631630 buf_init_from_buf(&variable_entry->name, name);
632631
633 VariableTableEntry *existing_var = find_variable(irb->codegen, node->block_context, name);
632 VariableTableEntry *existing_var = find_variable(codegen, node->block_context, name);
634633 if (existing_var && !existing_var->shadowable) {
635 ErrorMsg *msg = add_node_error(irb->codegen, node,
634 ErrorMsg *msg = add_node_error(codegen, node,
636635 buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
637 add_error_note(irb->codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
638 variable_entry->type = irb->codegen->builtin_types.entry_invalid;
636 add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
637 variable_entry->type = codegen->builtin_types.entry_invalid;
639638 } else {
640 auto primitive_table_entry = irb->codegen->primitive_type_table.maybe_get(name);
639 auto primitive_table_entry = codegen->primitive_type_table.maybe_get(name);
641640 if (primitive_table_entry) {
642641 TypeTableEntry *type = primitive_table_entry->value;
643 add_node_error(irb->codegen, node,
642 add_node_error(codegen, node,
644643 buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
645 variable_entry->type = irb->codegen->builtin_types.entry_invalid;
644 variable_entry->type = codegen->builtin_types.entry_invalid;
646645 } else {
647646 AstNode *decl_node = find_decl(node->block_context, name);
648647 if (decl_node && decl_node->type != NodeTypeVariableDeclaration) {
649 ErrorMsg *msg = add_node_error(irb->codegen, node,
648 ErrorMsg *msg = add_node_error(codegen, node,
650649 buf_sprintf("redefinition of '%s'", buf_ptr(name)));
651 add_error_note(irb->codegen, msg, decl_node, buf_sprintf("previous definition is here"));
652 variable_entry->type = irb->codegen->builtin_types.entry_invalid;
650 add_error_note(codegen, msg, decl_node, buf_sprintf("previous definition is here"));
651 variable_entry->type = codegen->builtin_types.entry_invalid;
653652 }
654653 }
655654 }
......@@ -666,6 +665,15 @@ static VariableTableEntry *ir_add_local_var(IrBuilder *irb, AstNode *node, Buf *
666665 return variable_entry;
667666}
668667
668// Set name to nullptr to make the variable anonymous (not visible to programmer).
669static VariableTableEntry *ir_add_local_var(IrBuilder *irb, AstNode *node, Buf *name,
670 bool is_const, bool is_shadowable)
671{
672 VariableTableEntry *var = add_local_var(irb->codegen, node, name, is_const, is_shadowable);
673 var->mem_slot_index = exec_next_mem_slot(irb->exec);
674 return var;
675}
676
669677static IrInstruction *ir_gen_block(IrBuilder *irb, AstNode *block_node) {
670678 assert(block_node->type == NodeTypeBlock);
671679
......@@ -1224,6 +1232,13 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
12241232 return ir_gen_array_access(irb, node, lval);
12251233 case NodeTypeUnwrapErrorExpr:
12261234 case NodeTypeReturnExpr:
1235 // TODO
1236 //if (!scope->fn_entry) {
1237 // add_node_error(ira->codegen, source_node,
1238 // buf_sprintf("return expression outside function definition"));
1239 // return ira->codegen->builtin_types.entry_invalid;
1240 //}
1241
12271242 case NodeTypeDefer:
12281243 case NodeTypeSliceExpr:
12291244 case NodeTypeFieldAccessExpr:
......@@ -1933,20 +1948,12 @@ static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value,
19331948 zig_unreachable();
19341949}
19351950
1936static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructionReturn *return_instruction) {
1937 AstNode *source_node = return_instruction->base.source_node;
1938 BlockContext *scope = source_node->block_context;
1939 if (!scope->fn_entry) {
1940 add_node_error(ira->codegen, source_node, buf_sprintf("return expression outside function definition"));
1941 return ira->codegen->builtin_types.entry_invalid;
1942 }
1943
1944 TypeTableEntry *expected_return_type = scope->fn_entry->type_entry->data.fn.fn_type_id.return_type;
1945
1946 IrInstruction *value = ir_get_casted_value(ira, return_instruction->value->other, expected_return_type);
1947 if (value == ira->codegen->invalid_instruction) {
1951static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
1952 IrInstructionReturn *return_instruction)
1953{
1954 IrInstruction *value = ir_get_casted_value(ira, return_instruction->value->other, ira->explicit_return_type);
1955 if (value == ira->codegen->invalid_instruction)
19481956 return ira->codegen->builtin_types.entry_invalid;
1949 }
19501957 ira->implicit_return_type_list.append(value);
19511958
19521959 IrInstruction *new_instruction = ir_build_return_from(&ira->new_irb, &return_instruction->base, value);
......@@ -2333,43 +2340,10 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
23332340 IrInstruction *var_type = nullptr;
23342341 if (decl_var_instruction->var_type != nullptr) {
23352342 var_type = decl_var_instruction->var_type->other;
2336 explicit_type = ir_get_canonical_type(ira, var_type);
2337 switch (explicit_type->id) {
2338 case TypeTableEntryIdTypeDecl:
2339 zig_unreachable();
2340 case TypeTableEntryIdInvalid:
2341 explicit_type = ira->codegen->builtin_types.entry_invalid;
2342 break;
2343 case TypeTableEntryIdUnreachable:
2344 case TypeTableEntryIdVar:
2345 case TypeTableEntryIdNumLitFloat:
2346 case TypeTableEntryIdNumLitInt:
2347 case TypeTableEntryIdUndefLit:
2348 case TypeTableEntryIdNullLit:
2349 case TypeTableEntryIdBlock:
2350 add_node_error(ira->codegen, var_type->source_node,
2351 buf_sprintf("variable of type '%s' not allowed", buf_ptr(&explicit_type->name)));
2352 explicit_type = ira->codegen->builtin_types.entry_invalid;
2353 break;
2354 case TypeTableEntryIdNamespace:
2355 case TypeTableEntryIdMetaType:
2356 case TypeTableEntryIdVoid:
2357 case TypeTableEntryIdBool:
2358 case TypeTableEntryIdInt:
2359 case TypeTableEntryIdFloat:
2360 case TypeTableEntryIdPointer:
2361 case TypeTableEntryIdArray:
2362 case TypeTableEntryIdStruct:
2363 case TypeTableEntryIdMaybe:
2364 case TypeTableEntryIdErrorUnion:
2365 case TypeTableEntryIdPureError:
2366 case TypeTableEntryIdEnum:
2367 case TypeTableEntryIdUnion:
2368 case TypeTableEntryIdFn:
2369 case TypeTableEntryIdGenericFn:
2370 // OK
2371 break;
2372 }
2343 TypeTableEntry *proposed_type = ir_get_canonical_type(ira, var_type);
2344 explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type);
2345 if (explicit_type->id == TypeTableEntryIdInvalid)
2346 return explicit_type;
23732347 }
23742348
23752349 IrInstruction *init_value = decl_var_instruction->init_value->other;
......@@ -4306,3 +4280,21 @@ bool ir_has_side_effects(IrInstruction *instruction) {
43064280 }
43074281 zig_unreachable();
43084282}
4283
4284IrInstruction *ir_exec_const_result(IrExecutable *exec) {
4285 if (exec->basic_block_list.length != 1)
4286 return nullptr;
4287
4288 IrBasicBlock *bb = exec->basic_block_list.at(0);
4289 if (bb->instruction_list.length != 1)
4290 return nullptr;
4291
4292 IrInstruction *only_inst = bb->instruction_list.at(0);
4293 if (only_inst->id != IrInstructionIdReturn)
4294 return nullptr;
4295
4296 IrInstructionReturn *ret_inst = (IrInstructionReturn *)only_inst;
4297 IrInstruction *value = ret_inst->value;
4298 assert(value->static_value.ok);
4299 return value;
4300}
src/ir.hpp+2
......@@ -16,6 +16,8 @@ IrInstruction *ir_gen_fn(CodeGen *g, FnTableEntry *fn_entry);
1616TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable,
1717 TypeTableEntry *expected_type, AstNode *expected_type_source_node);
1818
19IrInstruction *ir_exec_const_result(IrExecutable *exec);
20
1921bool ir_has_side_effects(IrInstruction *instruction);
2022
2123#endif