Skip to content

Commit df64831

Browse files
committed
stage2: Teach Liveness that safety checks do not modify memory
This change adds to Liveness a simple pattern match for the try-like `.condbr` blocks emitted by Sema's safety checks. This allows us to determine that these do not modify memory, which permits us to elide additional loads in the backend. As @Vexu points out in the main issue, this is probably not a complete solution on its own. We'll still want a way to reliably narrow the load/copy when performing several consecutive accesses, such as `foo.arr[x][y].z` Resolves #12215
1 parent a4eb221 commit df64831

File tree

1 file changed

+35
-0
lines changed

1 file changed

+35
-0
lines changed

src/Liveness.zig

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,41 @@ pub fn categorizeOperand(
500500
return .complex;
501501
},
502502
.block => {
503+
const extra = air.extraData(Air.Block, air_datas[inst].ty_pl.payload);
504+
const body = air.extra[extra.end..][0..extra.data.body_len];
505+
506+
if (body.len == 1 and air_tags[body[0]] == .cond_br) {
507+
// Peephole optimization for "panic-like" conditionals, which have
508+
// one empty branch and another which calls a `noreturn` function.
509+
// This allows us to infer that safety checks do not modify memory,
510+
// as far as control flow successors are concerned.
511+
512+
const inst_data = air_datas[body[0]].pl_op;
513+
const cond_extra = air.extraData(Air.CondBr, inst_data.payload);
514+
if (inst_data.operand == operand_ref and operandDies(l, body[0], 0))
515+
return .tomb;
516+
517+
if (cond_extra.data.then_body_len != 1 or cond_extra.data.else_body_len != 1)
518+
return .complex;
519+
520+
var operand_live: bool = true;
521+
for (air.extra[cond_extra.end..][0..2]) |cond_inst| {
522+
if (l.categorizeOperand(air, cond_inst, operand) == .tomb)
523+
operand_live = false;
524+
525+
switch (air_tags[cond_inst]) {
526+
.br => { // Breaks immediately back to block
527+
const br = air_datas[cond_inst].br;
528+
if (br.block_inst != inst)
529+
return .complex;
530+
},
531+
.call => {}, // Calls a noreturn function
532+
else => return .complex,
533+
}
534+
}
535+
return if (operand_live) .none else .tomb;
536+
}
537+
503538
return .complex;
504539
},
505540
.@"try" => {

0 commit comments

Comments
 (0)