From 0262e4b138e6fa27188c3b8607fe81a74f0f13f1 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 19 Feb 2013 14:55:40 -0500 Subject: [PATCH] use range assert when loading enum discriminant Closes #4924 --- src/librustc/lib/llvm.rs | 9 +++++++++ src/librustc/middle/trans/_match.rs | 25 +++++++++++++++++++++++-- src/librustc/middle/trans/build.rs | 23 ++++++++++++++++++++++- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index c58ab494ed3..694cfb94e96 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 8864e2e0a08..46aed07c66d 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -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; } } diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index 43953b68f59..671f92624e1 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -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; }