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:
@@ -844,6 +844,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
.bit_or => return self.genBitOr(inst.castTag(.bit_or).?),
|
||||
.block => return self.genBlock(inst.castTag(.block).?),
|
||||
.br => return self.genBr(inst.castTag(.br).?),
|
||||
.br_block_flat => return self.genBrBlockFlat(inst.castTag(.br_block_flat).?),
|
||||
.breakpoint => return self.genBreakpoint(inst.src),
|
||||
.brvoid => return self.genBrVoid(inst.castTag(.brvoid).?),
|
||||
.bool_and => return self.genBoolOp(inst.castTag(.bool_and).?),
|
||||
@@ -2441,17 +2442,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
}
|
||||
}
|
||||
|
||||
fn genBrBlockFlat(self: *Self, parent_inst: *ir.Inst.BrBlockFlat) !MCValue {
|
||||
try self.genBody(parent_inst.body);
|
||||
const last = parent_inst.body.instructions[parent_inst.body.instructions.len - 1];
|
||||
return self.br(parent_inst.base.src, parent_inst.block, last);
|
||||
}
|
||||
|
||||
fn genBr(self: *Self, inst: *ir.Inst.Br) !MCValue {
|
||||
if (inst.operand.ty.hasCodeGenBits()) {
|
||||
const operand = try self.resolveInst(inst.operand);
|
||||
const block_mcv = @bitCast(MCValue, inst.block.codegen.mcv);
|
||||
if (block_mcv == .none) {
|
||||
inst.block.codegen.mcv = @bitCast(AnyMCValue, operand);
|
||||
} else {
|
||||
try self.setRegOrMem(inst.base.src, inst.block.base.ty, block_mcv, operand);
|
||||
}
|
||||
}
|
||||
return self.brVoid(inst.base.src, inst.block);
|
||||
return self.br(inst.base.src, inst.block, inst.operand);
|
||||
}
|
||||
|
||||
fn genBrVoid(self: *Self, inst: *ir.Inst.BrVoid) !MCValue {
|
||||
@@ -2478,6 +2476,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
}
|
||||
}
|
||||
|
||||
fn br(self: *Self, src: usize, block: *ir.Inst.Block, operand: *ir.Inst) !MCValue {
|
||||
if (operand.ty.hasCodeGenBits()) {
|
||||
const operand_mcv = try self.resolveInst(operand);
|
||||
const block_mcv = @bitCast(MCValue, block.codegen.mcv);
|
||||
if (block_mcv == .none) {
|
||||
block.codegen.mcv = @bitCast(AnyMCValue, operand_mcv);
|
||||
} else {
|
||||
try self.setRegOrMem(src, block.base.ty, block_mcv, operand_mcv);
|
||||
}
|
||||
}
|
||||
return self.brVoid(src, block);
|
||||
}
|
||||
|
||||
fn brVoid(self: *Self, src: usize, block: *ir.Inst.Block) !MCValue {
|
||||
// Emit a jump with a relocation. It will be patched up after the block ends.
|
||||
try block.codegen.relocs.ensureCapacity(self.gpa, block.codegen.relocs.items.len + 1);
|
||||
|
||||
Reference in New Issue
Block a user