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...@@ -49,6 +49,9 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte
49static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);49static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);
50static void resolve_use_decl(CodeGen *g, AstNode *node);50static void resolve_use_decl(CodeGen *g, AstNode *node);
51static void preview_use_decl(CodeGen *g, AstNode *node);51static 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
53AstNode *first_executing_node(AstNode *node) {56AstNode *first_executing_node(AstNode *node) {
54 switch (node->type) {57 switch (node->type) {
...@@ -1677,6 +1680,129 @@ static void preview_error_value_decl(CodeGen *g, AstNode *node) {...@@ -1677,6 +1680,129 @@ static void preview_error_value_decl(CodeGen *g, AstNode *node) {
1677 node->data.error_value_decl.top_level_decl.resolution = TldResolutionOk;1680 node->data.error_value_decl.top_level_decl.resolution = TldResolutionOk;
1678}1681}
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
1680void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) {1806void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) {
1681 TopLevelDecl *tld = get_as_top_level_decl(node);1807 TopLevelDecl *tld = get_as_top_level_decl(node);
1682 if (tld->resolution != TldResolutionUnresolved) {1808 if (tld->resolution != TldResolutionUnresolved) {
...@@ -1705,14 +1831,8 @@ void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) {...@@ -1705,14 +1831,8 @@ void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) {
1705 resolve_struct_decl(g, import, node);1831 resolve_struct_decl(g, import, node);
1706 break;1832 break;
1707 case NodeTypeVariableDeclaration:1833 case NodeTypeVariableDeclaration:
1708 {1834 resolve_var_decl(g, import, node);
1709 AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;1835 break;
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 }
1716 case NodeTypeTypeDecl:1836 case NodeTypeTypeDecl:
1717 {1837 {
1718 AstNode *type_node = node->data.type_decl.child_type;1838 AstNode *type_node = node->data.type_decl.child_type;
...@@ -3566,6 +3686,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,...@@ -3566,6 +3686,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
3566}3686}
35673687
3568// Set name to nullptr to make the variable anonymous (not visible to programmer).3688// 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
3569static VariableTableEntry *add_local_var_shadowable(CodeGen *g, AstNode *source_node, ImportTableEntry *import,3690static VariableTableEntry *add_local_var_shadowable(CodeGen *g, AstNode *source_node, ImportTableEntry *import,
3570 BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node,3691 BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node,
3571 bool shadowable)3692 bool shadowable)
src/analyze.hpp+1
...@@ -58,5 +58,6 @@ void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only);...@@ -58,5 +58,6 @@ void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only);
58TopLevelDecl *get_as_top_level_decl(AstNode *node);58TopLevelDecl *get_as_top_level_decl(AstNode *node);
59void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node);59void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node);
60bool type_is_codegen_pointer(TypeTableEntry *type);60bool type_is_codegen_pointer(TypeTableEntry *type);
61TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry);
6162
62#endif63#endif
src/codegen.cpp+1-1
...@@ -2885,7 +2885,7 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn...@@ -2885,7 +2885,7 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn
2885 VariableTableEntry *var = instruction->var;2885 VariableTableEntry *var = instruction->var;
2886 if (type_has_bits(var->type)) {2886 if (type_has_bits(var->type)) {
2887 assert(var->value_ref);2887 assert(var->value_ref);
2888 return get_handle_value(g, var->value_ref, var->type);2888 return var->value_ref;
2889 } else {2889 } else {
2890 return nullptr;2890 return nullptr;
2891 }2891 }
src/ir.cpp+55-63
...@@ -617,39 +617,38 @@ static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) {...@@ -617,39 +617,38 @@ static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) {
617 irb->current_basic_block = basic_block;617 irb->current_basic_block = basic_block;
618}618}
619619
620// Set name to nullptr to make the variable anonymous (not visible to programmer).620static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, Buf *name,
621static VariableTableEntry *ir_add_local_var(IrBuilder *irb, AstNode *node, Buf *name,
622 bool is_const, bool is_shadowable)621 bool is_const, bool is_shadowable)
623{622{
624 VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);623 VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
625 variable_entry->block_context = node->block_context;624 variable_entry->block_context = node->block_context;
626 variable_entry->import = node->owner;625 variable_entry->import = node->owner;
627 variable_entry->shadowable = is_shadowable;626 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
630 if (name) {629 if (name) {
631 buf_init_from_buf(&variable_entry->name, name);630 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);
634 if (existing_var && !existing_var->shadowable) {633 if (existing_var && !existing_var->shadowable) {
635 ErrorMsg *msg = add_node_error(irb->codegen, node,634 ErrorMsg *msg = add_node_error(codegen, node,
636 buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));635 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"));636 add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
638 variable_entry->type = irb->codegen->builtin_types.entry_invalid;637 variable_entry->type = codegen->builtin_types.entry_invalid;
639 } else {638 } 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);
641 if (primitive_table_entry) {640 if (primitive_table_entry) {
642 TypeTableEntry *type = primitive_table_entry->value;641 TypeTableEntry *type = primitive_table_entry->value;
643 add_node_error(irb->codegen, node,642 add_node_error(codegen, node,
644 buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));643 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;
646 } else {645 } else {
647 AstNode *decl_node = find_decl(node->block_context, name);646 AstNode *decl_node = find_decl(node->block_context, name);
648 if (decl_node && decl_node->type != NodeTypeVariableDeclaration) {647 if (decl_node && decl_node->type != NodeTypeVariableDeclaration) {
649 ErrorMsg *msg = add_node_error(irb->codegen, node,648 ErrorMsg *msg = add_node_error(codegen, node,
650 buf_sprintf("redefinition of '%s'", buf_ptr(name)));649 buf_sprintf("redefinition of '%s'", buf_ptr(name)));
651 add_error_note(irb->codegen, msg, decl_node, buf_sprintf("previous definition is here"));650 add_error_note(codegen, msg, decl_node, buf_sprintf("previous definition is here"));
652 variable_entry->type = irb->codegen->builtin_types.entry_invalid;651 variable_entry->type = codegen->builtin_types.entry_invalid;
653 }652 }
654 }653 }
655 }654 }
...@@ -666,6 +665,15 @@ static VariableTableEntry *ir_add_local_var(IrBuilder *irb, AstNode *node, Buf *...@@ -666,6 +665,15 @@ static VariableTableEntry *ir_add_local_var(IrBuilder *irb, AstNode *node, Buf *
666 return variable_entry;665 return variable_entry;
667}666}
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
669static IrInstruction *ir_gen_block(IrBuilder *irb, AstNode *block_node) {677static IrInstruction *ir_gen_block(IrBuilder *irb, AstNode *block_node) {
670 assert(block_node->type == NodeTypeBlock);678 assert(block_node->type == NodeTypeBlock);
671679
...@@ -1224,6 +1232,13 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont...@@ -1224,6 +1232,13 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
1224 return ir_gen_array_access(irb, node, lval);1232 return ir_gen_array_access(irb, node, lval);
1225 case NodeTypeUnwrapErrorExpr:1233 case NodeTypeUnwrapErrorExpr:
1226 case NodeTypeReturnExpr:1234 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
1227 case NodeTypeDefer:1242 case NodeTypeDefer:
1228 case NodeTypeSliceExpr:1243 case NodeTypeSliceExpr:
1229 case NodeTypeFieldAccessExpr:1244 case NodeTypeFieldAccessExpr:
...@@ -1933,20 +1948,12 @@ static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value,...@@ -1933,20 +1948,12 @@ static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value,
1933 zig_unreachable();1948 zig_unreachable();
1934}1949}
19351950
1936static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructionReturn *return_instruction) {1951static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
1937 AstNode *source_node = return_instruction->base.source_node;1952 IrInstructionReturn *return_instruction)
1938 BlockContext *scope = source_node->block_context;1953{
1939 if (!scope->fn_entry) {1954 IrInstruction *value = ir_get_casted_value(ira, return_instruction->value->other, ira->explicit_return_type);
1940 add_node_error(ira->codegen, source_node, buf_sprintf("return expression outside function definition"));1955 if (value == ira->codegen->invalid_instruction)
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) {
1948 return ira->codegen->builtin_types.entry_invalid;1956 return ira->codegen->builtin_types.entry_invalid;
1949 }
1950 ira->implicit_return_type_list.append(value);1957 ira->implicit_return_type_list.append(value);
19511958
1952 IrInstruction *new_instruction = ir_build_return_from(&ira->new_irb, &return_instruction->base, value);1959 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...@@ -2333,43 +2340,10 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
2333 IrInstruction *var_type = nullptr;2340 IrInstruction *var_type = nullptr;
2334 if (decl_var_instruction->var_type != nullptr) {2341 if (decl_var_instruction->var_type != nullptr) {
2335 var_type = decl_var_instruction->var_type->other;2342 var_type = decl_var_instruction->var_type->other;
2336 explicit_type = ir_get_canonical_type(ira, var_type);2343 TypeTableEntry *proposed_type = ir_get_canonical_type(ira, var_type);
2337 switch (explicit_type->id) {2344 explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type);
2338 case TypeTableEntryIdTypeDecl:2345 if (explicit_type->id == TypeTableEntryIdInvalid)
2339 zig_unreachable();2346 return explicit_type;
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 }
2373 }2347 }
23742348
2375 IrInstruction *init_value = decl_var_instruction->init_value->other;2349 IrInstruction *init_value = decl_var_instruction->init_value->other;
...@@ -4306,3 +4280,21 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -4306,3 +4280,21 @@ bool ir_has_side_effects(IrInstruction *instruction) {
4306 }4280 }
4307 zig_unreachable();4281 zig_unreachable();
4308}4282}
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);...@@ -16,6 +16,8 @@ IrInstruction *ir_gen_fn(CodeGen *g, FnTableEntry *fn_entry);
16TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable,16TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable,
17 TypeTableEntry *expected_type, AstNode *expected_type_source_node);17 TypeTableEntry *expected_type, AstNode *expected_type_source_node);
1818
19IrInstruction *ir_exec_const_result(IrExecutable *exec);
20
19bool ir_has_side_effects(IrInstruction *instruction);21bool ir_has_side_effects(IrInstruction *instruction);
2022
21#endif23#endif