Have a cached unreachable block inside MIR state

It is useful for various cases where direct unreachable cannot be translated and a separate block
is necessary.
This commit is contained in:
Simonas Kazlauskas 2015-12-19 16:47:52 +02:00
parent 4e86dcdb72
commit a1e13983f7
3 changed files with 24 additions and 7 deletions

View File

@ -265,7 +265,7 @@ pub enum Terminator<'tcx> {
}
}
#[derive(RustcEncodable, RustcDecodable)]
#[derive(Clone, Copy, RustcEncodable, RustcDecodable)]
pub enum CallTargets {
/// The only target that should be entered when function returns normally.
Return(BasicBlock),

View File

@ -9,15 +9,15 @@
// except according to those terms.
use llvm::BasicBlockRef;
use middle::infer;
use middle::ty;
use rustc::mir::repr as mir;
use trans::adt;
use trans::base;
use trans::build;
use trans::attributes;
use trans::common::{self, Block};
use trans::debuginfo::DebugLoc;
use trans::type_of;
use trans::type_::Type;
use super::MirContext;
use super::operand::OperandValue::{FatPtr, Immediate, Ref};
@ -56,10 +56,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
// The else branch of the Switch can't be hit, so branch to an unreachable
// instruction so LLVM knows that
// FIXME it might be nice to have just one such block (created lazilly), we could
// store it in the "MIR trans" state.
let unreachable_blk = bcx.fcx.new_temp_block("enum-variant-unreachable");
build::Unreachable(unreachable_blk);
let unreachable_blk = self.unreachable_block();
let switch = build::Switch(bcx, discr, unreachable_blk.llbb, targets.len());
assert_eq!(adt_def.variants.len(), targets.len());
@ -164,6 +161,18 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
}
fn unreachable_block(&mut self) -> Block<'bcx, 'tcx> {
match self.unreachable_block {
Some(b) => b,
None => {
let bl = self.fcx.new_block(false, "unreachable", None);
build::Unreachable(bl);
self.unreachable_block = Some(bl);
bl
}
}
}
fn bcx(&self, bb: mir::BasicBlock) -> Block<'bcx, 'tcx> {
self.blocks[bb.index()]
}

View File

@ -28,6 +28,9 @@ use self::operand::OperandRef;
pub struct MirContext<'bcx, 'tcx:'bcx> {
mir: &'bcx mir::Mir<'tcx>,
/// Function context
fcx: &'bcx common::FunctionContext<'bcx, 'tcx>,
/// When unwinding is initiated, we have to store this personality
/// value somewhere so that we can load it and re-use it in the
/// resume instruction. The personality is (afaik) some kind of
@ -40,6 +43,9 @@ pub struct MirContext<'bcx, 'tcx:'bcx> {
/// A `Block` for each MIR `BasicBlock`
blocks: Vec<Block<'bcx, 'tcx>>,
/// Cached unreachable block
unreachable_block: Option<Block<'bcx, 'tcx>>,
/// An LLVM alloca for each MIR `VarDecl`
vars: Vec<LvalueRef<'tcx>>,
@ -116,8 +122,10 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
let mut mircx = MirContext {
mir: mir,
fcx: fcx,
llpersonalityslot: None,
blocks: block_bcxs,
unreachable_block: None,
vars: vars,
temps: temps,
args: args,