Generates an operand which uses a value.
(
&mut self,
block: Block,
is_first_inst: bool,
allow_non_allocatable: bool,
mut try_reuse_operand: impl FnMut(&mut Self) -> Result<Option<RegClass>>,
)
| 517 | |
| 518 | /// Generates an operand which uses a value. |
| 519 | fn gen_use( |
| 520 | &mut self, |
| 521 | block: Block, |
| 522 | is_first_inst: bool, |
| 523 | allow_non_allocatable: bool, |
| 524 | mut try_reuse_operand: impl FnMut(&mut Self) -> Result<Option<RegClass>>, |
| 525 | ) -> Result<Operand> { |
| 526 | // Generate a NonAllocatable operand if we have non-allocatable registers. |
| 527 | if allow_non_allocatable && !self.non_allocatable_regs.is_empty() && self.u.arbitrary()? { |
| 528 | let reg = *self.u.choose(&self.non_allocatable_regs)?; |
| 529 | return Ok(Operand::fixed_nonallocatable(reg)); |
| 530 | } |
| 531 | |
| 532 | // Try to use a fixed register. We only do this if it doesn't introduce |
| 533 | // a conflict with an existing fixed-register constraint. |
| 534 | if self.u.arbitrary()? { |
| 535 | let bank = RegBank::new(self.u.choose_index(self.reginfo.num_banks())?); |
| 536 | let reg = *self.u.choose(&self.reg_per_bank[bank])?; |
| 537 | if self.check_fixed_conflict(reg, true, false) { |
| 538 | let value = self.get_value_for_use(bank, block, is_first_inst)?; |
| 539 | return Ok(Operand::new( |
| 540 | OperandKind::Use(value), |
| 541 | OperandConstraint::Fixed(reg), |
| 542 | )); |
| 543 | } |
| 544 | } |
| 545 | |
| 546 | let class = if let Some(class) = try_reuse_operand(self)? { |
| 547 | class |
| 548 | } else { |
| 549 | // Pick a register class to use. |
| 550 | RegClass::new(self.u.choose_index(self.reginfo.num_classes())?) |
| 551 | }; |
| 552 | |
| 553 | let bank = self.reginfo.bank_for_class(class); |
| 554 | let group_size = self.reginfo.class_group_size(class); |
| 555 | let kind = if group_size > 1 { |
| 556 | let mut values = vec![]; |
| 557 | for _ in 0..group_size { |
| 558 | values.push(self.get_value_for_use(bank, block, is_first_inst)?); |
| 559 | } |
| 560 | let value_group = self.func.value_groups.push(values); |
| 561 | OperandKind::UseGroup(value_group) |
| 562 | } else { |
| 563 | let value = self.get_value_for_use(bank, block, is_first_inst)?; |
| 564 | OperandKind::Use(value) |
| 565 | }; |
| 566 | Ok(Operand::new(kind, OperandConstraint::Class(class))) |
| 567 | } |
| 568 | |
| 569 | /// Adds an indirect rematerialization recipe for a value defined at |
| 570 | /// the current program point. |
no test coverage detected