]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/common.rs
Merge remote-tracking branch 'tbu/pr_doc_smallfix'
[rust.git] / src / librustc / middle / trans / common.rs
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)];
12
13 //! Code that is useful in various trans modules.
14
15 use driver::session::Session;
16 use lib::llvm::{ValueRef, BasicBlockRef, BuilderRef};
17 use lib::llvm::{True, False, Bool};
18 use lib::llvm::llvm;
19 use lib;
20 use middle::lang_items::LangItem;
21 use middle::trans::base;
22 use middle::trans::build;
23 use middle::trans::cleanup;
24 use middle::trans::datum;
25 use middle::trans::datum::{Datum, Lvalue};
26 use middle::trans::debuginfo;
27 use middle::trans::type_::Type;
28 use middle::ty::substs;
29 use middle::ty;
30 use middle::typeck;
31 use util::ppaux::Repr;
32
33 use arena::TypedArena;
34 use std::c_str::ToCStr;
35 use std::cell::{Cell, RefCell};
36 use collections::HashMap;
37 use std::libc::{c_uint, c_longlong, c_ulonglong, c_char};
38 use syntax::ast::Ident;
39 use syntax::ast;
40 use syntax::ast_map::{PathElem, PathName};
41 use syntax::codemap::Span;
42 use syntax::parse::token::InternedString;
43 use syntax::parse::token;
44
45 pub use middle::trans::context::CrateContext;
46
47 fn type_is_newtype_immediate(ccx: &CrateContext, ty: ty::t) -> bool {
48     match ty::get(ty).sty {
49         ty::ty_struct(def_id, ref substs) => {
50             let fields = ty::struct_fields(ccx.tcx, def_id, substs);
51             fields.len() == 1 &&
52                 fields[0].ident.name == token::special_idents::unnamed_field.name &&
53                 type_is_immediate(ccx, fields[0].mt.ty)
54         }
55         _ => false
56     }
57 }
58
59 pub fn type_is_immediate(ccx: &CrateContext, ty: ty::t) -> bool {
60     use middle::trans::machine::llsize_of_alloc;
61     use middle::trans::type_of::sizing_type_of;
62     let tcx = ccx.tcx;
63     let simple = ty::type_is_scalar(ty) || ty::type_is_boxed(ty) ||
64         ty::type_is_unique(ty) || ty::type_is_region_ptr(ty) ||
65         type_is_newtype_immediate(ccx, ty) || ty::type_is_bot(ty) ||
66         ty::type_is_simd(tcx, ty);
67     if simple {
68         return true;
69     }
70     match ty::get(ty).sty {
71         ty::ty_bot => true,
72         ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) => {
73             let llty = sizing_type_of(ccx, ty);
74             llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type)
75         }
76         _ => type_is_zero_size(ccx, ty)
77     }
78 }
79
80 pub fn type_is_zero_size(ccx: &CrateContext, ty: ty::t) -> bool {
81     /*!
82      * Identify types which have size zero at runtime.
83      */
84
85     use middle::trans::machine::llsize_of_alloc;
86     use middle::trans::type_of::sizing_type_of;
87     let llty = sizing_type_of(ccx, ty);
88     llsize_of_alloc(ccx, llty) == 0
89 }
90
91 pub fn return_type_is_void(ccx: &CrateContext, ty: ty::t) -> bool {
92     /*!
93      * Identifies types which we declare to be equivalent to `void`
94      * in C for the purpose of function return types. These are
95      * `()`, bot, and uninhabited enums. Note that all such types
96      * are also zero-size, but not all zero-size types use a `void`
97      * return type (in order to aid with C ABI compatibility).
98      */
99
100     ty::type_is_nil(ty) || ty::type_is_bot(ty) || ty::type_is_empty(ccx.tcx, ty)
101 }
102
103 pub fn gensym_name(name: &str) -> PathElem {
104     PathName(token::gensym(name))
105 }
106
107 pub struct tydesc_info {
108     ty: ty::t,
109     tydesc: ValueRef,
110     size: ValueRef,
111     align: ValueRef,
112     name: ValueRef,
113     visit_glue: Cell<Option<ValueRef>>,
114 }
115
116 /*
117  * A note on nomenclature of linking: "extern", "foreign", and "upcall".
118  *
119  * An "extern" is an LLVM symbol we wind up emitting an undefined external
120  * reference to. This means "we don't have the thing in this compilation unit,
121  * please make sure you link it in at runtime". This could be a reference to
122  * C code found in a C library, or rust code found in a rust crate.
123  *
124  * Most "externs" are implicitly declared (automatically) as a result of a
125  * user declaring an extern _module_ dependency; this causes the rust driver
126  * to locate an extern crate, scan its compilation metadata, and emit extern
127  * declarations for any symbols used by the declaring crate.
128  *
129  * A "foreign" is an extern that references C (or other non-rust ABI) code.
130  * There is no metadata to scan for extern references so in these cases either
131  * a header-digester like bindgen, or manual function prototypes, have to
132  * serve as declarators. So these are usually given explicitly as prototype
133  * declarations, in rust code, with ABI attributes on them noting which ABI to
134  * link via.
135  *
136  * An "upcall" is a foreign call generated by the compiler (not corresponding
137  * to any user-written call in the code) into the runtime library, to perform
138  * some helper task such as bringing a task to life, allocating memory, etc.
139  *
140  */
141
142 pub struct NodeInfo {
143     id: ast::NodeId,
144     span: Span,
145 }
146
147 pub fn expr_info(expr: &ast::Expr) -> NodeInfo {
148     NodeInfo { id: expr.id, span: expr.span }
149 }
150
151 pub struct Stats {
152     n_static_tydescs: Cell<uint>,
153     n_glues_created: Cell<uint>,
154     n_null_glues: Cell<uint>,
155     n_real_glues: Cell<uint>,
156     n_fns: Cell<uint>,
157     n_monos: Cell<uint>,
158     n_inlines: Cell<uint>,
159     n_closures: Cell<uint>,
160     n_llvm_insns: Cell<uint>,
161     llvm_insns: RefCell<HashMap<~str, uint>>,
162     // (ident, time-in-ms, llvm-instructions)
163     fn_stats: RefCell<~[(~str, uint, uint)]>,
164 }
165
166 pub struct BuilderRef_res {
167     B: BuilderRef,
168 }
169
170 impl Drop for BuilderRef_res {
171     fn drop(&mut self) {
172         unsafe {
173             llvm::LLVMDisposeBuilder(self.B);
174         }
175     }
176 }
177
178 pub fn BuilderRef_res(B: BuilderRef) -> BuilderRef_res {
179     BuilderRef_res {
180         B: B
181     }
182 }
183
184 pub type ExternMap = HashMap<~str, ValueRef>;
185
186 // Here `self_ty` is the real type of the self parameter to this method. It
187 // will only be set in the case of default methods.
188 pub struct param_substs {
189     tys: ~[ty::t],
190     self_ty: Option<ty::t>,
191     vtables: Option<typeck::vtable_res>,
192     self_vtables: Option<typeck::vtable_param_res>
193 }
194
195 impl param_substs {
196     pub fn validate(&self) {
197         for t in self.tys.iter() { assert!(!ty::type_needs_infer(*t)); }
198         for t in self.self_ty.iter() { assert!(!ty::type_needs_infer(*t)); }
199     }
200 }
201
202 fn param_substs_to_str(this: &param_substs, tcx: ty::ctxt) -> ~str {
203     format!("param_substs \\{tys:{}, vtables:{}\\}",
204          this.tys.repr(tcx),
205          this.vtables.repr(tcx))
206 }
207
208 impl Repr for param_substs {
209     fn repr(&self, tcx: ty::ctxt) -> ~str {
210         param_substs_to_str(self, tcx)
211     }
212 }
213
214 // work around bizarre resolve errors
215 type RvalueDatum = datum::Datum<datum::Rvalue>;
216 type LvalueDatum = datum::Datum<datum::Lvalue>;
217
218 // Function context.  Every LLVM function we create will have one of
219 // these.
220 pub struct FunctionContext<'a> {
221     // The ValueRef returned from a call to llvm::LLVMAddFunction; the
222     // address of the first instruction in the sequence of
223     // instructions for this function that will go in the .text
224     // section of the executable we're generating.
225     llfn: ValueRef,
226
227     // The environment argument in a closure.
228     llenv: Option<ValueRef>,
229
230     // The place to store the return value. If the return type is immediate,
231     // this is an alloca in the function. Otherwise, it's the hidden first
232     // parameter to the function. After function construction, this should
233     // always be Some.
234     llretptr: Cell<Option<ValueRef>>,
235
236     entry_bcx: RefCell<Option<&'a Block<'a>>>,
237
238     // These elements: "hoisted basic blocks" containing
239     // administrative activities that have to happen in only one place in
240     // the function, due to LLVM's quirks.
241     // A marker for the place where we want to insert the function's static
242     // allocas, so that LLVM will coalesce them into a single alloca call.
243     alloca_insert_pt: Cell<Option<ValueRef>>,
244     llreturn: Cell<Option<BasicBlockRef>>,
245
246     // The a value alloca'd for calls to upcalls.rust_personality. Used when
247     // outputting the resume instruction.
248     personality: Cell<Option<ValueRef>>,
249
250     // True if the caller expects this fn to use the out pointer to
251     // return. Either way, your code should write into llretptr, but if
252     // this value is false, llretptr will be a local alloca.
253     caller_expects_out_pointer: bool,
254
255     // Maps arguments to allocas created for them in llallocas.
256     llargs: RefCell<HashMap<ast::NodeId, LvalueDatum>>,
257
258     // Maps the def_ids for local variables to the allocas created for
259     // them in llallocas.
260     lllocals: RefCell<HashMap<ast::NodeId, LvalueDatum>>,
261
262     // Same as above, but for closure upvars
263     llupvars: RefCell<HashMap<ast::NodeId, ValueRef>>,
264
265     // The NodeId of the function, or -1 if it doesn't correspond to
266     // a user-defined function.
267     id: ast::NodeId,
268
269     // If this function is being monomorphized, this contains the type
270     // substitutions used.
271     param_substs: Option<@param_substs>,
272
273     // The source span and nesting context where this function comes from, for
274     // error reporting and symbol generation.
275     span: Option<Span>,
276
277     // The arena that blocks are allocated from.
278     block_arena: &'a TypedArena<Block<'a>>,
279
280     // This function's enclosing crate context.
281     ccx: @CrateContext,
282
283     // Used and maintained by the debuginfo module.
284     debug_context: debuginfo::FunctionDebugContext,
285
286     // Cleanup scopes.
287     scopes: RefCell<~[cleanup::CleanupScope<'a>]>,
288 }
289
290 impl<'a> FunctionContext<'a> {
291     pub fn arg_pos(&self, arg: uint) -> uint {
292         let arg = self.env_arg_pos() + arg;
293         if self.llenv.is_some() {
294             arg + 1
295         } else {
296             arg
297         }
298     }
299
300     pub fn out_arg_pos(&self) -> uint {
301         assert!(self.caller_expects_out_pointer);
302         0u
303     }
304
305     pub fn env_arg_pos(&self) -> uint {
306         if self.caller_expects_out_pointer {
307             1u
308         } else {
309             0u
310         }
311     }
312
313     pub fn cleanup(&self) {
314         unsafe {
315             llvm::LLVMInstructionEraseFromParent(self.alloca_insert_pt
316                                                      .get()
317                                                      .unwrap());
318         }
319         // Remove the cycle between fcx and bcx, so memory can be freed
320         self.entry_bcx.set(None);
321     }
322
323     pub fn get_llreturn(&self) -> BasicBlockRef {
324         if self.llreturn.get().is_none() {
325             self.llreturn.set(Some(base::mk_return_basic_block(self.llfn)));
326         }
327
328         self.llreturn.get().unwrap()
329     }
330
331     pub fn new_block(&'a self,
332                      is_lpad: bool,
333                      name: &str,
334                      opt_node_id: Option<ast::NodeId>)
335                      -> &'a Block<'a> {
336         unsafe {
337             let llbb = name.with_c_str(|buf| {
338                     llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx,
339                                                         self.llfn,
340                                                         buf)
341                 });
342             Block::new(llbb, is_lpad, opt_node_id, self)
343         }
344     }
345
346     pub fn new_id_block(&'a self,
347                         name: &str,
348                         node_id: ast::NodeId)
349                         -> &'a Block<'a> {
350         self.new_block(false, name, Some(node_id))
351     }
352
353     pub fn new_temp_block(&'a self,
354                           name: &str)
355                           -> &'a Block<'a> {
356         self.new_block(false, name, None)
357     }
358
359     pub fn join_blocks(&'a self,
360                        id: ast::NodeId,
361                        in_cxs: &[&'a Block<'a>])
362                        -> &'a Block<'a> {
363         let out = self.new_id_block("join", id);
364         let mut reachable = false;
365         for bcx in in_cxs.iter() {
366             if !bcx.unreachable.get() {
367                 build::Br(*bcx, out.llbb);
368                 reachable = true;
369             }
370         }
371         if !reachable {
372             build::Unreachable(out);
373         }
374         return out;
375     }
376 }
377
378 pub fn warn_not_to_commit(ccx: &mut CrateContext, msg: &str) {
379     if !ccx.do_not_commit_warning_issued.get() {
380         ccx.do_not_commit_warning_issued.set(true);
381         ccx.sess.warn(msg.to_str() + " -- do not commit like this!");
382     }
383 }
384
385 // Heap selectors. Indicate which heap something should go on.
386 #[deriving(Eq)]
387 pub enum heap {
388     heap_managed,
389     heap_exchange,
390     heap_exchange_closure
391 }
392
393 // Basic block context.  We create a block context for each basic block
394 // (single-entry, single-exit sequence of instructions) we generate from Rust
395 // code.  Each basic block we generate is attached to a function, typically
396 // with many basic blocks per function.  All the basic blocks attached to a
397 // function are organized as a directed graph.
398 pub struct Block<'a> {
399     // The BasicBlockRef returned from a call to
400     // llvm::LLVMAppendBasicBlock(llfn, name), which adds a basic
401     // block to the function pointed to by llfn.  We insert
402     // instructions into that block by way of this block context.
403     // The block pointing to this one in the function's digraph.
404     llbb: BasicBlockRef,
405     terminated: Cell<bool>,
406     unreachable: Cell<bool>,
407
408     // Is this block part of a landing pad?
409     is_lpad: bool,
410
411     // AST node-id associated with this block, if any. Used for
412     // debugging purposes only.
413     opt_node_id: Option<ast::NodeId>,
414
415     // The function context for the function to which this block is
416     // attached.
417     fcx: &'a FunctionContext<'a>,
418 }
419
420 impl<'a> Block<'a> {
421     pub fn new<'a>(
422                llbb: BasicBlockRef,
423                is_lpad: bool,
424                opt_node_id: Option<ast::NodeId>,
425                fcx: &'a FunctionContext<'a>)
426                -> &'a Block<'a> {
427         fcx.block_arena.alloc(Block {
428             llbb: llbb,
429             terminated: Cell::new(false),
430             unreachable: Cell::new(false),
431             is_lpad: is_lpad,
432             opt_node_id: opt_node_id,
433             fcx: fcx
434         })
435     }
436
437     pub fn ccx(&self) -> @CrateContext { self.fcx.ccx }
438     pub fn tcx(&self) -> ty::ctxt {
439         self.fcx.ccx.tcx
440     }
441     pub fn sess(&self) -> Session { self.fcx.ccx.sess }
442
443     pub fn ident(&self, ident: Ident) -> ~str {
444         token::get_ident(ident).get().to_str()
445     }
446
447     pub fn node_id_to_str(&self, id: ast::NodeId) -> ~str {
448         self.tcx().map.node_to_str(id)
449     }
450
451     pub fn expr_to_str(&self, e: &ast::Expr) -> ~str {
452         e.repr(self.tcx())
453     }
454
455     pub fn expr_is_lval(&self, e: &ast::Expr) -> bool {
456         ty::expr_is_lval(self.tcx(), self.ccx().maps.method_map, e)
457     }
458
459     pub fn expr_kind(&self, e: &ast::Expr) -> ty::ExprKind {
460         ty::expr_kind(self.tcx(), self.ccx().maps.method_map, e)
461     }
462
463     pub fn def(&self, nid: ast::NodeId) -> ast::Def {
464         let def_map = self.tcx().def_map.borrow();
465         match def_map.get().find(&nid) {
466             Some(&v) => v,
467             None => {
468                 self.tcx().sess.bug(format!(
469                     "no def associated with node id {:?}", nid));
470             }
471         }
472     }
473
474     pub fn val_to_str(&self, val: ValueRef) -> ~str {
475         self.ccx().tn.val_to_str(val)
476     }
477
478     pub fn llty_str(&self, ty: Type) -> ~str {
479         self.ccx().tn.type_to_str(ty)
480     }
481
482     pub fn ty_to_str(&self, t: ty::t) -> ~str {
483         t.repr(self.tcx())
484     }
485
486     pub fn to_str(&self) -> ~str {
487         let blk: *Block = self;
488         format!("[block {}]", blk)
489     }
490 }
491
492 pub struct Result<'a> {
493     bcx: &'a Block<'a>,
494     val: ValueRef
495 }
496
497 pub fn rslt<'a>(bcx: &'a Block<'a>, val: ValueRef) -> Result<'a> {
498     Result {
499         bcx: bcx,
500         val: val,
501     }
502 }
503
504 impl<'a> Result<'a> {
505     pub fn unpack(&self, bcx: &mut &'a Block<'a>) -> ValueRef {
506         *bcx = self.bcx;
507         return self.val;
508     }
509 }
510
511 pub fn val_ty(v: ValueRef) -> Type {
512     unsafe {
513         Type::from_ref(llvm::LLVMTypeOf(v))
514     }
515 }
516
517 // LLVM constant constructors.
518 pub fn C_null(t: Type) -> ValueRef {
519     unsafe {
520         llvm::LLVMConstNull(t.to_ref())
521     }
522 }
523
524 pub fn C_undef(t: Type) -> ValueRef {
525     unsafe {
526         llvm::LLVMGetUndef(t.to_ref())
527     }
528 }
529
530 pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef {
531     unsafe {
532         llvm::LLVMConstInt(t.to_ref(), u, sign_extend as Bool)
533     }
534 }
535
536 pub fn C_floating(s: &str, t: Type) -> ValueRef {
537     unsafe {
538         s.with_c_str(|buf| llvm::LLVMConstRealOfString(t.to_ref(), buf))
539     }
540 }
541
542 pub fn C_nil() -> ValueRef {
543     C_struct([], false)
544 }
545
546 pub fn C_bool(val: bool) -> ValueRef {
547     C_integral(Type::bool(), val as u64, false)
548 }
549
550 pub fn C_i1(val: bool) -> ValueRef {
551     C_integral(Type::i1(), val as u64, false)
552 }
553
554 pub fn C_i32(i: i32) -> ValueRef {
555     return C_integral(Type::i32(), i as u64, true);
556 }
557
558 pub fn C_i64(i: i64) -> ValueRef {
559     return C_integral(Type::i64(), i as u64, true);
560 }
561
562 pub fn C_u64(i: u64) -> ValueRef {
563     return C_integral(Type::i64(), i, false);
564 }
565
566 pub fn C_int(cx: &CrateContext, i: int) -> ValueRef {
567     return C_integral(cx.int_type, i as u64, true);
568 }
569
570 pub fn C_uint(cx: &CrateContext, i: uint) -> ValueRef {
571     return C_integral(cx.int_type, i as u64, false);
572 }
573
574 pub fn C_u8(i: uint) -> ValueRef {
575     return C_integral(Type::i8(), i as u64, false);
576 }
577
578
579 // This is a 'c-like' raw string, which differs from
580 // our boxed-and-length-annotated strings.
581 pub fn C_cstr(cx: &CrateContext, s: InternedString) -> ValueRef {
582     unsafe {
583         {
584             let const_cstr_cache = cx.const_cstr_cache.borrow();
585             match const_cstr_cache.get().find(&s) {
586                 Some(&llval) => return llval,
587                 None => ()
588             }
589         }
590
591         let sc = llvm::LLVMConstStringInContext(cx.llcx,
592                                                 s.get().as_ptr() as *c_char,
593                                                 s.get().len() as c_uint,
594                                                 False);
595
596         let gsym = token::gensym("str");
597         let g = format!("str{}", gsym).with_c_str(|buf| {
598             llvm::LLVMAddGlobal(cx.llmod, val_ty(sc).to_ref(), buf)
599         });
600         llvm::LLVMSetInitializer(g, sc);
601         llvm::LLVMSetGlobalConstant(g, True);
602         lib::llvm::SetLinkage(g, lib::llvm::InternalLinkage);
603
604         let mut const_cstr_cache = cx.const_cstr_cache.borrow_mut();
605         const_cstr_cache.get().insert(s, g);
606         g
607     }
608 }
609
610 // NB: Do not use `do_spill_noroot` to make this into a constant string, or
611 // you will be kicked off fast isel. See issue #4352 for an example of this.
612 pub fn C_str_slice(cx: &CrateContext, s: InternedString) -> ValueRef {
613     unsafe {
614         let len = s.get().len();
615         let cs = llvm::LLVMConstPointerCast(C_cstr(cx, s), Type::i8p().to_ref());
616         C_struct([cs, C_uint(cx, len)], false)
617     }
618 }
619
620 pub fn C_binary_slice(cx: &CrateContext, data: &[u8]) -> ValueRef {
621     unsafe {
622         let len = data.len();
623         let lldata = C_bytes(data);
624
625         let gsym = token::gensym("binary");
626         let g = format!("binary{}", gsym).with_c_str(|buf| {
627             llvm::LLVMAddGlobal(cx.llmod, val_ty(lldata).to_ref(), buf)
628         });
629         llvm::LLVMSetInitializer(g, lldata);
630         llvm::LLVMSetGlobalConstant(g, True);
631         lib::llvm::SetLinkage(g, lib::llvm::InternalLinkage);
632
633         let cs = llvm::LLVMConstPointerCast(g, Type::i8p().to_ref());
634         C_struct([cs, C_uint(cx, len)], false)
635     }
636 }
637
638 pub fn C_zero_byte_arr(size: uint) -> ValueRef {
639     unsafe {
640         let mut i = 0u;
641         let mut elts: ~[ValueRef] = ~[];
642         while i < size { elts.push(C_u8(0u)); i += 1u; }
643         return llvm::LLVMConstArray(Type::i8().to_ref(),
644                                     elts.as_ptr(), elts.len() as c_uint);
645     }
646 }
647
648 pub fn C_struct(elts: &[ValueRef], packed: bool) -> ValueRef {
649     unsafe {
650
651         llvm::LLVMConstStructInContext(base::task_llcx(),
652                                        elts.as_ptr(), elts.len() as c_uint,
653                                        packed as Bool)
654     }
655 }
656
657 pub fn C_named_struct(T: Type, elts: &[ValueRef]) -> ValueRef {
658     unsafe {
659         llvm::LLVMConstNamedStruct(T.to_ref(), elts.as_ptr(), elts.len() as c_uint)
660     }
661 }
662
663 pub fn C_array(ty: Type, elts: &[ValueRef]) -> ValueRef {
664     unsafe {
665         return llvm::LLVMConstArray(ty.to_ref(), elts.as_ptr(), elts.len() as c_uint);
666     }
667 }
668
669 pub fn C_bytes(bytes: &[u8]) -> ValueRef {
670     unsafe {
671         let ptr = bytes.as_ptr() as *c_char;
672         return llvm::LLVMConstStringInContext(base::task_llcx(), ptr, bytes.len() as c_uint, True);
673     }
674 }
675
676 pub fn get_param(fndecl: ValueRef, param: uint) -> ValueRef {
677     unsafe {
678         llvm::LLVMGetParam(fndecl, param as c_uint)
679     }
680 }
681
682 pub fn const_get_elt(cx: &CrateContext, v: ValueRef, us: &[c_uint])
683                   -> ValueRef {
684     unsafe {
685         let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint);
686
687         debug!("const_get_elt(v={}, us={:?}, r={})",
688                cx.tn.val_to_str(v), us, cx.tn.val_to_str(r));
689
690         return r;
691     }
692 }
693
694 pub fn is_const(v: ValueRef) -> bool {
695     unsafe {
696         llvm::LLVMIsConstant(v) == True
697     }
698 }
699
700 pub fn const_to_int(v: ValueRef) -> c_longlong {
701     unsafe {
702         llvm::LLVMConstIntGetSExtValue(v)
703     }
704 }
705
706 pub fn const_to_uint(v: ValueRef) -> c_ulonglong {
707     unsafe {
708         llvm::LLVMConstIntGetZExtValue(v)
709     }
710 }
711
712 pub fn is_undef(val: ValueRef) -> bool {
713     unsafe {
714         llvm::LLVMIsUndef(val) != False
715     }
716 }
717
718 pub fn is_null(val: ValueRef) -> bool {
719     unsafe {
720         llvm::LLVMIsNull(val) != False
721     }
722 }
723
724 // Used to identify cached monomorphized functions and vtables
725 #[deriving(Eq,Hash)]
726 pub enum mono_param_id {
727     mono_precise(ty::t, Option<@~[mono_id]>),
728     mono_any,
729     mono_repr(uint /* size */,
730               uint /* align */,
731               MonoDataClass,
732               datum::RvalueMode),
733 }
734
735 #[deriving(Eq,Hash)]
736 pub enum MonoDataClass {
737     MonoBits,    // Anything not treated differently from arbitrary integer data
738     MonoNonNull, // Non-null pointers (used for optional-pointer optimization)
739     // FIXME(#3547)---scalars and floats are
740     // treated differently in most ABIs.  But we
741     // should be doing something more detailed
742     // here.
743     MonoFloat
744 }
745
746 pub fn mono_data_classify(t: ty::t) -> MonoDataClass {
747     match ty::get(t).sty {
748         ty::ty_float(_) => MonoFloat,
749         ty::ty_rptr(..) | ty::ty_uniq(..) | ty::ty_box(..) |
750         ty::ty_str(ty::vstore_uniq) | ty::ty_vec(_, ty::vstore_uniq) |
751         ty::ty_bare_fn(..) => MonoNonNull,
752         // Is that everything?  Would closures or slices qualify?
753         _ => MonoBits
754     }
755 }
756
757
758 #[deriving(Eq,Hash)]
759 pub struct mono_id_ {
760     def: ast::DefId,
761     params: ~[mono_param_id]
762 }
763
764 pub type mono_id = @mono_id_;
765
766 pub fn umax(cx: &Block, a: ValueRef, b: ValueRef) -> ValueRef {
767     let cond = build::ICmp(cx, lib::llvm::IntULT, a, b);
768     return build::Select(cx, cond, b, a);
769 }
770
771 pub fn umin(cx: &Block, a: ValueRef, b: ValueRef) -> ValueRef {
772     let cond = build::ICmp(cx, lib::llvm::IntULT, a, b);
773     return build::Select(cx, cond, a, b);
774 }
775
776 pub fn align_to(cx: &Block, off: ValueRef, align: ValueRef) -> ValueRef {
777     let mask = build::Sub(cx, align, C_int(cx.ccx(), 1));
778     let bumped = build::Add(cx, off, mask);
779     return build::And(cx, bumped, build::Not(cx, mask));
780 }
781
782 pub fn monomorphize_type(bcx: &Block, t: ty::t) -> ty::t {
783     match bcx.fcx.param_substs {
784         Some(substs) => {
785             ty::subst_tps(bcx.tcx(), substs.tys, substs.self_ty, t)
786         }
787         _ => {
788             assert!(!ty::type_has_params(t));
789             assert!(!ty::type_has_self(t));
790             t
791         }
792     }
793 }
794
795 pub fn node_id_type(bcx: &Block, id: ast::NodeId) -> ty::t {
796     let tcx = bcx.tcx();
797     let t = ty::node_id_to_type(tcx, id);
798     monomorphize_type(bcx, t)
799 }
800
801 pub fn expr_ty(bcx: &Block, ex: &ast::Expr) -> ty::t {
802     node_id_type(bcx, ex.id)
803 }
804
805 pub fn expr_ty_adjusted(bcx: &Block, ex: &ast::Expr) -> ty::t {
806     let tcx = bcx.tcx();
807     let t = ty::expr_ty_adjusted(tcx, ex);
808     monomorphize_type(bcx, t)
809 }
810
811 pub fn node_id_type_params(bcx: &Block, id: ast::NodeId) -> ~[ty::t] {
812     let tcx = bcx.tcx();
813     let params = ty::node_id_to_type_params(tcx, id);
814
815     if !params.iter().all(|t| !ty::type_needs_infer(*t)) {
816         bcx.sess().bug(
817             format!("type parameters for node {} include inference types: {}",
818                  id, params.map(|t| bcx.ty_to_str(*t)).connect(",")));
819     }
820
821     match bcx.fcx.param_substs {
822       Some(substs) => {
823         params.iter().map(|t| {
824             ty::subst_tps(tcx, substs.tys, substs.self_ty, *t)
825         }).collect()
826       }
827       _ => params
828     }
829 }
830
831 pub fn node_vtables(bcx: &Block, id: ast::NodeId)
832                  -> Option<typeck::vtable_res> {
833     let vtable_map = bcx.ccx().maps.vtable_map.borrow();
834     let raw_vtables = vtable_map.get().find(&id);
835     raw_vtables.map(|vts| resolve_vtables_in_fn_ctxt(bcx.fcx, *vts))
836 }
837
838 // Apply the typaram substitutions in the FunctionContext to some
839 // vtables. This should eliminate any vtable_params.
840 pub fn resolve_vtables_in_fn_ctxt(fcx: &FunctionContext, vts: typeck::vtable_res)
841     -> typeck::vtable_res {
842     resolve_vtables_under_param_substs(fcx.ccx.tcx,
843                                        fcx.param_substs,
844                                        vts)
845 }
846
847 pub fn resolve_vtables_under_param_substs(tcx: ty::ctxt,
848                                           param_substs: Option<@param_substs>,
849                                           vts: typeck::vtable_res)
850     -> typeck::vtable_res {
851     @vts.iter().map(|ds|
852       resolve_param_vtables_under_param_substs(tcx,
853                                                param_substs,
854                                                *ds))
855         .collect()
856 }
857
858 pub fn resolve_param_vtables_under_param_substs(
859     tcx: ty::ctxt,
860     param_substs: Option<@param_substs>,
861     ds: typeck::vtable_param_res)
862     -> typeck::vtable_param_res {
863     @ds.iter().map(
864         |d| resolve_vtable_under_param_substs(tcx,
865                                               param_substs,
866                                               d))
867         .collect()
868 }
869
870
871
872 pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt,
873                                          param_substs: Option<@param_substs>,
874                                          vt: &typeck::vtable_origin)
875                                          -> typeck::vtable_origin {
876     match *vt {
877         typeck::vtable_static(trait_id, ref tys, sub) => {
878             let tys = match param_substs {
879                 Some(substs) => {
880                     tys.iter().map(|t| {
881                         ty::subst_tps(tcx, substs.tys, substs.self_ty, *t)
882                     }).collect()
883                 }
884                 _ => tys.to_owned()
885             };
886             typeck::vtable_static(
887                 trait_id, tys,
888                 resolve_vtables_under_param_substs(tcx, param_substs, sub))
889         }
890         typeck::vtable_param(n_param, n_bound) => {
891             match param_substs {
892                 Some(substs) => {
893                     find_vtable(tcx, substs, n_param, n_bound)
894                 }
895                 _ => {
896                     tcx.sess.bug(format!(
897                         "resolve_vtable_under_param_substs: asked to lookup \
898                          but no vtables in the fn_ctxt!"))
899                 }
900             }
901         }
902     }
903 }
904
905 pub fn find_vtable(tcx: ty::ctxt,
906                    ps: &param_substs,
907                    n_param: typeck::param_index,
908                    n_bound: uint)
909                    -> typeck::vtable_origin {
910     debug!("find_vtable(n_param={:?}, n_bound={}, ps={})",
911            n_param, n_bound, ps.repr(tcx));
912
913     let param_bounds = match n_param {
914         typeck::param_self => ps.self_vtables.expect("self vtables missing"),
915         typeck::param_numbered(n) => {
916             let tables = ps.vtables
917                 .expect("vtables missing where they are needed");
918             tables[n]
919         }
920     };
921     param_bounds[n_bound].clone()
922 }
923
924 pub fn dummy_substs(tps: ~[ty::t]) -> ty::substs {
925     substs {
926         regions: ty::ErasedRegions,
927         self_ty: None,
928         tps: tps
929     }
930 }
931
932 pub fn filename_and_line_num_from_span(bcx: &Block, span: Span)
933                                        -> (ValueRef, ValueRef) {
934     let loc = bcx.sess().parse_sess.cm.lookup_char_pos(span.lo);
935     let filename_cstr = C_cstr(bcx.ccx(),
936                                token::intern_and_get_ident(loc.file.name));
937     let filename = build::PointerCast(bcx, filename_cstr, Type::i8p());
938     let line = C_int(bcx.ccx(), loc.line as int);
939     (filename, line)
940 }
941
942 // Casts a Rust bool value to an i1.
943 pub fn bool_to_i1(bcx: &Block, llval: ValueRef) -> ValueRef {
944     build::ICmp(bcx, lib::llvm::IntNE, llval, C_bool(false))
945 }
946
947 pub fn langcall(bcx: &Block,
948                 span: Option<Span>,
949                 msg: &str,
950                 li: LangItem)
951                 -> ast::DefId {
952     match bcx.tcx().lang_items.require(li) {
953         Ok(id) => id,
954         Err(s) => {
955             let msg = format!("{} {}", msg, s);
956             match span {
957                 Some(span) => { bcx.tcx().sess.span_fatal(span, msg); }
958                 None => { bcx.tcx().sess.fatal(msg); }
959             }
960         }
961     }
962 }