diff options
| author | Cody Tapscott <topolarity@tapscott.me> | 2022-10-05 05:34:42 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-12-12 18:48:10 -0500 |
| commit | 25d3713b07a100d8fdb349317db97fd9d0c1e366 (patch) | |
| tree | e714bd6365744e115b5c5e78caceb70046469482 /src | |
| parent | d0eef26687ca2b4b206b70f001741314d4b8bae8 (diff) | |
| download | zig-25d3713b07a100d8fdb349317db97fd9d0c1e366.tar.gz zig-25d3713b07a100d8fdb349317db97fd9d0c1e366.zip | |
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
Diffstat (limited to 'src')
| -rw-r--r-- | src/Liveness.zig | 35 |
1 files changed, 35 insertions, 0 deletions
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" => { |
