Commit 4299cd4446
Changed files (2)
src/all_types.hpp
@@ -1996,6 +1996,11 @@ struct ScopeDecls {
bool any_imports_failed;
};
+enum LVal {
+ LValNone,
+ LValPtr,
+};
+
// This scope comes from a block expression in user code.
// NodeTypeBlock
struct ScopeBlock {
@@ -2004,12 +2009,14 @@ struct ScopeBlock {
Buf *name;
IrBasicBlock *end_block;
IrInstruction *is_comptime;
+ ResultLocPeerParent *peer_parent;
ZigList<IrInstruction *> *incoming_values;
ZigList<IrBasicBlock *> *incoming_blocks;
AstNode *safety_set_node;
AstNode *fast_math_set_node;
+ LVal lval;
bool safety_off;
bool fast_math_on;
};
@@ -2047,11 +2054,6 @@ struct ScopeCImport {
Buf buf;
};
-enum LVal {
- LValNone,
- LValPtr,
-};
-
// This scope is created for a loop such as for or while in order to
// make break and continue statements work.
// NodeTypeForExpr or NodeTypeWhileExpr
src/ir.cpp
@@ -3759,7 +3759,17 @@ static ZigVar *ir_create_var(IrBuilder *irb, AstNode *node, Scope *scope, Buf *n
return var;
}
-static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) {
+static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) {
+ ResultLocPeer *result = allocate<ResultLocPeer>(1);
+ result->base.id = ResultLocIdPeer;
+ result->base.source_instruction = peer_parent->base.source_instruction;
+ result->parent = peer_parent;
+ return result;
+}
+
+static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node, LVal lval,
+ ResultLoc *result_loc)
+{
assert(block_node->type == NodeTypeBlock);
ZigList<IrInstruction *> incoming_values = {0};
@@ -3777,15 +3787,24 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
if (block_node->data.block.statements.length == 0) {
// {}
- return ir_build_const_void(irb, child_scope, block_node);
+ return ir_lval_wrap(irb, parent_scope, ir_build_const_void(irb, child_scope, block_node), lval, result_loc);
}
if (block_node->data.block.name != nullptr) {
+ scope_block->lval = lval;
scope_block->incoming_blocks = &incoming_blocks;
scope_block->incoming_values = &incoming_values;
scope_block->end_block = ir_create_basic_block(irb, parent_scope, "BlockEnd");
scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node,
ir_should_inline(irb->exec, parent_scope));
+
+ scope_block->peer_parent = allocate<ResultLocPeerParent>(1);
+ scope_block->peer_parent->base.id = ResultLocIdPeerParent;
+ scope_block->peer_parent->base.source_instruction = scope_block->is_comptime;
+ scope_block->peer_parent->end_bb = scope_block->end_block;
+ scope_block->peer_parent->is_comptime = scope_block->is_comptime;
+ scope_block->peer_parent->parent = result_loc;
+ ir_build_reset_result(irb, parent_scope, block_node, &scope_block->peer_parent->base);
}
bool is_continuation_unreachable = false;
@@ -3821,23 +3840,41 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
return noreturn_return_value;
}
+ if (scope_block->peer_parent != nullptr && scope_block->peer_parent->peers.length != 0) {
+ scope_block->peer_parent->peers.last()->next_bb = scope_block->end_block;
+ }
ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block);
- return ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length,
- incoming_blocks.items, incoming_values.items, nullptr);
+ IrInstruction *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length,
+ incoming_blocks.items, incoming_values.items, scope_block->peer_parent);
+ return ir_expr_wrap(irb, parent_scope, phi, result_loc);
} else {
incoming_blocks.append(irb->current_basic_block);
- incoming_values.append(ir_mark_gen(ir_build_const_void(irb, parent_scope, block_node)));
+ IrInstruction *else_expr_result = ir_mark_gen(ir_build_const_void(irb, parent_scope, block_node));
+
+ if (scope_block->peer_parent != nullptr) {
+ ResultLocPeer *peer_result = create_peer_result(scope_block->peer_parent);
+ scope_block->peer_parent->peers.append(peer_result);
+ ir_build_end_expr(irb, parent_scope, block_node, else_expr_result, &peer_result->base);
+
+ if (scope_block->peer_parent->peers.length != 0) {
+ scope_block->peer_parent->peers.last()->next_bb = scope_block->end_block;
+ }
+ }
+
+ incoming_values.append(else_expr_result);
}
if (block_node->data.block.name != nullptr) {
ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime));
ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block);
- return ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length,
- incoming_blocks.items, incoming_values.items, nullptr);
+ IrInstruction *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length,
+ incoming_blocks.items, incoming_values.items, scope_block->peer_parent);
+ return ir_expr_wrap(irb, parent_scope, phi, result_loc);
} else {
ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
- return ir_mark_gen(ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)));
+ IrInstruction *void_inst = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
+ return ir_lval_wrap(irb, parent_scope, void_inst, lval, result_loc);
}
}
@@ -3964,14 +4001,6 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod
return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, nullptr);
}
-static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) {
- ResultLocPeer *result = allocate<ResultLocPeer>(1);
- result->base.id = ResultLocIdPeer;
- result->base.source_instruction = peer_parent->base.source_instruction;
- result->parent = peer_parent;
- return result;
-}
-
static ResultLocPeerParent *ir_build_result_peers(IrBuilder *irb, IrInstruction *cond_br_inst,
IrBasicBlock *end_block, ResultLoc *parent, IrInstruction *is_comptime)
{
@@ -7216,7 +7245,11 @@ static IrInstruction *ir_gen_return_from_block(IrBuilder *irb, Scope *break_scop
IrInstruction *result_value;
if (node->data.break_expr.expr) {
- result_value = ir_gen_node(irb, node->data.break_expr.expr, break_scope);
+ ResultLocPeer *peer_result = create_peer_result(block_scope->peer_parent);
+ block_scope->peer_parent->peers.append(peer_result);
+
+ result_value = ir_gen_node_extra(irb, node->data.break_expr.expr, break_scope, block_scope->lval,
+ &peer_result->base);
if (result_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
} else {
@@ -8193,7 +8226,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeTestDecl:
zig_unreachable();
case NodeTypeBlock:
- return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval, result_loc);
+ return ir_gen_block(irb, scope, node, lval, result_loc);
case NodeTypeGroupedExpr:
return ir_gen_node_raw(irb, node->data.grouped_expr, scope, lval, result_loc);
case NodeTypeBinOpExpr:
@@ -15066,6 +15099,21 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
ResultLocPeer *result_peer = reinterpret_cast<ResultLocPeer *>(result_loc);
ResultLocPeerParent *peer_parent = result_peer->parent;
+ if (peer_parent->peers.length == 1) {
+ IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent,
+ value_type, value, false, non_null_comptime);
+ result_peer->suspend_pos.basic_block_index = SIZE_MAX;
+ result_peer->suspend_pos.instruction_index = SIZE_MAX;
+ if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) ||
+ parent_result_loc->value.type->id == ZigTypeIdUnreachable)
+ {
+ return parent_result_loc;
+ }
+ result_loc->written = true;
+ result_loc->resolved_loc = parent_result_loc;
+ return result_loc->resolved_loc;
+ }
+
bool is_comptime;
if (!ir_resolve_comptime(ira, peer_parent->is_comptime->child, &is_comptime))
return ira->codegen->invalid_instruction;
@@ -16670,7 +16718,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh
ResultLocPeerParent *peer_parent = phi_instruction->peer_parent;
if (peer_parent != nullptr && !peer_parent->skipped && !peer_parent->done_resuming &&
- peer_parent->peers.length != 0)
+ peer_parent->peers.length >= 2)
{
if (peer_parent->resolved_type == nullptr) {
IrInstruction **instructions = allocate<IrInstruction *>(peer_parent->peers.length);