authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-10 14:04:04-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-10 20:57:49-04:00
log23d7921758524f76f2157e6f8a5823da2511396a
tree14f71cfd47fb4b26d48c5c5a662e3bfd61be84b0
parentcb54e9a3c20783863cf346dc935e2940d26d26d0

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.

2 files changed, 20 insertions(+), 9 deletions(-)

src/Air.zig+7-2
......@@ -221,11 +221,16 @@ pub const Inst = struct {
221221 /// Reinterpret the memory representation of a value as a different type.
222222 /// Uses the `ty_op` field.
223223 bitcast,
224 /// Uses the `ty_pl` field with payload `Block`.
224 /// Uses the `ty_pl` field with payload `Block`. A block runs its body which always ends
225 /// with a `noreturn` instruction, so the only way to proceed to the code after the `block`
226 /// is to encounter a `br` that targets this `block`. If the `block` type is `noreturn`,
227 /// then there do not exist any `br` instructions targetting this `block`.
225228 block,
226229 /// A labeled block of code that loops forever. At the end of the body it is implied
227230 /// to repeat; no explicit "repeat" instruction terminates loop bodies.
228 /// Result type is always noreturn; no instructions in a block follow this one.
231 /// Result type is always `noreturn`; no instructions in a block follow this one.
232 /// The body never ends with a `noreturn` instruction, so the "repeat" operation
233 /// is always statically reachable.
229234 /// Uses the `ty_pl` field. Payload is `Block`.
230235 loop,
231236 /// Return from a block with a result.
src/Sema.zig+13-7
......@@ -5294,14 +5294,20 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
52945294
52955295 try sema.analyzeBody(&loop_block, body);
52965296
5297 try child_block.instructions.append(gpa, loop_inst);
5297 if (sema.typeOf(Air.indexToRef(loop_block.instructions.items[loop_block.instructions.items.len - 1])).isNoReturn()) {
5298 // If the loop ended with a noreturn terminator, then there is no way for it to loop,
5299 // so we can just use the block instead.
5300 try child_block.instructions.appendSlice(gpa, loop_block.instructions.items);
5301 } else {
5302 try child_block.instructions.append(gpa, loop_inst);
52985303
5299 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
5300 loop_block.instructions.items.len);
5301 sema.air_instructions.items(.data)[loop_inst].ty_pl.payload = sema.addExtraAssumeCapacity(
5302 Air.Block{ .body_len = @intCast(u32, loop_block.instructions.items.len) },
5303 );
5304 sema.air_extra.appendSliceAssumeCapacity(loop_block.instructions.items);
5304 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
5305 loop_block.instructions.items.len);
5306 sema.air_instructions.items(.data)[loop_inst].ty_pl.payload = sema.addExtraAssumeCapacity(
5307 Air.Block{ .body_len = @intCast(u32, loop_block.instructions.items.len) },
5308 );
5309 sema.air_extra.appendSliceAssumeCapacity(loop_block.instructions.items);
5310 }
53055311 return sema.analyzeBlockBody(parent_block, src, &child_block, merges);
53065312}
53075313