mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 08:14:48 +00:00
blocks have result location semantics
This commit is contained in:
parent
4f21dc8a80
commit
4299cd4446
@ -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
|
||||
|
||||
86
src/ir.cpp
86
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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user