From 0262e4b138e6fa27188c3b8607fe81a74f0f13f1 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 19 Feb 2013 14:55:40 -0500 Subject: [PATCH 1/3] 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 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 8864e2e0a082..46aed07c66dc 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 43953b68f599..671f92624e13 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -14,7 +14,7 @@ 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 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; } From 12b43b274bfc962143afbb087f11b9e2137b0758 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 19 Feb 2013 19:15:03 -0500 Subject: [PATCH 2/3] add range assert when loading bools --- src/librustc/middle/trans/build.rs | 9 ++++----- src/librustc/middle/trans/datum.rs | 8 +++++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index 671f92624e13..bb870dfbf5bd 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -16,6 +16,7 @@ use lib::llvm::{Opcode, IntPredicate, RealPredicate, True, False}; use lib::llvm::{ValueRef, TypeRef, BasicBlockRef, BuilderRef, ModuleRef}; 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; @@ -540,13 +541,11 @@ 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 t = llvm::LLVMGetElementType(llvm::LLVMTypeOf(PointerVal)); + let min = llvm::LLVMConstInt(t, lo, signed); + let max = llvm::LLVMConstInt(t, hi, signed); - 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, diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 49779b9bbcc8..6f1d971263ce 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) + } + } } } } From fa6e3b49bf74dbfb18c7ac1996c8c054c5673f10 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 19 Feb 2013 21:18:19 -0500 Subject: [PATCH 3/3] replace explicit loops with foldr --- src/librustc/middle/trans/_match.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 46aed07c66dc..8085e4a66e16 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -1369,19 +1369,14 @@ pub fn compile_submatch(bcx: block, PointerCast(bcx, val, T_opaque_enum_ptr(ccx)); let discrimptr = GEPi(bcx, enumptr, [0u, 0u]); - 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; - } - } + 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,