diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2016-12-05 18:43:16 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2016-12-05 18:43:16 -0500 |
| commit | 24048b2af62f1b36678aa08a20d0754cb712e485 (patch) | |
| tree | 09519ba8509ba40a3c1d9c85eee7d35f181ca37b /src | |
| parent | 0541532ed6cf5a32b57a4a3f74e6d3a1699223a7 (diff) | |
| download | zig-24048b2af62f1b36678aa08a20d0754cb712e485.tar.gz zig-24048b2af62f1b36678aa08a20d0754cb712e485.zip | |
IR: implement break and continue
Diffstat (limited to 'src')
| -rw-r--r-- | src/all_types.hpp | 19 | ||||
| -rw-r--r-- | src/analyze.cpp | 36 | ||||
| -rw-r--r-- | src/ast_render.cpp | 65 | ||||
| -rw-r--r-- | src/codegen.cpp | 85 | ||||
| -rw-r--r-- | src/ir.cpp | 199 | ||||
| -rw-r--r-- | src/ir_print.cpp | 2 |
6 files changed, 213 insertions, 193 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index dc701e2935..1fd22d650b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -642,9 +642,11 @@ struct AstNodeBoolLiteral { }; struct AstNodeBreakExpr { + bool is_inline; // TODO }; struct AstNodeContinueExpr { + bool is_inline; // TODO }; struct AstNodeArrayType { @@ -1233,11 +1235,21 @@ struct LabelTableEntry { bool used; }; +enum ScopeId { + ScopeIdDecls, + ScopeIdBlock, + ScopeIdDefer, + ScopeIdVarDecl, + ScopeIdCImport, + ScopeIdLoop, + ScopeIdFnDef, +}; + struct Scope { - AstNode *node; + ScopeId id; + AstNode *source_node; - // if the scope has a parent, this is it. Every scope has a parent except - // ScopeIdGlobal + // if the scope has a parent, this is it Scope *parent; ZigLLVMDIScope *di_scope; @@ -1293,6 +1305,7 @@ struct ScopeCImport { // This scope is created for a loop such as for or while in order to // make break and continue statements work. // NodeTypeForExpr or NodeTypeWhileExpr +// TODO I think we can get rid of this struct ScopeLoop { Scope base; }; diff --git a/src/analyze.cpp b/src/analyze.cpp index 87b713b297..0908ddade8 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -130,15 +130,16 @@ ScopeDecls *get_container_scope(TypeTableEntry *type_entry) { return *get_container_scope_ptr(type_entry); } -void init_scope(Scope *dest, AstNode *node, Scope *parent) { - dest->node = node; +void init_scope(Scope *dest, ScopeId id, AstNode *source_node, Scope *parent) { + dest->id = id; + dest->source_node = source_node; dest->parent = parent; } static ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import) { assert(node->type == NodeTypeRoot || node->type == NodeTypeContainerDecl); ScopeDecls *scope = allocate<ScopeDecls>(1); - init_scope(&scope->base, node, parent); + init_scope(&scope->base, ScopeIdDecls, node, parent); scope->decl_table.init(4); scope->container_type = container_type; scope->import = import; @@ -148,7 +149,7 @@ static ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEnt Scope *create_block_scope(AstNode *node, Scope *parent) { assert(node->type == NodeTypeBlock); ScopeBlock *scope = allocate<ScopeBlock>(1); - init_scope(&scope->base, node, parent); + init_scope(&scope->base, ScopeIdBlock, node, parent); scope->label_table.init(1); return &scope->base; } @@ -156,14 +157,13 @@ Scope *create_block_scope(AstNode *node, Scope *parent) { Scope *create_defer_scope(AstNode *node, Scope *parent) { assert(node->type == NodeTypeDefer); ScopeDefer *scope = allocate<ScopeDefer>(1); - init_scope(&scope->base, node, parent); + init_scope(&scope->base, ScopeIdDefer, node, parent); return &scope->base; } Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var) { - assert(node->type == NodeTypeVariableDeclaration || node->type == NodeTypeParamDecl); ScopeVarDecl *scope = allocate<ScopeVarDecl>(1); - init_scope(&scope->base, node, parent); + init_scope(&scope->base, ScopeIdVarDecl, node, parent); scope->var = var; return &scope->base; } @@ -171,7 +171,7 @@ Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var) { Scope *create_cimport_scope(AstNode *node, Scope *parent) { assert(node->type == NodeTypeFnCallExpr); ScopeCImport *scope = allocate<ScopeCImport>(1); - init_scope(&scope->base, node, parent); + init_scope(&scope->base, ScopeIdCImport, node, parent); buf_resize(&scope->c_import_buf, 0); return &scope->base; } @@ -179,21 +179,21 @@ Scope *create_cimport_scope(AstNode *node, Scope *parent) { Scope *create_loop_scope(AstNode *node, Scope *parent) { assert(node->type == NodeTypeWhileExpr || node->type == NodeTypeForExpr); ScopeLoop *scope = allocate<ScopeLoop>(1); - init_scope(&scope->base, node, parent); + init_scope(&scope->base, ScopeIdLoop, node, parent); return &scope->base; } ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry) { assert(node->type == NodeTypeFnDef); ScopeFnDef *scope = allocate<ScopeFnDef>(1); - init_scope(&scope->base, node, parent); + init_scope(&scope->base, ScopeIdFnDef, node, parent); scope->fn_entry = fn_entry; return scope; } ImportTableEntry *get_scope_import(Scope *scope) { while (scope) { - if (scope->node->type == NodeTypeRoot || scope->node->type == NodeTypeContainerDecl) { + if (scope->id == ScopeIdDecls) { ScopeDecls *decls_scope = (ScopeDecls *)scope; assert(decls_scope->import); return decls_scope->import; @@ -1991,9 +1991,7 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry * Tld *find_decl(Scope *scope, Buf *name) { while (scope) { - if (scope->node->type == NodeTypeRoot || - scope->node->type == NodeTypeContainerDecl) - { + if (scope->id == ScopeIdDecls) { ScopeDecls *decls_scope = (ScopeDecls *)scope; auto entry = decls_scope->decl_table.maybe_get(name); if (entry) @@ -2006,15 +2004,11 @@ Tld *find_decl(Scope *scope, Buf *name) { VariableTableEntry *find_variable(CodeGen *g, Scope *scope, Buf *name) { while (scope) { - if (scope->node->type == NodeTypeVariableDeclaration || - scope->node->type == NodeTypeParamDecl) - { + if (scope->id == ScopeIdVarDecl) { ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; if (buf_eql_buf(name, &var_scope->var->name)) return var_scope->var; - } else if (scope->node->type == NodeTypeRoot || - scope->node->type == NodeTypeContainerDecl) - { + } else if (scope->id == ScopeIdDecls) { ScopeDecls *decls_scope = (ScopeDecls *)scope; auto entry = decls_scope->decl_table.maybe_get(name); if (entry) { @@ -2034,7 +2028,7 @@ VariableTableEntry *find_variable(CodeGen *g, Scope *scope, Buf *name) { FnTableEntry *scope_fn_entry(Scope *scope) { while (scope) { - if (scope->node->type == NodeTypeFnDef) { + if (scope->id == ScopeIdFnDef) { ScopeFnDef *fn_scope = (ScopeFnDef *)scope; return fn_scope->fn_entry; } diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 236213bf91..9d3f6fc4e5 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -364,6 +364,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { case NodeTypeSwitchProng: case NodeTypeSwitchRange: case NodeTypeLabel: + case NodeTypeStructValueField: zig_unreachable(); case NodeTypeRoot: 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) { } case NodeTypeContainerInitExpr: render_node_ungrouped(ar, node->data.container_init_expr.type); - fprintf(ar->f, "{"); - assert(node->data.container_init_expr.entries.length == 0); + if (node->data.container_init_expr.kind == ContainerInitKindStruct) { + fprintf(ar->f, "{\n"); + ar->indent += ar->indent_size; + } else { + fprintf(ar->f, "{"); + } + for (size_t i = 0; i < node->data.container_init_expr.entries.length; i += 1) { + AstNode *entry = node->data.container_init_expr.entries.at(i); + if (entry->type == NodeTypeStructValueField) { + Buf *name = entry->data.struct_val_field.name; + AstNode *expr = entry->data.struct_val_field.expr; + fprintf(ar->f, ".%s = ", buf_ptr(name)); + render_node_grouped(ar, expr); + fprintf(ar->f, ",\n"); + } else { + if (i != 0) + fprintf(ar->f, ", "); + render_node_grouped(ar, entry); + } + } fprintf(ar->f, "}"); + if (node->data.container_init_expr.kind == ContainerInitKindStruct) { + ar->indent -= ar->indent_size; + } break; case NodeTypeArrayType: { @@ -788,7 +810,40 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { } case NodeTypeGoto: { - fprintf(ar->f, "goto %s", buf_ptr(node->data.goto_expr.name)); + const char *inline_str = node->data.goto_expr.is_inline ? "inline " : ""; + fprintf(ar->f, "%sgoto %s", inline_str, buf_ptr(node->data.goto_expr.name)); + break; + } + case NodeTypeForExpr: + { + const char *inline_str = node->data.for_expr.is_inline ? "inline " : ""; + fprintf(ar->f, "%sfor (", inline_str); + render_node_grouped(ar, node->data.for_expr.array_expr); + fprintf(ar->f, ") "); + if (node->data.for_expr.elem_node) { + fprintf(ar->f, "|"); + if (node->data.for_expr.elem_is_ptr) + fprintf(ar->f, "*"); + render_node_grouped(ar, node->data.for_expr.elem_node); + if (node->data.for_expr.index_node) { + fprintf(ar->f, ", "); + render_node_grouped(ar, node->data.for_expr.index_node); + } + fprintf(ar->f, "| "); + } + render_node_grouped(ar, node->data.for_expr.body); + break; + } + case NodeTypeBreak: + { + const char *inline_str = node->data.break_expr.is_inline ? "inline " : ""; + fprintf(ar->f, "%sbreak", inline_str); + break; + } + case NodeTypeContinue: + { + const char *inline_str = node->data.continue_expr.is_inline ? "inline " : ""; + fprintf(ar->f, "%scontinue", inline_str); break; } case NodeTypeFnDecl: @@ -797,12 +852,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { case NodeTypeUnwrapErrorExpr: case NodeTypeSliceExpr: case NodeTypeStructField: - case NodeTypeStructValueField: case NodeTypeUse: case NodeTypeZeroesLiteral: - case NodeTypeForExpr: - case NodeTypeBreak: - case NodeTypeContinue: zig_panic("TODO more ast rendering"); } } diff --git a/src/codegen.cpp b/src/codegen.cpp index 6b872e8775..8106b9f33a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -277,40 +277,55 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { if (scope->di_scope) return scope->di_scope; - if (scope->node->type == NodeTypeFnDef) { - assert(scope->parent); - ScopeFnDef *fn_scope = (ScopeFnDef *)scope; - FnTableEntry *fn_table_entry = fn_scope->fn_entry; - unsigned line_number = fn_table_entry->proto_node->line + 1; - unsigned scope_line = line_number; - bool is_definition = fn_table_entry->fn_def_node != nullptr; - unsigned flags = 0; - bool is_optimized = g->is_release_build; - ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder, - get_di_scope(g, scope->parent), buf_ptr(&fn_table_entry->symbol_name), "", - scope->node->owner->di_file, line_number, - fn_table_entry->type_entry->di_type, fn_table_entry->internal_linkage, - is_definition, scope_line, flags, is_optimized, nullptr); - - scope->di_scope = ZigLLVMSubprogramToScope(subprogram); - ZigLLVMFnSetSubprogram(fn_llvm_value(g, fn_table_entry), subprogram); - } else if (scope->node->type == NodeTypeRoot) { - scope->di_scope = ZigLLVMFileToScope(scope->node->owner->di_file); - } else if (scope->node->type == NodeTypeContainerDecl) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - assert(decls_scope->container_type); - scope->di_scope = ZigLLVMTypeToScope(decls_scope->container_type->di_type); - } else { - assert(scope->parent); - ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder, - get_di_scope(g, scope->parent), - scope->node->owner->di_file, - scope->node->line + 1, - scope->node->column + 1); - scope->di_scope = ZigLLVMLexicalBlockToScope(di_block); + ImportTableEntry *import = get_scope_import(scope); + switch (scope->id) { + case ScopeIdCImport: + zig_unreachable(); + case ScopeIdFnDef: + { + assert(scope->parent); + ScopeFnDef *fn_scope = (ScopeFnDef *)scope; + FnTableEntry *fn_table_entry = fn_scope->fn_entry; + unsigned line_number = fn_table_entry->proto_node->line + 1; + unsigned scope_line = line_number; + bool is_definition = fn_table_entry->fn_def_node != nullptr; + unsigned flags = 0; + bool is_optimized = g->is_release_build; + ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder, + get_di_scope(g, scope->parent), buf_ptr(&fn_table_entry->symbol_name), "", + import->di_file, line_number, + fn_table_entry->type_entry->di_type, fn_table_entry->internal_linkage, + is_definition, scope_line, flags, is_optimized, nullptr); + + scope->di_scope = ZigLLVMSubprogramToScope(subprogram); + ZigLLVMFnSetSubprogram(fn_llvm_value(g, fn_table_entry), subprogram); + return scope->di_scope; + } + case ScopeIdDecls: + if (scope->parent) { + ScopeDecls *decls_scope = (ScopeDecls *)scope; + assert(decls_scope->container_type); + scope->di_scope = ZigLLVMTypeToScope(decls_scope->container_type->di_type); + } else { + scope->di_scope = ZigLLVMFileToScope(import->di_file); + } + return scope->di_scope; + case ScopeIdBlock: + case ScopeIdDefer: + case ScopeIdVarDecl: + case ScopeIdLoop: + { + assert(scope->parent); + ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder, + get_di_scope(g, scope->parent), + import->di_file, + scope->source_node->line + 1, + scope->source_node->column + 1); + scope->di_scope = ZigLLVMLexicalBlockToScope(di_block); + return scope->di_scope; + } } - - return scope->di_scope; + zig_unreachable(); } static void clear_debug_source_node(CodeGen *g) { @@ -400,11 +415,11 @@ static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) { // TODO memoize Scope *scope = instruction->scope; while (scope) { - if (scope->node->type == NodeTypeBlock) { + if (scope->id == ScopeIdBlock) { ScopeBlock *block_scope = (ScopeBlock *)scope; if (block_scope->safety_set_node) return !block_scope->safety_off; - } else if (scope->node->type == NodeTypeRoot || scope->node->type == NodeTypeContainerDecl) { + } else if (scope->id == ScopeIdDecls) { ScopeDecls *decls_scope = (ScopeDecls *)scope; if (decls_scope->safety_set_node) return !decls_scope->safety_off; diff --git a/src/ir.cpp b/src/ir.cpp index f354b5a5e7..f1bd362dee 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -18,12 +18,17 @@ struct IrExecContext { size_t mem_slot_count; }; +struct LoopStackItem { + IrBasicBlock *break_block; + IrBasicBlock *continue_block; + bool is_inline; +}; + struct IrBuilder { CodeGen *codegen; IrExecutable *exec; IrBasicBlock *current_basic_block; - ZigList<IrBasicBlock *> break_block_stack; - ZigList<IrBasicBlock *> continue_block_stack; + ZigList<LoopStackItem> loop_stack; }; struct IrAnalyze { @@ -1241,13 +1246,17 @@ static void ir_gen_defers_for_block(IrBuilder *irb, Scope *parent_scope, Scope * bool gen_error_defers, bool gen_maybe_defers) { while (inner_scope != outer_scope) { - if (inner_scope->node->type == NodeTypeDefer && - ((inner_scope->node->data.defer.kind == ReturnKindUnconditional) || - (gen_error_defers && inner_scope->node->data.defer.kind == ReturnKindError) || - (gen_maybe_defers && inner_scope->node->data.defer.kind == ReturnKindMaybe))) - { - AstNode *defer_expr_node = inner_scope->node->data.defer.expr; - ir_gen_node(irb, defer_expr_node, parent_scope); + if (inner_scope->id == ScopeIdDefer) { + assert(inner_scope->source_node->type == NodeTypeDefer); + ReturnKind defer_kind = inner_scope->source_node->data.defer.kind; + if (defer_kind == ReturnKindUnconditional || + (gen_error_defers && defer_kind == ReturnKindError) || + (gen_maybe_defers && defer_kind == ReturnKindMaybe)) + { + AstNode *defer_expr_node = inner_scope->source_node->data.defer.expr; + ir_gen_node(irb, defer_expr_node, parent_scope); + } + } inner_scope = inner_scope->parent; } @@ -2070,11 +2079,12 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n ir_set_cursor_at_end(irb, body_block); - irb->break_block_stack.append(end_block); - irb->continue_block_stack.append(continue_block); + LoopStackItem *loop_stack_item = irb->loop_stack.add_one(); + loop_stack_item->break_block = end_block; + loop_stack_item->continue_block = continue_block; + loop_stack_item->is_inline = is_inline; ir_gen_node(irb, node->data.while_expr.body, scope); - irb->break_block_stack.pop(); - irb->continue_block_stack.pop(); + irb->loop_stack.pop(); ir_build_br(irb, scope, node, continue_block, is_inline); ir_set_cursor_at_end(irb, end_block); @@ -2096,9 +2106,11 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo } assert(elem_node->type == NodeTypeSymbol); - IrInstruction *array_val = ir_gen_node(irb, array_node, parent_scope); - if (array_val == irb->codegen->invalid_instruction) - return array_val; + IrInstruction *array_val_ptr = ir_gen_node_extra(irb, array_node, parent_scope, LValPurposeAddressOf); + if (array_val_ptr == irb->codegen->invalid_instruction) + return array_val_ptr; + + IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr); IrInstruction *array_type = ir_build_typeof(irb, parent_scope, array_node, array_val); 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 ir_build_cond_br(irb, child_scope, node, cond, body_block, end_block, is_inline); ir_set_cursor_at_end(irb, body_block); - IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val, index_val, true); + IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val_ptr, index_val, true); IrInstruction *elem_val; if (node->data.for_expr.elem_is_ptr) { elem_val = elem_ptr; @@ -2164,11 +2176,12 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo } ir_build_store_ptr(irb, child_scope, node, elem_var_ptr, elem_val); - irb->break_block_stack.append(end_block); - irb->continue_block_stack.append(continue_block); + LoopStackItem *loop_stack_item = irb->loop_stack.add_one(); + loop_stack_item->break_block = end_block; + loop_stack_item->continue_block = continue_block; + loop_stack_item->is_inline = is_inline; ir_gen_node(irb, body_node, child_scope); - irb->break_block_stack.pop(); - irb->continue_block_stack.pop(); + irb->loop_stack.pop(); ir_build_br(irb, child_scope, node, continue_block, is_inline); @@ -2195,14 +2208,14 @@ static IrInstruction *ir_gen_this_literal(IrBuilder *irb, Scope *scope, AstNode return ir_build_const_fn(irb, scope, node, fn_entry); } - if (scope->node->type == NodeTypeContainerDecl) { + if (scope->id == ScopeIdDecls) { ScopeDecls *decls_scope = (ScopeDecls *)scope; TypeTableEntry *container_type = decls_scope->container_type; assert(container_type); return ir_build_const_type(irb, scope, node, container_type); } - if (scope->node->type == NodeTypeBlock) + if (scope->id == ScopeIdBlock) return ir_build_const_scope(irb, scope, node, scope); zig_unreachable(); @@ -2246,8 +2259,7 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n return ir_build_array_type(irb, scope, node, size_value, child_type); } else { - IrInstruction *child_type = ir_gen_node_extra(irb, child_type_node, - scope, LValPurposeAddressOf); + IrInstruction *child_type = ir_gen_node(irb, child_type_node, scope); if (child_type == irb->codegen->invalid_instruction) return child_type; @@ -2575,7 +2587,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * static LabelTableEntry *find_label(IrExecutable *exec, Scope *scope, Buf *name) { while (scope) { - if (scope->node->type == NodeTypeBlock) { + if (scope->id == ScopeIdBlock) { ScopeBlock *block_scope = (ScopeBlock *)scope; auto entry = block_scope->label_table.maybe_get(name); if (entry) @@ -2589,7 +2601,7 @@ static LabelTableEntry *find_label(IrExecutable *exec, Scope *scope, Buf *name) static ScopeBlock *find_block_scope(IrExecutable *exec, Scope *scope) { while (scope) { - if (scope->node->type == NodeTypeBlock) + if (scope->id == ScopeIdBlock) return (ScopeBlock *)scope; scope = scope->parent; } @@ -2637,6 +2649,36 @@ static IrInstruction *ir_gen_goto(IrBuilder *irb, Scope *scope, AstNode *node) { return ir_build_unreachable(irb, scope, node); } +static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeBreak); + + if (irb->loop_stack.length == 0) { + add_node_error(irb->codegen, node, + buf_sprintf("'break' expression outside loop")); + return irb->codegen->invalid_instruction; + } + + bool is_inline = ir_should_inline(irb) || node->data.break_expr.is_inline; + LoopStackItem *loop_stack_item = &irb->loop_stack.last(); + IrBasicBlock *dest_block = loop_stack_item->break_block; + return ir_build_br(irb, scope, node, dest_block, is_inline); +} + +static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeContinue); + + if (irb->loop_stack.length == 0) { + add_node_error(irb->codegen, node, + buf_sprintf("'continue' expression outside loop")); + return irb->codegen->invalid_instruction; + } + + bool is_inline = ir_should_inline(irb) || node->data.continue_expr.is_inline; + LoopStackItem *loop_stack_item = &irb->loop_stack.last(); + IrBasicBlock *dest_block = loop_stack_item->continue_block; + return ir_build_br(irb, scope, node, dest_block, is_inline); +} + static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LValPurpose lval) { if (lval == LValPurposeNone) return value; @@ -2712,11 +2754,13 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_goto(irb, scope, node), lval); case NodeTypeTypeLiteral: return ir_lval_wrap(irb, scope, ir_gen_type_literal(irb, scope, node), lval); + case NodeTypeBreak: + return ir_lval_wrap(irb, scope, ir_gen_break(irb, scope, node), lval); + case NodeTypeContinue: + return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval); case NodeTypeUnwrapErrorExpr: case NodeTypeDefer: case NodeTypeSliceExpr: - case NodeTypeBreak: - case NodeTypeContinue: case NodeTypeCharLiteral: case NodeTypeZeroesLiteral: case NodeTypeErrorType: @@ -7704,87 +7748,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { // } //} // -//static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, -// TypeTableEntry *expected_type, AstNode *node) -//{ -// assert(node->type == NodeTypeWhileExpr); -// -// AstNode **condition_node = &node->data.while_expr.condition; -// AstNode *while_body_node = node->data.while_expr.body; -// AstNode **continue_expr_node = &node->data.while_expr.continue_expr; -// -// TypeTableEntry *condition_type = analyze_expression(g, import, context, -// g->builtin_types.entry_bool, *condition_node); -// -// if (*continue_expr_node) { -// analyze_expression(g, import, context, g->builtin_types.entry_void, *continue_expr_node); -// } -// -// BlockContext *child_context = new_block_context(node, context); -// child_context->parent_loop_node = node; -// -// analyze_expression(g, import, child_context, g->builtin_types.entry_void, while_body_node); -// -// -// TypeTableEntry *expr_return_type = g->builtin_types.entry_void; -// -// if (condition_type->id == TypeTableEntryIdInvalid) { -// expr_return_type = g->builtin_types.entry_invalid; -// } else { -// // if the condition is a simple constant expression and there are no break statements -// // then the return type is unreachable -// ConstExprValue *const_val = &get_resolved_expr(*condition_node)->const_val; -// if (const_val->ok) { -// if (const_val->data.x_bool) { -// node->data.while_expr.condition_always_true = true; -// if (!node->data.while_expr.contains_break) { -// expr_return_type = g->builtin_types.entry_unreachable; -// } -// } -// } -// } -// -// return expr_return_type; -//} -// -//static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, -// TypeTableEntry *expected_type, AstNode *node) -//{ -// assert(node->type == NodeTypeBreak); -// -// AstNode *loop_node = context->parent_loop_node; -// if (loop_node) { -// if (loop_node->type == NodeTypeWhileExpr) { -// loop_node->data.while_expr.contains_break = true; -// } else if (loop_node->type == NodeTypeForExpr) { -// loop_node->data.for_expr.contains_break = true; -// } else { -// zig_unreachable(); -// } -// } else { -// add_node_error(g, node, buf_sprintf("'break' expression outside loop")); -// } -// return g->builtin_types.entry_unreachable; -//} -// -//static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, -// TypeTableEntry *expected_type, AstNode *node) -//{ -// AstNode *loop_node = context->parent_loop_node; -// if (loop_node) { -// if (loop_node->type == NodeTypeWhileExpr) { -// loop_node->data.while_expr.contains_continue = true; -// } else if (loop_node->type == NodeTypeForExpr) { -// loop_node->data.for_expr.contains_continue = true; -// } else { -// zig_unreachable(); -// } -// } else { -// add_node_error(g, node, buf_sprintf("'continue' expression outside loop")); -// } -// return g->builtin_types.entry_unreachable; -//} -// //static TypeTableEntry *analyze_defer(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context, // TypeTableEntry *expected_type, AstNode *node) //{ @@ -8592,22 +8555,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { // } //} // -//static LLVMValueRef gen_break(CodeGen *g, AstNode *node) { -// assert(node->type == NodeTypeBreak); -// LLVMBasicBlockRef dest_block = g->break_block_stack.last(); -// -// set_debug_source_node(g, node); -// return LLVMBuildBr(g->builder, dest_block); -//} - -//static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) { -// assert(node->type == NodeTypeContinue); -// LLVMBasicBlockRef dest_block = g->continue_block_stack.last(); -// -// set_debug_source_node(g, node); -// return LLVMBuildBr(g->builder, dest_block); -//} -// //static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl, // bool unwrap_maybe, LLVMValueRef *init_value, TypeTableEntry **expr_type, bool var_is_ptr) //{ diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 3e8e877f39..7f27ab104b 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -104,7 +104,7 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const } case TypeTableEntryIdBlock: { - AstNode *node = const_val->data.x_block->node; + AstNode *node = const_val->data.x_block->source_node; fprintf(irp->f, "(scope:%zu:%zu)", node->line + 1, node->column + 1); return; } |
