fix double nested peer result locations

```zig
export fn entry(x: bool) i32 {
    return if (x)
        if (x) a else b
    else
        if (x) c else d;
}
```
This commit is contained in:
Andrew Kelley 2019-06-12 21:46:04 -04:00
parent 0d62c92947
commit cdf14baa45
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
2 changed files with 45 additions and 33 deletions

View File

@ -3649,10 +3649,16 @@ struct ResultLocReturn {
ResultLoc base;
};
struct IrSuspendPosition {
size_t basic_block_index;
size_t instruction_index;
};
struct ResultLocPeerParent {
ResultLoc base;
bool skipped;
bool done_resuming;
ResultLoc *parent;
ResultLocPeer *peers;
size_t peer_count;
@ -3660,11 +3666,6 @@ struct ResultLocPeerParent {
IrInstruction *is_comptime;
};
struct IrSuspendPosition {
size_t basic_block_index;
size_t instruction_index;
};
struct ResultLocPeer {
ResultLoc base;

View File

@ -16395,45 +16395,56 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh
}
ResultLocPeerParent *peer_parent = phi_instruction->peer_parent;
if (peer_parent != nullptr && peer_parent->resolved_type == nullptr && !peer_parent->skipped) {
// Suspend the phi first so that it gets resumed last
ira->resume_stack.add_one();
for (size_t i = ira->resume_stack.length;;) {
if (i <= 1) break;
i -= 1;
ira->resume_stack.items[i] = ira->resume_stack.items[i-1];
}
ira_suspend(ira, &phi_instruction->base, nullptr, &ira->resume_stack.items[0]);
if (peer_parent != nullptr && !peer_parent->skipped && !peer_parent->done_resuming) {
if (peer_parent->resolved_type == nullptr) {
IrInstruction **instructions = allocate<IrInstruction *>(peer_parent->peer_count);
for (size_t i = 0; i < peer_parent->peer_count; i += 1) {
ResultLocPeer *this_peer = &peer_parent->peers[i];
IrInstruction **instructions = allocate<IrInstruction *>(peer_parent->peer_count);
for (size_t i = 0; i < peer_parent->peer_count; i += 1) {
ResultLocPeer *this_peer = &peer_parent->peers[i];
ResultLocPeer *opposite_peer = &peer_parent->peers[peer_parent->peer_count - i - 1];
IrInstruction *gen_instruction = this_peer->base.gen_instruction;
if (gen_instruction == nullptr) {
// unreachable instructions will cause implicit_elem_type to be null
if (this_peer->base.implicit_elem_type == nullptr) {
instructions[i] = ir_const_unreachable(ira, this_peer->base.source_instruction);
IrInstruction *gen_instruction = this_peer->base.gen_instruction;
if (gen_instruction == nullptr) {
// unreachable instructions will cause implicit_elem_type to be null
if (this_peer->base.implicit_elem_type == nullptr) {
instructions[i] = ir_const_unreachable(ira, this_peer->base.source_instruction);
} else {
instructions[i] = ir_const(ira, this_peer->base.source_instruction,
this_peer->base.implicit_elem_type);
instructions[i]->value.special = ConstValSpecialRuntime;
}
} else {
instructions[i] = ir_const(ira, this_peer->base.source_instruction,
this_peer->base.implicit_elem_type);
instructions[i]->value.special = ConstValSpecialRuntime;
instructions[i] = gen_instruction;
}
} else {
instructions[i] = gen_instruction;
}
ZigType *expected_type = ir_result_loc_expected_type(ira, &phi_instruction->base, peer_parent->parent);
peer_parent->resolved_type = ir_resolve_peer_types(ira,
peer_parent->base.source_instruction->source_node, expected_type, instructions,
peer_parent->peer_count);
// In case resolving the parent activates a suspend, do it now
IrInstruction *parent_result_loc = ir_resolve_result(ira, &phi_instruction->base, peer_parent->parent,
peer_parent->resolved_type, nullptr);
if (parent_result_loc != nullptr &&
(type_is_invalid(parent_result_loc->value.type) || instr_is_unreachable(parent_result_loc)))
{
return parent_result_loc;
}
}
IrSuspendPosition suspend_pos;
ira_suspend(ira, &phi_instruction->base, nullptr, &suspend_pos);
ira->resume_stack.append(suspend_pos);
for (size_t i = 0; i < peer_parent->peer_count; i += 1) {
ResultLocPeer *opposite_peer = &peer_parent->peers[peer_parent->peer_count - i - 1];
if (opposite_peer->base.implicit_elem_type != nullptr &&
opposite_peer->base.implicit_elem_type->id != ZigTypeIdUnreachable)
{
ira->resume_stack.append(opposite_peer->suspend_pos);
}
}
ZigType *expected_type = ir_result_loc_expected_type(ira, &phi_instruction->base, peer_parent->parent);
peer_parent->resolved_type = ir_resolve_peer_types(ira,
peer_parent->base.source_instruction->source_node, expected_type, instructions,
peer_parent->peer_count);
peer_parent->done_resuming = true;
return ira_resume(ira);
}