sema: after block gets peer type resolved, insert type coercions

on the break instruction operands. This involves a new TZIR instruction,
br_block_flat, which represents a break instruction where the operand is
the result of a flat block. See the doc comments on the instructions for
more details.

How it works: when adding break instructions in semantic analysis, the
underlying allocation is slightly padded so that it is the size of a
br_block_flat instruction, which allows the break instruction to later
be converted without removing instructions inside the parent body. The
extra type coercion instructions go into the body of the br_block_flat,
and backends are responsible for dispatching the instruction correctly
(it should map to the same function calls for related instructions).
This commit is contained in:
Andrew Kelley
2021-01-22 16:45:09 -07:00
parent 06bb360dd2
commit 588171c30b
5 changed files with 171 additions and 39 deletions

View File

@@ -671,14 +671,36 @@ pub const Scope = struct {
};
pub const Merges = struct {
results: ArrayListUnmanaged(*Inst),
block_inst: *Inst.Block,
/// Separate array list from break_inst_list so that it can be passed directly
/// to resolvePeerTypes.
results: ArrayListUnmanaged(*Inst),
/// Keeps track of the break instructions so that the operand can be replaced
/// if we need to add type coercion at the end of block analysis.
/// Same indexes, capacity, length as `results`.
br_list: ArrayListUnmanaged(*Inst.Br),
};
/// For debugging purposes.
pub fn dump(self: *Block, mod: Module) void {
zir.dumpBlock(mod, self);
}
pub fn makeSubBlock(parent: *Block) Block {
return .{
.parent = parent,
.inst_table = parent.inst_table,
.func = parent.func,
.owner_decl = parent.owner_decl,
.src_decl = parent.src_decl,
.instructions = .{},
.arena = parent.arena,
.label = null,
.inlining = parent.inlining,
.is_comptime = parent.is_comptime,
.branch_quota = parent.branch_quota,
};
}
};
/// This is a temporary structure, references to it are valid only
@@ -2107,7 +2129,7 @@ pub fn addBr(
src: usize,
target_block: *Inst.Block,
operand: *Inst,
) !*Inst {
) !*Inst.Br {
const inst = try scope_block.arena.create(Inst.Br);
inst.* = .{
.base = .{
@@ -2119,7 +2141,7 @@ pub fn addBr(
.block = target_block,
};
try scope_block.instructions.append(self.gpa, &inst.base);
return &inst.base;
return inst;
}
pub fn addCondBr(