From 25d3713b07a100d8fdb349317db97fd9d0c1e366 Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Wed, 5 Oct 2022 05:34:42 -0700 Subject: [PATCH] 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 --- src/Liveness.zig | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/Liveness.zig b/src/Liveness.zig index a1a7e6b215..7b2f2fd40d 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -501,6 +501,41 @@ pub fn categorizeOperand( return .complex; }, .block => { + const extra = air.extraData(Air.Block, air_datas[inst].ty_pl.payload); + const body = air.extra[extra.end..][0..extra.data.body_len]; + + if (body.len == 1 and air_tags[body[0]] == .cond_br) { + // Peephole optimization for "panic-like" conditionals, which have + // one empty branch and another which calls a `noreturn` function. + // This allows us to infer that safety checks do not modify memory, + // as far as control flow successors are concerned. + + const inst_data = air_datas[body[0]].pl_op; + const cond_extra = air.extraData(Air.CondBr, inst_data.payload); + if (inst_data.operand == operand_ref and operandDies(l, body[0], 0)) + return .tomb; + + if (cond_extra.data.then_body_len != 1 or cond_extra.data.else_body_len != 1) + return .complex; + + var operand_live: bool = true; + for (air.extra[cond_extra.end..][0..2]) |cond_inst| { + if (l.categorizeOperand(air, cond_inst, operand) == .tomb) + operand_live = false; + + switch (air_tags[cond_inst]) { + .br => { // Breaks immediately back to block + const br = air_datas[cond_inst].br; + if (br.block_inst != inst) + return .complex; + }, + .call => {}, // Calls a noreturn function + else => return .complex, + } + } + return if (operand_live) .none else .tomb; + } + return .complex; }, .@"try" => {