1 // Copyright 2012-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 // Information concerning the machine representation of various types.
12
13 use lib::llvm::{ValueRef};
14 use lib::llvm::False;
15 use lib::llvm::llvm;
16 use middle::trans::common::*;
17
18 use middle::trans::type_::Type;
19
20 // ______________________________________________________________________
21 // compute sizeof / alignof
22
23 // Returns the number of bytes clobbered by a Store to this type.
24 pub fn llsize_of_store(cx: &CrateContext, ty: Type) -> u64 {
25 unsafe {
26 return llvm::LLVMStoreSizeOfType(cx.td.lltd, ty.to_ref()) as u64;
27 }
28 }
29
30 // Returns the number of bytes between successive elements of type T in an
31 // array of T. This is the "ABI" size. It includes any ABI-mandated padding.
32 pub fn llsize_of_alloc(cx: &CrateContext, ty: Type) -> u64 {
33 unsafe {
34 return llvm::LLVMABISizeOfType(cx.td.lltd, ty.to_ref()) as u64;
35 }
36 }
37
38 // Returns, as near as we can figure, the "real" size of a type. As in, the
39 // bits in this number of bytes actually carry data related to the datum
40 // with the type. Not junk, padding, accidentally-damaged words, or
41 // whatever. Rounds up to the nearest byte though, so if you have a 1-bit
42 // value, we return 1 here, not 0. Most of rustc works in bytes. Be warned
43 // that LLVM *does* distinguish between e.g. a 1-bit value and an 8-bit value
44 // at the codegen level! In general you should prefer `llbitsize_of_real`
45 // below.
46 pub fn llsize_of_real(cx: &CrateContext, ty: Type) -> u64 {
47 unsafe {
48 let nbits = llvm::LLVMSizeOfTypeInBits(cx.td.lltd, ty.to_ref()) as u64;
49 if nbits & 7 != 0 {
50 // Not an even number of bytes, spills into "next" byte.
51 1 + (nbits >> 3)
52 } else {
53 nbits >> 3
54 }
55 }
56 }
57
58 /// Returns the "real" size of the type in bits.
59 pub fn llbitsize_of_real(cx: &CrateContext, ty: Type) -> u64 {
60 unsafe {
61 llvm::LLVMSizeOfTypeInBits(cx.td.lltd, ty.to_ref()) as u64
62 }
63 }
64
65 /// Returns the size of the type as an LLVM constant integer value.
66 pub fn llsize_of(cx: &CrateContext, ty: Type) -> ValueRef {
67 // Once upon a time, this called LLVMSizeOf, which does a
68 // getelementptr(1) on a null pointer and casts to an int, in
69 // order to obtain the type size as a value without requiring the
70 // target data layout. But we have the target data layout, so
71 // there's no need for that contrivance. The instruction
72 // selection DAG generator would flatten that GEP(1) node into a
73 // constant of the type's alloc size, so let's save it some work.
74 return C_uint(cx, llsize_of_alloc(cx, ty) as uint);
75 }
76
77 // Returns the "default" size of t (see above), or 1 if the size would
78 // be zero. This is important for things like vectors that expect
79 // space to be consumed.
80 pub fn nonzero_llsize_of(cx: &CrateContext, ty: Type) -> ValueRef {
81 if llbitsize_of_real(cx, ty) == 0 {
82 unsafe { llvm::LLVMConstInt(cx.int_type.to_ref(), 1, False) }
83 } else {
84 llsize_of(cx, ty)
85 }
86 }
87
88 // Returns the preferred alignment of the given type for the current target.
89 // The preferred alignment may be larger than the alignment used when
90 // packing the type into structs. This will be used for things like
91 // allocations inside a stack frame, which LLVM has a free hand in.
92 pub fn llalign_of_pref(cx: &CrateContext, ty: Type) -> u64 {
93 unsafe {
94 return llvm::LLVMPreferredAlignmentOfType(cx.td.lltd, ty.to_ref()) as u64;
95 }
96 }
97
98 // Returns the minimum alignment of a type required by the platform.
99 // This is the alignment that will be used for struct fields, arrays,
100 // and similar ABI-mandated things.
101 pub fn llalign_of_min(cx: &CrateContext, ty: Type) -> u64 {
102 unsafe {
103 return llvm::LLVMABIAlignmentOfType(cx.td.lltd, ty.to_ref()) as u64;
104 }
105 }
106
107 // Returns the "default" alignment of t, which is calculated by casting
108 // null to a record containing a single-bit followed by a t value, then
109 // doing gep(0,1) to get at the trailing (and presumably padded) t cell.
110 pub fn llalign_of(cx: &CrateContext, ty: Type) -> ValueRef {
111 unsafe {
112 return llvm::LLVMConstIntCast(
113 llvm::LLVMAlignOf(ty.to_ref()), cx.int_type.to_ref(), False);
114 }
115 }
116
117 pub fn llelement_offset(cx: &CrateContext, struct_ty: Type, element: uint) -> u64 {
118 unsafe {
119 return llvm::LLVMOffsetOfElement(cx.td.lltd, struct_ty.to_ref(), element as u32) as u64;
120 }
121 }
librustc/middle/trans/machine.rs:116:1-116:1 -fn- definition:
pub fn llelement_offset(cx: &CrateContext, struct_ty: Type, element: uint) -> u64 {
unsafe {
return llvm::LLVMOffsetOfElement(cx.td.lltd, struct_ty.to_ref(), element as u32) as u64;
references:- 2librustc/middle/trans/debuginfo.rs:
446: let llvm_env_data_type = type_of::type_of(cx, env_data_type);
447: let byte_offset_of_var_in_env = machine::llelement_offset(cx, llvm_env_data_type, env_index);
--
1781: FixedMemberOffset { bytes } => bytes as u64,
1782: ComputedMemberOffset => machine::llelement_offset(cx, composite_llvm_type, i)
1783: };
librustc/middle/trans/machine.rs:58:49-58:49 -fn- definition:
/// Returns the "real" size of the type in bits.
pub fn llbitsize_of_real(cx: &CrateContext, ty: Type) -> u64 {
unsafe {
references:- 880: pub fn nonzero_llsize_of(cx: &CrateContext, ty: Type) -> ValueRef {
81: if llbitsize_of_real(cx, ty) == 0 {
82: unsafe { llvm::LLVMConstInt(cx.int_type.to_ref(), 1, False) }
librustc/middle/trans/adt.rs:
554: assert_eq!(val_ty(ptr), llty.ptr_to());
555: let bits = machine::llbitsize_of_real(bcx.ccx(), llty);
556: assert!(bits <= 64);
librustc/middle/trans/expr.rs:
467: let ix_size = machine::llbitsize_of_real(bcx.ccx(), val_ty(ix_val));
468: let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type);
469: let ix_val = {
librustc/middle/trans/intrinsic.rs:
136: let size = machine::llsize_of(ccx, lltp_ty);
137: let int_size = machine::llbitsize_of_real(ccx, ccx.int_type);
138: let name = if allow_overlap {
--
166: let size = machine::llsize_of(ccx, lltp_ty);
167: let name = if machine::llbitsize_of_real(ccx, ccx.int_type) == 32 {
168: "llvm.memset.p0i8.i32"
--
384: let in_type_size = machine::llbitsize_of_real(ccx, llintype);
385: let out_type_size = machine::llbitsize_of_real(ccx, llouttype);
386: if in_type_size != out_type_size {
librustc/middle/trans/machine.rs:45:10-45:10 -fn- definition:
// below.
pub fn llsize_of_real(cx: &CrateContext, ty: Type) -> u64 {
unsafe {
references:- 3librustc/middle/trans/intrinsic.rs:
299: let lltp_ty = type_of::type_of(ccx, tp_ty);
300: Ret(bcx, C_uint(ccx, machine::llsize_of_real(ccx, lltp_ty) as uint));
301: }
librustc/middle/trans/reflect.rs:
68: let tr = type_of(self.bcx.ccx(), t);
69: let s = machine::llsize_of_real(self.bcx.ccx(), tr);
70: let a = machine::llalign_of_min(self.bcx.ccx(), tr);
librustc/middle/trans/glue.rs:
407: if ccx.sess().count_type_sizes() {
408: println!("{}\t{}", llsize_of_real(ccx, llty),
409: ppaux::ty_to_str(ccx.tcx(), t));
librustc/middle/trans/machine.rs:31:77-31:77 -fn- definition:
// array of T. This is the "ABI" size. It includes any ABI-mandated padding.
pub fn llsize_of_alloc(cx: &CrateContext, ty: Type) -> u64 {
unsafe {
references:- 1773: // constant of the type's alloc size, so let's save it some work.
74: return C_uint(cx, llsize_of_alloc(cx, ty) as uint);
75: }
librustc/middle/trans/adt.rs:
796: offsets.push(offset);
797: offset += machine::llsize_of_alloc(ccx, llty) as u64;
798: }
--
833: cfields.push(val);
834: offset += machine::llsize_of_alloc(ccx, val_ty(val)) as u64;
835: }
librustc/middle/trans/glue.rs:
92: // returned for `Box<ZeroSizeType>`.
93: if llsize_of_alloc(ccx, llty) == 0 {
94: ty::mk_i8()
librustc/middle/trans/expr.rs:
1179: // `Box<ZeroSizeType>`.
1180: let bcx = if llsize_of_alloc(bcx.ccx(), llty) == 0 {
1181: trans_into(bcx, contents, SaveIn(val))
librustc/middle/trans/common.rs:
88: let llty = sizing_type_of(ccx, ty);
89: llsize_of_alloc(ccx, llty) == 0
90: }
librustc/middle/trans/consts.rs:
273: let llty = type_of::sizing_type_of(cx, ety_adjusted);
274: let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
275: let tsize = machine::llsize_of_alloc(cx, llty);
276: if csize != tsize {
librustc/middle/trans/tvec.rs:
415: let llunit_size = nonzero_llsize_of(ccx, llunit_ty);
416: let llunit_alloc_size = llsize_of_alloc(ccx, llunit_ty);
librustc/middle/trans/cabi_x86.rs:
67: Struct => {
68: let size = llsize_of_alloc(ccx, t);
69: if size == 0 {
librustc/middle/trans/debuginfo.rs:
2329: fn size_and_align_of(cx: &CrateContext, llvm_type: Type) -> (u64, u64) {
2330: (machine::llsize_of_alloc(cx, llvm_type), machine::llalign_of_min(cx, llvm_type))
2331: }
librustc/middle/trans/common.rs:
74: let llty = sizing_type_of(ccx, ty);
75: llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type)
76: }
librustc/middle/trans/machine.rs:100:36-100:36 -fn- definition:
// and similar ABI-mandated things.
pub fn llalign_of_min(cx: &CrateContext, ty: Type) -> u64 {
unsafe {
references:- 15librustc/middle/trans/adt.rs:
823: if !st.packed {
824: let val_align = machine::llalign_of_min(ccx, val_ty(val))
825: /*bad*/as u64;
librustc/middle/trans/base.rs:
1032: let llsz = llsize_of(ccx, llty);
1033: let llalign = llalign_of_min(ccx, llty);
1034: call_memcpy(bcx, dst, src, llsz, llalign as u32);
librustc/middle/trans/foreign.rs:
420: let llrust_size = machine::llsize_of_store(ccx, llrust_ret_ty);
421: let llforeign_align = machine::llalign_of_min(ccx, llforeign_ret_ty);
422: let llrust_align = machine::llalign_of_min(ccx, llrust_ret_ty);
423: let llalign = cmp::min(llforeign_align, llrust_align);
librustc/middle/trans/intrinsic.rs:
164: let lltp_ty = type_of::type_of(ccx, tp_ty);
165: let align = C_i32(ccx, machine::llalign_of_min(ccx, lltp_ty) as i32);
166: let size = machine::llsize_of(ccx, lltp_ty);
--
318: let lltp_ty = type_of::type_of(ccx, tp_ty);
319: Ret(bcx, C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty) as uint));
320: }
librustc/middle/trans/reflect.rs:
69: let s = machine::llsize_of_real(self.bcx.ccx(), tr);
70: let a = machine::llalign_of_min(self.bcx.ccx(), tr);
71: return vec!(self.c_uint(s as uint),
librustc/middle/trans/debuginfo.rs:
2329: fn size_and_align_of(cx: &CrateContext, llvm_type: Type) -> (u64, u64) {
2330: (machine::llsize_of_alloc(cx, llvm_type), machine::llalign_of_min(cx, llvm_type))
2331: }
librustc/middle/trans/base.rs:
1066: let size = machine::llsize_of(ccx, ty);
1067: let align = C_i32(ccx, llalign_of_min(ccx, ty) as i32);
1068: let volatile = C_i1(ccx, false);
librustc/middle/trans/machine.rs:91:68-91:68 -fn- definition:
// allocations inside a stack frame, which LLVM has a free hand in.
pub fn llalign_of_pref(cx: &CrateContext, ty: Type) -> u64 {
unsafe {
references:- 3librustc/middle/trans/builder.rs:
520: let ty = Type::from_ref(llvm::LLVMTypeOf(ptr));
521: let align = llalign_of_pref(self.ccx, ty.element_type());
522: llvm::LLVMBuildAtomicStore(self.llbuilder, val, ptr, order, align as c_uint);
librustc/middle/trans/intrinsic.rs:
323: let lltp_ty = type_of::type_of(ccx, tp_ty);
324: Ret(bcx, C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty) as uint));
325: }
librustc/middle/trans/builder.rs:
464: let ty = Type::from_ref(llvm::LLVMTypeOf(ptr));
465: let align = llalign_of_pref(self.ccx, ty.element_type());
466: llvm::LLVMBuildAtomicLoad(self.llbuilder, ptr, noname(), order,
librustc/middle/trans/machine.rs:65:68-65:68 -fn- definition:
/// Returns the size of the type as an LLVM constant integer value.
pub fn llsize_of(cx: &CrateContext, ty: Type) -> ValueRef {
// Once upon a time, this called LLVMSizeOf, which does a
references:- 1183: } else {
84: llsize_of(cx, ty)
85: }
librustc/middle/trans/glue.rs:
412: let llsize = llsize_of(ccx, llty);
413: let llalign = llalign_of(ccx, llty);
librustc/middle/trans/expr.rs:
1171: let llty = type_of::type_of(bcx.ccx(), contents_ty);
1172: let size = llsize_of(bcx.ccx(), llty);
1173: // We need to a make a pointer type because box_ty is ty_bot
--
1201: let Result {bcx, val: bx} = malloc_raw_dyn_managed(bcx, contents_ty, MallocFnLangItem,
1202: llsize_of(bcx.ccx(), ty));
1203: let body = GEPi(bcx, bx, [0u, abi::box_field_body]);
librustc/middle/trans/base.rs:
1031: let llty = type_of::type_of(ccx, t);
1032: let llsz = llsize_of(ccx, llty);
1033: let llalign = llalign_of_min(ccx, llty);
--
1065: let llzeroval = C_u8(ccx, 0);
1066: let size = machine::llsize_of(ccx, ty);
1067: let align = C_i32(ccx, llalign_of_min(ccx, ty) as i32);
librustc/middle/trans/closure.rs:
146: let ty = type_of(bcx.ccx(), cdata_ty);
147: let size = llsize_of(bcx.ccx(), ty);
148: // we treat proc as @ here, which isn't ideal
librustc/middle/trans/tvec.rs:
279: let vecsize = Add(bcx, alloc, llsize_of(ccx, ccx.opaque_vec_type));
librustc/middle/trans/intrinsic.rs:
438: let llsize = llsize_of(ccx, llintype);
439: call_memcpy(bcx, lldestptr, llsrcptr, llsize, 1);
librustc/middle/trans/machine.rs:79:25-79:25 -fn- definition:
// space to be consumed.
pub fn nonzero_llsize_of(cx: &CrateContext, ty: Type) -> ValueRef {
if llbitsize_of_real(cx, ty) == 0 {
references:- 2librustc/middle/trans/tvec.rs:
414: let llunit_ty = type_of::type_of(ccx, unit_ty);
415: let llunit_size = nonzero_llsize_of(ccx, llunit_ty);
416: let llunit_alloc_size = llsize_of_alloc(ccx, llunit_ty);