Generates a function skeleton with a randomly generated CFG. These blocks do not contain any instructions yet.
(&mut self)
| 223 | /// |
| 224 | /// These blocks do not contain any instructions yet. |
| 225 | fn gen_cfg_skeleton(&mut self) -> Result<()> { |
| 226 | // To avoid critical edges, we need to ensure that blocks with multiple |
| 227 | // successors only jump to blocks with a single predecessors, and that |
| 228 | // blocks with multiple predecessors are only jumped to from blocks with |
| 229 | // a single successor. |
| 230 | let mut can_add_succ = vec![]; |
| 231 | let mut can_add_pred = vec![]; |
| 232 | |
| 233 | // Create the entry points. |
| 234 | let num_entries = self |
| 235 | .u |
| 236 | .int_in_range(self.config.entry_points.clone())? |
| 237 | .max(1); |
| 238 | for _ in 0..num_entries { |
| 239 | let entry_frequency = self.block_frequency()?; |
| 240 | let entry = self.func.blocks.push(BlockData { |
| 241 | insts: InstRange::new(Inst::new(0), Inst::new(0)), |
| 242 | preds: vec![], |
| 243 | succs: vec![], |
| 244 | block_params_in: vec![], |
| 245 | block_params_out: vec![], |
| 246 | immediate_dominator: None.into(), |
| 247 | frequency: entry_frequency, |
| 248 | is_critical_edge: false, |
| 249 | }); |
| 250 | self.func.entry_points.push(entry); |
| 251 | can_add_succ.push(entry); |
| 252 | } |
| 253 | |
| 254 | // Repeatedly add edges to the CFG, either to a new block, or to an |
| 255 | // existing block. |
| 256 | for _ in 0..self.u.int_in_range(self.config.cfg_edges.clone())? { |
| 257 | if can_add_succ.is_empty() { |
| 258 | break; |
| 259 | } |
| 260 | |
| 261 | let from = *self.u.choose(&can_add_succ)?; |
| 262 | let mut to = None; |
| 263 | |
| 264 | // If the chosen block has no successors, try linking it to an |
| 265 | // existing block that accepts predecessors. |
| 266 | if !can_add_pred.is_empty() |
| 267 | && self.func.blocks[from].succs.is_empty() |
| 268 | && self.u.arbitrary()? |
| 269 | { |
| 270 | to = Some(*self.u.choose(&can_add_pred)?); |
| 271 | } |
| 272 | |
| 273 | if let Some(to) = to { |
| 274 | // Create an edge to an existing block. |
| 275 | self.func.blocks[from].succs.push(to); |
| 276 | self.func.blocks[to].preds.push(from); |
| 277 | |
| 278 | // If the `to` block now has multiple predecessors, prevent |
| 279 | // adding new successors to them. |
| 280 | if self.func.blocks[to].preds.len() > 1 { |
| 281 | can_add_succ.retain(|b| !self.func.blocks[to].preds.contains(b)); |
| 282 | } |
no test coverage detected