]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012-2014 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_camel_case_types, non_snake_case)] | |
12 | ||
13 | //! Code that is useful in various trans modules. | |
14 | ||
1a4d82fc | 15 | use llvm; |
32a655c1 | 16 | use llvm::{ValueRef, ContextRef, TypeKind}; |
7453a54e | 17 | use llvm::{True, False, Bool, OperandBundleDef}; |
54a0048b | 18 | use rustc::hir::def_id::DefId; |
476ff2be | 19 | use rustc::hir::map::DefPathData; |
7cac9316 | 20 | use rustc::middle::lang_items::LangItem; |
54a0048b | 21 | use base; |
54a0048b | 22 | use builder::Builder; |
54a0048b | 23 | use consts; |
54a0048b SL |
24 | use declare; |
25 | use machine; | |
54a0048b SL |
26 | use monomorphize; |
27 | use type_::Type; | |
28 | use value::Value; | |
29 | use rustc::ty::{self, Ty, TyCtxt}; | |
cc61c64b | 30 | use rustc::ty::layout::{Layout, LayoutTyper}; |
8bb4bdeb | 31 | use rustc::ty::subst::{Subst, Substs}; |
54a0048b | 32 | use rustc::hir; |
1a4d82fc | 33 | |
1a4d82fc | 34 | use libc::{c_uint, c_char}; |
476ff2be | 35 | use std::iter; |
54a0048b | 36 | |
cc61c64b | 37 | use syntax::attr; |
32a655c1 SL |
38 | use syntax::symbol::InternedString; |
39 | use syntax_pos::Span; | |
1a4d82fc | 40 | |
32a655c1 | 41 | pub use context::{CrateContext, SharedCrateContext}; |
1a4d82fc | 42 | |
32a655c1 SL |
43 | pub fn type_is_fat_ptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { |
44 | if let Layout::FatPointer { .. } = *ccx.layout_of(ty) { | |
45 | true | |
46 | } else { | |
47 | false | |
1a4d82fc JJ |
48 | } |
49 | } | |
50 | ||
1a4d82fc | 51 | pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { |
32a655c1 SL |
52 | let layout = ccx.layout_of(ty); |
53 | match *layout { | |
54 | Layout::CEnum { .. } | | |
55 | Layout::Scalar { .. } | | |
56 | Layout::Vector { .. } => true, | |
57 | ||
58 | Layout::FatPointer { .. } => false, | |
59 | ||
60 | Layout::Array { .. } | | |
61 | Layout::Univariant { .. } | | |
62 | Layout::General { .. } | | |
63 | Layout::UntaggedUnion { .. } | | |
64 | Layout::RawNullablePointer { .. } | | |
65 | Layout::StructWrappedNullablePointer { .. } => { | |
cc61c64b | 66 | !layout.is_unsized() && layout.size(ccx).bytes() == 0 |
1a4d82fc | 67 | } |
1a4d82fc JJ |
68 | } |
69 | } | |
70 | ||
3157f602 XL |
71 | /// Returns Some([a, b]) if the type has a pair of fields with types a and b. |
72 | pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) | |
73 | -> Option<[Ty<'tcx>; 2]> { | |
74 | match ty.sty { | |
9e0c209e | 75 | ty::TyAdt(adt, substs) => { |
3157f602 XL |
76 | assert_eq!(adt.variants.len(), 1); |
77 | let fields = &adt.variants[0].fields; | |
78 | if fields.len() != 2 { | |
79 | return None; | |
80 | } | |
81 | Some([monomorphize::field_ty(ccx.tcx(), substs, &fields[0]), | |
82 | monomorphize::field_ty(ccx.tcx(), substs, &fields[1])]) | |
83 | } | |
476ff2be SL |
84 | ty::TyClosure(def_id, substs) => { |
85 | let mut tys = substs.upvar_tys(def_id, ccx.tcx()); | |
86 | tys.next().and_then(|first_ty| tys.next().and_then(|second_ty| { | |
87 | if tys.next().is_some() { | |
88 | None | |
89 | } else { | |
90 | Some([first_ty, second_ty]) | |
91 | } | |
92 | })) | |
93 | } | |
8bb4bdeb | 94 | ty::TyTuple(tys, _) => { |
3157f602 XL |
95 | if tys.len() != 2 { |
96 | return None; | |
97 | } | |
98 | Some([tys[0], tys[1]]) | |
99 | } | |
100 | _ => None | |
101 | } | |
102 | } | |
103 | ||
104 | /// Returns true if the type is represented as a pair of immediates. | |
105 | pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) | |
106 | -> bool { | |
9e0c209e | 107 | match *ccx.layout_of(ty) { |
3157f602 XL |
108 | Layout::FatPointer { .. } => true, |
109 | Layout::Univariant { ref variant, .. } => { | |
110 | // There must be only 2 fields. | |
c30ab7b3 | 111 | if variant.offsets.len() != 2 { |
3157f602 XL |
112 | return false; |
113 | } | |
114 | ||
115 | match type_pair_fields(ccx, ty) { | |
116 | Some([a, b]) => { | |
117 | type_is_immediate(ccx, a) && type_is_immediate(ccx, b) | |
118 | } | |
119 | None => false | |
120 | } | |
121 | } | |
122 | _ => false | |
123 | } | |
124 | } | |
125 | ||
1a4d82fc JJ |
126 | /// Identify types which have size zero at runtime. |
127 | pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { | |
cc61c64b XL |
128 | let layout = ccx.layout_of(ty); |
129 | !layout.is_unsized() && layout.size(ccx).bytes() == 0 | |
1a4d82fc JJ |
130 | } |
131 | ||
1a4d82fc JJ |
132 | /* |
133 | * A note on nomenclature of linking: "extern", "foreign", and "upcall". | |
134 | * | |
135 | * An "extern" is an LLVM symbol we wind up emitting an undefined external | |
136 | * reference to. This means "we don't have the thing in this compilation unit, | |
137 | * please make sure you link it in at runtime". This could be a reference to | |
138 | * C code found in a C library, or rust code found in a rust crate. | |
139 | * | |
140 | * Most "externs" are implicitly declared (automatically) as a result of a | |
141 | * user declaring an extern _module_ dependency; this causes the rust driver | |
142 | * to locate an extern crate, scan its compilation metadata, and emit extern | |
143 | * declarations for any symbols used by the declaring crate. | |
144 | * | |
145 | * A "foreign" is an extern that references C (or other non-rust ABI) code. | |
146 | * There is no metadata to scan for extern references so in these cases either | |
147 | * a header-digester like bindgen, or manual function prototypes, have to | |
148 | * serve as declarators. So these are usually given explicitly as prototype | |
149 | * declarations, in rust code, with ABI attributes on them noting which ABI to | |
150 | * link via. | |
151 | * | |
152 | * An "upcall" is a foreign call generated by the compiler (not corresponding | |
153 | * to any user-written call in the code) into the runtime library, to perform | |
154 | * some helper task such as bringing a task to life, allocating memory, etc. | |
155 | * | |
156 | */ | |
157 | ||
7453a54e SL |
158 | /// A structure representing an active landing pad for the duration of a basic |
159 | /// block. | |
160 | /// | |
161 | /// Each `Block` may contain an instance of this, indicating whether the block | |
162 | /// is part of a landing pad or not. This is used to make decision about whether | |
163 | /// to emit `invoke` instructions (e.g. in a landing pad we don't continue to | |
164 | /// use `invoke`) and also about various function call metadata. | |
165 | /// | |
166 | /// For GNU exceptions (`landingpad` + `resume` instructions) this structure is | |
167 | /// just a bunch of `None` instances (not too interesting), but for MSVC | |
168 | /// exceptions (`cleanuppad` + `cleanupret` instructions) this contains data. | |
169 | /// When inside of a landing pad, each function call in LLVM IR needs to be | |
170 | /// annotated with which landing pad it's a part of. This is accomplished via | |
171 | /// the `OperandBundleDef` value created for MSVC landing pads. | |
32a655c1 SL |
172 | pub struct Funclet { |
173 | cleanuppad: ValueRef, | |
174 | operand: OperandBundleDef, | |
7453a54e SL |
175 | } |
176 | ||
32a655c1 SL |
177 | impl Funclet { |
178 | pub fn new(cleanuppad: ValueRef) -> Funclet { | |
179 | Funclet { | |
180 | cleanuppad: cleanuppad, | |
181 | operand: OperandBundleDef::new("funclet", &[cleanuppad]), | |
7453a54e SL |
182 | } |
183 | } | |
184 | ||
32a655c1 | 185 | pub fn cleanuppad(&self) -> ValueRef { |
3157f602 XL |
186 | self.cleanuppad |
187 | } | |
7453a54e | 188 | |
32a655c1 SL |
189 | pub fn bundle(&self) -> &OperandBundleDef { |
190 | &self.operand | |
7453a54e | 191 | } |
1a4d82fc JJ |
192 | } |
193 | ||
1a4d82fc JJ |
194 | pub fn val_ty(v: ValueRef) -> Type { |
195 | unsafe { | |
196 | Type::from_ref(llvm::LLVMTypeOf(v)) | |
197 | } | |
198 | } | |
199 | ||
200 | // LLVM constant constructors. | |
201 | pub fn C_null(t: Type) -> ValueRef { | |
202 | unsafe { | |
203 | llvm::LLVMConstNull(t.to_ref()) | |
204 | } | |
205 | } | |
206 | ||
207 | pub fn C_undef(t: Type) -> ValueRef { | |
208 | unsafe { | |
209 | llvm::LLVMGetUndef(t.to_ref()) | |
210 | } | |
211 | } | |
212 | ||
213 | pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef { | |
214 | unsafe { | |
215 | llvm::LLVMConstInt(t.to_ref(), u, sign_extend as Bool) | |
216 | } | |
217 | } | |
218 | ||
8bb4bdeb XL |
219 | pub fn C_big_integral(t: Type, u: u128) -> ValueRef { |
220 | unsafe { | |
221 | let words = [u as u64, u.wrapping_shr(64) as u64]; | |
222 | llvm::LLVMConstIntOfArbitraryPrecision(t.to_ref(), 2, words.as_ptr()) | |
32a655c1 SL |
223 | } |
224 | } | |
225 | ||
92a42be0 SL |
226 | pub fn C_floating_f64(f: f64, t: Type) -> ValueRef { |
227 | unsafe { | |
228 | llvm::LLVMConstReal(t.to_ref(), f) | |
229 | } | |
230 | } | |
231 | ||
1a4d82fc JJ |
232 | pub fn C_nil(ccx: &CrateContext) -> ValueRef { |
233 | C_struct(ccx, &[], false) | |
234 | } | |
235 | ||
236 | pub fn C_bool(ccx: &CrateContext, val: bool) -> ValueRef { | |
237 | C_integral(Type::i1(ccx), val as u64, false) | |
238 | } | |
239 | ||
240 | pub fn C_i32(ccx: &CrateContext, i: i32) -> ValueRef { | |
241 | C_integral(Type::i32(ccx), i as u64, true) | |
242 | } | |
243 | ||
c34b1796 AL |
244 | pub fn C_u32(ccx: &CrateContext, i: u32) -> ValueRef { |
245 | C_integral(Type::i32(ccx), i as u64, false) | |
246 | } | |
247 | ||
1a4d82fc JJ |
248 | pub fn C_u64(ccx: &CrateContext, i: u64) -> ValueRef { |
249 | C_integral(Type::i64(ccx), i, false) | |
250 | } | |
251 | ||
1a4d82fc JJ |
252 | pub fn C_uint<I: AsU64>(ccx: &CrateContext, i: I) -> ValueRef { |
253 | let v = i.as_u64(); | |
254 | ||
e9174d1e SL |
255 | let bit_size = machine::llbitsize_of_real(ccx, ccx.int_type()); |
256 | ||
257 | if bit_size < 64 { | |
258 | // make sure it doesn't overflow | |
259 | assert!(v < (1<<bit_size)); | |
1a4d82fc JJ |
260 | } |
261 | ||
262 | C_integral(ccx.int_type(), v, false) | |
263 | } | |
264 | ||
265 | pub trait AsI64 { fn as_i64(self) -> i64; } | |
266 | pub trait AsU64 { fn as_u64(self) -> u64; } | |
267 | ||
268 | // FIXME: remove the intptr conversions, because they | |
269 | // are host-architecture-dependent | |
270 | impl AsI64 for i64 { fn as_i64(self) -> i64 { self as i64 }} | |
271 | impl AsI64 for i32 { fn as_i64(self) -> i64 { self as i64 }} | |
c34b1796 | 272 | impl AsI64 for isize { fn as_i64(self) -> i64 { self as i64 }} |
1a4d82fc JJ |
273 | |
274 | impl AsU64 for u64 { fn as_u64(self) -> u64 { self as u64 }} | |
275 | impl AsU64 for u32 { fn as_u64(self) -> u64 { self as u64 }} | |
c34b1796 | 276 | impl AsU64 for usize { fn as_u64(self) -> u64 { self as u64 }} |
1a4d82fc | 277 | |
e9174d1e | 278 | pub fn C_u8(ccx: &CrateContext, i: u8) -> ValueRef { |
1a4d82fc JJ |
279 | C_integral(Type::i8(ccx), i as u64, false) |
280 | } | |
281 | ||
282 | ||
283 | // This is a 'c-like' raw string, which differs from | |
284 | // our boxed-and-length-annotated strings. | |
285 | pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> ValueRef { | |
286 | unsafe { | |
7453a54e SL |
287 | if let Some(&llval) = cx.const_cstr_cache().borrow().get(&s) { |
288 | return llval; | |
1a4d82fc JJ |
289 | } |
290 | ||
291 | let sc = llvm::LLVMConstStringInContext(cx.llcx(), | |
85aaf69f SL |
292 | s.as_ptr() as *const c_char, |
293 | s.len() as c_uint, | |
1a4d82fc | 294 | !null_terminated as Bool); |
c30ab7b3 | 295 | let sym = cx.generate_local_symbol_name("str"); |
9346a6ac | 296 | let g = declare::define_global(cx, &sym[..], val_ty(sc)).unwrap_or_else(||{ |
54a0048b | 297 | bug!("symbol `{}` is already defined", sym); |
9346a6ac | 298 | }); |
1a4d82fc JJ |
299 | llvm::LLVMSetInitializer(g, sc); |
300 | llvm::LLVMSetGlobalConstant(g, True); | |
9e0c209e | 301 | llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage); |
1a4d82fc JJ |
302 | |
303 | cx.const_cstr_cache().borrow_mut().insert(s, g); | |
304 | g | |
305 | } | |
306 | } | |
307 | ||
308 | // NB: Do not use `do_spill_noroot` to make this into a constant string, or | |
309 | // you will be kicked off fast isel. See issue #4352 for an example of this. | |
310 | pub fn C_str_slice(cx: &CrateContext, s: InternedString) -> ValueRef { | |
85aaf69f | 311 | let len = s.len(); |
1a4d82fc | 312 | let cs = consts::ptrcast(C_cstr(cx, s, false), Type::i8p(cx)); |
476ff2be | 313 | C_named_struct(cx.str_slice_type(), &[cs, C_uint(cx, len)]) |
1a4d82fc JJ |
314 | } |
315 | ||
1a4d82fc JJ |
316 | pub fn C_struct(cx: &CrateContext, elts: &[ValueRef], packed: bool) -> ValueRef { |
317 | C_struct_in_context(cx.llcx(), elts, packed) | |
318 | } | |
319 | ||
320 | pub fn C_struct_in_context(llcx: ContextRef, elts: &[ValueRef], packed: bool) -> ValueRef { | |
321 | unsafe { | |
322 | llvm::LLVMConstStructInContext(llcx, | |
323 | elts.as_ptr(), elts.len() as c_uint, | |
324 | packed as Bool) | |
325 | } | |
326 | } | |
327 | ||
328 | pub fn C_named_struct(t: Type, elts: &[ValueRef]) -> ValueRef { | |
329 | unsafe { | |
330 | llvm::LLVMConstNamedStruct(t.to_ref(), elts.as_ptr(), elts.len() as c_uint) | |
331 | } | |
332 | } | |
333 | ||
334 | pub fn C_array(ty: Type, elts: &[ValueRef]) -> ValueRef { | |
335 | unsafe { | |
336 | return llvm::LLVMConstArray(ty.to_ref(), elts.as_ptr(), elts.len() as c_uint); | |
337 | } | |
338 | } | |
339 | ||
85aaf69f SL |
340 | pub fn C_vector(elts: &[ValueRef]) -> ValueRef { |
341 | unsafe { | |
342 | return llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint); | |
343 | } | |
344 | } | |
345 | ||
1a4d82fc JJ |
346 | pub fn C_bytes(cx: &CrateContext, bytes: &[u8]) -> ValueRef { |
347 | C_bytes_in_context(cx.llcx(), bytes) | |
348 | } | |
349 | ||
350 | pub fn C_bytes_in_context(llcx: ContextRef, bytes: &[u8]) -> ValueRef { | |
351 | unsafe { | |
352 | let ptr = bytes.as_ptr() as *const c_char; | |
353 | return llvm::LLVMConstStringInContext(llcx, ptr, bytes.len() as c_uint, True); | |
354 | } | |
355 | } | |
356 | ||
54a0048b | 357 | pub fn const_get_elt(v: ValueRef, us: &[c_uint]) |
1a4d82fc JJ |
358 | -> ValueRef { |
359 | unsafe { | |
360 | let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint); | |
361 | ||
54a0048b SL |
362 | debug!("const_get_elt(v={:?}, us={:?}, r={:?})", |
363 | Value(v), us, Value(r)); | |
1a4d82fc | 364 | |
54a0048b | 365 | r |
1a4d82fc JJ |
366 | } |
367 | } | |
368 | ||
1a4d82fc JJ |
369 | pub fn const_to_uint(v: ValueRef) -> u64 { |
370 | unsafe { | |
371 | llvm::LLVMConstIntGetZExtValue(v) | |
372 | } | |
373 | } | |
374 | ||
c34b1796 AL |
375 | fn is_const_integral(v: ValueRef) -> bool { |
376 | unsafe { | |
377 | !llvm::LLVMIsAConstantInt(v).is_null() | |
378 | } | |
379 | } | |
380 | ||
32a655c1 | 381 | #[inline] |
32a655c1 SL |
382 | fn hi_lo_to_u128(lo: u64, hi: u64) -> u128 { |
383 | ((hi as u128) << 64) | (lo as u128) | |
c34b1796 AL |
384 | } |
385 | ||
32a655c1 | 386 | pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option<u128> { |
c34b1796 AL |
387 | unsafe { |
388 | if is_const_integral(v) { | |
32a655c1 SL |
389 | let (mut lo, mut hi) = (0u64, 0u64); |
390 | let success = llvm::LLVMRustConstInt128Get(v, sign_ext, | |
391 | &mut hi as *mut u64, &mut lo as *mut u64); | |
392 | if success { | |
393 | Some(hi_lo_to_u128(lo, hi)) | |
394 | } else { | |
395 | None | |
396 | } | |
c34b1796 AL |
397 | } else { |
398 | None | |
399 | } | |
400 | } | |
401 | } | |
402 | ||
1a4d82fc JJ |
403 | pub fn is_undef(val: ValueRef) -> bool { |
404 | unsafe { | |
405 | llvm::LLVMIsUndef(val) != False | |
406 | } | |
407 | } | |
408 | ||
409 | #[allow(dead_code)] // potentially useful | |
410 | pub fn is_null(val: ValueRef) -> bool { | |
411 | unsafe { | |
412 | llvm::LLVMIsNull(val) != False | |
413 | } | |
414 | } | |
415 | ||
3157f602 | 416 | pub fn langcall(tcx: TyCtxt, |
1a4d82fc JJ |
417 | span: Option<Span>, |
418 | msg: &str, | |
419 | li: LangItem) | |
e9174d1e | 420 | -> DefId { |
3157f602 | 421 | match tcx.lang_items.require(li) { |
1a4d82fc JJ |
422 | Ok(id) => id, |
423 | Err(s) => { | |
424 | let msg = format!("{} {}", msg, s); | |
425 | match span { | |
3157f602 XL |
426 | Some(span) => tcx.sess.span_fatal(span, &msg[..]), |
427 | None => tcx.sess.fatal(&msg[..]), | |
1a4d82fc JJ |
428 | } |
429 | } | |
430 | } | |
431 | } | |
e9174d1e | 432 | |
92a42be0 SL |
433 | // To avoid UB from LLVM, these two functions mask RHS with an |
434 | // appropriate mask unconditionally (i.e. the fallback behavior for | |
435 | // all shifts). For 32- and 64-bit types, this matches the semantics | |
436 | // of Java. (See related discussion on #1877 and #10183.) | |
437 | ||
32a655c1 SL |
438 | pub fn build_unchecked_lshift<'a, 'tcx>( |
439 | bcx: &Builder<'a, 'tcx>, | |
440 | lhs: ValueRef, | |
441 | rhs: ValueRef | |
442 | ) -> ValueRef { | |
92a42be0 SL |
443 | let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShl, lhs, rhs); |
444 | // #1877, #10183: Ensure that input is always valid | |
32a655c1 SL |
445 | let rhs = shift_mask_rhs(bcx, rhs); |
446 | bcx.shl(lhs, rhs) | |
92a42be0 SL |
447 | } |
448 | ||
32a655c1 SL |
449 | pub fn build_unchecked_rshift<'a, 'tcx>( |
450 | bcx: &Builder<'a, 'tcx>, lhs_t: Ty<'tcx>, lhs: ValueRef, rhs: ValueRef | |
451 | ) -> ValueRef { | |
92a42be0 SL |
452 | let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShr, lhs, rhs); |
453 | // #1877, #10183: Ensure that input is always valid | |
32a655c1 | 454 | let rhs = shift_mask_rhs(bcx, rhs); |
92a42be0 SL |
455 | let is_signed = lhs_t.is_signed(); |
456 | if is_signed { | |
32a655c1 | 457 | bcx.ashr(lhs, rhs) |
92a42be0 | 458 | } else { |
32a655c1 | 459 | bcx.lshr(lhs, rhs) |
92a42be0 SL |
460 | } |
461 | } | |
462 | ||
32a655c1 | 463 | fn shift_mask_rhs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, rhs: ValueRef) -> ValueRef { |
92a42be0 | 464 | let rhs_llty = val_ty(rhs); |
32a655c1 | 465 | bcx.and(rhs, shift_mask_val(bcx, rhs_llty, rhs_llty, false)) |
92a42be0 SL |
466 | } |
467 | ||
32a655c1 SL |
468 | pub fn shift_mask_val<'a, 'tcx>( |
469 | bcx: &Builder<'a, 'tcx>, | |
470 | llty: Type, | |
471 | mask_llty: Type, | |
472 | invert: bool | |
473 | ) -> ValueRef { | |
92a42be0 SL |
474 | let kind = llty.kind(); |
475 | match kind { | |
476 | TypeKind::Integer => { | |
477 | // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc. | |
478 | let val = llty.int_width() - 1; | |
479 | if invert { | |
480 | C_integral(mask_llty, !val, true) | |
481 | } else { | |
482 | C_integral(mask_llty, val, false) | |
483 | } | |
484 | }, | |
485 | TypeKind::Vector => { | |
486 | let mask = shift_mask_val(bcx, llty.element_type(), mask_llty.element_type(), invert); | |
32a655c1 | 487 | bcx.vector_splat(mask_llty.vector_length(), mask) |
92a42be0 | 488 | }, |
54a0048b | 489 | _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind), |
92a42be0 SL |
490 | } |
491 | } | |
476ff2be | 492 | |
8bb4bdeb XL |
493 | pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, |
494 | ty: Ty<'tcx>) | |
495 | -> ty::PolyFnSig<'tcx> | |
476ff2be SL |
496 | { |
497 | match ty.sty { | |
8bb4bdeb | 498 | ty::TyFnDef(_, _, sig) => sig, |
476ff2be | 499 | // Shims currently have type TyFnPtr. Not sure this should remain. |
8bb4bdeb | 500 | ty::TyFnPtr(sig) => sig, |
476ff2be SL |
501 | ty::TyClosure(def_id, substs) => { |
502 | let tcx = ccx.tcx(); | |
8bb4bdeb | 503 | let sig = tcx.closure_type(def_id).subst(tcx, substs.substs); |
476ff2be SL |
504 | |
505 | let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv); | |
506 | let env_ty = match tcx.closure_kind(def_id) { | |
507 | ty::ClosureKind::Fn => tcx.mk_imm_ref(tcx.mk_region(env_region), ty), | |
508 | ty::ClosureKind::FnMut => tcx.mk_mut_ref(tcx.mk_region(env_region), ty), | |
509 | ty::ClosureKind::FnOnce => ty, | |
510 | }; | |
511 | ||
8bb4bdeb | 512 | sig.map_bound(|sig| tcx.mk_fn_sig( |
476ff2be SL |
513 | iter::once(env_ty).chain(sig.inputs().iter().cloned()), |
514 | sig.output(), | |
8bb4bdeb XL |
515 | sig.variadic, |
516 | sig.unsafety, | |
517 | sig.abi | |
518 | )) | |
476ff2be SL |
519 | } |
520 | _ => bug!("unexpected type {:?} to ty_fn_sig", ty) | |
521 | } | |
522 | } | |
523 | ||
cc61c64b XL |
524 | pub fn requests_inline<'a, 'tcx>( |
525 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
526 | instance: &ty::Instance<'tcx> | |
527 | ) -> bool { | |
528 | if is_inline_instance(tcx, instance) { | |
529 | return true | |
530 | } | |
7cac9316 XL |
531 | if let ty::InstanceDef::DropGlue(..) = instance.def { |
532 | // Drop glue wants to be instantiated at every translation | |
533 | // unit, but without an #[inline] hint. We should make this | |
534 | // available to normal end-users. | |
535 | return true | |
536 | } | |
cc61c64b XL |
537 | attr::requests_inline(&instance.def.attrs(tcx)[..]) |
538 | } | |
539 | ||
540 | pub fn is_inline_instance<'a, 'tcx>( | |
541 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
542 | instance: &ty::Instance<'tcx> | |
543 | ) -> bool { | |
544 | let def_id = match instance.def { | |
545 | ty::InstanceDef::Item(def_id) => def_id, | |
546 | ty::InstanceDef::DropGlue(_, Some(_)) => return false, | |
547 | _ => return true | |
548 | }; | |
549 | match tcx.def_key(def_id).disambiguated_data.data { | |
550 | DefPathData::StructCtor | | |
551 | DefPathData::EnumVariant(..) | | |
552 | DefPathData::ClosureExpr => true, | |
553 | _ => false | |
554 | } | |
476ff2be | 555 | } |
8bb4bdeb XL |
556 | |
557 | /// Given a DefId and some Substs, produces the monomorphic item type. | |
558 | pub fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, | |
559 | def_id: DefId, | |
560 | substs: &'tcx Substs<'tcx>) | |
561 | -> Ty<'tcx> | |
562 | { | |
7cac9316 | 563 | let ty = shared.tcx().type_of(def_id); |
cc61c64b XL |
564 | shared.tcx().trans_apply_param_substs(substs, &ty) |
565 | } | |
566 | ||
567 | /// Return the substituted type of an instance. | |
568 | pub fn instance_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, | |
569 | instance: &ty::Instance<'tcx>) | |
570 | -> Ty<'tcx> | |
571 | { | |
572 | let ty = instance.def.def_ty(shared.tcx()); | |
573 | shared.tcx().trans_apply_param_substs(instance.substs, &ty) | |
8bb4bdeb | 574 | } |