about summary refs log tree commit diff
path: root/src/librustc_trans/trans/base.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc_trans/trans/base.rs')
-rw-r--r--src/librustc_trans/trans/base.rs257
1 files changed, 116 insertions, 141 deletions
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index 54c50b7a62b..7f7b5cd8006 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -26,7 +26,6 @@
 #![allow(non_camel_case_types)]
 
 pub use self::ValueOrigin::*;
-pub use self::scalar_type::*;
 
 use super::CrateTranslation;
 use super::ModuleTranslation;
@@ -40,7 +39,6 @@ use metadata::{csearch, encoder, loader};
 use middle::astencode;
 use middle::cfg;
 use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
-use middle::subst;
 use middle::weak_lang_items;
 use middle::subst::{Subst, Substs};
 use middle::ty::{self, Ty, ClosureTyper};
@@ -498,7 +496,7 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                               did: ast::DefId,
                               t: Ty<'tcx>,
                               parent_id: ast::DefId,
-                              substs: &subst::Substs<'tcx>)
+                              substs: &Substs<'tcx>)
                               -> ValueRef {
     let _icx = push_ctxt("trans_res_dtor");
     let did = inline::maybe_instantiate_inline(ccx, did);
@@ -507,9 +505,9 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         assert_eq!(did.krate, ast::LOCAL_CRATE);
 
         // Since we're in trans we don't care for any region parameters
-        let substs = subst::Substs::erased(substs.types.clone());
+        let substs = ccx.tcx().mk_substs(Substs::erased(substs.types.clone()));
 
-        let (val, _, _) = monomorphize::monomorphic_fn(ccx, did, &substs, None);
+        let (val, _, _) = monomorphize::monomorphic_fn(ccx, did, substs, None);
 
         val
     } else if did.krate == ast::LOCAL_CRATE {
@@ -532,137 +530,100 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
 }
 
-// Used only for creating scalar comparison glue.
-#[derive(Copy)]
-pub enum scalar_type { nil_type, signed_int, unsigned_int, floating_point, }
+pub fn bin_op_to_icmp_predicate(ccx: &CrateContext, op: ast::BinOp_, signed: bool)
+                                -> llvm::IntPredicate {
+    match op {
+        ast::BiEq => llvm::IntEQ,
+        ast::BiNe => llvm::IntNE,
+        ast::BiLt => if signed { llvm::IntSLT } else { llvm::IntULT },
+        ast::BiLe => if signed { llvm::IntSLE } else { llvm::IntULE },
+        ast::BiGt => if signed { llvm::IntSGT } else { llvm::IntUGT },
+        ast::BiGe => if signed { llvm::IntSGE } else { llvm::IntUGE },
+        op => {
+            ccx.sess().bug(&format!("comparison_op_to_icmp_predicate: expected \
+                                     comparison operator, found {:?}", op)[]);
+        }
+    }
+}
+
+pub fn bin_op_to_fcmp_predicate(ccx: &CrateContext, op: ast::BinOp_)
+                                -> llvm::RealPredicate {
+    match op {
+        ast::BiEq => llvm::RealOEQ,
+        ast::BiNe => llvm::RealUNE,
+        ast::BiLt => llvm::RealOLT,
+        ast::BiLe => llvm::RealOLE,
+        ast::BiGt => llvm::RealOGT,
+        ast::BiGe => llvm::RealOGE,
+        op => {
+            ccx.sess().bug(&format!("comparison_op_to_fcmp_predicate: expected \
+                                     comparison operator, found {:?}", op)[]);
+        }
+    }
+}
 
-pub fn compare_scalar_types<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
+pub fn compare_scalar_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                         lhs: ValueRef,
                                         rhs: ValueRef,
                                         t: Ty<'tcx>,
                                         op: ast::BinOp_,
                                         debug_loc: DebugLoc)
