(index<- )        ./librustc/middle/trans/type_.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri Apr 25 22:40:04 2014
   1  // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  #![allow(non_uppercase_pattern_statics)]
  12  
  13  use lib::llvm::{llvm, TypeRef, Bool, False, True, TypeKind};
  14  use lib::llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};
  15  
  16  use middle::trans::context::CrateContext;
  17  
  18  use syntax::ast;
  19  use syntax::abi::{X86, X86_64, Arm, Mips};
  20  
  21  use std::c_str::ToCStr;
  22  use std::cast;
  23  
  24  use libc::{c_uint};
  25  
  26  #[deriving(Clone, Eq, Show)]
  27  pub struct Type {
  28      rf: TypeRef
  29  }
  30  
  31  macro_rules! ty (
  32      ($e:expr) => ( Type::from_ref(unsafe { $e }))
  33  )
  34  
  35  /**
  36   * Wrapper for LLVM TypeRef
  37   */
  38  impl Type {
  39      #[inline(always)]
  40      pub fn from_ref(rTypeRef) -> Type {
  41          Type {
  42              rf: r
  43          }
  44      }
  45  
  46      #[inline(always)] // So it doesn't kill --opt-level=0 builds of the compiler
  47      pub fn to_ref(&self) -> TypeRef {
  48          self.rf
  49      }
  50  
  51      pub fn void(ccx&CrateContext) -> Type {
  52          ty!(llvm::LLVMVoidTypeInContext(ccx.llcx))
  53      }
  54  
  55      pub fn nil(ccx&CrateContext) -> Type {
  56          Type::empty_struct(ccx)
  57      }
  58  
  59      pub fn metadata(ccx&CrateContext) -> Type {
  60          ty!(llvm::LLVMMetadataTypeInContext(ccx.llcx))
  61      }
  62  
  63      pub fn i1(ccx&CrateContext) -> Type {
  64          ty!(llvm::LLVMInt1TypeInContext(ccx.llcx))
  65      }
  66  
  67      pub fn i8(ccx&CrateContext) -> Type {
  68          ty!(llvm::LLVMInt8TypeInContext(ccx.llcx))
  69      }
  70  
  71      pub fn i16(ccx&CrateContext) -> Type {
  72          ty!(llvm::LLVMInt16TypeInContext(ccx.llcx))
  73      }
  74  
  75      pub fn i32(ccx&CrateContext) -> Type {
  76          ty!(llvm::LLVMInt32TypeInContext(ccx.llcx))
  77      }
  78  
  79      pub fn i64(ccx&CrateContext) -> Type {
  80          ty!(llvm::LLVMInt64TypeInContext(ccx.llcx))
  81      }
  82  
  83      pub fn f32(ccx&CrateContext) -> Type {
  84          ty!(llvm::LLVMFloatTypeInContext(ccx.llcx))
  85      }
  86  
  87      pub fn f64(ccx&CrateContext) -> Type {
  88          ty!(llvm::LLVMDoubleTypeInContext(ccx.llcx))
  89      }
  90  
  91      pub fn f128(ccx&CrateContext) -> Type {
  92          ty!(llvm::LLVMFP128TypeInContext(ccx.llcx))
  93      }
  94  
  95      pub fn bool(ccx&CrateContext) -> Type {
  96          Type::i8(ccx)
  97      }
  98  
  99      pub fn char(ccx&CrateContext) -> Type {
 100          Type::i32(ccx)
 101      }
 102  
 103      pub fn i8p(ccx&CrateContext) -> Type {
 104          Type::i8(ccx).ptr_to()
 105      }
 106  
 107      pub fn int(ccx&CrateContext) -> Type {
 108          match ccx.tcx.sess.targ_cfg.arch {
 109              X86 | Arm | Mips => Type::i32(ccx),
 110              X86_64 => Type::i64(ccx)
 111          }
 112      }
 113  
 114      pub fn int_from_ty(ccx&CrateContext, tast::IntTy) -> Type {
 115          match t {
 116              ast::TyI => ccx.int_type,
 117              ast::TyI8 => Type::i8(ccx),
 118              ast::TyI16 => Type::i16(ccx),
 119              ast::TyI32 => Type::i32(ccx),
 120              ast::TyI64 => Type::i64(ccx)
 121          }
 122      }
 123  
 124      pub fn uint_from_ty(ccx&CrateContext, tast::UintTy) -> Type {
 125          match t {
 126              ast::TyU => ccx.int_type,
 127              ast::TyU8 => Type::i8(ccx),
 128              ast::TyU16 => Type::i16(ccx),
 129              ast::TyU32 => Type::i32(ccx),
 130              ast::TyU64 => Type::i64(ccx)
 131          }
 132      }
 133  
 134      pub fn float_from_ty(ccx&CrateContext, tast::FloatTy) -> Type {
 135          match t {
 136              ast::TyF32 => Type::f32(ccx),
 137              ast::TyF64 => Type::f64(ccx),
 138              ast::TyF128 => Type::f128(ccx)
 139          }
 140      }
 141  
 142      pub fn func(args&[Type], ret&Type) -> Type {
 143          let vec : &[TypeRef] = unsafe { cast::transmute(args) };
 144          ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
 145                                     args.len() as c_uint, False))
 146      }
 147  
 148      pub fn variadic_func(args&[Type], ret&Type) -> Type {
 149          let vec : &[TypeRef] = unsafe { cast::transmute(args) };
 150          ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
 151                                     args.len() as c_uint, True))
 152      }
 153  
 154      pub fn struct_(ccx&CrateContext, els&[Type], packedbool) -> Type {
 155          let els : &[TypeRef] = unsafe { cast::transmute(els) };
 156          ty!(llvm::LLVMStructTypeInContext(ccx.llcx, els.as_ptr(),
 157                                            els.len() as c_uint,
 158                                            packed as Bool))
 159      }
 160  
 161      pub fn named_struct(ccx&CrateContext, name&str) -> Type {
 162          ty!(name.with_c_str(|s| llvm::LLVMStructCreateNamed(ccx.llcx, s)))
 163      }
 164  
 165      pub fn empty_struct(ccx&CrateContext) -> Type {
 166          Type::struct_(ccx, [], false)
 167      }
 168  
 169      pub fn vtable(ccx&CrateContext) -> Type {
 170          Type::array(&Type::i8p(ccx).ptr_to(), 1)
 171      }
 172  
 173      pub fn generic_glue_fn(cx&CrateContext) -> Type {
 174          match cx.tn.find_type("glue_fn") {
 175              Some(ty) => return ty,
 176              None => ()
 177          }
 178  
 179          let ty = Type::glue_fn(cx, Type::i8p(cx));
 180          cx.tn.associate_type("glue_fn", &ty);
 181  
 182          ty
 183      }
 184  
 185      pub fn glue_fn(ccx&CrateContext, tType) -> Type {
 186          Type::func([t], &Type::void(ccx))
 187      }
 188  
 189      pub fn tydesc(ccx&CrateContext) -> Type {
 190          let mut tydesc = Type::named_struct(ccx, "tydesc");
 191          let glue_fn_ty = Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to();
 192  
 193          let int_ty = Type::int(ccx);
 194  
 195          // Must mirror:
 196          //
 197          // std::unstable::intrinsics::TyDesc
 198  
 199          let elems = [int_ty,     // size
 200                       int_ty,     // align
 201                       glue_fn_ty, // drop
 202                       glue_fn_ty, // visit
 203                       Type::struct_(ccx, [Type::i8p(ccx), Type::int(ccx)], false)]; // name
 204          tydesc.set_struct_body(elems, false);
 205  
 206          tydesc
 207      }
 208  
 209      pub fn array(ty&Type, lenu64) -> Type {
 210          ty!(llvm::LLVMArrayType(ty.to_ref(), len as c_uint))
 211      }
 212  
 213      pub fn vector(ty&Type, lenu64) -> Type {
 214          ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint))
 215      }
 216  
 217      pub fn vec(ccx&CrateContext, ty&Type) -> Type {
 218          Type::struct_(ccx,
 219              [Type::int(ccx), Type::int(ccx), Type::array(ty, 0)],
 220          false)
 221      }
 222  
 223      pub fn opaque_vec(ccx&CrateContext) -> Type {
 224          Type::vec(ccx, &Type::i8(ccx))
 225      }
 226  
 227      // The box pointed to by @T.
 228      pub fn at_box(ccx&CrateContext, tyType) -> Type {
 229          Type::struct_(ccx, [
 230              ccx.int_type, Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to(),
 231              Type::i8p(ccx), Type::i8p(ccx), ty
 232          ], false)
 233      }
 234  
 235      pub fn opaque_trait(ccx&CrateContext) -> Type {
 236          let vtable = Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to().ptr_to();
 237          Type::struct_(ccx, [vtable, Type::i8p(ccx)], false)
 238      }
 239  
 240      pub fn kind(&self) -> TypeKind {
 241          unsafe {
 242              llvm::LLVMGetTypeKind(self.to_ref())
 243          }
 244      }
 245  
 246      pub fn set_struct_body(&mut self, els&[Type], packedbool) {
 247          unsafe {
 248              let vec : &[TypeRef] = cast::transmute(els);
 249              llvm::LLVMStructSetBody(self.to_ref(), vec.as_ptr(),
 250                                      els.len() as c_uint, packed as Bool)
 251          }
 252      }
 253  
 254      pub fn ptr_to(&self) -> Type {
 255          ty!(llvm::LLVMPointerType(self.to_ref(), 0))
 256      }
 257  
 258      pub fn is_packed(&self) -> bool {
 259          unsafe {
 260              llvm::LLVMIsPackedStruct(self.to_ref()) == True
 261          }
 262      }
 263  
 264      pub fn element_type(&self) -> Type {
 265          unsafe {
 266              Type::from_ref(llvm::LLVMGetElementType(self.to_ref()))
 267          }
 268      }
 269  
 270      pub fn array_length(&self) -> uint {
 271          unsafe {
 272              llvm::LLVMGetArrayLength(self.to_ref()) as uint
 273          }
 274      }
 275  
 276      pub fn field_types(&self) -> Vec<Type> {
 277          unsafe {
 278              let n_elts = llvm::LLVMCountStructElementTypes(self.to_ref()) as uint;
 279              if n_elts == 0 {
 280                  return Vec::new();
 281              }
 282              let mut elts = Vec::from_elem(n_elts, 0 as TypeRef);
 283              llvm::LLVMGetStructElementTypes(self.to_ref(), elts.get_mut(0));
 284              cast::transmute(elts)
 285          }
 286      }
 287  
 288      pub fn return_type(&self) -> Type {
 289          ty!(llvm::LLVMGetReturnType(self.to_ref()))
 290      }
 291  
 292      pub fn func_params(&self) -> Vec<Type> {
 293          unsafe {
 294              let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as uint;
 295              let args = Vec::from_elem(n_args, 0 as TypeRef);
 296              llvm::LLVMGetParamTypes(self.to_ref(), args.as_ptr());
 297              cast::transmute(args)
 298          }
 299      }
 300  
 301      pub fn float_width(&self) -> uint {
 302          match self.kind() {
 303              Float => 32,
 304              Double => 64,
 305              X86_FP80 => 80,
 306              FP128 | PPC_FP128 => 128,
 307              _ => fail!("llvm_float_width called on a non-float type")
 308          }
 309      }
 310  }