authorgravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-10-05 05:34:42-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-12 18:48:10-05:00
log25d3713b07a100d8fdb349317db97fd9d0c1e366
treee714bd6365744e115b5c5e78caceb70046469482
parentd0eef26687ca2b4b206b70f001741314d4b8bae8

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 https://github.com/ziglang/zig/issues/12215

1 files changed, 35 insertions(+), 0 deletions(-)

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