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.
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.
13 Code that is useful in various trans modules.
17 use back::{abi, upcall};
19 use driver::session::Session;
20 use lib::llvm::{ModuleRef, ValueRef, TypeRef, BasicBlockRef, BuilderRef};
21 use lib::llvm::{True, False, Bool};
22 use lib::llvm::{llvm, TargetData, TypeNames, associate_type, name_has_type};
24 use metadata::common::LinkMeta;
25 use middle::astencode;
27 use middle::trans::adt;
28 use middle::trans::base;
29 use middle::trans::build;
30 use middle::trans::callee;
31 use middle::trans::datum;
32 use middle::trans::debuginfo;
33 use middle::trans::expr;
34 use middle::trans::glue;
35 use middle::trans::reachable;
36 use middle::trans::shape;
37 use middle::trans::type_of;
38 use middle::trans::type_use;
39 use middle::ty::substs;
42 use util::ppaux::{Repr};
44 use core::cast::transmute;
46 use core::hashmap::{HashMap, HashSet};
47 use core::libc::{c_uint, c_longlong, c_ulonglong};
49 use core::vec::raw::to_ptr;
50 use syntax::ast::ident;
51 use syntax::ast_map::{path, path_elt};
52 use syntax::codemap::span;
53 use syntax::parse::token::ident_interner;
54 use syntax::{ast, ast_map};
55 use syntax::abi::{X86, X86_64, Arm, Mips};
57 pub type namegen = @fn(s: ~str) -> ident;
58 pub fn new_namegen(intr: @ident_interner) -> namegen {
59 let f: @fn(s: ~str) -> ident = |prefix| {
60 intr.gensym(@fmt!("%s_%u",
62 intr.gensym(@prefix).repr))
67 pub type addrspace = c_uint;
69 // Address spaces communicate to LLVM which destructors need to run for
71 // 0 is ignored by the GC, and is used for all non-GC'd pointers.
72 // 1 is for opaque GC'd boxes.
73 // >= 2 are for specific types (e.g. resources).
74 pub static default_addrspace: addrspace = 0;
75 pub static gc_box_addrspace: addrspace = 1;
77 pub type addrspace_gen = @fn() -> addrspace;
78 pub fn new_addrspace_gen() -> addrspace_gen {
80 let result: addrspace_gen = || { *i += 1; *i };
84 pub struct tydesc_info {
90 take_glue: Option<ValueRef>,
91 drop_glue: Option<ValueRef>,
92 free_glue: Option<ValueRef>,
93 visit_glue: Option<ValueRef>
97 * A note on nomenclature of linking: "extern", "foreign", and "upcall".
99 * An "extern" is an LLVM symbol we wind up emitting an undefined external
100 * reference to. This means "we don't have the thing in this compilation unit,
101 * please make sure you link it in at runtime". This could be a reference to
102 * C code found in a C library, or rust code found in a rust crate.
104 * Most "externs" are implicitly declared (automatically) as a result of a
105 * user declaring an extern _module_ dependency; this causes the rust driver
106 * to locate an extern crate, scan its compilation metadata, and emit extern
107 * declarations for any symbols used by the declaring crate.
109 * A "foreign" is an extern that references C (or other non-rust ABI) code.
110 * There is no metadata to scan for extern references so in these cases either
111 * a header-digester like bindgen, or manual function prototypes, have to
112 * serve as declarators. So these are usually given explicitly as prototype
113 * declarations, in rust code, with ABI attributes on them noting which ABI to
116 * An "upcall" is a foreign call generated by the compiler (not corresponding
117 * to any user-written call in the code) into the runtime library, to perform
118 * some helper task such as bringing a task to life, allocating memory, etc.
123 n_static_tydescs: uint,
124 n_glues_created: uint,
131 llvm_insn_ctxt: @mut ~[~str],
132 llvm_insns: @mut HashMap<~str, uint>,
133 fn_times: @mut ~[(~str, int)] // (ident, time)
136 pub struct BuilderRef_res {
140 impl Drop for BuilderRef_res {
143 llvm::LLVMDisposeBuilder(self.B);
148 pub fn BuilderRef_res(B: BuilderRef) -> BuilderRef_res {
154 pub type ExternMap = @mut HashMap<@str, ValueRef>;
156 // Crate context. Every crate we compile has one of these.
157 pub struct CrateContext {
158 sess: session::Session,
163 intrinsics: HashMap<~str, ValueRef>,
164 item_vals: @mut HashMap<ast::node_id, ValueRef>,
165 exp_map2: resolve::ExportMap2,
166 reachable: reachable::map,
167 item_symbols: @mut HashMap<ast::node_id, ~str>,
169 enum_sizes: @mut HashMap<ty::t, uint>,
170 discrims: @mut HashMap<ast::def_id, ValueRef>,
171 discrim_symbols: @mut HashMap<ast::node_id, @~str>,
172 tydescs: @mut HashMap<ty::t, @mut tydesc_info>,
173 // Set when running emit_tydescs to enforce that no more tydescs are
175 finished_tydescs: @mut bool,
176 // Track mapping of external ids to local items imported for inlining
177 external: @mut HashMap<ast::def_id, Option<ast::node_id>>,
178 // Cache instances of monomorphized functions
179 monomorphized: @mut HashMap<mono_id, ValueRef>,
180 monomorphizing: @mut HashMap<ast::def_id, uint>,
181 // Cache computed type parameter uses (see type_use.rs)
182 type_use_cache: @mut HashMap<ast::def_id, @~[type_use::type_uses]>,
183 // Cache generated vtables
184 vtables: @mut HashMap<mono_id, ValueRef>,
185 // Cache of constant strings,
186 const_cstr_cache: @mut HashMap<@~str, ValueRef>,
188 // Reverse-direction for const ptrs cast from globals.
189 // Key is an int, cast from a ValueRef holding a *T,
190 // Val is a ValueRef holding a *[T].
192 // Needed because LLVM loses pointer->pointee association
193 // when we ptrcast, and we have to ptrcast during translation
194 // of a [T] const because we form a slice, a [*T,int] pair, not
195 // a pointer to an LLVM array type.
196 const_globals: @mut HashMap<int, ValueRef>,
198 // Cache of emitted const values
199 const_values: @mut HashMap<ast::node_id, ValueRef>,
201 // Cache of external const values
202 extern_const_values: @mut HashMap<ast::def_id, ValueRef>,
204 module_data: @mut HashMap<~str, ValueRef>,
205 lltypes: @mut HashMap<ty::t, TypeRef>,
206 llsizingtypes: @mut HashMap<ty::t, TypeRef>,
207 adt_reprs: @mut HashMap<ty::t, @adt::Repr>,
209 next_addrspace: addrspace_gen,
210 symbol_hasher: @hash::State,
211 type_hashcodes: @mut HashMap<ty::t, @str>,
212 type_short_names: @mut HashMap<ty::t, ~str>,
213 all_llvm_symbols: @mut HashSet<@~str>,
215 maps: astencode::Maps,
217 upcalls: @upcall::Upcalls,
218 tydesc_type: TypeRef,
222 opaque_vec_type: TypeRef,
223 builder: BuilderRef_res,
224 shape_cx: shape::Ctxt,
226 // Set when at least one function uses GC. Needed so that
227 // decl_gc_metadata knows whether to link to the module metadata, which
228 // is not emitted by LLVM's GC pass when no functions use GC.
230 dbg_cx: Option<debuginfo::DebugContext>,
231 do_not_commit_warning_issued: @mut bool
234 // Types used for llself.
235 pub struct ValSelfData {
241 pub enum local_val { local_mem(ValueRef), local_imm(ValueRef), }
243 // Here `self_ty` is the real type of the self parameter to this method. It
244 // will only be set in the case of default methods.
245 pub struct param_substs {
247 vtables: Option<typeck::vtable_res>,
248 type_param_defs: @~[ty::TypeParameterDef],
249 self_ty: Option<ty::t>
252 pub impl param_substs {
254 for self.tys.each |t| { assert!(!ty::type_needs_infer(*t)); }
255 for self.self_ty.each |t| { assert!(!ty::type_needs_infer(*t)); }
259 fn param_substs_to_str(self: ¶m_substs,
260 tcx: ty::ctxt) -> ~str
262 fmt!("param_substs {tys:%s, vtables:%s, type_param_defs:%s}",
264 self.vtables.repr(tcx),
265 self.type_param_defs.repr(tcx))
268 impl Repr for param_substs {
269 fn repr(&self, tcx: ty::ctxt) -> ~str {
270 param_substs_to_str(self, tcx)
274 impl Repr for @param_substs {
275 fn repr(&self, tcx: ty::ctxt) -> ~str {
276 param_substs_to_str(*self, tcx)
280 // Function context. Every LLVM function we create will have one of
282 pub struct fn_ctxt_ {
283 // The ValueRef returned from a call to llvm::LLVMAddFunction; the
284 // address of the first instruction in the sequence of
285 // instructions for this function that will go in the .text
286 // section of the executable we're generating.
289 // The implicit environment argument that arrives in the function we're
293 // The place to store the return value. If the return type is immediate,
294 // this is an alloca in the function. Otherwise, it's the hidden first
295 // parameter to the function. After function construction, this should
297 llretptr: Option<ValueRef>,
299 // These elements: "hoisted basic blocks" containing
300 // administrative activities that have to happen in only one place in
301 // the function, due to LLVM's quirks.
302 // A block for all the function's static allocas, so that LLVM
303 // will coalesce them into a single alloca call.
304 llstaticallocas: BasicBlockRef,
305 // A block containing code that copies incoming arguments to space
306 // already allocated by code in one of the llallocas blocks.
307 // (LLVM requires that arguments be copied to local allocas before
308 // allowing most any operation to be performed on them.)
309 llloadenv: Option<BasicBlockRef>,
310 llreturn: BasicBlockRef,
311 // The 'self' value currently in use in this function, if there
314 // NB: This is the type of the self *variable*, not the self *type*. The
315 // self type is set only for default methods, while the self variable is
316 // set for all methods.
317 llself: Option<ValSelfData>,
318 // The a value alloca'd for calls to upcalls.rust_personality. Used when
319 // outputting the resume instruction.
320 personality: Option<ValueRef>,
321 // If this is a for-loop body that returns, this holds the pointers needed
322 // for that (flagptr, retptr)
323 loop_ret: Option<(ValueRef, ValueRef)>,
325 // True if this function has an immediate return value, false otherwise.
326 // If this is false, the llretptr will alias the first argument of the
328 has_immediate_return_value: bool,
330 // Maps arguments to allocas created for them in llallocas.
331 llargs: @mut HashMap<ast::node_id, local_val>,
332 // Maps the def_ids for local variables to the allocas created for
333 // them in llallocas.
334 lllocals: @mut HashMap<ast::node_id, local_val>,
335 // Same as above, but for closure upvars
336 llupvars: @mut HashMap<ast::node_id, ValueRef>,
338 // The node_id of the function, or -1 if it doesn't correspond to
339 // a user-defined function.
342 // The def_id of the impl we're inside, or None if we aren't inside one.
343 impl_id: Option<ast::def_id>,
345 // If this function is being monomorphized, this contains the type
346 // substitutions used.
347 param_substs: Option<@param_substs>,
349 // The source span and nesting context where this function comes from, for
350 // error reporting and symbol generation.
354 // This function's enclosing crate context.
358 pub type fn_ctxt = @mut fn_ctxt_;
360 pub fn warn_not_to_commit(ccx: @CrateContext, msg: &str) {
361 if !*ccx.do_not_commit_warning_issued {
362 *ccx.do_not_commit_warning_issued = true;
363 ccx.sess.warn(msg.to_str() + ~" -- do not commit like this!");
367 // Heap selectors. Indicate which heap something should go on.
378 normal_exit_and_unwind
382 clean(@fn(block) -> block, cleantype),
383 clean_temp(ValueRef, @fn(block) -> block, cleantype),
386 // Used to remember and reuse existing cleanup paths
387 // target: none means the path ends in an resume instruction
388 pub struct cleanup_path {
389 target: Option<BasicBlockRef>,
393 pub fn scope_clean_changed(scope_info: &mut scope_info) {
394 if scope_info.cleanup_paths.len() > 0u { scope_info.cleanup_paths = ~[]; }
395 scope_info.landing_pad = None;
398 pub fn cleanup_type(cx: ty::ctxt, ty: ty::t) -> cleantype {
399 if ty::type_needs_unwind_cleanup(cx, ty) {
400 normal_exit_and_unwind
406 // This is not the same as datum::Datum::root(), which is used to keep copies
407 // of @ values live for as long as a borrowed pointer to the interior exists.
408 // In the new GC, we can identify immediates on the stack without difficulty,
409 // but have trouble knowing where non-immediates are on the stack. For
410 // non-immediates, we must add an additional level of indirection, which
411 // allows us to alloca a pointer with the right addrspace.
412 pub fn root_for_cleanup(bcx: block, v: ValueRef, t: ty::t)
413 -> (ValueRef, bool) {
416 let addrspace = base::get_tydesc(ccx, t).addrspace;
417 if addrspace > gc_box_addrspace {
418 let llty = type_of::type_of_rooted(ccx, t);
419 let root = base::alloca(bcx, llty);
420 build::Store(bcx, build::PointerCast(bcx, v, llty), root);
427 pub fn add_clean(bcx: block, val: ValueRef, t: ty::t) {
428 if !ty::type_needs_drop(bcx.tcx(), t) { return; }
429 debug!("add_clean(%s, %s, %s)",
431 val_str(bcx.ccx().tn, val),
433 let (root, rooted) = root_for_cleanup(bcx, val, t);
434 let cleanup_type = cleanup_type(bcx.tcx(), t);
435 do in_scope_cx(bcx) |scope_info| {
436 scope_info.cleanups.push(
437 clean(|a| glue::drop_ty_root(a, root, rooted, t),
439 scope_clean_changed(scope_info);
443 pub fn add_clean_temp_immediate(cx: block, val: ValueRef, ty: ty::t) {
444 if !ty::type_needs_drop(cx.tcx(), ty) { return; }
445 debug!("add_clean_temp_immediate(%s, %s, %s)",
446 cx.to_str(), val_str(cx.ccx().tn, val),
448 let cleanup_type = cleanup_type(cx.tcx(), ty);
449 do in_scope_cx(cx) |scope_info| {
450 scope_info.cleanups.push(
451 clean_temp(val, |a| glue::drop_ty_immediate(a, val, ty),
453 scope_clean_changed(scope_info);
456 pub fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) {
457 if !ty::type_needs_drop(bcx.tcx(), t) { return; }
458 debug!("add_clean_temp_mem(%s, %s, %s)",
459 bcx.to_str(), val_str(bcx.ccx().tn, val),
461 let (root, rooted) = root_for_cleanup(bcx, val, t);
462 let cleanup_type = cleanup_type(bcx.tcx(), t);
463 do in_scope_cx(bcx) |scope_info| {
464 scope_info.cleanups.push(
465 clean_temp(val, |a| glue::drop_ty_root(a, root, rooted, t),
467 scope_clean_changed(scope_info);
470 pub fn add_clean_frozen_root(bcx: block, val: ValueRef, t: ty::t) {
471 debug!("add_clean_frozen_root(%s, %s, %s)",
472 bcx.to_str(), val_str(bcx.ccx().tn, val),
474 let (root, rooted) = root_for_cleanup(bcx, val, t);
475 let cleanup_type = cleanup_type(bcx.tcx(), t);
476 do in_scope_cx(bcx) |scope_info| {
477 scope_info.cleanups.push(
478 clean_temp(val, |bcx| {
479 let bcx = callee::trans_lang_call(
481 bcx.tcx().lang_items.return_to_mut_fn(),
484 build::PointerCast(bcx,
486 T_ptr(T_ptr(T_i8()))))
490 glue::drop_ty_root(bcx, root, rooted, t)
492 scope_clean_changed(scope_info);
495 pub fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) {
496 let free_fn = match heap {
497 heap_managed | heap_managed_unique => {
498 let f: @fn(block) -> block = |a| glue::trans_free(a, ptr);
502 let f: @fn(block) -> block = |a| glue::trans_exchange_free(a, ptr);
506 do in_scope_cx(cx) |scope_info| {
507 scope_info.cleanups.push(clean_temp(ptr, free_fn,
508 normal_exit_and_unwind));
509 scope_clean_changed(scope_info);
513 // Note that this only works for temporaries. We should, at some point, move
514 // to a system where we can also cancel the cleanup on local variables, but
515 // this will be more involved. For now, we simply zero out the local, and the
516 // drop glue checks whether it is zero.
517 pub fn revoke_clean(cx: block, val: ValueRef) {
518 do in_scope_cx(cx) |scope_info| {
519 let cleanup_pos = vec::position(
522 clean_temp(v, _, _) if v == val => true,
525 for cleanup_pos.each |i| {
526 scope_info.cleanups =
527 vec::append(vec::slice(scope_info.cleanups, 0u, *i).to_vec(),
528 vec::slice(scope_info.cleanups,
530 scope_info.cleanups.len()));
531 scope_clean_changed(scope_info);
536 pub fn block_cleanups(bcx: block) -> ~[cleanup] {
538 block_non_scope => ~[],
539 block_scope(ref mut inf) => /*bad*/copy inf.cleanups
543 pub enum block_kind {
544 // A scope at the end of which temporary values created inside of it are
545 // cleaned up. May correspond to an actual block in the language, but also
546 // to an implicit scope, for example, calls introduce an implicit scope in
547 // which the arguments are evaluated and cleaned up.
548 block_scope(scope_info),
550 // A non-scope block is a basic block created as a translation artifact
551 // from translating code that expresses conditional logic rather than by
552 // explicit { ... } block structure in the source language. It's called a
553 // non-scope block because it doesn't introduce a new variable scope.
557 pub struct scope_info {
558 loop_break: Option<block>,
559 loop_label: Option<ident>,
560 // A list of functions that must be run at when leaving this
561 // block, cleaning up any variables that were introduced in the
563 cleanups: ~[cleanup],
564 // Existing cleanup paths that may be reused, indexed by destination and
565 // cleared when the set of cleanups changes.
566 cleanup_paths: ~[cleanup_path],
567 // Unwinding landing pad. Also cleared when cleanups change.
568 landing_pad: Option<BasicBlockRef>,
571 pub trait get_node_info {
572 fn info(&self) -> Option<NodeInfo>;
575 impl get_node_info for @ast::expr {
576 fn info(&self) -> Option<NodeInfo> {
577 Some(NodeInfo { id: self.id, span: self.span })
581 impl get_node_info for ast::blk {
582 fn info(&self) -> Option<NodeInfo> {
583 Some(NodeInfo { id: self.node.id, span: self.span })
587 impl get_node_info for Option<@ast::expr> {
588 fn info(&self) -> Option<NodeInfo> {
589 self.chain_ref(|s| s.info())
593 pub struct NodeInfo {
598 // Basic block context. We create a block context for each basic block
599 // (single-entry, single-exit sequence of instructions) we generate from Rust
600 // code. Each basic block we generate is attached to a function, typically
601 // with many basic blocks per function. All the basic blocks attached to a
602 // function are organized as a directed graph.
604 // The BasicBlockRef returned from a call to
605 // llvm::LLVMAppendBasicBlock(llfn, name), which adds a basic
606 // block to the function pointed to by llfn. We insert
607 // instructions into that block by way of this block context.
608 // The block pointing to this one in the function's digraph.
612 parent: Option<block>,
613 // The 'kind' of basic block this is.
614 kind: @mut block_kind,
615 // Is this block part of a landing pad?
617 // info about the AST node this block originated from, if any
618 node_info: Option<NodeInfo>,
619 // The function context for the function to which this block is
624 pub fn block_(llbb: BasicBlockRef, parent: Option<block>, kind: block_kind,
625 is_lpad: bool, node_info: Option<NodeInfo>, fcx: fn_ctxt)
635 node_info: node_info,
640 pub type block = @mut block_;
642 pub fn mk_block(llbb: BasicBlockRef, parent: Option<block>, kind: block_kind,
643 is_lpad: bool, node_info: Option<NodeInfo>, fcx: fn_ctxt)
645 @mut block_(llbb, parent, kind, is_lpad, node_info, fcx)
648 // First two args are retptr, env
649 pub static first_real_arg: uint = 2u;
656 pub fn rslt(bcx: block, val: ValueRef) -> Result {
657 Result {bcx: bcx, val: val}
661 fn unpack(&self, bcx: &mut block) -> ValueRef {
667 pub fn ty_str(tn: @TypeNames, t: TypeRef) -> @str {
668 return lib::llvm::type_to_str(tn, t);
671 pub fn val_ty(v: ValueRef) -> TypeRef {
673 return llvm::LLVMTypeOf(v);
677 pub fn val_str(tn: @TypeNames, v: ValueRef) -> @str {
678 return ty_str(tn, val_ty(v));
681 pub fn in_scope_cx(cx: block, f: &fn(si: &mut scope_info)) {
685 // XXX: Borrow check bug workaround.
686 let kind: &mut block_kind = &mut *cur.kind;
688 block_scope(ref mut inf) => {
689 debug!("in_scope_cx: selected cur=%s (cx=%s)",
690 cur.to_str(), cx.to_str());
697 cur = block_parent(cur);
701 pub fn block_parent(cx: block) -> block {
704 None => cx.sess().bug(fmt!("block_parent called on root block %?",
712 fn ccx(@mut self) -> @CrateContext { *self.fcx.ccx }
713 fn tcx(@mut self) -> ty::ctxt { self.fcx.ccx.tcx }
714 fn sess(@mut self) -> Session { self.fcx.ccx.sess }
716 fn node_id_to_str(@mut self, id: ast::node_id) -> ~str {
717 ast_map::node_id_to_str(self.tcx().items, id, self.sess().intr())
720 fn expr_to_str(@mut self, e: @ast::expr) -> ~str {
724 fn expr_is_lval(@mut self, e: @ast::expr) -> bool {
725 ty::expr_is_lval(self.tcx(), self.ccx().maps.method_map, e)
728 fn expr_kind(@mut self, e: @ast::expr) -> ty::ExprKind {
729 ty::expr_kind(self.tcx(), self.ccx().maps.method_map, e)
732 fn def(@mut self, nid: ast::node_id) -> ast::def {
733 match self.tcx().def_map.find(&nid) {
736 self.tcx().sess.bug(fmt!(
737 "No def associated with node id %?", nid));
742 fn val_str(@mut self, val: ValueRef) -> @str {
743 val_str(self.ccx().tn, val)
746 fn llty_str(@mut self, llty: TypeRef) -> @str {
747 ty_str(self.ccx().tn, llty)
750 fn ty_to_str(@mut self, t: ty::t) -> ~str {
753 fn to_str(@mut self) -> ~str {
755 match self.node_info {
756 Some(node_info) => fmt!("[block %d]", node_info.id),
757 None => fmt!("[block %x]", transmute(&*self)),
763 // LLVM type constructors.
764 pub fn T_void() -> TypeRef {
766 return llvm::LLVMVoidType();
770 pub fn T_nil() -> TypeRef {
771 return T_struct(~[], false)
774 pub fn T_metadata() -> TypeRef { unsafe { return llvm::LLVMMetadataType(); } }
776 pub fn T_i1() -> TypeRef { unsafe { return llvm::LLVMInt1Type(); } }
778 pub fn T_i8() -> TypeRef { unsafe { return llvm::LLVMInt8Type(); } }
780 pub fn T_i16() -> TypeRef { unsafe { return llvm::LLVMInt16Type(); } }
782 pub fn T_i32() -> TypeRef { unsafe { return llvm::LLVMInt32Type(); } }
784 pub fn T_i64() -> TypeRef { unsafe { return llvm::LLVMInt64Type(); } }
786 pub fn T_f32() -> TypeRef { unsafe { return llvm::LLVMFloatType(); } }
788 pub fn T_f64() -> TypeRef { unsafe { return llvm::LLVMDoubleType(); } }
790 pub fn T_bool() -> TypeRef { return T_i8(); }
792 pub fn T_int(targ_cfg: @session::config) -> TypeRef {
793 return match targ_cfg.arch {
801 pub fn T_int_ty(cx: @CrateContext, t: ast::int_ty) -> TypeRef {
803 ast::ty_i => cx.int_type,
804 ast::ty_char => T_char(),
805 ast::ty_i8 => T_i8(),
806 ast::ty_i16 => T_i16(),
807 ast::ty_i32 => T_i32(),
808 ast::ty_i64 => T_i64()
812 pub fn T_uint_ty(cx: @CrateContext, t: ast::uint_ty) -> TypeRef {
814 ast::ty_u => cx.int_type,
815 ast::ty_u8 => T_i8(),
816 ast::ty_u16 => T_i16(),
817 ast::ty_u32 => T_i32(),
818 ast::ty_u64 => T_i64()
822 pub fn T_float_ty(cx: @CrateContext, t: ast::float_ty) -> TypeRef {
824 ast::ty_f => cx.float_type,
825 ast::ty_f32 => T_f32(),
826 ast::ty_f64 => T_f64()
830 pub fn T_float(targ_cfg: @session::config) -> TypeRef {
831 return match targ_cfg.arch {
839 pub fn T_char() -> TypeRef { return T_i32(); }
841 pub fn T_size_t(targ_cfg: @session::config) -> TypeRef {
842 return T_int(targ_cfg);
845 pub fn T_fn(inputs: &[TypeRef], output: TypeRef) -> TypeRef {
847 return llvm::LLVMFunctionType(output, to_ptr(inputs),
848 inputs.len() as c_uint,
853 pub fn T_fn_pair(cx: @CrateContext, tfn: TypeRef) -> TypeRef {
854 return T_struct(~[T_ptr(tfn), T_opaque_cbox_ptr(cx)], false);
857 pub fn T_ptr(t: TypeRef) -> TypeRef {
859 return llvm::LLVMPointerType(t, default_addrspace);
863 pub fn T_root(t: TypeRef, addrspace: addrspace) -> TypeRef {
865 return llvm::LLVMPointerType(t, addrspace);
869 pub fn T_struct(elts: &[TypeRef], packed: bool) -> TypeRef {
871 return llvm::LLVMStructType(to_ptr(elts),
872 elts.len() as c_uint,
877 pub fn T_named_struct(name: &str) -> TypeRef {
879 let c = llvm::LLVMGetGlobalContext();
880 return str::as_c_str(name, |buf| llvm::LLVMStructCreateNamed(c, buf));
884 pub fn set_struct_body(t: TypeRef, elts: &[TypeRef], packed: bool) {
886 llvm::LLVMStructSetBody(t,
888 elts.len() as c_uint,
893 pub fn T_empty_struct() -> TypeRef { return T_struct(~[], false); }
895 // A vtable is, in reality, a vtable pointer followed by zero or more pointers
896 // to tydescs and other vtables that it closes over. But the types and number
897 // of those are rarely known to the code that needs to manipulate them, so
898 // they are described by this opaque type.
899 pub fn T_vtable() -> TypeRef { T_array(T_ptr(T_i8()), 1u) }
901 pub fn T_task(targ_cfg: @session::config) -> TypeRef {
902 let t = T_named_struct(~"task");
906 // Stack segment pointer
913 // Crate cache pointer
915 let t_int = T_int(targ_cfg);
917 ~[t_int, t_int, t_int, t_int,
918 t_int, t_int, t_int, t_int];
919 set_struct_body(t, elems, false);
923 pub fn T_tydesc_field(cx: @CrateContext, field: uint) -> TypeRef {
924 // Bit of a kludge: pick the fn typeref out of the tydesc..
927 let mut tydesc_elts: ~[TypeRef] =
928 vec::from_elem::<TypeRef>(abi::n_tydesc_fields,
930 llvm::LLVMGetStructElementTypes(
932 ptr::to_mut_unsafe_ptr(&mut tydesc_elts[0]));
933 let t = llvm::LLVMGetElementType(tydesc_elts[field]);
938 pub fn T_generic_glue_fn(cx: @CrateContext) -> TypeRef {
940 match name_has_type(cx.tn, s) {
944 let t = T_tydesc_field(cx, abi::tydesc_field_drop_glue);
945 associate_type(cx.tn, s, t);
949 pub fn T_tydesc(targ_cfg: @session::config) -> TypeRef {
950 let tydesc = T_named_struct(~"tydesc");
951 let tydescpp = T_ptr(T_ptr(tydesc));
952 let pvoid = T_ptr(T_i8());
954 T_ptr(T_fn(~[T_ptr(T_nil()), T_ptr(T_nil()), tydescpp,
957 let int_type = T_int(targ_cfg);
959 ~[int_type, int_type,
960 glue_fn_ty, glue_fn_ty, glue_fn_ty, glue_fn_ty,
961 T_ptr(T_i8()), T_ptr(T_i8())];
962 set_struct_body(tydesc, elems, false);
966 pub fn T_array(t: TypeRef, n: uint) -> TypeRef {
968 return llvm::LLVMArrayType(t, n as c_uint);
973 pub fn T_vec2(targ_cfg: @session::config, t: TypeRef) -> TypeRef {
974 return T_struct(~[T_int(targ_cfg), // fill
975 T_int(targ_cfg), // alloc
976 T_array(t, 0u)], // elements
980 pub fn T_vec(ccx: @CrateContext, t: TypeRef) -> TypeRef {
981 return T_vec2(ccx.sess.targ_cfg, t);
984 // Note that the size of this one is in bytes.
985 pub fn T_opaque_vec(targ_cfg: @session::config) -> TypeRef {
986 return T_vec2(targ_cfg, T_i8());
989 // Let T be the content of a box @T. tuplify_box_ty(t) returns the
990 // representation of @T as a tuple (i.e., the ty::t version of what T_box()
992 pub fn tuplify_box_ty(tcx: ty::ctxt, t: ty::t) -> ty::t {
993 let ptr = ty::mk_ptr(
995 ty::mt {ty: ty::mk_nil(), mutbl: ast::m_imm}
997 return ty::mk_tup(tcx, ~[ty::mk_uint(), ty::mk_type(tcx),
1002 pub fn T_box_header_fields(cx: @CrateContext) -> ~[TypeRef] {
1003 let ptr = T_ptr(T_i8());
1004 return ~[cx.int_type, T_ptr(cx.tydesc_type), ptr, ptr];
1007 pub fn T_box_header(cx: @CrateContext) -> TypeRef {
1008 return T_struct(T_box_header_fields(cx), false);
1011 pub fn T_box(cx: @CrateContext, t: TypeRef) -> TypeRef {
1012 return T_struct(vec::append(T_box_header_fields(cx), ~[t]), false);
1015 pub fn T_box_ptr(t: TypeRef) -> TypeRef {
1017 return llvm::LLVMPointerType(t, gc_box_addrspace);
1021 pub fn T_opaque_box(cx: @CrateContext) -> TypeRef {
1022 return T_box(cx, T_i8());
1025 pub fn T_opaque_box_ptr(cx: @CrateContext) -> TypeRef {
1026 return T_box_ptr(T_opaque_box(cx));
1029 pub fn T_unique(cx: @CrateContext, t: TypeRef) -> TypeRef {
1030 return T_struct(vec::append(T_box_header_fields(cx), ~[t]), false);
1033 pub fn T_unique_ptr(t: TypeRef) -> TypeRef {
1035 return llvm::LLVMPointerType(t, gc_box_addrspace);
1039 pub fn T_port(cx: @CrateContext, _t: TypeRef) -> TypeRef {
1040 return T_struct(~[cx.int_type], false); // Refcount
1044 pub fn T_chan(cx: @CrateContext, _t: TypeRef) -> TypeRef {
1045 return T_struct(~[cx.int_type], false); // Refcount
1049 pub fn T_taskptr(cx: @CrateContext) -> TypeRef { return T_ptr(cx.task_type); }
1052 pub fn T_opaque_cbox_ptr(cx: @CrateContext) -> TypeRef {
1053 // closures look like boxes (even when they are ~fn or &fn)
1054 // see trans_closure.rs
1055 return T_opaque_box_ptr(cx);
1058 pub fn T_enum_discrim(cx: @CrateContext) -> TypeRef {
1062 pub fn T_captured_tydescs(cx: @CrateContext, n: uint) -> TypeRef {
1063 return T_struct(vec::from_elem::<TypeRef>(n, T_ptr(cx.tydesc_type)), false);
1066 pub fn T_opaque_trait(cx: @CrateContext, store: ty::TraitStore) -> TypeRef {
1068 ty::BoxTraitStore => {
1069 T_struct(~[T_ptr(cx.tydesc_type), T_opaque_box_ptr(cx)], false)
1071 ty::UniqTraitStore => {
1072 T_struct(~[T_ptr(cx.tydesc_type),
1073 T_unique_ptr(T_unique(cx, T_i8())),
1074 T_ptr(cx.tydesc_type)],
1077 ty::RegionTraitStore(_) => {
1078 T_struct(~[T_ptr(cx.tydesc_type), T_ptr(T_i8())], false)
1083 pub fn T_opaque_port_ptr() -> TypeRef { return T_ptr(T_i8()); }
1085 pub fn T_opaque_chan_ptr() -> TypeRef { return T_ptr(T_i8()); }
1088 // LLVM constant constructors.
1089 pub fn C_null(t: TypeRef) -> ValueRef {
1091 return llvm::LLVMConstNull(t);
1095 pub fn C_undef(t: TypeRef) -> ValueRef {
1097 return llvm::LLVMGetUndef(t);
1101 pub fn C_integral(t: TypeRef, u: u64, sign_extend: Bool) -> ValueRef {
1103 return llvm::LLVMConstInt(t, u, sign_extend);
1107 pub fn C_floating(s: &str, t: TypeRef) -> ValueRef {
1109 return str::as_c_str(s, |buf| llvm::LLVMConstRealOfString(t, buf));
1113 pub fn C_nil() -> ValueRef {
1114 return C_struct(~[]);
1117 pub fn C_bool(b: bool) -> ValueRef {
1118 C_integral(T_bool(), if b { 1u64 } else { 0u64 }, False)
1121 pub fn C_i1(b: bool) -> ValueRef {
1122 return C_integral(T_i1(), if b { 1 } else { 0 }, False);
1125 pub fn C_i32(i: i32) -> ValueRef {
1126 return C_integral(T_i32(), i as u64, True);
1129 pub fn C_i64(i: i64) -> ValueRef {
1130 return C_integral(T_i64(), i as u64, True);
1133 pub fn C_int(cx: @CrateContext, i: int) -> ValueRef {
1134 return C_integral(cx.int_type, i as u64, True);
1137 pub fn C_uint(cx: @CrateContext, i: uint) -> ValueRef {
1138 return C_integral(cx.int_type, i as u64, False);
1141 pub fn C_u8(i: uint) -> ValueRef {
1142 return C_integral(T_i8(), i as u64, False);
1146 // This is a 'c-like' raw string, which differs from
1147 // our boxed-and-length-annotated strings.
1148 pub fn C_cstr(cx: @CrateContext, s: @~str) -> ValueRef {
1150 match cx.const_cstr_cache.find(&s) {
1151 Some(&llval) => return llval,
1155 let sc = do str::as_c_str(*s) |buf| {
1156 llvm::LLVMConstString(buf, s.len() as c_uint, False)
1159 str::as_c_str(fmt!("str%u", (cx.names)(~"str").repr),
1160 |buf| llvm::LLVMAddGlobal(cx.llmod, val_ty(sc), buf));
1161 llvm::LLVMSetInitializer(g, sc);
1162 llvm::LLVMSetGlobalConstant(g, True);
1163 lib::llvm::SetLinkage(g, lib::llvm::InternalLinkage);
1165 cx.const_cstr_cache.insert(s, g);
1171 // NB: Do not use `do_spill_noroot` to make this into a constant string, or
1172 // you will be kicked off fast isel. See issue #4352 for an example of this.
1173 pub fn C_estr_slice(cx: @CrateContext, s: @~str) -> ValueRef {
1176 let cs = llvm::LLVMConstPointerCast(C_cstr(cx, s), T_ptr(T_i8()));
1177 C_struct(~[cs, C_uint(cx, len + 1u /* +1 for null */)])
1181 // Returns a Plain Old LLVM String:
1182 pub fn C_postr(s: &str) -> ValueRef {
1184 return do str::as_c_str(s) |buf| {
1185 llvm::LLVMConstString(buf, str::len(s) as c_uint, False)
1190 pub fn C_zero_byte_arr(size: uint) -> ValueRef {
1193 let mut elts: ~[ValueRef] = ~[];
1194 while i < size { elts.push(C_u8(0u)); i += 1u; }
1195 return llvm::LLVMConstArray(T_i8(),
1196 vec::raw::to_ptr(elts),
1197 elts.len() as c_uint);
1201 pub fn C_struct(elts: &[ValueRef]) -> ValueRef {
1203 do vec::as_imm_buf(elts) |ptr, len| {
1204 llvm::LLVMConstStruct(ptr, len as c_uint, False)
1209 pub fn C_packed_struct(elts: &[ValueRef]) -> ValueRef {
1211 do vec::as_imm_buf(elts) |ptr, len| {
1212 llvm::LLVMConstStruct(ptr, len as c_uint, True)
1217 pub fn C_named_struct(T: TypeRef, elts: &[ValueRef]) -> ValueRef {
1219 do vec::as_imm_buf(elts) |ptr, len| {
1220 llvm::LLVMConstNamedStruct(T, ptr, len as c_uint)
1225 pub fn C_array(ty: TypeRef, elts: &[ValueRef]) -> ValueRef {
1227 return llvm::LLVMConstArray(ty, vec::raw::to_ptr(elts),
1228 elts.len() as c_uint);
1232 pub fn C_bytes(bytes: &[u8]) -> ValueRef {
1234 return llvm::LLVMConstString(
1235 cast::transmute(vec::raw::to_ptr(bytes)),
1236 bytes.len() as c_uint, True);
1240 pub fn C_bytes_plus_null(bytes: &[u8]) -> ValueRef {
1242 return llvm::LLVMConstString(
1243 cast::transmute(vec::raw::to_ptr(bytes)),
1244 bytes.len() as c_uint, False);
1248 pub fn C_shape(ccx: @CrateContext, bytes: ~[u8]) -> ValueRef {
1250 let llshape = C_bytes_plus_null(bytes);
1251 let name = fmt!("shape%u", (ccx.names)(~"shape").repr);
1252 let llglobal = str::as_c_str(name, |buf| {
1253 llvm::LLVMAddGlobal(ccx.llmod, val_ty(llshape), buf)
1255 llvm::LLVMSetInitializer(llglobal, llshape);
1256 llvm::LLVMSetGlobalConstant(llglobal, True);
1257 lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage);
1258 return llvm::LLVMConstPointerCast(llglobal, T_ptr(T_i8()));
1262 pub fn get_param(fndecl: ValueRef, param: uint) -> ValueRef {
1264 llvm::LLVMGetParam(fndecl, param as c_uint)
1268 pub fn const_get_elt(cx: @CrateContext, v: ValueRef, us: &[c_uint])
1271 let r = do vec::as_imm_buf(us) |p, len| {
1272 llvm::LLVMConstExtractValue(v, p, len as c_uint)
1275 debug!("const_get_elt(v=%s, us=%?, r=%s)",
1276 val_str(cx.tn, v), us, val_str(cx.tn, r));
1282 pub fn const_to_int(v: ValueRef) -> c_longlong {
1284 llvm::LLVMConstIntGetSExtValue(v)
1288 pub fn const_to_uint(v: ValueRef) -> c_ulonglong {
1290 llvm::LLVMConstIntGetZExtValue(v)
1294 pub fn is_undef(val: ValueRef) -> bool {
1296 llvm::LLVMIsUndef(val) != False
1300 pub fn is_null(val: ValueRef) -> bool {
1302 llvm::LLVMIsNull(val) != False
1306 // Used to identify cached monomorphized functions and vtables
1308 pub enum mono_param_id {
1309 mono_precise(ty::t, Option<~[mono_id]>),
1311 mono_repr(uint /* size */,
1318 pub enum MonoDataClass {
1319 MonoBits, // Anything not treated differently from arbitrary integer data
1320 MonoNonNull, // Non-null pointers (used for optional-pointer optimization)
1321 // FIXME(#3547)---scalars and floats are
1322 // treated differently in most ABIs. But we
1323 // should be doing something more detailed
1328 pub fn mono_data_classify(t: ty::t) -> MonoDataClass {
1329 match ty::get(t).sty {
1330 ty::ty_float(_) => MonoFloat,
1331 ty::ty_rptr(*) | ty::ty_uniq(*) |
1332 ty::ty_box(*) | ty::ty_opaque_box(*) |
1333 ty::ty_estr(ty::vstore_uniq) | ty::ty_evec(_, ty::vstore_uniq) |
1334 ty::ty_estr(ty::vstore_box) | ty::ty_evec(_, ty::vstore_box) |
1335 ty::ty_bare_fn(*) => MonoNonNull,
1336 // Is that everything? Would closures or slices qualify?
1343 pub struct mono_id_ {
1345 params: ~[mono_param_id],
1346 impl_did_opt: Option<ast::def_id>
1349 pub type mono_id = @mono_id_;
1351 impl to_bytes::IterBytes for mono_param_id {
1352 fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
1354 mono_precise(t, ref mids) =>
1355 to_bytes::iter_bytes_3(&0u8, &ty::type_id(t), mids, lsb0, f),
1357 mono_any => 1u8.iter_bytes(lsb0, f),
1359 mono_repr(ref a, ref b, ref c, ref d) =>
1360 to_bytes::iter_bytes_5(&2u8, a, b, c, d, lsb0, f)
1365 impl to_bytes::IterBytes for MonoDataClass {
1366 fn iter_bytes(&self, lsb0: bool, f:to_bytes::Cb) {
1367 (*self as u8).iter_bytes(lsb0, f)
1371 impl to_bytes::IterBytes for mono_id_ {
1372 fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
1373 to_bytes::iter_bytes_2(&self.def, &self.params, lsb0, f);
1377 pub fn umax(cx: block, a: ValueRef, b: ValueRef) -> ValueRef {
1378 let cond = build::ICmp(cx, lib::llvm::IntULT, a, b);
1379 return build::Select(cx, cond, b, a);
1382 pub fn umin(cx: block, a: ValueRef, b: ValueRef) -> ValueRef {
1383 let cond = build::ICmp(cx, lib::llvm::IntULT, a, b);
1384 return build::Select(cx, cond, a, b);
1387 pub fn align_to(cx: block, off: ValueRef, align: ValueRef) -> ValueRef {
1388 let mask = build::Sub(cx, align, C_int(cx.ccx(), 1));
1389 let bumped = build::Add(cx, off, mask);
1390 return build::And(cx, bumped, build::Not(cx, mask));
1393 pub fn path_str(sess: session::Session, p: &[path_elt]) -> ~str {
1394 let mut r = ~"", first = true;
1397 ast_map::path_name(s) | ast_map::path_mod(s) => {
1398 if first { first = false; }
1399 else { r += ~"::"; }
1400 r += *sess.str_of(s);
1407 pub fn monomorphize_type(bcx: block, t: ty::t) -> ty::t {
1408 match bcx.fcx.param_substs {
1410 ty::subst_tps(bcx.tcx(), substs.tys, substs.self_ty, t)
1412 _ => { assert!(!ty::type_has_params(t)); t }
1416 pub fn node_id_type(bcx: block, id: ast::node_id) -> ty::t {
1417 let tcx = bcx.tcx();
1418 let t = ty::node_id_to_type(tcx, id);
1419 monomorphize_type(bcx, t)
1422 pub fn expr_ty(bcx: block, ex: @ast::expr) -> ty::t {
1423 node_id_type(bcx, ex.id)
1426 pub fn expr_ty_adjusted(bcx: block, ex: @ast::expr) -> ty::t {
1427 let tcx = bcx.tcx();
1428 let t = ty::expr_ty_adjusted(tcx, ex);
1429 monomorphize_type(bcx, t)
1432 pub fn node_id_type_params(bcx: block, id: ast::node_id) -> ~[ty::t] {
1433 let tcx = bcx.tcx();
1434 let params = ty::node_id_to_type_params(tcx, id);
1436 if !params.all(|t| !ty::type_needs_infer(*t)) {
1438 fmt!("Type parameters for node %d include inference types: %s",
1439 id, str::connect(params.map(|t| bcx.ty_to_str(*t)), ",")));
1442 match bcx.fcx.param_substs {
1444 do vec::map(params) |t| {
1445 ty::subst_tps(tcx, substs.tys, substs.self_ty, *t)
1452 pub fn node_vtables(bcx: block, id: ast::node_id)
1453 -> Option<typeck::vtable_res> {
1454 let raw_vtables = bcx.ccx().maps.vtable_map.find(&id);
1456 |&vts| resolve_vtables_in_fn_ctxt(bcx.fcx, *vts))
1459 pub fn resolve_vtables_in_fn_ctxt(fcx: fn_ctxt, vts: typeck::vtable_res)
1460 -> typeck::vtable_res {
1461 @vec::map(*vts, |d| resolve_vtable_in_fn_ctxt(fcx, copy *d))
1464 // Apply the typaram substitutions in the fn_ctxt to a vtable. This should
1465 // eliminate any vtable_params.
1466 pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
1467 -> typeck::vtable_origin {
1468 let tcx = fcx.ccx.tcx;
1470 typeck::vtable_static(trait_id, tys, sub) => {
1471 let tys = match fcx.param_substs {
1473 do vec::map(tys) |t| {
1474 ty::subst_tps(tcx, substs.tys, substs.self_ty, *t)
1479 typeck::vtable_static(trait_id, tys,
1480 resolve_vtables_in_fn_ctxt(fcx, sub))
1482 typeck::vtable_param(n_param, n_bound) => {
1483 match fcx.param_substs {
1485 find_vtable(tcx, substs, n_param, n_bound)
1489 "resolve_vtable_in_fn_ctxt: asked to lookup but \
1490 no vtables in the fn_ctxt!"))
1497 pub fn find_vtable(tcx: ty::ctxt, ps: ¶m_substs,
1498 n_param: uint, n_bound: uint)
1499 -> typeck::vtable_origin {
1500 debug!("find_vtable(n_param=%u, n_bound=%u, ps=%s)",
1501 n_param, n_bound, ps.repr(tcx));
1503 // Vtables are stored in a flat array, finding the right one is
1505 let first_n_type_param_defs = ps.type_param_defs.slice(0, n_param);
1506 let vtables_to_skip =
1507 ty::count_traits_and_supertraits(tcx, first_n_type_param_defs);
1508 let vtable_off = vtables_to_skip + n_bound;
1509 /*bad*/ copy ps.vtables.get()[vtable_off]
1512 pub fn dummy_substs(tps: ~[ty::t]) -> ty::substs {
1514 self_r: Some(ty::re_bound(ty::br_self)),
1520 // Casts a Rust bool value to an i1.
1521 pub fn bool_to_i1(bcx: block, llval: ValueRef) -> ValueRef {
1522 build::ICmp(bcx, lib::llvm::IntNE, llval, C_bool(false))
1529 // indent-tabs-mode: nil
1530 // c-basic-offset: 4
1531 // buffer-file-coding-system: utf-8-unix