use range assert when loading enum discriminant

Closes #4924
This commit is contained in:
Daniel Micay 2013-02-19 14:55:40 -05:00
parent 1171a214a6
commit 0262e4b138
3 changed files with 54 additions and 3 deletions

View File

@ -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;

View File

@ -1361,13 +1361,34 @@ 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);
let mut min_discrim = variants[0].disr_val;
for uint::range(1, variants.len()) |idx| {
if variants[idx].disr_val < min_discrim {
min_discrim = variants[idx].disr_val;
}
}
let mut max_discrim = variants[0].disr_val;
for uint::range(1, variants.len()) |idx| {
if variants[idx].disr_val > max_discrim {
max_discrim = variants[idx].disr_val;
}
}
test_val = LoadRangeAssert(bcx, discrimptr,
min_discrim as c_ulonglong,
(max_discrim + 1)
as c_ulonglong,
lib::llvm::True);
kind = switch;
}
}

View File

@ -14,7 +14,7 @@
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 core::cast::transmute;
@ -536,6 +536,27 @@ 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);
let ccx = cx.fcx.ccx;
let ty = val_ty(PointerVal);
unsafe {
assert llvm::LLVMGetTypeKind(ty) != lib::llvm::Array;
let min = llvm::LLVMConstInt(ccx.int_type, lo, signed);
let max = llvm::LLVMConstInt(ccx.int_type, 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; }