Optimize a "skeleton" instruction. Returns an optional command of how to continue processing the optimized instruction (e.g. removing it or replacing it with a new instruction).
(
&mut self,
inst: Inst,
block: Block,
)
| 468 | /// Returns an optional command of how to continue processing the optimized |
| 469 | /// instruction (e.g. removing it or replacing it with a new instruction). |
| 470 | fn optimize_skeleton_inst( |
| 471 | &mut self, |
| 472 | inst: Inst, |
| 473 | block: Block, |
| 474 | ) -> Option<SkeletonInstSimplification> { |
| 475 | self.stats.skeleton_inst += 1; |
| 476 | |
| 477 | // If we have a rewrite rule for this instruction, do that first, so |
| 478 | // that GVN and alias analysis only see simplified skeleton |
| 479 | // instructions. |
| 480 | if let Some(cmd) = self.simplify_skeleton_inst(inst) { |
| 481 | self.stats.skeleton_inst_simplified += 1; |
| 482 | return Some(cmd); |
| 483 | } |
| 484 | |
| 485 | // First, can we try to deduplicate? We need to keep some copy |
| 486 | // of the instruction around because it's side-effecting, but |
| 487 | // we may be able to reuse an earlier instance of it. |
| 488 | if is_mergeable_for_egraph(self.func, inst) { |
| 489 | let result = self.func.dfg.inst_results(inst).get(0).copied(); |
| 490 | trace!(" -> mergeable side-effecting op {}", inst); |
| 491 | |
| 492 | // Does this instruction already exist? If so, add entries to |
| 493 | // the value-map to rewrite uses of its results to the results |
| 494 | // of the original (existing) instruction. If not, optimize |
| 495 | // the new instruction. |
| 496 | // |
| 497 | // Note that the GVN map is scoped, which is important |
| 498 | // here: because effectful ops are not removed from the |
| 499 | // skeleton (`Layout`), we need to be mindful of whether |
| 500 | // our current position is dominated by an instance of the |
| 501 | // instruction. (See #5796 for details.) |
| 502 | let ty = self.func.dfg.ctrl_typevar(inst); |
| 503 | match self |
| 504 | .gvn_map |
| 505 | .entry(&NullCtx, (ty, self.func.dfg.insts[inst])) |
| 506 | { |
| 507 | ScopedEntry::Occupied(o) => { |
| 508 | let orig_result = *o.get(); |
| 509 | match (result, orig_result) { |
| 510 | (Some(result), Some(orig_result)) => { |
| 511 | // Hit in GVN map -- reuse value. |
| 512 | self.stats.skeleton_inst_gvn += 1; |
| 513 | self.value_to_opt_value[result] = orig_result; |
| 514 | self.available_block[result] = self.available_block[orig_result]; |
| 515 | trace!(" -> merges result {} to {}", result, orig_result); |
| 516 | } |
| 517 | (None, None) => { |
| 518 | // Hit in the GVN map, but the instruction doesn't |
| 519 | // produce results, only side effects. Nothing else |
| 520 | // to do here. |
| 521 | self.stats.skeleton_inst_gvn += 1; |
| 522 | trace!(" -> merges with dominating instruction"); |
| 523 | } |
| 524 | (_, _) => unreachable!(), |
| 525 | } |
| 526 | Some(SkeletonInstSimplification::Remove) |
| 527 | } |
no test coverage detected