authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-05 18:43:16-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-05 18:43:16-05:00
log24048b2af62f1b36678aa08a20d0754cb712e485
tree09519ba8509ba40a3c1d9c85eee7d35f181ca37b
parent0541532ed6cf5a32b57a4a3f74e6d3a1699223a7

IR: implement break and continue


7 files changed, 228 insertions(+), 193 deletions(-)

src/all_types.hpp+16-3
...@@ -642,9 +642,11 @@ struct AstNodeBoolLiteral {...@@ -642,9 +642,11 @@ struct AstNodeBoolLiteral {
642};642};
643643
644struct AstNodeBreakExpr {644struct AstNodeBreakExpr {
645 bool is_inline; // TODO
645};646};
646647
647struct AstNodeContinueExpr {648struct AstNodeContinueExpr {
649 bool is_inline; // TODO
648};650};
649651
650struct AstNodeArrayType {652struct AstNodeArrayType {
...@@ -1233,11 +1235,21 @@ struct LabelTableEntry {...@@ -1233,11 +1235,21 @@ struct LabelTableEntry {
1233 bool used;1235 bool used;
1234};1236};
12351237
1238enum ScopeId {
1239 ScopeIdDecls,
1240 ScopeIdBlock,
1241 ScopeIdDefer,
1242 ScopeIdVarDecl,
1243 ScopeIdCImport,
1244 ScopeIdLoop,
1245 ScopeIdFnDef,
1246};
1247
1236struct Scope {1248struct Scope {
1237 AstNode *node;1249 ScopeId id;
1250 AstNode *source_node;
12381251
1239 // if the scope has a parent, this is it. Every scope has a parent except1252 // if the scope has a parent, this is it
1240 // ScopeIdGlobal
1241 Scope *parent;1253 Scope *parent;
12421254
1243 ZigLLVMDIScope *di_scope;1255 ZigLLVMDIScope *di_scope;
...@@ -1293,6 +1305,7 @@ struct ScopeCImport {...@@ -1293,6 +1305,7 @@ struct ScopeCImport {
1293// This scope is created for a loop such as for or while in order to1305// This scope is created for a loop such as for or while in order to
1294// make break and continue statements work.1306// make break and continue statements work.
1295// NodeTypeForExpr or NodeTypeWhileExpr1307// NodeTypeForExpr or NodeTypeWhileExpr
1308// TODO I think we can get rid of this
1296struct ScopeLoop {1309struct ScopeLoop {
1297 Scope base;1310 Scope base;
1298};1311};
src/analyze.cpp+15-21
...@@ -130,15 +130,16 @@ ScopeDecls *get_container_scope(TypeTableEntry *type_entry) {...@@ -130,15 +130,16 @@ ScopeDecls *get_container_scope(TypeTableEntry *type_entry) {
130 return *get_container_scope_ptr(type_entry);130 return *get_container_scope_ptr(type_entry);
131}131}
132132
133void init_scope(Scope *dest, AstNode *node, Scope *parent) {133void init_scope(Scope *dest, ScopeId id, AstNode *source_node, Scope *parent) {
134 dest->node = node;134 dest->id = id;
135 dest->source_node = source_node;
135 dest->parent = parent;136 dest->parent = parent;
136}137}
137138
138static ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import) {139static ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import) {
139 assert(node->type == NodeTypeRoot || node->type == NodeTypeContainerDecl);140 assert(node->type == NodeTypeRoot || node->type == NodeTypeContainerDecl);
140 ScopeDecls *scope = allocate<ScopeDecls>(1);141 ScopeDecls *scope = allocate<ScopeDecls>(1);
141 init_scope(&scope->base, node, parent);142 init_scope(&scope->base, ScopeIdDecls, node, parent);
142 scope->decl_table.init(4);143 scope->decl_table.init(4);
143 scope->container_type = container_type;144 scope->container_type = container_type;
144 scope->import = import;145 scope->import = import;
...@@ -148,7 +149,7 @@ static ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEnt...@@ -148,7 +149,7 @@ static ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEnt
148Scope *create_block_scope(AstNode *node, Scope *parent) {149Scope *create_block_scope(AstNode *node, Scope *parent) {
149 assert(node->type == NodeTypeBlock);150 assert(node->type == NodeTypeBlock);
150 ScopeBlock *scope = allocate<ScopeBlock>(1);151 ScopeBlock *scope = allocate<ScopeBlock>(1);
151 init_scope(&scope->base, node, parent);152 init_scope(&scope->base, ScopeIdBlock, node, parent);
152 scope->label_table.init(1);153 scope->label_table.init(1);
153 return &scope->base;154 return &scope->base;
154}155}
...@@ -156,14 +157,13 @@ Scope *create_block_scope(AstNode *node, Scope *parent) {...@@ -156,14 +157,13 @@ Scope *create_block_scope(AstNode *node, Scope *parent) {
156Scope *create_defer_scope(AstNode *node, Scope *parent) {157Scope *create_defer_scope(AstNode *node, Scope *parent) {
157 assert(node->type == NodeTypeDefer);158 assert(node->type == NodeTypeDefer);
158 ScopeDefer *scope = allocate<ScopeDefer>(1);159 ScopeDefer *scope = allocate<ScopeDefer>(1);
159 init_scope(&scope->base, node, parent);160 init_scope(&scope->base, ScopeIdDefer, node, parent);
160 return &scope->base;161 return &scope->base;
161}162}
162163
163Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var) {164Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var) {
164 assert(node->type == NodeTypeVariableDeclaration || node->type == NodeTypeParamDecl);
165 ScopeVarDecl *scope = allocate<ScopeVarDecl>(1);165 ScopeVarDecl *scope = allocate<ScopeVarDecl>(1);
166 init_scope(&scope->base, node, parent);166 init_scope(&scope->base, ScopeIdVarDecl, node, parent);
167 scope->var = var;167 scope->var = var;
168 return &scope->base;168 return &scope->base;
169}169}
...@@ -171,7 +171,7 @@ Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var) {...@@ -171,7 +171,7 @@ Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var) {
171Scope *create_cimport_scope(AstNode *node, Scope *parent) {171Scope *create_cimport_scope(AstNode *node, Scope *parent) {
172 assert(node->type == NodeTypeFnCallExpr);172 assert(node->type == NodeTypeFnCallExpr);
173 ScopeCImport *scope = allocate<ScopeCImport>(1);173 ScopeCImport *scope = allocate<ScopeCImport>(1);
174 init_scope(&scope->base, node, parent);174 init_scope(&scope->base, ScopeIdCImport, node, parent);
175 buf_resize(&scope->c_import_buf, 0);175 buf_resize(&scope->c_import_buf, 0);
176 return &scope->base;176 return &scope->base;
177}177}
...@@ -179,21 +179,21 @@ Scope *create_cimport_scope(AstNode *node, Scope *parent) {...@@ -179,21 +179,21 @@ Scope *create_cimport_scope(AstNode *node, Scope *parent) {
179Scope *create_loop_scope(AstNode *node, Scope *parent) {179Scope *create_loop_scope(AstNode *node, Scope *parent) {
180 assert(node->type == NodeTypeWhileExpr || node->type == NodeTypeForExpr);180 assert(node->type == NodeTypeWhileExpr || node->type == NodeTypeForExpr);
181 ScopeLoop *scope = allocate<ScopeLoop>(1);181 ScopeLoop *scope = allocate<ScopeLoop>(1);
182 init_scope(&scope->base, node, parent);182 init_scope(&scope->base, ScopeIdLoop, node, parent);
183 return &scope->base;183 return &scope->base;
184}184}
185185
186ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry) {186ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry) {
187 assert(node->type == NodeTypeFnDef);187 assert(node->type == NodeTypeFnDef);
188 ScopeFnDef *scope = allocate<ScopeFnDef>(1);188 ScopeFnDef *scope = allocate<ScopeFnDef>(1);
189 init_scope(&scope->base, node, parent);189 init_scope(&scope->base, ScopeIdFnDef, node, parent);
190 scope->fn_entry = fn_entry;190 scope->fn_entry = fn_entry;
191 return scope;191 return scope;
192}192}
193193
194ImportTableEntry *get_scope_import(Scope *scope) {194ImportTableEntry *get_scope_import(Scope *scope) {
195 while (scope) {195 while (scope) {
196 if (scope->node->type == NodeTypeRoot || scope->node->type == NodeTypeContainerDecl) {196 if (scope->id == ScopeIdDecls) {
197 ScopeDecls *decls_scope = (ScopeDecls *)scope;197 ScopeDecls *decls_scope = (ScopeDecls *)scope;
198 assert(decls_scope->import);198 assert(decls_scope->import);
199 return decls_scope->import;199 return decls_scope->import;
...@@ -1991,9 +1991,7 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *...@@ -1991,9 +1991,7 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
19911991
1992Tld *find_decl(Scope *scope, Buf *name) {1992Tld *find_decl(Scope *scope, Buf *name) {
1993 while (scope) {1993 while (scope) {
1994 if (scope->node->type == NodeTypeRoot ||1994 if (scope->id == ScopeIdDecls) {
1995 scope->node->type == NodeTypeContainerDecl)
1996 {
1997 ScopeDecls *decls_scope = (ScopeDecls *)scope;1995 ScopeDecls *decls_scope = (ScopeDecls *)scope;
1998 auto entry = decls_scope->decl_table.maybe_get(name);1996 auto entry = decls_scope->decl_table.maybe_get(name);
1999 if (entry)1997 if (entry)
...@@ -2006,15 +2004,11 @@ Tld *find_decl(Scope *scope, Buf *name) {...@@ -2006,15 +2004,11 @@ Tld *find_decl(Scope *scope, Buf *name) {
20062004
2007VariableTableEntry *find_variable(CodeGen *g, Scope *scope, Buf *name) {2005VariableTableEntry *find_variable(CodeGen *g, Scope *scope, Buf *name) {
2008 while (scope) {2006 while (scope) {
2009 if (scope->node->type == NodeTypeVariableDeclaration ||2007 if (scope->id == ScopeIdVarDecl) {
2010 scope->node->type == NodeTypeParamDecl)
2011 {
2012 ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;2008 ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
2013 if (buf_eql_buf(name, &var_scope->var->name))2009 if (buf_eql_buf(name, &var_scope->var->name))
2014 return var_scope->var;2010 return var_scope->var;
2015 } else if (scope->node->type == NodeTypeRoot ||2011 } else if (scope->id == ScopeIdDecls) {
2016 scope->node->type == NodeTypeContainerDecl)
2017 {
2018 ScopeDecls *decls_scope = (ScopeDecls *)scope;2012 ScopeDecls *decls_scope = (ScopeDecls *)scope;
2019 auto entry = decls_scope->decl_table.maybe_get(name);2013 auto entry = decls_scope->decl_table.maybe_get(name);
2020 if (entry) {2014 if (entry) {
...@@ -2034,7 +2028,7 @@ VariableTableEntry *find_variable(CodeGen *g, Scope *scope, Buf *name) {...@@ -2034,7 +2028,7 @@ VariableTableEntry *find_variable(CodeGen *g, Scope *scope, Buf *name) {
20342028
2035FnTableEntry *scope_fn_entry(Scope *scope) {2029FnTableEntry *scope_fn_entry(Scope *scope) {
2036 while (scope) {2030 while (scope) {
2037 if (scope->node->type == NodeTypeFnDef) {2031 if (scope->id == ScopeIdFnDef) {
2038 ScopeFnDef *fn_scope = (ScopeFnDef *)scope;2032 ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
2039 return fn_scope->fn_entry;2033 return fn_scope->fn_entry;
2040 }2034 }
src/ast_render.cpp+58-7
...@@ -364,6 +364,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -364,6 +364,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
364 case NodeTypeSwitchProng:364 case NodeTypeSwitchProng:
365 case NodeTypeSwitchRange:365 case NodeTypeSwitchRange:
366 case NodeTypeLabel:366 case NodeTypeLabel:
367 case NodeTypeStructValueField:
367 zig_unreachable();368 zig_unreachable();
368 case NodeTypeRoot:369 case NodeTypeRoot:
369 for (size_t i = 0; i < node->data.root.top_level_decls.length; i += 1) {370 for (size_t i = 0; i < node->data.root.top_level_decls.length; i += 1) {
...@@ -602,9 +603,30 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -602,9 +603,30 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
602 }603 }
603 case NodeTypeContainerInitExpr:604 case NodeTypeContainerInitExpr:
604 render_node_ungrouped(ar, node->data.container_init_expr.type);605 render_node_ungrouped(ar, node->data.container_init_expr.type);
605 fprintf(ar->f, "{");606 if (node->data.container_init_expr.kind == ContainerInitKindStruct) {
606 assert(node->data.container_init_expr.entries.length == 0);607 fprintf(ar->f, "{\n");
608 ar->indent += ar->indent_size;
609 } else {
610 fprintf(ar->f, "{");
611 }
612 for (size_t i = 0; i < node->data.container_init_expr.entries.length; i += 1) {
613 AstNode *entry = node->data.container_init_expr.entries.at(i);
614 if (entry->type == NodeTypeStructValueField) {
615 Buf *name = entry->data.struct_val_field.name;
616 AstNode *expr = entry->data.struct_val_field.expr;
617 fprintf(ar->f, ".%s = ", buf_ptr(name));
618 render_node_grouped(ar, expr);
619 fprintf(ar->f, ",\n");
620 } else {
621 if (i != 0)
622 fprintf(ar->f, ", ");
623 render_node_grouped(ar, entry);
624 }
625 }
607 fprintf(ar->f, "}");626 fprintf(ar->f, "}");
627 if (node->data.container_init_expr.kind == ContainerInitKindStruct) {
628 ar->indent -= ar->indent_size;
629 }
608 break;630 break;
609 case NodeTypeArrayType:631 case NodeTypeArrayType:
610 {632 {
...@@ -788,7 +810,40 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -788,7 +810,40 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
788 }810 }
789 case NodeTypeGoto:811 case NodeTypeGoto:
790 {812 {
791 fprintf(ar->f, "goto %s", buf_ptr(node->data.goto_expr.name));813 const char *inline_str = node->data.goto_expr.is_inline ? "inline " : "";
814 fprintf(ar->f, "%sgoto %s", inline_str, buf_ptr(node->data.goto_expr.name));
815 break;
816 }
817 case NodeTypeForExpr:
818 {
819 const char *inline_str = node->data.for_expr.is_inline ? "inline " : "";
820 fprintf(ar->f, "%sfor (", inline_str);
821 render_node_grouped(ar, node->data.for_expr.array_expr);
822 fprintf(ar->f, ") ");
823 if (node->data.for_expr.elem_node) {
824 fprintf(ar->f, "|");
825 if (node->data.for_expr.elem_is_ptr)
826 fprintf(ar->f, "*");
827 render_node_grouped(ar, node->data.for_expr.elem_node);
828 if (node->data.for_expr.index_node) {
829 fprintf(ar->f, ", ");
830 render_node_grouped(ar, node->data.for_expr.index_node);
831 }
832 fprintf(ar->f, "| ");
833 }
834 render_node_grouped(ar, node->data.for_expr.body);
835 break;
836 }
837 case NodeTypeBreak:
838 {
839 const char *inline_str = node->data.break_expr.is_inline ? "inline " : "";
840 fprintf(ar->f, "%sbreak", inline_str);
841 break;
842 }
843 case NodeTypeContinue:
844 {
845 const char *inline_str = node->data.continue_expr.is_inline ? "inline " : "";
846 fprintf(ar->f, "%scontinue", inline_str);
792 break;847 break;
793 }848 }
794 case NodeTypeFnDecl:849 case NodeTypeFnDecl:
...@@ -797,12 +852,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -797,12 +852,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
797 case NodeTypeUnwrapErrorExpr:852 case NodeTypeUnwrapErrorExpr:
798 case NodeTypeSliceExpr:853 case NodeTypeSliceExpr:
799 case NodeTypeStructField:854 case NodeTypeStructField:
800 case NodeTypeStructValueField:
801 case NodeTypeUse:855 case NodeTypeUse:
802 case NodeTypeZeroesLiteral:856 case NodeTypeZeroesLiteral:
803 case NodeTypeForExpr:
804 case NodeTypeBreak:
805 case NodeTypeContinue:
806 zig_panic("TODO more ast rendering");857 zig_panic("TODO more ast rendering");
807 }858 }
808}859}
src/codegen.cpp+50-35
...@@ -277,40 +277,55 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {...@@ -277,40 +277,55 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
277 if (scope->di_scope)277 if (scope->di_scope)
278 return scope->di_scope;278 return scope->di_scope;
279279
280 if (scope->node->type == NodeTypeFnDef) {280 ImportTableEntry *import = get_scope_import(scope);
281 assert(scope->parent);281 switch (scope->id) {
282 ScopeFnDef *fn_scope = (ScopeFnDef *)scope;282 case ScopeIdCImport:
283 FnTableEntry *fn_table_entry = fn_scope->fn_entry;283 zig_unreachable();
284 unsigned line_number = fn_table_entry->proto_node->line + 1;284 case ScopeIdFnDef:
285 unsigned scope_line = line_number;285 {
286 bool is_definition = fn_table_entry->fn_def_node != nullptr;286 assert(scope->parent);
287 unsigned flags = 0;287 ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
288 bool is_optimized = g->is_release_build;288 FnTableEntry *fn_table_entry = fn_scope->fn_entry;
289 ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,289 unsigned line_number = fn_table_entry->proto_node->line + 1;
290 get_di_scope(g, scope->parent), buf_ptr(&fn_table_entry->symbol_name), "",290 unsigned scope_line = line_number;
291 scope->node->owner->di_file, line_number,291 bool is_definition = fn_table_entry->fn_def_node != nullptr;
292 fn_table_entry->type_entry->di_type, fn_table_entry->internal_linkage,292 unsigned flags = 0;
293 is_definition, scope_line, flags, is_optimized, nullptr);293 bool is_optimized = g->is_release_build;
294294 ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,
295 scope->di_scope = ZigLLVMSubprogramToScope(subprogram);295 get_di_scope(g, scope->parent), buf_ptr(&fn_table_entry->symbol_name), "",
296 ZigLLVMFnSetSubprogram(fn_llvm_value(g, fn_table_entry), subprogram);296 import->di_file, line_number,
297 } else if (scope->node->type == NodeTypeRoot) {297 fn_table_entry->type_entry->di_type, fn_table_entry->internal_linkage,
298 scope->di_scope = ZigLLVMFileToScope(scope->node->owner->di_file);298 is_definition, scope_line, flags, is_optimized, nullptr);
299 } else if (scope->node->type == NodeTypeContainerDecl) {299
300 ScopeDecls *decls_scope = (ScopeDecls *)scope;300 scope->di_scope = ZigLLVMSubprogramToScope(subprogram);
301 assert(decls_scope->container_type);301 ZigLLVMFnSetSubprogram(fn_llvm_value(g, fn_table_entry), subprogram);
302 scope->di_scope = ZigLLVMTypeToScope(decls_scope->container_type->di_type);302 return scope->di_scope;
303 } else {303 }
304 assert(scope->parent);304 case ScopeIdDecls:
305 ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder,305 if (scope->parent) {
306 get_di_scope(g, scope->parent),306 ScopeDecls *decls_scope = (ScopeDecls *)scope;
307 scope->node->owner->di_file,307 assert(decls_scope->container_type);
308 scope->node->line + 1,308 scope->di_scope = ZigLLVMTypeToScope(decls_scope->container_type->di_type);
309 scope->node->column + 1);309 } else {
310 scope->di_scope = ZigLLVMLexicalBlockToScope(di_block);310 scope->di_scope = ZigLLVMFileToScope(import->di_file);
311 }
312 return scope->di_scope;
313 case ScopeIdBlock:
314 case ScopeIdDefer:
315 case ScopeIdVarDecl:
316 case ScopeIdLoop:
317 {
318 assert(scope->parent);
319 ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder,
320 get_di_scope(g, scope->parent),
321 import->di_file,
322 scope->source_node->line + 1,
323 scope->source_node->column + 1);
324 scope->di_scope = ZigLLVMLexicalBlockToScope(di_block);
325 return scope->di_scope;
326 }
311 }327 }
312328 zig_unreachable();
313 return scope->di_scope;
314}329}
315330
316static void clear_debug_source_node(CodeGen *g) {331static void clear_debug_source_node(CodeGen *g) {
...@@ -400,11 +415,11 @@ static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) {...@@ -400,11 +415,11 @@ static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) {
400 // TODO memoize415 // TODO memoize
401 Scope *scope = instruction->scope;416 Scope *scope = instruction->scope;
402 while (scope) {417 while (scope) {
403 if (scope->node->type == NodeTypeBlock) {418 if (scope->id == ScopeIdBlock) {
404 ScopeBlock *block_scope = (ScopeBlock *)scope;419 ScopeBlock *block_scope = (ScopeBlock *)scope;
405 if (block_scope->safety_set_node)420 if (block_scope->safety_set_node)
406 return !block_scope->safety_off;421 return !block_scope->safety_off;
407 } else if (scope->node->type == NodeTypeRoot || scope->node->type == NodeTypeContainerDecl) {422 } else if (scope->id == ScopeIdDecls) {
408 ScopeDecls *decls_scope = (ScopeDecls *)scope;423 ScopeDecls *decls_scope = (ScopeDecls *)scope;
409 if (decls_scope->safety_set_node)424 if (decls_scope->safety_set_node)
410 return !decls_scope->safety_off;425 return !decls_scope->safety_off;
src/ir.cpp+73-126
...@@ -18,12 +18,17 @@ struct IrExecContext {...@@ -18,12 +18,17 @@ struct IrExecContext {
18 size_t mem_slot_count;18 size_t mem_slot_count;
19};19};
2020
21struct LoopStackItem {
22 IrBasicBlock *break_block;
23 IrBasicBlock *continue_block;
24 bool is_inline;
25};
26
21struct IrBuilder {27struct IrBuilder {
22 CodeGen *codegen;28 CodeGen *codegen;
23 IrExecutable *exec;29 IrExecutable *exec;
24 IrBasicBlock *current_basic_block;30 IrBasicBlock *current_basic_block;
25 ZigList<IrBasicBlock *> break_block_stack;31 ZigList<LoopStackItem> loop_stack;
26 ZigList<IrBasicBlock *> continue_block_stack;
27};32};
2833
29struct IrAnalyze {34struct IrAnalyze {
...@@ -1241,13 +1246,17 @@ static void ir_gen_defers_for_block(IrBuilder *irb, Scope *parent_scope, Scope *...@@ -1241,13 +1246,17 @@ static void ir_gen_defers_for_block(IrBuilder *irb, Scope *parent_scope, Scope *
1241 bool gen_error_defers, bool gen_maybe_defers)1246 bool gen_error_defers, bool gen_maybe_defers)
1242{1247{
1243 while (inner_scope != outer_scope) {1248 while (inner_scope != outer_scope) {
1244 if (inner_scope->node->type == NodeTypeDefer &&1249 if (inner_scope->id == ScopeIdDefer) {
1245 ((inner_scope->node->data.defer.kind == ReturnKindUnconditional) ||1250 assert(inner_scope->source_node->type == NodeTypeDefer);
1246 (gen_error_defers && inner_scope->node->data.defer.kind == ReturnKindError) ||1251 ReturnKind defer_kind = inner_scope->source_node->data.defer.kind;
1247 (gen_maybe_defers && inner_scope->node->data.defer.kind == ReturnKindMaybe)))1252 if (defer_kind == ReturnKindUnconditional ||
1248 {1253 (gen_error_defers && defer_kind == ReturnKindError) ||
1249 AstNode *defer_expr_node = inner_scope->node->data.defer.expr;1254 (gen_maybe_defers && defer_kind == ReturnKindMaybe))
1250 ir_gen_node(irb, defer_expr_node, parent_scope);1255 {
1256 AstNode *defer_expr_node = inner_scope->source_node->data.defer.expr;
1257 ir_gen_node(irb, defer_expr_node, parent_scope);
1258 }
1259
1251 }1260 }
1252 inner_scope = inner_scope->parent;1261 inner_scope = inner_scope->parent;
1253 }1262 }
...@@ -2070,11 +2079,12 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -2070,11 +2079,12 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
20702079
2071 ir_set_cursor_at_end(irb, body_block);2080 ir_set_cursor_at_end(irb, body_block);
20722081
2073 irb->break_block_stack.append(end_block);2082 LoopStackItem *loop_stack_item = irb->loop_stack.add_one();
2074 irb->continue_block_stack.append(continue_block);2083 loop_stack_item->break_block = end_block;
2084 loop_stack_item->continue_block = continue_block;
2085 loop_stack_item->is_inline = is_inline;
2075 ir_gen_node(irb, node->data.while_expr.body, scope);2086 ir_gen_node(irb, node->data.while_expr.body, scope);
2076 irb->break_block_stack.pop();2087 irb->loop_stack.pop();
2077 irb->continue_block_stack.pop();
20782088
2079 ir_build_br(irb, scope, node, continue_block, is_inline);2089 ir_build_br(irb, scope, node, continue_block, is_inline);
2080 ir_set_cursor_at_end(irb, end_block);2090 ir_set_cursor_at_end(irb, end_block);
...@@ -2096,9 +2106,11 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo...@@ -2096,9 +2106,11 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
2096 }2106 }
2097 assert(elem_node->type == NodeTypeSymbol);2107 assert(elem_node->type == NodeTypeSymbol);
20982108
2099 IrInstruction *array_val = ir_gen_node(irb, array_node, parent_scope);2109 IrInstruction *array_val_ptr = ir_gen_node_extra(irb, array_node, parent_scope, LValPurposeAddressOf);
2100 if (array_val == irb->codegen->invalid_instruction)2110 if (array_val_ptr == irb->codegen->invalid_instruction)
2101 return array_val;2111 return array_val_ptr;
2112
2113 IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr);
21022114
2103 IrInstruction *array_type = ir_build_typeof(irb, parent_scope, array_node, array_val);2115 IrInstruction *array_type = ir_build_typeof(irb, parent_scope, array_node, array_val);
2104 IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_type);2116 IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_type);
...@@ -2155,7 +2167,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo...@@ -2155,7 +2167,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
2155 ir_build_cond_br(irb, child_scope, node, cond, body_block, end_block, is_inline);2167 ir_build_cond_br(irb, child_scope, node, cond, body_block, end_block, is_inline);
21562168
2157 ir_set_cursor_at_end(irb, body_block);2169 ir_set_cursor_at_end(irb, body_block);
2158 IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val, index_val, true);2170 IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val_ptr, index_val, true);
2159 IrInstruction *elem_val;2171 IrInstruction *elem_val;
2160 if (node->data.for_expr.elem_is_ptr) {2172 if (node->data.for_expr.elem_is_ptr) {
2161 elem_val = elem_ptr;2173 elem_val = elem_ptr;
...@@ -2164,11 +2176,12 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo...@@ -2164,11 +2176,12 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
2164 }2176 }
2165 ir_build_store_ptr(irb, child_scope, node, elem_var_ptr, elem_val);2177 ir_build_store_ptr(irb, child_scope, node, elem_var_ptr, elem_val);
21662178
2167 irb->break_block_stack.append(end_block);2179 LoopStackItem *loop_stack_item = irb->loop_stack.add_one();
2168 irb->continue_block_stack.append(continue_block);2180 loop_stack_item->break_block = end_block;
2181 loop_stack_item->continue_block = continue_block;
2182 loop_stack_item->is_inline = is_inline;
2169 ir_gen_node(irb, body_node, child_scope);2183 ir_gen_node(irb, body_node, child_scope);
2170 irb->break_block_stack.pop();2184 irb->loop_stack.pop();
2171 irb->continue_block_stack.pop();
21722185
2173 ir_build_br(irb, child_scope, node, continue_block, is_inline);2186 ir_build_br(irb, child_scope, node, continue_block, is_inline);
21742187
...@@ -2195,14 +2208,14 @@ static IrInstruction *ir_gen_this_literal(IrBuilder *irb, Scope *scope, AstNode...@@ -2195,14 +2208,14 @@ static IrInstruction *ir_gen_this_literal(IrBuilder *irb, Scope *scope, AstNode
2195 return ir_build_const_fn(irb, scope, node, fn_entry);2208 return ir_build_const_fn(irb, scope, node, fn_entry);
2196 }2209 }
21972210
2198 if (scope->node->type == NodeTypeContainerDecl) {2211 if (scope->id == ScopeIdDecls) {
2199 ScopeDecls *decls_scope = (ScopeDecls *)scope;2212 ScopeDecls *decls_scope = (ScopeDecls *)scope;
2200 TypeTableEntry *container_type = decls_scope->container_type;2213 TypeTableEntry *container_type = decls_scope->container_type;
2201 assert(container_type);2214 assert(container_type);
2202 return ir_build_const_type(irb, scope, node, container_type);2215 return ir_build_const_type(irb, scope, node, container_type);
2203 }2216 }
22042217
2205 if (scope->node->type == NodeTypeBlock)2218 if (scope->id == ScopeIdBlock)
2206 return ir_build_const_scope(irb, scope, node, scope);2219 return ir_build_const_scope(irb, scope, node, scope);
22072220
2208 zig_unreachable();2221 zig_unreachable();
...@@ -2246,8 +2259,7 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n...@@ -2246,8 +2259,7 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
22462259
2247 return ir_build_array_type(irb, scope, node, size_value, child_type);2260 return ir_build_array_type(irb, scope, node, size_value, child_type);
2248 } else {2261 } else {
2249 IrInstruction *child_type = ir_gen_node_extra(irb, child_type_node,2262 IrInstruction *child_type = ir_gen_node(irb, child_type_node, scope);
2250 scope, LValPurposeAddressOf);
2251 if (child_type == irb->codegen->invalid_instruction)2263 if (child_type == irb->codegen->invalid_instruction)
2252 return child_type;2264 return child_type;
22532265
...@@ -2575,7 +2587,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -2575,7 +2587,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
25752587
2576static LabelTableEntry *find_label(IrExecutable *exec, Scope *scope, Buf *name) {2588static LabelTableEntry *find_label(IrExecutable *exec, Scope *scope, Buf *name) {
2577 while (scope) {2589 while (scope) {
2578 if (scope->node->type == NodeTypeBlock) {2590 if (scope->id == ScopeIdBlock) {
2579 ScopeBlock *block_scope = (ScopeBlock *)scope;2591 ScopeBlock *block_scope = (ScopeBlock *)scope;
2580 auto entry = block_scope->label_table.maybe_get(name);2592 auto entry = block_scope->label_table.maybe_get(name);
2581 if (entry)2593 if (entry)
...@@ -2589,7 +2601,7 @@ static LabelTableEntry *find_label(IrExecutable *exec, Scope *scope, Buf *name)...@@ -2589,7 +2601,7 @@ static LabelTableEntry *find_label(IrExecutable *exec, Scope *scope, Buf *name)
25892601
2590static ScopeBlock *find_block_scope(IrExecutable *exec, Scope *scope) {2602static ScopeBlock *find_block_scope(IrExecutable *exec, Scope *scope) {
2591 while (scope) {2603 while (scope) {
2592 if (scope->node->type == NodeTypeBlock)2604 if (scope->id == ScopeIdBlock)
2593 return (ScopeBlock *)scope;2605 return (ScopeBlock *)scope;
2594 scope = scope->parent;2606 scope = scope->parent;
2595 }2607 }
...@@ -2637,6 +2649,36 @@ static IrInstruction *ir_gen_goto(IrBuilder *irb, Scope *scope, AstNode *node) {...@@ -2637,6 +2649,36 @@ static IrInstruction *ir_gen_goto(IrBuilder *irb, Scope *scope, AstNode *node) {
2637 return ir_build_unreachable(irb, scope, node);2649 return ir_build_unreachable(irb, scope, node);
2638}2650}
26392651
2652static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *scope, AstNode *node) {
2653 assert(node->type == NodeTypeBreak);
2654
2655 if (irb->loop_stack.length == 0) {
2656 add_node_error(irb->codegen, node,
2657 buf_sprintf("'break' expression outside loop"));
2658 return irb->codegen->invalid_instruction;
2659 }
2660
2661 bool is_inline = ir_should_inline(irb) || node->data.break_expr.is_inline;
2662 LoopStackItem *loop_stack_item = &irb->loop_stack.last();
2663 IrBasicBlock *dest_block = loop_stack_item->break_block;
2664 return ir_build_br(irb, scope, node, dest_block, is_inline);
2665}
2666
2667static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *scope, AstNode *node) {
2668 assert(node->type == NodeTypeContinue);
2669
2670 if (irb->loop_stack.length == 0) {
2671 add_node_error(irb->codegen, node,
2672 buf_sprintf("'continue' expression outside loop"));
2673 return irb->codegen->invalid_instruction;
2674 }
2675
2676 bool is_inline = ir_should_inline(irb) || node->data.continue_expr.is_inline;
2677 LoopStackItem *loop_stack_item = &irb->loop_stack.last();
2678 IrBasicBlock *dest_block = loop_stack_item->continue_block;
2679 return ir_build_br(irb, scope, node, dest_block, is_inline);
2680}
2681
2640static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LValPurpose lval) {2682static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LValPurpose lval) {
2641 if (lval == LValPurposeNone)2683 if (lval == LValPurposeNone)
2642 return value;2684 return value;
...@@ -2712,11 +2754,13 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop...@@ -2712,11 +2754,13 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
2712 return ir_lval_wrap(irb, scope, ir_gen_goto(irb, scope, node), lval);2754 return ir_lval_wrap(irb, scope, ir_gen_goto(irb, scope, node), lval);
2713 case NodeTypeTypeLiteral:2755 case NodeTypeTypeLiteral:
2714 return ir_lval_wrap(irb, scope, ir_gen_type_literal(irb, scope, node), lval);2756 return ir_lval_wrap(irb, scope, ir_gen_type_literal(irb, scope, node), lval);
2757 case NodeTypeBreak:
2758 return ir_lval_wrap(irb, scope, ir_gen_break(irb, scope, node), lval);
2759 case NodeTypeContinue:
2760 return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval);
2715 case NodeTypeUnwrapErrorExpr:2761 case NodeTypeUnwrapErrorExpr:
2716 case NodeTypeDefer:2762 case NodeTypeDefer:
2717 case NodeTypeSliceExpr:2763 case NodeTypeSliceExpr:
2718 case NodeTypeBreak:
2719 case NodeTypeContinue:
2720 case NodeTypeCharLiteral:2764 case NodeTypeCharLiteral:
2721 case NodeTypeZeroesLiteral:2765 case NodeTypeZeroesLiteral:
2722 case NodeTypeErrorType:2766 case NodeTypeErrorType:
...@@ -7704,87 +7748,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -7704,87 +7748,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
7704// }7748// }
7705//}7749//}
7706//7750//
7707//static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
7708// TypeTableEntry *expected_type, AstNode *node)
7709//{
7710// assert(node->type == NodeTypeWhileExpr);
7711//
7712// AstNode **condition_node = &node->data.while_expr.condition;
7713// AstNode *while_body_node = node->data.while_expr.body;
7714// AstNode **continue_expr_node = &node->data.while_expr.continue_expr;
7715//
7716// TypeTableEntry *condition_type = analyze_expression(g, import, context,
7717// g->builtin_types.entry_bool, *condition_node);
7718//
7719// if (*continue_expr_node) {
7720// analyze_expression(g, import, context, g->builtin_types.entry_void, *continue_expr_node);
7721// }
7722//
7723// BlockContext *child_context = new_block_context(node, context);
7724// child_context->parent_loop_node = node;
7725//
7726// analyze_expression(g, import, child_context, g->builtin_types.entry_void, while_body_node);
7727//
7728//
7729// TypeTableEntry *expr_return_type = g->builtin_types.entry_void;
7730//
7731// if (condition_type->id == TypeTableEntryIdInvalid) {
7732// expr_return_type = g->builtin_types.entry_invalid;
7733// } else {
7734// // if the condition is a simple constant expression and there are no break statements
7735// // then the return type is unreachable
7736// ConstExprValue *const_val = &get_resolved_expr(*condition_node)->const_val;
7737// if (const_val->ok) {
7738// if (const_val->data.x_bool) {
7739// node->data.while_expr.condition_always_true = true;
7740// if (!node->data.while_expr.contains_break) {
7741// expr_return_type = g->builtin_types.entry_unreachable;
7742// }
7743// }
7744// }
7745// }
7746//
7747// return expr_return_type;
7748//}
7749//
7750//static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
7751// TypeTableEntry *expected_type, AstNode *node)
7752//{
7753// assert(node->type == NodeTypeBreak);
7754//
7755// AstNode *loop_node = context->parent_loop_node;
7756// if (loop_node) {
7757// if (loop_node->type == NodeTypeWhileExpr) {
7758// loop_node->data.while_expr.contains_break = true;
7759// } else if (loop_node->type == NodeTypeForExpr) {
7760// loop_node->data.for_expr.contains_break = true;
7761// } else {
7762// zig_unreachable();
7763// }
7764// } else {
7765// add_node_error(g, node, buf_sprintf("'break' expression outside loop"));
7766// }
7767// return g->builtin_types.entry_unreachable;
7768//}
7769//
7770//static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
7771// TypeTableEntry *expected_type, AstNode *node)
7772//{
7773// AstNode *loop_node = context->parent_loop_node;
7774// if (loop_node) {
7775// if (loop_node->type == NodeTypeWhileExpr) {
7776// loop_node->data.while_expr.contains_continue = true;
7777// } else if (loop_node->type == NodeTypeForExpr) {
7778// loop_node->data.for_expr.contains_continue = true;
7779// } else {
7780// zig_unreachable();
7781// }
7782// } else {
7783// add_node_error(g, node, buf_sprintf("'continue' expression outside loop"));
7784// }
7785// return g->builtin_types.entry_unreachable;
7786//}
7787//
7788//static TypeTableEntry *analyze_defer(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,7751//static TypeTableEntry *analyze_defer(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
7789// TypeTableEntry *expected_type, AstNode *node)7752// TypeTableEntry *expected_type, AstNode *node)
7790//{7753//{
...@@ -8592,22 +8555,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -8592,22 +8555,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
8592// }8555// }
8593//}8556//}
8594//8557//
8595//static LLVMValueRef gen_break(CodeGen *g, AstNode *node) {
8596// assert(node->type == NodeTypeBreak);
8597// LLVMBasicBlockRef dest_block = g->break_block_stack.last();
8598//
8599// set_debug_source_node(g, node);
8600// return LLVMBuildBr(g->builder, dest_block);
8601//}
8602
8603//static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) {
8604// assert(node->type == NodeTypeContinue);
8605// LLVMBasicBlockRef dest_block = g->continue_block_stack.last();
8606//
8607// set_debug_source_node(g, node);
8608// return LLVMBuildBr(g->builder, dest_block);
8609//}
8610//
8611//static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,8558//static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,
8612// bool unwrap_maybe, LLVMValueRef *init_value, TypeTableEntry **expr_type, bool var_is_ptr)8559// bool unwrap_maybe, LLVMValueRef *init_value, TypeTableEntry **expr_type, bool var_is_ptr)
8613//{8560//{
src/ir_print.cpp+1-1
...@@ -104,7 +104,7 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const...@@ -104,7 +104,7 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
104 }104 }
105 case TypeTableEntryIdBlock:105 case TypeTableEntryIdBlock:
106 {106 {
107 AstNode *node = const_val->data.x_block->node;107 AstNode *node = const_val->data.x_block->source_node;
108 fprintf(irp->f, "(scope:%zu:%zu)", node->line + 1, node->column + 1);108 fprintf(irp->f, "(scope:%zu:%zu)", node->line + 1, node->column + 1);
109 return;109 return;
110 }110 }
test/self_hosted2.zig+15
...@@ -139,6 +139,20 @@ fn testFnWithInlineArgs() {...@@ -139,6 +139,20 @@ fn testFnWithInlineArgs() {
139}139}
140140
141141
142fn testContinueInForLoop() {
143 const array = []i32 {1, 2, 3, 4, 5};
144 var sum : i32 = 0;
145 for (array) |x| {
146 sum += x;
147 if (x < 3) {
148 continue;
149 }
150 break;
151 }
152 assert(sum == 6);
153}
154
155
142fn assert(ok: bool) {156fn assert(ok: bool) {
143 if (!ok)157 if (!ok)
144 @unreachable();158 @unreachable();
...@@ -158,6 +172,7 @@ fn runAllTests() {...@@ -158,6 +172,7 @@ fn runAllTests() {
158 testCompileTimeFib();172 testCompileTimeFib();
159 testCompileTimeGenericEval();173 testCompileTimeGenericEval();
160 testFnWithInlineArgs();174 testFnWithInlineArgs();
175 testContinueInForLoop();
161}176}
162177
163export nakedcc fn _start() -> unreachable {178export nakedcc fn _start() -> unreachable {