-                                        -> Result<'blk, 'tcx> {
-    let f = |a| Result::new(cx, compare_scalar_values(cx, lhs, rhs, a, op, debug_loc));
-
+                                        -> ValueRef {
     match t.sty {
-        ty::ty_tup(ref tys) if tys.is_empty() => f(nil_type),
-        ty::ty_bool | ty::ty_uint(_) | ty::ty_char => f(unsigned_int),
-        ty::ty_ptr(mt) if common::type_is_sized(cx.tcx(), mt.ty) => f(unsigned_int),
-        ty::ty_int(_) => f(signed_int),
-        ty::ty_float(_) => f(floating_point),
-            // Should never get here, because t is scalar.
-        _ => cx.sess().bug("non-scalar type passed to compare_scalar_types")
-    }
-}
-
-
-// A helper function to do the actual comparison of scalar values.
-pub fn compare_scalar_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
-                                         lhs: ValueRef,
-                                         rhs: ValueRef,
-                                         nt: scalar_type,
-                                         op: ast::BinOp_,
-                                         debug_loc: DebugLoc)
-                                         -> ValueRef {
-    let _icx = push_ctxt("compare_scalar_values");
-    fn die(cx: Block) -> ! {
-        cx.sess().bug("compare_scalar_values: must be a comparison operator");
-    }
-    match nt {
-      nil_type => {
-        // We don't need to do actual comparisons for nil.
-        // () == () holds but () < () does not.
-        match op {
-          ast::BiEq | ast::BiLe | ast::BiGe => return C_bool(cx.ccx(), true),
-          ast::BiNe | ast::BiLt | ast::BiGt => return C_bool(cx.ccx(), false),
-          // refinements would be nice
-          _ => die(cx)
+        ty::ty_tup(ref tys) if tys.is_empty() => {
+            // We don't need to do actual comparisons for nil.
+            // () == () holds but () < () does not.
+            match op {
+                ast::BiEq | ast::BiLe | ast::BiGe => return C_bool(bcx.ccx(), true),
+                ast::BiNe | ast::BiLt | ast::BiGt => return C_bool(bcx.ccx(), false),
+                // refinements would be nice
+                _ => bcx.sess().bug("compare_scalar_types: must be a comparison operator")
+            }
         }
-      }
-      floating_point => {
-        let cmp = match op {
-          ast::BiEq => llvm::RealOEQ,
-          ast::BiNe => llvm::RealUNE,
-          ast::BiLt => llvm::RealOLT,
-          ast::BiLe => llvm::RealOLE,
-          ast::BiGt => llvm::RealOGT,
-          ast::BiGe => llvm::RealOGE,
-          _ => die(cx)
-        };
-        return FCmp(cx, cmp, lhs, rhs, debug_loc);
-      }
-      signed_int => {
-        let cmp = match op {
-          ast::BiEq => llvm::IntEQ,
-          ast::BiNe => llvm::IntNE,
-          ast::BiLt => llvm::IntSLT,
-          ast::BiLe => llvm::IntSLE,
-          ast::BiGt => llvm::IntSGT,
-          ast::BiGe => llvm::IntSGE,
-          _ => die(cx)
-        };
-        return ICmp(cx, cmp, lhs, rhs, debug_loc);
-      }
-      unsigned_int => {
-        let cmp = match op {
-          ast::BiEq => llvm::IntEQ,
-          ast::BiNe => llvm::IntNE,
-          ast::BiLt => llvm::IntULT,
-          ast::BiLe => llvm::IntULE,
-          ast::BiGt => llvm::IntUGT,
-          ast::BiGe => llvm::IntUGE,
-          _ => die(cx)
-        };
-        return ICmp(cx, cmp, lhs, rhs, debug_loc);
-      }
+        ty::ty_bool | ty::ty_uint(_) | ty::ty_char => {
+            ICmp(bcx, bin_op_to_icmp_predicate(bcx.ccx(), op, false), lhs, rhs, debug_loc)
+        }
+        ty::ty_ptr(mt) if common::type_is_sized(bcx.tcx(), mt.ty) => {
+            ICmp(bcx, bin_op_to_icmp_predicate(bcx.ccx(), op, false), lhs, rhs, debug_loc)
+        }
+        ty::ty_int(_) => {
+            ICmp(bcx, bin_op_to_icmp_predicate(bcx.ccx(), op, true), lhs, rhs, debug_loc)
+        }
+        ty::ty_float(_) => {
+            FCmp(bcx, bin_op_to_fcmp_predicate(bcx.ccx(), op), lhs, rhs, debug_loc)
+        }
+        // Should never get here, because t is scalar.
+        _ => bcx.sess().bug("non-scalar type passed to compare_scalar_types")
     }
 }
 
-pub fn compare_simd_types<'blk, 'tcx>(
-                    cx: Block<'blk, 'tcx>,
-                    lhs: ValueRef,
-                    rhs: ValueRef,
-                    t: Ty<'tcx>,
-                    size: uint,
-                    op: ast::BinOp_,
-                    debug_loc: DebugLoc)
-                    -> ValueRef {
-    let cmp = match t.sty {
+pub fn compare_simd_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                                      lhs: ValueRef,
+                                      rhs: ValueRef,
+                                      t: Ty<'tcx>,
+                                      op: ast::BinOp_,
+                                      debug_loc: DebugLoc)
+                                      -> ValueRef {
+    let signed = match t.sty {
         ty::ty_float(_) => {
             // The comparison operators for floating point vectors are challenging.
             // LLVM outputs a `< size x i1 >`, but if we perform a sign extension
             // then bitcast to a floating point vector, the result will be `-NaN`
             // for each truth value. Because of this they are unsupported.
-            cx.sess().bug("compare_simd_types: comparison operators \
-                           not supported for floating point SIMD types")
-        },
-        ty::ty_uint(_) => match op {
-            ast::BiEq => llvm::IntEQ,
-            ast::BiNe => llvm::IntNE,
-            ast::BiLt => llvm::IntULT,
-            ast::BiLe => llvm::IntULE,
-            ast::BiGt => llvm::IntUGT,
-            ast::BiGe => llvm::IntUGE,
-            _ => cx.sess().bug("compare_simd_types: must be a comparison operator"),
-        },
-        ty::ty_int(_) => match op {
-            ast::BiEq => llvm::IntEQ,
-            ast::BiNe => llvm::IntNE,
-            ast::BiLt => llvm::IntSLT,
-            ast::BiLe => llvm::IntSLE,
-            ast::BiGt => llvm::IntSGT,
-            ast::BiGe => llvm::IntSGE,
-            _ => cx.sess().bug("compare_simd_types: must be a comparison operator"),
+            bcx.sess().bug("compare_simd_types: comparison operators \
+                            not supported for floating point SIMD types")
         },
-        _ => cx.sess().bug("compare_simd_types: invalid SIMD type"),
+        ty::ty_uint(_) => false,
+        ty::ty_int(_) => true,
+        _ => bcx.sess().bug("compare_simd_types: invalid SIMD type"),
     };
-    let return_ty = Type::vector(&type_of(cx.ccx(), t), size as u64);
+
+    let cmp = bin_op_to_icmp_predicate(bcx.ccx(), op, signed);
     // LLVM outputs an `< size x i1 >`, so we need to perform a sign extension
     // to get the correctly sized type. This will compile to a single instruction
     // once the IR is converted to assembly if the SIMD instruction is supported
     // by the target architecture.
-    SExt(cx, ICmp(cx, cmp, lhs, rhs, debug_loc), return_ty)
+    SExt(bcx, ICmp(bcx, cmp, lhs, rhs, debug_loc), val_ty(lhs))
 }
 
 // Iterates through the elements of a structural type.
@@ -679,7 +640,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
                                    repr: &adt::Repr<'tcx>,
                                    av: ValueRef,
                                    variant: &ty::VariantInfo<'tcx>,
-                                   substs: &subst::Substs<'tcx>,
+                                   substs: &Substs<'tcx>,
                                    f: &mut F)
                                    -> Block<'blk, 'tcx> where
         F: FnMut(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
@@ -1034,21 +995,39 @@ pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                            ptr: ValueRef, t: Ty<'tcx>) -> ValueRef {
     if type_is_zero_size(cx.ccx(), t) {
         C_undef(type_of::type_of(cx.ccx(), t))
-    } else if ty::type_is_bool(t) {
-        Trunc(cx, LoadRangeAssert(cx, ptr, 0, 2, llvm::False), Type::i1(cx.ccx()))
     } else if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() {
         // We want to pass small aggregates as immediate values, but using an aggregate LLVM type
         // for this leads to bad optimizations, so its arg type is an appropriately sized integer
         // and we have to convert it
         Load(cx, BitCast(cx, ptr, type_of::arg_type_of(cx.ccx(), t).ptr_to()))
-    } else if ty::type_is_region_ptr(t) || ty::type_is_unique(t) {
-        LoadNonNull(cx, ptr)
-    } else if ty::type_is_char(t) {
-        // a char is a Unicode codepoint, and so takes values from 0
-        // to 0x10FFFF inclusive only.
-        LoadRangeAssert(cx, ptr, 0, 0x10FFFF + 1, llvm::False)
     } else {
-        Load(cx, ptr)
+        unsafe {
+            let global = llvm::LLVMIsAGlobalVariable(ptr);
+            if !global.is_null() && llvm::LLVMIsGlobalConstant(global) == llvm::True {
+                let val = llvm::LLVMGetInitializer(global);
+                if !val.is_null() {
+                    // This could go into its own function, for DRY.
+                    // (something like "pre-store packing/post-load unpacking")
+                    if ty::type_is_bool(t) {
+                        return Trunc(cx, val, Type::i1(cx.ccx()));
+                    } else {
+                        return val;
+                    }
+                }
+            }
+        }
+        if ty::type_is_bool(t) {
+            Trunc(cx, LoadRangeAssert(cx, ptr, 0, 2, llvm::False), Type::i1(cx.ccx()))
+        } else if ty::type_is_char(t) {
+            // a char is a Unicode codepoint, and so takes values from 0
+            // to 0x10FFFF inclusive only.
+            LoadRangeAssert(cx, ptr, 0, 0x10FFFF + 1, llvm::False)
+        } else if (ty::type_is_region_ptr(t) || ty::type_is_unique(t))
+                  && !common::type_is_fat_ptr(cx.tcx(), t) {
+            LoadNonNull(cx, ptr)
+        } else {
+            Load(cx, ptr)
+        }
     }
 }
 
@@ -1064,7 +1043,7 @@ pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t
         Store(cx, v, BitCast(cx, dst, type_of::arg_type_of(cx.ccx(), t).ptr_to()));
     } else {
         Store(cx, v, dst);
-    };
+    }
 }
 
 pub fn init_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, local: &ast::Local)
