Sema: avoid emitting loops that can't loop
If a `loop` ends with a `noreturn` instruction, then it cannot loop and will be emitted as a `block` instead.
This commit is contained in:
committed by
Andrew Kelley
parent
cb54e9a3c2
commit
23d7921758
@@ -221,11 +221,16 @@ pub const Inst = struct {
|
||||
/// Reinterpret the memory representation of a value as a different type.
|
||||
/// Uses the `ty_op` field.
|
||||
bitcast,
|
||||
/// Uses the `ty_pl` field with payload `Block`.
|
||||
/// Uses the `ty_pl` field with payload `Block`. A block runs its body which always ends
|
||||
/// with a `noreturn` instruction, so the only way to proceed to the code after the `block`
|
||||
/// is to encounter a `br` that targets this `block`. If the `block` type is `noreturn`,
|
||||
/// then there do not exist any `br` instructions targetting this `block`.
|
||||
block,
|
||||
/// A labeled block of code that loops forever. At the end of the body it is implied
|
||||
/// to repeat; no explicit "repeat" instruction terminates loop bodies.
|
||||
/// Result type is always noreturn; no instructions in a block follow this one.
|
||||
/// Result type is always `noreturn`; no instructions in a block follow this one.
|
||||
/// The body never ends with a `noreturn` instruction, so the "repeat" operation
|
||||
/// is always statically reachable.
|
||||
/// Uses the `ty_pl` field. Payload is `Block`.
|
||||
loop,
|
||||
/// Return from a block with a result.
|
||||
|
||||
20
src/Sema.zig
20
src/Sema.zig
@@ -5294,14 +5294,20 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
|
||||
try sema.analyzeBody(&loop_block, body);
|
||||
|
||||
try child_block.instructions.append(gpa, loop_inst);
|
||||
if (sema.typeOf(Air.indexToRef(loop_block.instructions.items[loop_block.instructions.items.len - 1])).isNoReturn()) {
|
||||
// If the loop ended with a noreturn terminator, then there is no way for it to loop,
|
||||
// so we can just use the block instead.
|
||||
try child_block.instructions.appendSlice(gpa, loop_block.instructions.items);
|
||||
} else {
|
||||
try child_block.instructions.append(gpa, loop_inst);
|
||||
|
||||
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
|
||||
loop_block.instructions.items.len);
|
||||
sema.air_instructions.items(.data)[loop_inst].ty_pl.payload = sema.addExtraAssumeCapacity(
|
||||
Air.Block{ .body_len = @intCast(u32, loop_block.instructions.items.len) },
|
||||
);
|
||||
sema.air_extra.appendSliceAssumeCapacity(loop_block.instructions.items);
|
||||
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
|
||||
loop_block.instructions.items.len);
|
||||
sema.air_instructions.items(.data)[loop_inst].ty_pl.payload = sema.addExtraAssumeCapacity(
|
||||
Air.Block{ .body_len = @intCast(u32, loop_block.instructions.items.len) },
|
||||
);
|
||||
sema.air_extra.appendSliceAssumeCapacity(loop_block.instructions.items);
|
||||
}
|
||||
return sema.analyzeBlockBody(parent_block, src, &child_block, merges);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user