Creates a random amount of blocks in this function
(&mut self, builder: &mut FunctionBuilder)
| 1688 | |
| 1689 | /// Creates a random amount of blocks in this function |
| 1690 | fn generate_blocks(&mut self, builder: &mut FunctionBuilder) -> Result<()> { |
| 1691 | let extra_block_count = self.param(&self.config.blocks_per_function)?; |
| 1692 | |
| 1693 | // We must always have at least one block, so we generate the "extra" blocks and add 1 for |
| 1694 | // the entry block. |
| 1695 | let block_count = 1 + extra_block_count; |
| 1696 | |
| 1697 | // Blocks need to be sorted in ascending order |
| 1698 | self.resources.blocks = (0..block_count) |
| 1699 | .map(|i| { |
| 1700 | let is_entry = i == 0; |
| 1701 | let block = builder.create_block(); |
| 1702 | |
| 1703 | // Optionally mark blocks that are not the entry block as cold |
| 1704 | if !is_entry { |
| 1705 | if bool::arbitrary(self.u)? { |
| 1706 | builder.set_cold_block(block); |
| 1707 | } |
| 1708 | } |
| 1709 | |
| 1710 | // The first block has to have the function signature, but for the rest of them we generate |
| 1711 | // a random signature; |
| 1712 | if is_entry { |
| 1713 | builder.append_block_params_for_function_params(block); |
| 1714 | Ok(( |
| 1715 | block, |
| 1716 | self.signature.params.iter().map(|a| a.value_type).collect(), |
| 1717 | )) |
| 1718 | } else { |
| 1719 | let sig = self.generate_block_signature()?; |
| 1720 | sig.iter().for_each(|ty| { |
| 1721 | builder.append_block_param(block, *ty); |
| 1722 | }); |
| 1723 | Ok((block, sig)) |
| 1724 | } |
| 1725 | }) |
| 1726 | .collect::<Result<Vec<_>>>()?; |
| 1727 | |
| 1728 | // Valid blocks for jump tables have to have no parameters in the signature, and must also |
| 1729 | // not be the first block. |
| 1730 | self.resources.blocks_without_params = self.resources.blocks[1..] |
| 1731 | .iter() |
| 1732 | .filter(|(_, sig)| sig.len() == 0) |
| 1733 | .map(|(b, _)| *b) |
| 1734 | .collect(); |
| 1735 | |
| 1736 | // Compute the block CFG |
| 1737 | // |
| 1738 | // cranelift-frontend requires us to never generate unreachable blocks |
| 1739 | // To ensure this property we start by constructing a main "spine" of blocks. So block1 can |
| 1740 | // always jump to block2, and block2 can always jump to block3, etc... |
| 1741 | // |
| 1742 | // That is not a very interesting CFG, so we introduce variations on that, but always |
| 1743 | // ensuring that the property of pointing to the next block is maintained whatever the |
| 1744 | // branching mechanism we use. |
| 1745 | let blocks = self.resources.blocks.clone(); |
| 1746 | self.resources.block_terminators = blocks |
| 1747 | .iter() |
no test coverage detected