@@ -1162,7 +1141,7 @@ pub fn memcpy_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         let llalign = type_of::align_of(ccx, t);
         call_memcpy(bcx, dst, src, llsz, llalign as u32);
     } else {
-        store_ty(bcx, Load(bcx, src), dst, t);
+        store_ty(bcx, load_ty(bcx, src, t), dst, t);
     }
 }
 
@@ -1425,7 +1404,7 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
                              id: ast::NodeId,
                              has_env: bool,
                              output_type: ty::FnOutput<'tcx>,
-                             param_substs: &'a Substs<'tcx>,
+                             param_substs: &'tcx Substs<'tcx>,
                              sp: Option<Span>,
                              block_arena: &'a TypedArena<common::BlockS<'a, 'tcx>>)
                              -> FunctionContext<'a, 'tcx> {
@@ -1793,7 +1772,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                    decl: &ast::FnDecl,
                                    body: &ast::Block,
                                    llfndecl: ValueRef,
-                                   param_substs: &Substs<'tcx>,
+                                   param_substs: &'tcx Substs<'tcx>,
                                    fn_ast_id: ast::NodeId,
                                    _attributes: &[ast::Attribute],
                                    output_type: ty::FnOutput<'tcx>,
@@ -1942,7 +1921,7 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                           decl: &ast::FnDecl,
                           body: &ast::Block,
                           llfndecl: ValueRef,
-                          param_substs: &Substs<'tcx>,
+                          param_substs: &'tcx Substs<'tcx>,
                           id: ast::NodeId,
                           attrs: &[ast::Attribute]) {
     let _s = StatRecorder::new(ccx, ccx.tcx().map.path_to_string(id).to_string());
@@ -1968,7 +1947,7 @@ pub fn trans_enum_variant<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                     variant: &ast::Variant,
                                     _args: &[ast::VariantArg],
                                     disr: ty::Disr,
-                                    param_substs: &Substs<'tcx>,
+                                    param_substs: &'tcx Substs<'tcx>,
                                     llfndecl: ValueRef) {
     let _icx = push_ctxt("trans_enum_variant");
 
@@ -2049,7 +2028,7 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 pub fn trans_tuple_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                     _fields: &[ast::StructField],
                                     ctor_id: ast::NodeId,
-                                    param_substs: &Substs<'tcx>,
+                                    param_substs: &'tcx Substs<'tcx>,
                                     llfndecl: ValueRef) {
     let _icx = push_ctxt("trans_tuple_struct");
 
@@ -2064,7 +2043,7 @@ pub fn trans_tuple_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                                      ctor_id: ast::NodeId,
                                                      disr: ty::Disr,
-                                                     param_substs: &Substs<'tcx>,
+                                                     param_substs: &'tcx Substs<'tcx>,
                                                      llfndecl: ValueRef) {
     let ctor_ty = ty::node_id_to_type(ccx.tcx(), ctor_id);
     let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &ctor_ty);
