Generate the contents of a basic block. This should be called in CFG post-order so that uses come before definitions.
(&mut self, block: Block)
| 369 | /// This should be called in CFG post-order so that uses come before |
| 370 | /// definitions. |
| 371 | fn gen_block_insts(&mut self, block: Block) -> Result<()> { |
| 372 | // We generate instructions in reverse, starting with the terminator. |
| 373 | // This allows us to know exactly what values need to be defined later. |
| 374 | let mut num_insts = self.u.int_in_range(self.config.insts_per_block.clone())?; |
| 375 | |
| 376 | // Set up outgoing blockparams if we have a single successor that itself |
| 377 | // has multiple predecessors. |
| 378 | if let [succ] = self.func.blocks[block].succs[..] { |
| 379 | if self.func.blocks[succ].preds.len() > 1 { |
| 380 | for idx in 0..self.func.blocks[succ].block_params_in.len() { |
| 381 | let bank = self.func.values[self.func.blocks[succ].block_params_in[idx]].bank; |
| 382 | // It's fine if this adds defs to the current block, we will |
| 383 | // increase num_insts below to ensure these have a defining |
| 384 | // instruction. |
| 385 | let value = self.get_value_for_use(bank, block, false)?; |
| 386 | self.func.blocks[block].block_params_out.push(value); |
| 387 | } |
| 388 | |
| 389 | // Our terminator cannot have operands. Create an empty |
| 390 | // terminator now before adding any instructions. |
| 391 | self.block_insts[block].push(InstData { |
| 392 | operands: vec![], |
| 393 | clobbers: vec![], |
| 394 | block, |
| 395 | terminator_kind: Some(TerminatorKind::Jump), |
| 396 | is_pure: false, |
| 397 | }); |
| 398 | |
| 399 | // If there are values that need to be defined in this block for |
| 400 | // outgoing blockparams, make sure it has at least one |
| 401 | // instruction. |
| 402 | if num_insts == 0 && !self.defs_by_blocks[block].is_empty() { |
| 403 | num_insts = 1; |
| 404 | } |
| 405 | } |
| 406 | } |
| 407 | |
| 408 | // We need a terminator instruction if an empty one wasn't created |
| 409 | // above. This one is allowed to have operands like a normal |
| 410 | // instruction. |
| 411 | if self.block_insts[block].is_empty() { |
| 412 | let is_ret = self.func.blocks[block].succs.is_empty(); |
| 413 | let mut terminator = self.gen_inst(block, num_insts == 0, is_ret)?; |
| 414 | terminator.is_pure = false; |
| 415 | terminator.terminator_kind = Some(if is_ret { |
| 416 | TerminatorKind::Ret |
| 417 | } else { |
| 418 | TerminatorKind::Branch |
| 419 | }); |
| 420 | self.block_insts[block].push(terminator); |
| 421 | } |
| 422 | |
| 423 | // Generate a sequence of instructions in the block. |
| 424 | for idx in 0..num_insts { |
| 425 | // If this is the last instruction we generate (i.e. the first one |
| 426 | // in the block) then we need to ensure all definitions assigned to |
| 427 | // this block are actually processed. |
| 428 | let inst = self.gen_inst(block, idx == num_insts - 1, false)?; |
no test coverage detected