Only SwitchInt over integers, not all consts

Also use a Cow to avoid full Vec for all SwitchInts
This commit is contained in:
Simonas Kazlauskas 2017-02-02 06:44:30 +02:00
parent aac82d9b13
commit a00a0adc79
10 changed files with 154 additions and 101 deletions

View file

@ -11,6 +11,7 @@
use llvm::{self, ValueRef, BasicBlockRef};
use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err};
use rustc::middle::lang_items;
use rustc::middle::const_val::ConstInt;
use rustc::ty::{self, layout, TypeFoldable};
use rustc::mir;
use abi::{Abi, FnType, ArgType};
@ -134,14 +135,24 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
}
mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
// TODO: cond_br if only 1 value
let (otherwise, targets) = targets.split_last().unwrap();
let discr = self.trans_operand(&bcx, discr).immediate();
let switch = bcx.switch(discr, llblock(self, *otherwise), values.len());
for (value, target) in values.iter().zip(targets) {
let val = Const::from_constval(bcx.ccx, value.clone(), switch_ty);
let llbb = llblock(self, *target);
bcx.add_case(switch, val.llval, llbb)
let discr = self.trans_operand(&bcx, discr);
if switch_ty == bcx.tcx().types.bool {
let lltrue = llblock(self, targets[0]);
let llfalse = llblock(self, targets[1]);
if let [ConstInt::Infer(0)] = values[..] {
bcx.cond_br(discr.immediate(), llfalse, lltrue);
} else {
bcx.cond_br(discr.immediate(), lltrue, llfalse);
}
} else {
let (otherwise, targets) = targets.split_last().unwrap();
let switch = bcx.switch(discr.immediate(),
llblock(self, *otherwise), values.len());
for (value, target) in values.iter().zip(targets) {
let val = Const::from_constint(bcx.ccx, value);
let llbb = llblock(self, *target);
bcx.add_case(switch, val.llval, llbb)
}
}
}

View file

@ -61,6 +61,33 @@ impl<'tcx> Const<'tcx> {
}
}
pub fn from_constint<'a>(ccx: &CrateContext<'a, 'tcx>, ci: &ConstInt)
-> Const<'tcx> {
let tcx = ccx.tcx();
let (llval, ty) = match *ci {
I8(v) => (C_integral(Type::i8(ccx), v as u64, true), tcx.types.i8),
I16(v) => (C_integral(Type::i16(ccx), v as u64, true), tcx.types.i16),
I32(v) => (C_integral(Type::i32(ccx), v as u64, true), tcx.types.i32),
I64(v) => (C_integral(Type::i64(ccx), v as u64, true), tcx.types.i64),
I128(v) => (C_big_integral(Type::i128(ccx), v as u128), tcx.types.i128),
Isize(v) => {
let i = v.as_i64(ccx.tcx().sess.target.int_type);
(C_integral(Type::int(ccx), i as u64, true), tcx.types.isize)
},
U8(v) => (C_integral(Type::i8(ccx), v as u64, false), tcx.types.u8),
U16(v) => (C_integral(Type::i16(ccx), v as u64, false), tcx.types.u16),
U32(v) => (C_integral(Type::i32(ccx), v as u64, false), tcx.types.u32),
U64(v) => (C_integral(Type::i64(ccx), v, false), tcx.types.u64),
U128(v) => (C_big_integral(Type::i128(ccx), v), tcx.types.u128),
Usize(v) => {
let u = v.as_u64(ccx.tcx().sess.target.uint_type);
(C_integral(Type::int(ccx), u, false), tcx.types.usize)
},
Infer(_) | InferSigned(_) => bug!("MIR must not use `{:?}`", ci),
};
Const { llval: llval, ty: ty }
}
/// Translate ConstVal into a LLVM constant value.
pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>,
cv: ConstVal,
@ -72,26 +99,7 @@ impl<'tcx> Const<'tcx> {
ConstVal::Float(F64(v)) => C_floating_f64(v, llty),
ConstVal::Float(FInfer {..}) => bug!("MIR must not use `{:?}`", cv),
ConstVal::Bool(v) => C_bool(ccx, v),
ConstVal::Integral(I8(v)) => C_integral(Type::i8(ccx), v as u64, true),
ConstVal::Integral(I16(v)) => C_integral(Type::i16(ccx), v as u64, true),
ConstVal::Integral(I32(v)) => C_integral(Type::i32(ccx), v as u64, true),
ConstVal::Integral(I64(v)) => C_integral(Type::i64(ccx), v as u64, true),
ConstVal::Integral(I128(v)) => C_big_integral(Type::i128(ccx), v as u128),
ConstVal::Integral(Isize(v)) => {
let i = v.as_i64(ccx.tcx().sess.target.int_type);
C_integral(Type::int(ccx), i as u64, true)
},
ConstVal::Integral(U8(v)) => C_integral(Type::i8(ccx), v as u64, false),
ConstVal::Integral(U16(v)) => C_integral(Type::i16(ccx), v as u64, false),
ConstVal::Integral(U32(v)) => C_integral(Type::i32(ccx), v as u64, false),
ConstVal::Integral(U64(v)) => C_integral(Type::i64(ccx), v, false),
ConstVal::Integral(U128(v)) => C_big_integral(Type::i128(ccx), v),
ConstVal::Integral(Usize(v)) => {
let u = v.as_u64(ccx.tcx().sess.target.uint_type);
C_integral(Type::int(ccx), u, false)
},
ConstVal::Integral(Infer(_)) |
ConstVal::Integral(InferSigned(_)) => bug!("MIR must not use `{:?}`", cv),
ConstVal::Integral(ref i) => return Const::from_constint(ccx, i),
ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
ConstVal::Struct(_) | ConstVal::Tuple(_) |