@@ -2302,13 +2281,14 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
             // translated everywhere it's needed.
             for (ref ccx, is_origin) in ccx.maybe_iter(!from_external && trans_everywhere) {
                 let llfn = get_item_val(ccx, item.id);
+                let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
                 if abi != Rust {
                     foreign::trans_rust_fn_with_foreign_abi(ccx,
                                                             &**decl,
                                                             &**body,
                                                             &item.attrs[],
                                                             llfn,
-                                                            &Substs::trans_empty(),
+                                                            empty_substs,
                                                             item.id,
                                                             None);
                 } else {
@@ -2316,7 +2296,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
                              &**decl,
                              &**body,
                              llfn,
-                             &Substs::trans_empty(),
+                             empty_substs,
                              item.id,
                              &item.attrs[]);
                 }
@@ -2792,7 +2772,8 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
 
                     // We need the translated value here, because for enums the
                     // LLVM type is not fully determined by the Rust type.
-                    let (v, ty) = consts::const_expr(ccx, &**expr);
+                    let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
+                    let (v, ty) = consts::const_expr(ccx, &**expr, empty_substs);
                     ccx.static_values().borrow_mut().insert(id, v);
                     unsafe {
                         // boolean SSA values are i1, but they have to be stored in i8 slots,
@@ -2820,12 +2801,6 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
                     }
                 }
 
-                ast::ItemConst(_, ref expr) => {
-                    let (v, _) = consts::const_expr(ccx, &**expr);
-                    ccx.const_values().borrow_mut().insert(id, v);
-                    v
-                }
-
                 ast::ItemFn(_, _, abi, _, _) => {
                     let sym = sym();
                     let llfn = if abi == Rust {