]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_codegen_llvm/common.rs
Use the method form for CodegenCx everywhere
[rust.git] / src / librustc_codegen_llvm / common.rs
index c9b464fd8f3dd48482fa3a307a3f55b0c0bc7856..569fbc9f0813efb8cf6a0765419bbb8c15cdd028 100644 (file)
@@ -13,7 +13,7 @@
 //! Code that is useful in various codegen modules.
 
 use llvm::{self, TypeKind};
-use llvm::{True, False, Bool, OperandBundleDef};
+use llvm::{True, False, Bool, BasicBlock};
 use rustc::hir::def_id::DefId;
 use rustc::middle::lang_items::LangItem;
 use abi;
 use type_::Type;
 use type_of::LayoutLlvmExt;
 use value::Value;
+use interfaces::{Backend, CommonMethods, CommonWriteMethods};
 
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::layout::{HasDataLayout, LayoutOf};
 use rustc::hir;
+use interfaces::BuilderMethods;
 
 use libc::{c_uint, c_char};
 
@@ -48,6 +50,87 @@ pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bo
     ty.is_freeze(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP)
 }
 
+pub struct OperandBundleDef<'a, Value: 'a> {
+    pub name: &'a str,
+    pub val: Value
+}
+
+impl OperandBundleDef<'ll, &'ll Value> {
+    pub fn new(name: &'ll str, val: &'ll Value) -> Self {
+        OperandBundleDef {
+            name,
+            val
+        }
+    }
+}
+
+pub enum IntPredicate {
+    IntEQ,
+    IntNE,
+    IntUGT,
+    IntUGE,
+    IntULT,
+    IntULE,
+    IntSGT,
+    IntSGE,
+    IntSLT,
+    IntSLE
+}
+
+#[allow(dead_code)]
+pub enum RealPredicate {
+    RealPredicateFalse,
+    RealOEQ,
+    RealOGT,
+    RealOGE,
+    RealOLT,
+    RealOLE,
+    RealONE,
+    RealORD,
+    RealUNO,
+    RealUEQ,
+    RealUGT,
+    RealUGE,
+    RealULT,
+    RealULE,
+    RealUNE,
+    RealPredicateTrue
+}
+
+pub enum AtomicRmwBinOp {
+    AtomicXchg,
+    AtomicAdd,
+    AtomicSub,
+    AtomicAnd,
+    AtomicNand,
+    AtomicOr,
+    AtomicXor,
+    AtomicMax,
+    AtomicMin,
+    AtomicUMax,
+    AtomicUMin
+}
+
+pub enum AtomicOrdering {
+    #[allow(dead_code)]
+    NotAtomic,
+    Unordered,
+    Monotonic,
+    // Consume,  // Not specified yet.
+    Acquire,
+    Release,
+    AcquireRelease,
+    SequentiallyConsistent,
+}
+
+pub enum SynchronizationScope {
+    // FIXME: figure out if this variant is needed at all.
+    #[allow(dead_code)]
+    Other,
+    SingleThread,
+    CrossThread,
+}
+
 /*
 * A note on nomenclature of linking: "extern", "foreign", and "upcall".
 *
@@ -90,14 +173,14 @@ pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bo
 /// the `OperandBundleDef` value created for MSVC landing pads.
 pub struct Funclet<'ll> {
     cleanuppad: &'ll Value,
-    operand: OperandBundleDef<'ll>,
+    operand: OperandBundleDef<'ll, &'ll Value>,
 }
 
 impl Funclet<'ll> {
     pub fn new(cleanuppad: &'ll Value) -> Self {
         Funclet {
             cleanuppad,
-            operand: OperandBundleDef::new("funclet", &[cleanuppad]),
+            operand: OperandBundleDef::new("funclet", cleanuppad),
         }
     }
 
@@ -105,204 +188,258 @@ pub fn cleanuppad(&self) -> &'ll Value {
         self.cleanuppad
     }
 
-    pub fn bundle(&self) -> &OperandBundleDef<'ll> {
+    pub fn bundle(&self) -> &OperandBundleDef<'ll, &'ll Value> {
         &self.operand
     }
 }
 
-pub fn val_ty(v: &'ll Value) -> &'ll Type {
-    unsafe {
-        llvm::LLVMTypeOf(v)
-    }
+impl Backend for CodegenCx<'ll, 'tcx> {
+    type Value = &'ll Value;
+    type BasicBlock = &'ll BasicBlock;
+    type Type = &'ll Type;
+    type Context = &'ll llvm::Context;
 }
 
-// LLVM constant constructors.
-pub fn C_null(t: &'ll Type) -> &'ll Value {
-    unsafe {
-        llvm::LLVMConstNull(t)
+impl<'ll, 'tcx: 'll> CommonMethods for CodegenCx<'ll, 'tcx> {
+
+    // LLVM constant constructors.
+    fn c_null(&self, t: &'ll Type) -> &'ll Value {
+        unsafe {
+            llvm::LLVMConstNull(t)
+        }
     }
-}
 
-pub fn C_undef(t: &'ll Type) -> &'ll Value {
-    unsafe {
-        llvm::LLVMGetUndef(t)
+    fn c_undef(&self, t: &'ll Type) -> &'ll Value {
+        unsafe {
+            llvm::LLVMGetUndef(t)
+        }
     }
-}
 
-pub fn C_int(t: &'ll Type, i: i64) -> &'ll Value {
-    unsafe {
-        llvm::LLVMConstInt(t, i as u64, True)
+    fn c_int(&self, t: &'ll Type, i: i64) -> &'ll Value {
+        unsafe {
+            llvm::LLVMConstInt(t, i as u64, True)
+        }
     }
-}
 
-pub fn C_uint(t: &'ll Type, i: u64) -> &'ll Value {
-    unsafe {
-        llvm::LLVMConstInt(t, i, False)
+    fn c_uint(&self, t: &'ll Type, i: u64) -> &'ll Value {
+        unsafe {
+            llvm::LLVMConstInt(t, i, False)
+        }
     }
-}
 
-pub fn C_uint_big(t: &'ll Type, u: u128) -> &'ll Value {
-    unsafe {
-        let words = [u as u64, (u >> 64) as u64];
-        llvm::LLVMConstIntOfArbitraryPrecision(t, 2, words.as_ptr())
+    fn c_uint_big(&self, t: &'ll Type, u: u128) -> &'ll Value {
+        unsafe {
+            let words = [u as u64, (u >> 64) as u64];
+            llvm::LLVMConstIntOfArbitraryPrecision(t, 2, words.as_ptr())
+        }
     }
-}
 
-pub fn C_bool(cx: &CodegenCx<'ll, '_>, val: bool) -> &'ll Value {
-    C_uint(Type::i1(cx), val as u64)
-}
+    fn c_bool(&self, val: bool) -> &'ll Value {
+        &self.c_uint(Type::i1(&self), val as u64)
+    }
 
-pub fn C_i32(cx: &CodegenCx<'ll, '_>, i: i32) -> &'ll Value {
-    C_int(Type::i32(cx), i as i64)
-}
+    fn c_i32(&self, i: i32) -> &'ll Value {
+        &self.c_int(Type::i32(&self), i as i64)
+    }
 
-pub fn C_u32(cx: &CodegenCx<'ll, '_>, i: u32) -> &'ll Value {
-    C_uint(Type::i32(cx), i as u64)
-}
+    fn c_u32(&self, i: u32) -> &'ll Value {
+        &self.c_uint(Type::i32(&self), i as u64)
+    }
 
-pub fn C_u64(cx: &CodegenCx<'ll, '_>, i: u64) -> &'ll Value {
-    C_uint(Type::i64(cx), i)
-}
+    fn c_u64(&self, i: u64) -> &'ll Value {
+        &self.c_uint(Type::i64(&self), i)
+    }
+
+    fn c_usize(&self, i: u64) -> &'ll Value {
+        let bit_size = self.data_layout().pointer_size.bits();
+        if bit_size < 64 {
+            // make sure it doesn't overflow
+            assert!(i < (1<<bit_size));
+        }
 
-pub fn C_usize(cx: &CodegenCx<'ll, '_>, i: u64) -> &'ll Value {
-    let bit_size = cx.data_layout().pointer_size.bits();
-    if bit_size < 64 {
-        // make sure it doesn't overflow
-        assert!(i < (1<<bit_size));
+        &self.c_uint(&self.isize_ty, i)
     }
 
-    C_uint(cx.isize_ty, i)
-}
+    fn c_u8(&self, i: u8) -> &'ll Value {
+        &self.c_uint(Type::i8(&self), i as u64)
+    }
 
-pub fn C_u8(cx: &CodegenCx<'ll, '_>, i: u8) -> &'ll Value {
-    C_uint(Type::i8(cx), i as u64)
-}
 
+    // This is a 'c-like' raw string, which differs from
+    // our boxed-and-length-annotated strings.
+    fn c_cstr(
+        &self,
+        s: LocalInternedString,
+        null_terminated: bool,
+    ) -> &'ll Value {
+        unsafe {
+            if let Some(&llval) = &self.const_cstr_cache.borrow().get(&s) {
+                return llval;
+            }
 
-// This is a 'c-like' raw string, which differs from
-// our boxed-and-length-annotated strings.
-pub fn C_cstr(
-    cx: &CodegenCx<'ll, '_>,
-    s: LocalInternedString,
-    null_terminated: bool,
-) -> &'ll Value {
-    unsafe {
-        if let Some(&llval) = cx.const_cstr_cache.borrow().get(&s) {
-            return llval;
+            let sc = llvm::LLVMConstStringInContext(&self.llcx,
+                                                    s.as_ptr() as *const c_char,
+                                                    s.len() as c_uint,
+                                                    !null_terminated as Bool);
+            let sym = &self.generate_local_symbol_name("str");
+            let g = declare::define_global(&self, &sym[..], &self.val_ty(sc)).unwrap_or_else(||{
+                bug!("symbol `{}` is already defined", sym);
+            });
+            llvm::LLVMSetInitializer(g, sc);
+            llvm::LLVMSetGlobalConstant(g, True);
+            llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
+
+            &self.const_cstr_cache.borrow_mut().insert(s, g);
+            g
         }
+    }
 
-        let sc = llvm::LLVMConstStringInContext(cx.llcx,
-                                                s.as_ptr() as *const c_char,
-                                                s.len() as c_uint,
-                                                !null_terminated as Bool);
-        let sym = cx.generate_local_symbol_name("str");
-        let g = declare::define_global(cx, &sym[..], val_ty(sc)).unwrap_or_else(||{
-            bug!("symbol `{}` is already defined", sym);
-        });
-        llvm::LLVMSetInitializer(g, sc);
-        llvm::LLVMSetGlobalConstant(g, True);
-        llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
-
-        cx.const_cstr_cache.borrow_mut().insert(s, g);
-        g
+    // NB: Do not use `do_spill_noroot` to make this into a constant string, or
+    // you will be kicked off fast isel. See issue #4352 for an example of this.
+    fn c_str_slice(&self, s: LocalInternedString) -> &'ll Value {
+        let len = s.len();
+        let cs = consts::ptrcast(&self.c_cstr(s, false),
+            &self.layout_of(&self.tcx.mk_str()).llvm_type(&self).ptr_to());
+        &self.c_fat_ptr(cs, &self.c_usize(len as u64))
     }
-}
 
-// NB: Do not use `do_spill_noroot` to make this into a constant string, or
-// you will be kicked off fast isel. See issue #4352 for an example of this.
-pub fn C_str_slice(cx: &CodegenCx<'ll, '_>, s: LocalInternedString) -> &'ll Value {
-    let len = s.len();
-    let cs = consts::ptrcast(C_cstr(cx, s, false),
-        cx.layout_of(cx.tcx.mk_str()).llvm_type(cx).ptr_to());
-    C_fat_ptr(cx, cs, C_usize(cx, len as u64))
-}
+    fn c_fat_ptr(
+        &self,
+        ptr: &'ll Value,
+        meta: &'ll Value
+    ) -> &'ll Value {
+        assert_eq!(abi::FAT_PTR_ADDR, 0);
+        assert_eq!(abi::FAT_PTR_EXTRA, 1);
+        &self.c_struct(&[ptr, meta], false)
+    }
 
-pub fn C_fat_ptr(cx: &CodegenCx<'ll, '_>, ptr: &'ll Value, meta: &'ll Value) -> &'ll Value {
-    assert_eq!(abi::FAT_PTR_ADDR, 0);
-    assert_eq!(abi::FAT_PTR_EXTRA, 1);
-    C_struct(cx, &[ptr, meta], false)
-}
+    fn c_struct(
+        &self,
+        elts: &[&'ll Value],
+        packed: bool
+    ) -> &'ll Value {
+        &self.c_struct_in_context(&self.llcx, elts, packed)
+    }
 
-pub fn C_struct(cx: &CodegenCx<'ll, '_>, elts: &[&'ll Value], packed: bool) -> &'ll Value {
-    C_struct_in_context(cx.llcx, elts, packed)
-}
+    fn c_array(&self, ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value {
+        unsafe {
+            return llvm::LLVMConstArray(ty, elts.as_ptr(), elts.len() as c_uint);
+        }
+    }
 
-pub fn C_struct_in_context(
-    llcx: &'ll llvm::Context,
-    elts: &[&'ll Value],
-    packed: bool,
-) -> &'ll Value {
-    unsafe {
-        llvm::LLVMConstStructInContext(llcx,
-                                       elts.as_ptr(), elts.len() as c_uint,
-                                       packed as Bool)
+    fn c_vector(&self, elts: &[&'ll Value]) -> &'ll Value {
+        unsafe {
+            return llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint);
+        }
     }
-}
 
-pub fn C_array(ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value {
-    unsafe {
-        return llvm::LLVMConstArray(ty, elts.as_ptr(), elts.len() as c_uint);
+    fn c_bytes(&self, bytes: &[u8]) -> &'ll Value {
+        &self.c_bytes_in_context(&self.llcx, bytes)
     }
-}
 
-pub fn C_vector(elts: &[&'ll Value]) -> &'ll Value {
-    unsafe {
-        return llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint);
+    fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
+        unsafe {
+            assert_eq!(idx as c_uint as u64, idx);
+            let us = &[idx as c_uint];
+            let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint);
+
+            debug!("const_get_elt(v={:?}, idx={}, r={:?})",
+                   v, idx, r);
+
+            r
+        }
     }
-}
 
-pub fn C_bytes(cx: &CodegenCx<'ll, '_>, bytes: &[u8]) -> &'ll Value {
-    C_bytes_in_context(cx.llcx, bytes)
-}
+    fn const_get_real(&self, v: &'ll Value) -> Option<(f64, bool)> {
+        unsafe {
+            if self.is_const_real(v) {
+                let mut loses_info: llvm::Bool = ::std::mem::uninitialized();
+                let r = llvm::LLVMConstRealGetDouble(v, &mut loses_info);
+                let loses_info = if loses_info == 1 { true } else { false };
+                Some((r, loses_info))
+            } else {
+                None
+            }
+        }
+    }
 
-pub fn C_bytes_in_context(llcx: &'ll llvm::Context, bytes: &[u8]) -> &'ll Value {
-    unsafe {
-        let ptr = bytes.as_ptr() as *const c_char;
-        return llvm::LLVMConstStringInContext(llcx, ptr, bytes.len() as c_uint, True);
+    fn const_to_uint(&self, v: &'ll Value) -> u64 {
+        unsafe {
+            llvm::LLVMConstIntGetZExtValue(v)
+        }
     }
-}
 
-pub fn const_get_elt(v: &'ll Value, idx: u64) -> &'ll Value {
-    unsafe {
-        assert_eq!(idx as c_uint as u64, idx);
-        let us = &[idx as c_uint];
-        let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint);
+    fn is_const_integral(&self, v: &'ll Value) -> bool {
+        unsafe {
+            llvm::LLVMIsAConstantInt(v).is_some()
+        }
+    }
 
-        debug!("const_get_elt(v={:?}, idx={}, r={:?})",
-               v, idx, r);
+    fn is_const_real(&self, v: &'ll Value) -> bool {
+        unsafe {
+            llvm::LLVMIsAConstantFP(v).is_some()
+        }
+    }
 
-        r
+    fn const_to_opt_u128(&self, v: &'ll Value, sign_ext: bool) -> Option<u128> {
+        unsafe {
+            if self.is_const_integral(v) {
+                let (mut lo, mut hi) = (0u64, 0u64);
+                let success = llvm::LLVMRustConstInt128Get(v, sign_ext,
+                                                           &mut hi, &mut lo);
+                if success {
+                    Some(hi_lo_to_u128(lo, hi))
+                } else {
+                    None
+                }
+            } else {
+                None
+            }
+        }
     }
 }
 
-pub fn const_get_real(v: &'ll Value) -> Option<(f64, bool)> {
+pub fn val_ty(v: &'ll Value) -> &'ll Type {
     unsafe {
-        if is_const_real(v) {
-            let mut loses_info: llvm::Bool = ::std::mem::uninitialized();
-            let r = llvm::LLVMConstRealGetDouble(v, &mut loses_info);
-            let loses_info = if loses_info == 1 { true } else { false };
-            Some((r, loses_info))
-        } else {
-            None
-        }
+        llvm::LLVMTypeOf(v)
     }
 }
 
-pub fn const_to_uint(v: &'ll Value) -> u64 {
+pub fn c_bytes_in_context(llcx: &'ll llvm::Context, bytes: &[u8]) -> &'ll Value {
     unsafe {
-        llvm::LLVMConstIntGetZExtValue(v)
+        let ptr = bytes.as_ptr() as *const c_char;
+        return llvm::LLVMConstStringInContext(llcx, ptr, bytes.len() as c_uint, True);
     }
 }
 
-pub fn is_const_integral(v: &'ll Value) -> bool {
+pub fn c_struct_in_context(
+    llcx: &'a llvm::Context,
+    elts: &[&'a Value],
+    packed: bool,
+) -> &'a Value {
     unsafe {
-        llvm::LLVMIsAConstantInt(v).is_some()
+        llvm::LLVMConstStructInContext(llcx,
+                                       elts.as_ptr(), elts.len() as c_uint,
+                                       packed as Bool)
     }
 }
 
-pub fn is_const_real(v: &'ll Value) -> bool {
-    unsafe {
-        llvm::LLVMIsAConstantFP(v).is_some()
+impl<'ll, 'tcx: 'll> CommonWriteMethods for CodegenCx<'ll, 'tcx> {
+    fn val_ty(&self, v: &'ll Value) -> &'ll Type {
+        val_ty(v)
+    }
+
+    fn c_bytes_in_context(&self, llcx: &'ll llvm::Context, bytes: &[u8]) -> &'ll Value {
+        c_bytes_in_context(llcx, bytes)
+    }
+
+    fn c_struct_in_context(
+        &self,
+        llcx: &'a llvm::Context,
+        elts: &[&'a Value],
+        packed: bool,
+    ) -> &'a Value {
+        c_struct_in_context(llcx, elts, packed)
     }
 }
 
@@ -312,23 +449,6 @@ fn hi_lo_to_u128(lo: u64, hi: u64) -> u128 {
     ((hi as u128) << 64) | (lo as u128)
 }
 
-pub fn const_to_opt_u128(v: &'ll Value, sign_ext: bool) -> Option<u128> {
-    unsafe {
-        if is_const_integral(v) {
-            let (mut lo, mut hi) = (0u64, 0u64);
-            let success = llvm::LLVMRustConstInt128Get(v, sign_ext,
-                                                       &mut hi, &mut lo);
-            if success {
-                Some(hi_lo_to_u128(lo, hi))
-            } else {
-                None
-            }
-        } else {
-            None
-        }
-    }
-}
-
 pub fn langcall(tcx: TyCtxt,
                 span: Option<Span>,
                 msg: &str,
@@ -374,7 +494,7 @@ pub fn build_unchecked_rshift(
 }
 
 fn shift_mask_rhs(bx: &Builder<'a, 'll, 'tcx>, rhs: &'ll Value) -> &'ll Value {
-    let rhs_llty = val_ty(rhs);
+    let rhs_llty = bx.cx().val_ty(rhs);
     bx.and(rhs, shift_mask_val(bx, rhs_llty, rhs_llty, false))
 }
 
@@ -390,9 +510,9 @@ pub fn shift_mask_val(
             // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
             let val = llty.int_width() - 1;
             if invert {
-                C_int(mask_llty, !val as i64)
+                bx.cx.c_int(mask_llty, !val as i64)
             } else {
-                C_uint(mask_llty, val)
+                bx.cx.c_uint(mask_llty, val)
             }
         },
         TypeKind::Vector => {