Isolates all group uses in the given register group by splitting them off into minimal segments that only cover a single instruction (or part of one) and are therefore always allocatable. The remaining live range pieces are collected into a separate non-group virtual register for each original group member, which can then be split as normal.
(&mut self, group: VirtRegGroup)
| 1088 | /// virtual register for each original group member, which can then be split |
| 1089 | /// as normal. |
| 1090 | fn isolate_group_uses(&mut self, group: VirtRegGroup) { |
| 1091 | self.invalidate_operand_group_mapping(group); |
| 1092 | |
| 1093 | // Find any group uses and split them into minimal segments |
| 1094 | let splitter = &mut self.allocator.splitter; |
| 1095 | splitter.minimal_segments.clear(); |
| 1096 | splitter.new_vregs.clear(); |
| 1097 | for group_index in 0..self.virt_regs.group_members(group).len() { |
| 1098 | splitter.segments.clear(); |
| 1099 | let vreg = self.virt_regs.group_members(group)[group_index]; |
| 1100 | let value_set = self.virt_regs[vreg].value_set; |
| 1101 | trace!("Isolating group uses in {vreg}"); |
| 1102 | stat!(self.stats, isolated_group_vregs); |
| 1103 | for &segment in self.virt_regs.segments(vreg) { |
| 1104 | let mut segment = segment; |
| 1105 | 'outer: loop { |
| 1106 | for &u in &self.uses[segment.use_list] { |
| 1107 | match u.kind { |
| 1108 | UseKind::GroupClassUse { |
| 1109 | slot: _, |
| 1110 | class: _, |
| 1111 | group_index: use_group_index, |
| 1112 | } |
| 1113 | | UseKind::GroupClassDef { |
| 1114 | slot: _, |
| 1115 | class: _, |
| 1116 | group_index: use_group_index, |
| 1117 | } => { |
| 1118 | debug_assert_eq!(use_group_index as usize, group_index); |
| 1119 | } |
| 1120 | UseKind::ClassUse { .. } |
| 1121 | | UseKind::ClassDef { .. } |
| 1122 | | UseKind::FixedDef { .. } |
| 1123 | | UseKind::FixedUse { .. } |
| 1124 | | UseKind::TiedUse { .. } |
| 1125 | | UseKind::ConstraintConflict { .. } |
| 1126 | | UseKind::BlockparamIn { .. } |
| 1127 | | UseKind::BlockparamOut { .. } => continue, |
| 1128 | }; |
| 1129 | |
| 1130 | trace!("Splitting around group use {}: {}", u.pos, u.kind); |
| 1131 | |
| 1132 | // If there is a live range segment with no uses before |
| 1133 | // this use, collect that segment for the non-group |
| 1134 | // portion. |
| 1135 | if u.pos != segment.live_range.from.round_to_prev_inst().inst() { |
| 1136 | let (before, after) = segment.split_at(u.pos, self.uses, self.hints); |
| 1137 | splitter.segments.push(before); |
| 1138 | segment = after; |
| 1139 | } |
| 1140 | |
| 1141 | if u.pos.next() == segment.live_range.to.round_to_next_inst().inst() { |
| 1142 | // If this use is on the last instruction of the segment |
| 1143 | // then split off the rest of the segment into a |
| 1144 | // minimal segment. |
| 1145 | trace!( |
| 1146 | "Generating minimal segment for {} at {}", |
| 1147 | segment.value, segment.live_range |
no test coverage detected