diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index c58ab494ed36..694cfb94e962 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -184,6 +184,15 @@ pub enum FileType { ObjectFile = 1 } +pub enum Metadata { + MD_dbg = 0, + MD_tbaa = 1, + MD_prof = 2, + MD_fpmath = 3, + MD_range = 4, + MD_tbaa_struct = 5 +} + // Opaque pointer types pub enum Module_opaque {} pub type ModuleRef = *Module_opaque; diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index a6813997ae83..962d5dbfbf07 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -1361,13 +1361,29 @@ pub fn compile_submatch(bcx: block, if opts.len() > 0u { match opts[0] { var(_, vdef) => { - if (*ty::enum_variants(tcx, vdef.enm)).len() == 1u { + let variants = ty::enum_variants(tcx, vdef.enm); + if variants.len() == 1 { kind = single; } else { let enumptr = PointerCast(bcx, val, T_opaque_enum_ptr(ccx)); let discrimptr = GEPi(bcx, enumptr, [0u, 0u]); - test_val = Load(bcx, discrimptr); + + + assert variants.len() > 1; + let min_discrim = do variants.foldr(0) |&x, y| { + int::min(x.disr_val, y) + }; + let max_discrim = do variants.foldr(0) |&x, y| { + int::max(x.disr_val, y) + }; + + test_val = LoadRangeAssert(bcx, discrimptr, + min_discrim as c_ulonglong, + (max_discrim + 1) + as c_ulonglong, + lib::llvm::True); + kind = switch; } } diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index da9dcc7c9afd..85e8be098789 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -14,8 +14,9 @@ use lib::llvm::llvm; use lib::llvm::{CallConv, TypeKind, AtomicBinOp, AtomicOrdering}; use lib::llvm::{Opcode, IntPredicate, RealPredicate, True, False}; use lib::llvm::{ValueRef, TypeRef, BasicBlockRef, BuilderRef, ModuleRef}; -use libc::{c_uint, c_int}; +use libc::{c_uint, c_int, c_ulonglong}; use middle::trans::common::*; +use middle::trans::machine::llsize_of_real; use core::cast::transmute; use core::cast; @@ -536,6 +537,25 @@ pub fn Load(cx: block, PointerVal: ValueRef) -> ValueRef { } } +pub fn LoadRangeAssert(cx: block, PointerVal: ValueRef, lo: c_ulonglong, + hi: c_ulonglong, signed: lib::llvm::Bool) -> ValueRef { + let value = Load(cx, PointerVal); + + unsafe { + let t = llvm::LLVMGetElementType(llvm::LLVMTypeOf(PointerVal)); + let min = llvm::LLVMConstInt(t, lo, signed); + let max = llvm::LLVMConstInt(t, hi, signed); + + + do vec::as_imm_buf([min, max]) |ptr, len| { + llvm::LLVMSetMetadata(value, lib::llvm::MD_range as c_uint, + llvm::LLVMMDNode(ptr, len as c_uint)); + } + } + + value +} + pub fn Store(cx: block, Val: ValueRef, Ptr: ValueRef) { unsafe { if cx.unreachable { return; } diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 206ee50111fd..9db06cea423f 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -431,7 +431,13 @@ pub impl Datum { } else { match self.mode { ByValue => self.val, - ByRef => Load(bcx, self.val) + ByRef => { + if ty::type_is_bool(self.ty) { + LoadRangeAssert(bcx, self.val, 0, 2, lib::llvm::True) + } else { + Load(bcx, self.val) + } + } } } }