| ... | @@ -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" => { |